2
\$\begingroup\$

On an AVR ATmega328P, once per second I am doing 3 AD conversions immediately following each other with 16x oversampling using SLEEP_MODE_ADC like this:

EMPTY_INTERRUPT(ADC_vect);

uint16_t getVoltage(uint8_t pin) {
    ADMUX = (0b11110000 & ADMUX) | pin;

    uint32_t overValue = 0;
    for (uint8_t i = 0; i < 16; i++) {
        sleep_mode();
        overValue += ADC;
    }
    int16_t mV = (((overValue >> 2) * AREF_MV) >> 12);

    return mV;
}

It works fine.

At the same time, I am generating a 4 kHz beep with a timer toggling an output pin, and I am reading and writing data over USART.

The beep has a short click once per second which looks like this: enter image description here

And every now and then a character sent over USART gets garbled.

While I'd expect that the beep timer is put to sleep during AD conversion in order reduce internal noise, I didn't quite expect USART tx/rx to be disturbed.

When I don't use sleep mode and do AD conversions like this:

    // sleep_mode();
    ADCSRA |= (1 << ADSC);
    loop_until_bit_is_clear(ADCSRA, ADSC);

the beep is "clean", there are no more USART tx/rx issues, and after some extensive measuring, I am pretty sure the AD conversion results are just as accurate as they are with sleep mode.

So I am wondering about two things:

  1. Is it expected that USART tx/rx gets disturbed by SLEEP_MODE_ADC?
  2. Does sleep mode actually make sense in combination with oversampling? Does some noise maybe not even help to increase accuracy (dithering) or does that apply only to noise coming from the sensors?
\$\endgroup\$
5
  • \$\begingroup\$ Do we have to guess which hardware you are using? \$\endgroup\$
    – Eugene Sh.
    May 4, 2015 at 17:09
  • \$\begingroup\$ Oops, sorry - added. \$\endgroup\$ May 4, 2015 at 17:11
  • 1
    \$\begingroup\$ Are you using the Arduino Serial routines or something else? If the Arduino ones, can you try Serial.flush() before sleeping. If your own routines, try waiting for any character in the buffer to be sent before going to sleep. The sleep mode will as I recall disable the clock to the USART baud generator meaning if a character is in the middle of being sent it will get corrupted. \$\endgroup\$ May 4, 2015 at 17:34
  • \$\begingroup\$ I am using own routines and I'll just try what you suggest... \$\endgroup\$ May 4, 2015 at 17:43
  • \$\begingroup\$ I have tried loop_until_bit_is_set(UCSR0A, UDRE0); (USART Data Register Empty) before going to sleep but it did not help. A _delay_ms(10) before entering the loop does help but is not very nice I guess. Also, I am receiving corrupted data sent to the AVR and I have no idea how to avoid data being received during those 3*16 calls to sleep_mode(). \$\endgroup\$ May 4, 2015 at 18:25

1 Answer 1

2
\$\begingroup\$
  1. Is it expected that USART tx/rx gets disturbed by SLEEP_MODE_ADC?

Absolutely. Both the USART and timers use clkIO for operation, and this is disabled in ADC Noise Reduction mode.

  1. Does sleep mode actually make sense in combination with oversampling? Does some noise maybe not even help to increase accuracy (dithering) or does that apply only to noise coming from the sensors?

You actually do want some noise when performing oversampling and decimation as you are, so I don't feel that ANR mode would make sense here; restrict your self to Idle mode (SLEEP_MODE_IDLE) in order to keep the USART and timers alive.

\$\endgroup\$
1
  • \$\begingroup\$ Nice. With SLEEP_MODE_IDLE my original code works fine, no click in the beep and no USART RX/TX issues. And no need to use loop_until_bit_is_clear(ADCSRA, ADSC). Thanks! \$\endgroup\$ May 4, 2015 at 21:49

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.