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_tADCchannel[9]={11,2,5,0,3,6,1,4,7};
2
uint16_tvalues[9]={0,0,0,0,0,0,0,0,0};
3
4
uint8_tj=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_tADCchannel[9]={11,2,5,0,3,6,1,4,7};
2
uint16_tvalues[9]={0,0,0,0,0,0,0,0,0};
3
4
uint8_tj=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_tADCchannel[9]={11,2,5,0,3,6,1,4,7};
2
uint16_tvalues[9]={0,0,0,0,0,0,0,0,0};
3
4
uint8_tj=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
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
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!