EmbDev.net

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


Author: Henrik (Guest)
Posted on:
Attached files:

Rate this post
0 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:
uint8_t ADCchannel[9] = {11,2,5,0,3,6,1,4,7};
uint16_t values[9] = {0,0,0,0,0,0,0,0,0};

uint8_t j = 0;
for(j=0; j<9; j++)
    {
      ADCCON |= ADC_SINGLESOFTWARECONV;
      ADCCP = ADCchannel[j];                 //select channel
      ADCCON |= ADC_ENABLE;                  //start conversion
      while(ADCSTA==0){}                     //wait for result
      values[j] = (uint16_t)(ADCDAT >> 16);  //store result                
    }
//write one result to DAC to test
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:
uint8_t ADCchannel[9] = {11,2,5,0,3,6,1,4,7};
uint16_t values[9] = {0,0,0,0,0,0,0,0,0};

uint8_t j = 0;
for(j=0; j<1; j++)
    {
      ADCCON |= ADC_SINGLESOFTWARECONV;
      ADCCP = ADCchannel[j];                 //select channel
      ADCCON |= ADC_ENABLE;                  //start conversion
      while(ADCSTA==0){}                     //wait for result
      values[j] = (uint16_t)(ADCDAT >> 16);  //store result                
    }
//write one result to DAC to test
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.
uint8_t ADCchannel[9] = {11,2,5,0,3,6,1,4,7};
uint16_t values[9] = {0,0,0,0,0,0,0,0,0};

uint8_t j = 0;
for(j=0; j<9; j++)
    {
      ADCCON |= ADC_SINGLESOFTWARECONV;
      ADCCP = ADCchannel[j];                 //select channel
      j--;
      ADCCON |= ADC_ENABLE;                  //start conversion
      while(ADCSTA==0){}                     //wait for result
      values[j] = (uint16_t)(ADCDAT >> 16);  //store result                
      j++;
    }
//write one result to DAC to test
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.
if((GP4DAT & Pin5_Val)!=0) {j=6;}
else{j=0;}
ADCCON |= ADC_SINGLESOFTWARECONV;
ADCCP = ADCchannel[j];
ADCCON |= ADC_ENABLE;
while(ADCSTA==0){}
values[j] = (uint16_t)(ADCDAT >> 16);
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

Author: MacLyon (Guest)
Posted on:

Rate this post
0 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

Author: Henrik (Guest)
Posted on:

Rate this post
0 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:
ADCCP = ADCchannel[j];                 //select channel
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!

Reply

Entering an e-mail address is optional. If you want to receive reply notifications by e-mail, please log in.

Rules — please read before posting

  • Post long source code as attachment, not in the text
  • Posting advertisements is forbidden.

Formatting options

  • [c]C code[/c]
  • [avrasm]AVR assembler code[/avrasm]
  • [code]code in other languages, ASCII drawings[/code]
  • [math]formula (LaTeX syntax)[/math]




Bild automatisch verkleinern, falls nötig
Note: the original post is older than 6 months. Please don't ask any new questions in this thread, but start a new one.