[En-Nut-Discussion] AVR ADC sample fails
Harald Kipp
harald.kipp at egnite.de
Tue Jul 7 14:37:43 CEST 2009
Hi all,
So far we at egnite never used the ADC routines, but regularly receive
requests about its API functions. Now we decided to provide a sample,
but miserably fail ourselves. :-(
Using a simple loop of ADC-reads plus a NutSleep(10000) lets the
NutSleep fail. It returns immediately. This look like a memory access
problem and I looked into arch/avr/dev/adc.c and started wondering about
a number of things, which I do not understand.
The allocation of ADC_buffer in ADCInit() is
ADC_buffer = NutHeapAlloc(sizeof(uint16_t) * ADC_BUF_SIZE + 2);
Immediately after this, ADCBufInit() is called, which contains:
buf[_adc_buf_head] = 0;
buf[_adc_buf_tail] = 0;
The related defines are
#define _adc_buf_head ADC_BUF_SIZE
#define _adc_buf_tail ADC_BUF_SIZE+1
Actually
buf[_adc_buf_tail] = 0;
is
buf[ADC_BUF_SIZE+1] = 0;
and will corrupt heap memory. Did I overlook something? This code is
nearly 5 years old!
Please tell me, that I'm not getting too old for this stuff,
Harald
P.S.:
More things to wonder about. Like in
inline int ADCBufRead(uint16_t * buf, uint16_t * read)
{
uint8_t tail, head;
tail = buf[_adc_buf_tail];
head = buf[_adc_buf_head];
Why the hell doesn't the compiler complain? buf[] is 16 bit, tail is 8
bit, so the upper byte is lost.
There are other things I still do not understand, but let's solve these
two first.
IMHO, the problem with the buffer overwrite is typical for _overusing_
preprocessor macros. To me
buf[ADC_BUF_SIZE+1] = 0;
is much easier to read than
buf[_adc_buf_tail] = 0;
Furthermore, the naming is most confusing. _abcd looks like a system
variable, while ABCD looks like a macro. Last not least, defining macros
#define _adc_buf_tail ADC_BUF_SIZE+1
without brackets may be very dangerous, because _adc_buf_tail*2 will
give the wrong result.
More information about the En-Nut-Discussion
mailing list