missing characters on serial read when timer2 interrupt is called

Hi! this is my first post, i was trying to figure out for several days how to solve this problem…

I’m missing reading characters from serial port when analogRead() is performed inside a timer2 interrupt every 1ms.

This is a reduced code where I replicate the problem,

Any help will be very wellcome!

David

static volatile uint32_t milliseconds = 0;
static void initInt(void)
{
 uint8_t savedStatus = SREG;
 cli();
 // Timer2 1ms
 // mode 2 (CTC Clear Timer when match)
 TCCR2A = 0x01 << WGM21;
 // Clock clk/128 (CS = 5)
 TCCR2B = 0x01 << CS22 | 0x01 << CS20;
 // 1ms
 OCR2A = 125 - 1;
 // Reset counter timer 2
 TCNT2 = 0;
 // Timer2 interrupt mode on OCR2A compare match
 TIMSK2 = 0x01 << OCIE2A;
 SREG = savedStatus;
}


static void intFunc(uint32_t mils)
{
   if (mils % 1000 == 0)
       digitalWrite(13, digitalRead(13) ^ 1);
   analogRead(A0);
   analogRead(A1);
   analogRead(A2);
   analogRead(A3);    
   analogRead(A4);
}

ISR(TIMER2_COMPA_vect)
{
   milliseconds++;
   intFunc(milliseconds);
}


void setup()
{
   initInt();
   pinMode(13, OUTPUT);
   Serial.begin(115200);
}

String lineGlobal = "";

void loop()
{
   while( Serial.available() ) {
   char auxChar = Serial.read();
   if( auxChar != '\r' )
     lineGlobal += auxChar;
   if( auxChar == '\n' ) {
     Serial.print(lineGlobal);
     lineGlobal = "";
   }
 }
}

Not too surprising. AnalogRead() takes over 100us; which probably means that you should NOT call it in an ISR. You're calling it 5x, so that will take over 500us. At 115200bps, you're getting a byte every 86us or so. You've got two bytes of buffering, so you need to let the serial port interrupt no less often than every ~160us. It won't be able to do that when you're in the timer ISR for over 500us.

westfw:
which probably means that you should call it in an ISR.

I suspect that should read “you should NOT call it in an ISR”

@dforco, have a look at the examples in Serial Input Basics - simple reliable ways to receive data.

And please modify your post and use the code button </> so your code looks like this and is easy to copy to a text editor. See How to use the Forum

…R

Thank you all for the very clear and detailed explanation. I thought that hardware serial reading was performing by the Atmel independently from the program processing. So that, I will have to review all timing... Have a great day! David

It is, up to two characters. After that it relies on the fact it can do the rest in an interrupt after that :) Which you block with a long interrupt ;)

Thank you! I've already updated the code tags, im sorry, im new, The system is continuously reading 7 analog inputs as this is part of a trueRMS voltage, current and power meter which takes 85 samples every 1mSeg on the 50HZ wave. I will try to use the remaining time (15ms between each reading block). Thank you all for the support! Have a great day david

If you want to take that many reading and space then exact, don't use analogRead(). analogRead() is waiting most of it's time for the reading to be done. It basicly sets the ADC to the right pin, calls to do a reading and then waits for it to be done. But if you want to go fast en precise it's better to do that yourself. You can make a strict timing based on an interrupt and in that only call to do a reading but don't wait. Use the ADC complete interrupt to get the result once it's done.

Many thanks for your help! Ir really appreciate it, David