|
|
View previous topic :: View next topic |
Author |
Message |
elcrcp
Joined: 11 Mar 2016 Posts: 62 Location: izmir / Turkey
|
is there an efficient way to write on a 16bit array item? |
Posted: Sat Jul 06, 2019 6:02 pm |
|
|
18f25k40 v5.081
Hello guys, I have a problem with 16 bit array coding. I have 3 arrays and each of them have 256 16bit items. What I do is reading a pin and writing that to related array item then shifting bits. (reading ADC output and writing to variable one by one). But it takes too many instruction lines to complete, 21 lines for 1 read. it takes only 4 lines per read if I use a normal 16 bit variables instead of arrays but then if i define 756 16bit variables and write reading code 256 times (can't use for loops with unique variable names of course) then my ram gets full, so I can't compile the code. I need to learn a way to use arrays much efficient, anyone has any idea about it?
array output
Code: |
........... sensor_data_1[pixel_pointer]|=input_state(ADC_outa); //read adc output
03BA: BCF FD8.0
03BC: RLCF 1E,W
03BE: MOVWF 02
03C0: RLCF 1F,W
03C2: MOVWF 03
03C4: MOVF 02,W
03C6: ADDLW 20
03C8: MOVWF FE9
03CA: MOVLW 00
03CC: ADDWFC 03,W
03CE: MOVWF FEA
03D0: MOVLW 00
03D2: BTFSC F8E.6
03D4: MOVLW 01
03D6: IORWF FEF,W
03D8: MOVWF 00
03DA: MOVFF FEC,03
03DE: MOVF 00,W
03E0: MOVF FED,F
03E2: MOVWF FEF
03E4: MOVFF 03,FEC |
variable output
Code: | ........... sensor_data_1_0|=input_state(ADC_outa); //read adc output
0362: MOVLW 00
0364: BTFSC F8E.6
0366: MOVLW 01
0368: IORWF 20,F |
array shifting
Code: |
............ sensor_data_1[pixel_pointer]=sensor_data_1[pixel_pointer]<<1; // shift data
0418: BCF FD8.0
041A: RLCF 1E,W
041C: MOVWF 02
041E: RLCF 1F,W
0420: MOVWF 03
0422: MOVF 02,W
0424: ADDLW 20
0426: MOVWF 01
0428: MOVLW 00
042A: ADDWFC 03,F
042C: MOVFF 03,627
0430: BCF FD8.0
0432: RLCF 1E,W
0434: MOVWF 02
0436: RLCF 1F,W
0438: MOVWF 03
043A: MOVF 02,W
043C: ADDLW 20
043E: MOVWF FE9
0440: MOVLW 00
0442: ADDWFC 03,W
0444: MOVWF FEA
0446: MOVFF FEC,629
044A: MOVF FED,F
044C: MOVFF FEF,628
0450: BCF FD8.0
0452: RLCF x28,W
0454: MOVWF 02
0456: RLCF x29,W
0458: MOVFF 627,FEA
045C: MOVFF 01,FE9
0460: MOVWF FEC
0462: MOVF FED,F
0464: MOVFF 02,FEF |
Variable Shifting
Code: | .................... sensor_data_1_0=sensor_data_1_0<<1; //shift data
0374: BCF FD8.0
0376: RLCF 20,F
0378: RLCF 21,F |
_________________ There is nothing you can't do if you try |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sun Jul 07, 2019 3:48 am |
|
|
Post the lines that declare the arrays. You have posted the usage, but
not the declarations.
Your arrays:
sensor_data_1_0
sensor_data_1 |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9243 Location: Greensville,Ontario
|
|
Posted: Sun Jul 07, 2019 4:36 am |
|
|
Yes, we need more information ! I'm GUESSING that you're reading data from a 16 by 16 bit RGB analog light sensor ? If you tell us the purpose of the program, we may be able to help with 'shortcuts' or other methods to capture/store/use the data.
Jay |
|
|
elcrcp
Joined: 11 Mar 2016 Posts: 62 Location: izmir / Turkey
|
|
Posted: Sun Jul 07, 2019 5:27 am |
|
|
Hi, I just used standard array declaration so didn't think it would be needed. Here is declaration and function for reading.
Code: | volatile unsigned int16 pixel_pointer=0,sensor_data_1[256],sensor_data_2[256],sensor_data_3[256];.
.
.
.
.
void get_one_reading(void)
{
/* Enable sensor integrations */
output_bit(Sensor_dis1,0);
output_bit(Sensor_dis2,0);
output_bit(Sensor_dis3,0);
/* Start sensor integrations */
output_bit(Sensor_si1,1);
output_bit(Sensor_si2,1);
output_bit(Sensor_si3,1);
delay_cycles(3); //give sime time for settling
output_bit(Sensor_clk,1); //sensor clock signal high
delay_cycles(2);
output_bit(Sensor_clk,0); //sensor clock signal low
/* Close integration signal to prevent reset */
output_bit(Sensor_si1,0);
output_bit(Sensor_si2,0);
output_bit(Sensor_si3,0);
/* Data is ready at the output pin of sensor at the moment */
for(int16 pixel_counter=0;pixel_counter<256;pixel_counter++)
{
sensor_data_1[pixel_pointer]=0;
sensor_data_2[pixel_pointer]=0;
sensor_data_3[pixel_pointer]=0;
output_bit(ADC_cs,0); //start adc conversion
for(int i=0;i<14;i++) //we will read 14 bits
{
output_bit(ADC_sclk,0); //send first clock signal to adc
sensor_data_1[pixel_pointer]|=input_state(ADC_outa); //read adc output
sensor_data_2[pixel_pointer]|=input_state(ADC_outb);
output_bit(ADC_sclk,1); //complete clock pulse
sensor_data_1[pixel_pointer]=sensor_data_1[pixel_pointer]<<1; //shift data
sensor_data_2[pixel_pointer]=sensor_data_2[pixel_pointer]<<1;
}
output_bit(ADC_cs,1); //stop adc conversion
output_bit(ADC_a1,1); //change adc input
output_bit(ADC_cs,0); //start adc conversion
for(int i=0;i<14;i++) //we will read 14 bits
{
output_bit(ADC_sclk,0); //send first clock signal to adc
sensor_data_3[pixel_pointer]|=input_state(ADC_outa); //read adc output
output_bit(ADC_sclk,1); //complete clock pulse
sensor_data_3[pixel_pointer]=sensor_data_1[pixel_pointer]<<1; //shift data
}
output_bit(ADC_cs,1); //stop adc conversion
output_bit(ADC_a1,0); //change adc input
output_bit(Sensor_clk,1);
delay_cycles(2);
output_bit(Sensor_clk,0);
pixel_pointer++;
}
} |
Program's purpose is pretty simple, I have 3 1x256 pixels analog light sensors and a fast adc, I trigger sensors and read outputs with adc then store them.
Thing is, reading adc output and storing them directly in array items tooks so much time and I want to avoid it.
But found a simple solution while I was writing this reply, reading outputs into a single variable and appointing it to a array item after 14 bit reading would help.
Still I wonder if I there is a way that I can do readings into an array item directly and much more efficiently. _________________ There is nothing you can't do if you try |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sun Jul 07, 2019 7:43 am |
|
|
Use the built-in CCS functions to do this. Example:
Code: | ..... shift_left(&sensor_data_1[pixel_pointer], 2, 0);
008A: BCF STATUS.C
008C: RLCF pixel_pointer,W
008E: MOVWF @02
0090: RLCF pixel_pointer+1,W
0092: MOVWF @03
0094: MOVF @02,W
0096: ADDLW sensor_data_1
0098: MOVWF @01
009A: MOVLW sensor_data_1+-6
009C: ADDWFC @03,F
009E: MOVFF 01,@@206
00A2: MOVFF 03,@@207
00A6: MOVFF @@207,FSR0H
00AA: MOVFF @@206,FSR0L
00AE: BCF STATUS.C
00B0: RLCF INDF0,F
00B2: RLCF PREINC0,F
.................... |
The shift_left() function is in the CCS manual.
http://www.ccsinfo.com/downloads/ccs_c_manual.pdf
Test program:
Code: |
#include <18F25K40.h>
#fuses NOWDT,PUT,BROWNOUT
#use delay(internal=4M)
unsigned int16 pixel_pointer=0,sensor_data_1[256];
//=================================
void main()
{
sensor_data_1[pixel_pointer] = sensor_data_1[pixel_pointer] << 1;
shift_left(&sensor_data_1[pixel_pointer], 2, 0);
while(TRUE);
}
|
|
|
|
elcrcp
Joined: 11 Mar 2016 Posts: 62 Location: izmir / Turkey
|
|
Posted: Sun Jul 07, 2019 3:59 pm |
|
|
Thanks for info PCM, i'll try for shifting, would you advice something more efficient for "sensor_data_1[pixel_pointer]|=input_state(ADC_outa);" too? _________________ There is nothing you can't do if you try |
|
|
sunitapr
Joined: 06 Aug 2019 Posts: 1 Location: Banned - spammer
|
16-bit array |
Posted: Tue Aug 06, 2019 12:24 am |
|
|
Thanks for sharing information. I will try this 16 bit array coding. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19539
|
|
Posted: Tue Aug 06, 2019 1:09 am |
|
|
There are some tricks to improve things a little, but the emphasis is on 'little'.
Problem is that as soon as you are involved in 'indirect addressing' (which
the 'array' implies), you are forced to be updating a pointer 'to' the data,
and transfers through the indirect addressing registers. Result much more
overhead. As an example though of how a little saving cam be made, compare the assembler from two different ways of accessing a 256word
array:
Code: |
int16 demo[256];
void main(void)
{
int16* ptr;
int16 ctr;
setup_adc_ports(sAN0);
setup_adc(ADC_CLOCK_DIV_32 | ADC_TAD_MUL_8);
//setup adc so Tacq is generated automatically
while(TRUE)
{
//Compare the two approaches:
for ( ctr=0;ctr<256;ctr++)
demo[ctr]=read_adc(); //first standard array access
ptr=demo;
for (ctr=0;ctr<256;ctr++)
*(ptr++)=read_adc(); //second using a pointer instead
}
}
.................... for ( ctr=0;ctr<256;ctr++)
0054: MOVLB 2
0056: CLRF x07
0058: CLRF x06
005A: MOVF x07,W
005C: SUBLW 00
005E: BTFSS FD8.0
0060: GOTO 009A
.................... demo[ctr]=read_adc();
0064: BCF FD8.0
0066: RLCF x06,W
0068: MOVWF 02
006A: RLCF x07,W
006C: MOVWF 03
006E: MOVF 02,W
0070: ADDLW 04
0072: MOVWF FE9
0074: MOVLW 00
0076: ADDWFC 03,W
0078: MOVWF FEA
007A: BSF F60.0
007C: NOP
007E: BTFSC F60.0
0080: GOTO 007E
0084: MOVFF F64,03
0088: MOVFF F63,FEF
008C: MOVFF F64,FEC
0090: INCF x06,F
0092: BTFSC FD8.2
0094: INCF x07,F
0096: GOTO 005A
.................... ptr=demo;
009A: CLRF x05
009C: MOVLW 04
009E: MOVWF x04
.................... for (ctr=0;ctr<256;ctr++)
00A0: CLRF x07
00A2: CLRF x06
00A4: MOVF x07,W
00A6: SUBLW 00
00A8: BTFSS FD8.0
00AA: GOTO 00E6
.................... *(ptr++)=read_adc();
00AE: MOVFF 205,03
00B2: MOVFF 204,00
00B6: MOVLW 02
00B8: ADDWF x04,F
00BA: BTFSC FD8.0
00BC: INCF x05,F
00BE: MOVFF 00,FE9
00C2: MOVFF 03,FEA
00C6: BSF F60.0
00C8: NOP
00CA: BTFSC F60.0
00CC: GOTO 00CA
00D0: MOVFF F64,03
00D4: MOVFF F63,FEF
00D8: MOVFF F64,FEC
00DC: INCF x06,F
00DE: BTFSC FD8.2
00E0: INCF x07,F
00E2: GOTO 00A4
00E6: GOTO 0056
|
The 'ponter' version is three instructions shorter than the 'array' version.
The difference is that in the 'array' version, the index has to be loaded
multiplied by two, and added to the start of the array. In the 'pointer'
version all that has to happen is to increment the pointer by two. A
small saving.
If you are not doing anything else accessing the registers, you could
pre-setup the addressing register, do the 'write' by direct access, and
just increment the register by two.
So, using the 'POSTINC' register, something like:
Code: |
#word FSR0=getenv("SFR:FSR0L")
#word INDF0=0xFEF //INDF0
#byte PREINC0=0xFEC //PREINC0
#byte POSTINC0=0xFEE //POSTINC0
//Now fastest approach using postinc0
FSR0=demo;
//Load FSR with the address
for (ctr=0;ctr<256;ctr++)
{
temp=read_adc();
POSTINC0=make8(temp,0); //LSB
POSTINC0=make8(temp,1); //MSB
}
//which generates:
.................... //Load indf with the address
.................... for (ctr=0;ctr<256;ctr++)
00EE: CLRF ctr+1
00F0: CLRF ctr
00F2: MOVF ctr+1,W
00F4: SUBLW 00
00F6: BTFSS STATUS.C
00F8: GOTO 0120
.................... {
.................... temp=read_adc();
00FC: BSF ADCON0.GO
00FE: NOP
0100: BTFSC ADCON0.GO
0102: GOTO 0100
0106: MOVFF ADRESL,temp
010A: MOVFF ADRESH,temp+1
.................... POSTINC0=make8(temp,0); //LSB
010E: MOVFF temp,POSTINC0
.................... POSTINC0=make8(temp,1); //MSB
0112: MOVFF temp+1,POSTINC0
0116: INCF x06,F
0118: BTFSC STATUS.Z
011A: INCF ctr+1,F
011C: GOTO 00F2
|
About seven instructions faster (if I have got it right!...).
Key here is using the POSTINC register which allows a single byte
to be transferred to where FSR0 'points', and then increments the FSR.
The two bytes have to be transferred separately (hence 'temp'), but
this means that the two bytes can actually be transferred in just a couple
of instructions.
This is done reading data from the standard PIC adc, rather than your
source, but shows how different the approaches can be. |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|