EmbDev.net

Forum: ARM programming with GCC/GNU tools loop shifts array entries


von Henrik (Guest)


Attached files:

Rate this post
useful
not useful
Hi everyone,

I need some help to find a bug in my program I just can't find!

I am using an ADuC7026 which has a ARM7TDMI core. For programming I use 
GNUARM and the light version of uVision as an emulator/disassembler.

I want to read the values of 9 different ADC channels and store them 
into an array.
The essentials of the code:
1
uint8_t ADCchannel[9] = {11,2,5,0,3,6,1,4,7};
2
uint16_t values[9] = {0,0,0,0,0,0,0,0,0};
3
4
uint8_t j = 0;
5
for(j=0; j<9; j++)
6
    {
7
      ADCCON |= ADC_SINGLESOFTWARECONV;
8
      ADCCP = ADCchannel[j];                 //select channel
9
      ADCCON |= ADC_ENABLE;                  //start conversion
10
      while(ADCSTA==0){}                     //wait for result
11
      values[j] = (uint16_t)(ADCDAT >> 16);  //store result                
12
    }
13
//write one result to DAC to test
14
DAC1_SETVAL(values[0]);

The error is that the result that should be stored in value[i] is stored 
in value[i+1] instead. And what should be value[8] gets value[0]. So 
every entry is shifted by one slot.


I found that when I modify my code so that the for-loop will only take 
one value of i, eg:
1
uint8_t ADCchannel[9] = {11,2,5,0,3,6,1,4,7};
2
uint16_t values[9] = {0,0,0,0,0,0,0,0,0};
3
4
uint8_t j = 0;
5
for(j=0; j<1; j++)
6
    {
7
      ADCCON |= ADC_SINGLESOFTWARECONV;
8
      ADCCP = ADCchannel[j];                 //select channel
9
      ADCCON |= ADC_ENABLE;                  //start conversion
10
      while(ADCSTA==0){}                     //wait for result
11
      values[j] = (uint16_t)(ADCDAT >> 16);  //store result                
12
    }
13
//write one result to DAC to test
14
DAC1_SETVAL(values[0]);
everything will work fine.(However I only get one out of the 9 values, 
of course.)

Adding a j--; j++; around the storing command will get the values stored 
at the correct location.
1
uint8_t ADCchannel[9] = {11,2,5,0,3,6,1,4,7};
2
uint16_t values[9] = {0,0,0,0,0,0,0,0,0};
3
4
uint8_t j = 0;
5
for(j=0; j<9; j++)
6
    {
7
      ADCCON |= ADC_SINGLESOFTWARECONV;
8
      ADCCP = ADCchannel[j];                 //select channel
9
      j--;
10
      ADCCON |= ADC_ENABLE;                  //start conversion
11
      while(ADCSTA==0){}                     //wait for result
12
      values[j] = (uint16_t)(ADCDAT >> 16);  //store result                
13
      j++;
14
    }
15
//write one result to DAC to test
16
DAC1_SETVAL(values[6]);

When I emulate my code with uVision from KEIL, I don't get the error. 
Looking at the disassembly showed however, that the assembler code of 
the first 2 shown codes doesn't change but for the value of the one 
comparison at the for loop, (As it should be!) which only serves to 
confuse me even more, as now it seems that the same code that works in 
one case does something else in the other.

It seems as if code that keeps the value of j for some time works fine, 
and code that changes j every time doesn't: switching j between 2 values 
with a switch will work fine, e.g.
1
if((GP4DAT & Pin5_Val)!=0) {j=6;}
2
else{j=0;}
3
ADCCON |= ADC_SINGLESOFTWARECONV;
4
ADCCP = ADCchannel[j];
5
ADCCON |= ADC_ENABLE;
6
while(ADCSTA==0){}
7
values[j] = (uint16_t)(ADCDAT >> 16);
8
DAC1_SETVAL(values[6]);

I think that I'm just missing something really small and stupid, but I 
just cannot find it! It might also be something with the compiler 
options, so I included the makefile I use.

Thanks a lot for your help already. I am really lost here :(
I appreciate any form of advice/ideas/hints!
Sorry for the long post...
Greetings
Henrik

von MacLyon (Guest)


Rate this post
useful
not useful
Look in disassembled listing how is managed the variable j - it is quit 
possible to be tested for completion before any block execution - this 
is compiler optimization.
Try to reverse the for statement by decreasing j : for (j=9; j>0; 
j--){...
and check the result.
MacLyon

von Henrik (Guest)


Rate this post
useful
not useful
Hi,

I found the mistake! Turns out that the foor loop was ok. The solution 
is to swap the first 2 lines in the loop:
1
ADCCP = ADCchannel[j];                 //select channel
2
ADCCON |= ADC_SINGLESOFTWARECONV;

Apparently setting the ADC-mode to Single Software Conversion disables 
the Multiplexer, so the channel wouldn't get switched until after the 
conversion, where the Mode-Bits of ADCCON get automatically reset.

Thanks for the help!

Please log in before posting. Registration is free and takes only a minute.
Existing account
Do you have a Google/GoogleMail account? No registration required!
Log in with Google account
No account? Register here.