-1

I have an ATmega1284p and I need to have the TXD0 (i.e. pin 9) set to LOW, before going to sleep. After waking up, I want to restore UART0 communication to work as expected. Here is my code:

Serial.begin(38400,SERIAL_8N1);

*do Stuff*

Serial.end();
//pinMode(9,OUTPUT);
//digitalWrite(9,LOW);      
//UCSR0B &= ~bit (RXEN0);  // disable receiver
//UCSR0B &= ~bit (TXEN0);  // disable transmitter
cli();           
set_sleep_mode (SLEEP_MODE_PWR_DOWN); 
sleep_enable();
// turn off brown-out enable in software
//MCUCR = bit (BODS) | bit (BODSE);  // turn on brown-out enable select
//MCUCR = bit (BODS);        // this must be done within 4 clock cycles of above
sleep_bod_disable();  //disable brown-out detection
sei();             // guarantees next instruction executed
sleep_cpu ();              // sleep within 3 clock cycles of above
sleep_disable();

//  UCSR0B |= bit (RXEN0);  // enable receiver
//  UCSR0B |= bit (TXEN0);  // enable transmitter  
//pinMode(9,OUTPUT);
//digitalWrite(9,HIGH);
//delay(100);
//pinMode(9,INPUT_PULLUP);
Serial.begin(38400,SERIAL_8N1);
delay(1000);
Serial.println("- Good Morning");

*do Stuff*

You can see in comments all the different things I tried:

  • Using Serial.end() and then, after waking up, Serial.begin()
  • Using the UCSR0B register
  • Using digitalWrite to set the pin to LOW and then, after waking up, either setting it to high, or setting it as input

All of the above combinations have the common problem that the cpu hangs after waking up, and the Serial is never restarted to print good morning message, neither does the program continue to execute further down.

4
  • 1
    Perhaps your terminal must be resetted as you have closed the serial connection. From my experience: Simply calling Serial.begin() does not trigger the Serial Terminal to reconnect again. I'm not sure, but the Serial.println might block then and that would be the reason your program won't be executed any further. Again; these are just guesses, but worth a try. ;-) Did the sleep mode work without the Serial shutdown? Can you try "the further processing" with out any println to see if the prints block or not? Can you recognize "further processing" without print statements? Commented Dec 31, 2020 at 9:33
  • 1
    Just a hint how to mark tried alternatives, which is easier to grasp and maintain than commenting each line: Use conditional compilation by #if 0 // try 1 ... #elif 1 // try 2 ... #endif. Commented Dec 31, 2020 at 10:17
  • 1
    Try adding delay(1000); after * do Stuff*. My guess is that there is still data being send over the serial connection when the MCU is put to sleep; leading to weird issues.
    – Gerben
    Commented Dec 31, 2020 at 16:12
  • Thanks for the sugggestions. I tried those, before the solution came to me, which I posted below. Just one suggestion about @Gerben 's comment: It is indeed common to still have data before going to sleep, but the best way I found to deal with such issues is by using Serial.flush(). Of course, both would work fine
    – NickG
    Commented Jan 2, 2021 at 0:47

1 Answer 1

1

After trying many different alternatives, it turns out that my mistake was that, foolishly, I had included Serial printing inside my ISR routines, which where accessed when my interrupt fired, in order to wake my uP. As a result, Serial.print was called, with Serial being closed (before issuing the Serial.begin command to restart it), thus breaking my uP.

Extra: Just wanted to comment about using Serial.print inside ISRs. Although it can lead to unexpected problems like this one, or timing issues (ISR would take too long to execute) and is definitely a bad practice, it can sometimes be useful for debug purposes during development to print some kind of message there.

Printing a message takes long, and the ISR will return before the message is completely transmitted, with the potential to cause a lot of headache. Also, interrupts are disabled inside ISRs, so delay() is not working to do some kind of flow control. The best way to print messages in ISRs that I have come across so far, is by using Serial.flush() before exiting the ISR, making sure the message is completely transmitted.

3
  • You should keep the ISR as short as possible, just to set the flag or something. It never a good idea to use I/O access (such as Serial.print() within an ISR routine, even for debugging purpose, do it outside of the ISR based on the flag set by ISR.
    – hcheung
    Commented Jan 2, 2021 at 2:24
  • I would suggest you read Nick Gammon's Interrupt.
    – hcheung
    Commented Jan 2, 2021 at 2:26
  • Thanks for the suggestion, I have already read it, a great tutorial indeed. And yes, keeping only flags inside ISRs is definitely the best practice.
    – NickG
    Commented Jan 2, 2021 at 3:05

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.