UART communication reset

Hello!

I am working on a simple project and want to enable interrupt based UART communication. However, I encountered a problem that after every transmission my Arduino UNO resets and I cannot determine why. I have deleted most of my code and written a simple program to check what is the current time (millis()) and after every transmission it seems the clock and everything else is set back to zero.

The only items I'm enabling or disabling are cli(), sei() and UDRIE0 interrupt register but from what I understand I am doing the correct thing by disabling them while writing and enabling them when transmitting. Otherwise it is a simple register shift which should not reset the clock.

Any idea where is my problem? You can find my full code below.

#include <RTClib.h>                 // for RTC
#include <avr/interrupt.h>
#include <arduino-timer.h>
#include <avr/io.h>
#include <string.h>
#include <stdio.h>
#include <math.h>


#define F_CPU 16000000UL
#define RX_BUFFER_SIZE 128
#define TX_BUFFER_SIZE 128
// definition for UART
#define BAUD 9600
// #define UBRR_VAL (((F_CPU / (BAUD * 16UL))) - 1)
#define UBRR_VAL (((F_CPU / (BAUD * 8UL))) - 1)
volatile char tx_buffer[TX_BUFFER_SIZE];
volatile uint8_t  tx_head = 0;
volatile uint8_t  tx_tail = 0;
bool rx_end;
volatile char uart_write[64]="";
unsigned long init_time = millis();
unsigned long current_time;
float tmp_mili;

//-----------------------------------------------------------------------------------------//
// Start of functions //
//-----------------------------------------------------------------------------------------//

// ISR(USART_TX_vect) { // interrupt write function, this function writes UART0 value without hard locking the processor
ISR(USART_UDRE_vect) { // interrupt write function, this function writes UART0 value without hard locking the processor
  if (tx_head != tx_tail) {
    UDR0 = tx_buffer[tx_tail];
    tx_tail = (tx_tail + 1) % sizeof(tx_buffer);
  } 
  // else {
    // cli();
    // UCSR0B &= ~(1<<UDRIE0); // disable UDRE interrupt if tx_buffer is empty
    // sei();  
  // }
}

void uart_init() {
  cli();
  UBRR0 = UBRR_VAL;
  // UBRR0H = (unsigned char) (UBRR_VAL >> 8); //  baud rate significant bits
  // UBRR0L = (unsigned char) UBRR_VAL; // baud rate insignificant bits
  UCSR0A = 0x00;
  UCSR0B = 0x00;
  UCSR0C = 0x00;
  
  // UCSR0A = (0<<RXC0) | (1<<TXC0); // Status register fo RX and TX completion
  // UCSR0A = (1<<UDRE0); // Status register for empty register
  // UCSR0A = (1<<FE0) | (1<<DOR0) | (1<<UPE0); // Error status registers Frame, Data OverRun and Parity
  UCSR0A = (1<<U2X0) | (0<<MPCM0); // Double speed disabled 0 ; Multi MCU mode 0 disabled 
  
  UCSR0B = (0<<RXCIE0) | (1<<TXCIE0);// RX Interrupt 0 disabled, TX interupt 1 enabled
  UCSR0B |= (0<<UDRIE0);// USART data register empty interrupt 0 disabled, 1 enabled
  UCSR0B |= (0<<RXEN0) | (1<<TXEN0);// RX 0 disabled, TX 1 Enabled
  UCSR0B |= (0<<UCSZ02);// Frame size 0 - disabled, 1 - 9 frame format
  //UCSR0B = (0<<RXB80) | (1<<TXB80);// RX and TX data storage for 9 bit frame format
 
  UCSR0C = (1<<UCSZ01) | (1<<UCSZ00); // Frame format - 1 1 8 bits
  UCSR0C |= (0<<UMSEL01) | (0<<UMSEL00); // USART mode - 0 0 Asynchronous USART mode
  UCSR0C |= (0 << UPM01 | 0 << UPM00); // Parity mode - 0 0 no parity
  UCSR0C |= (0 << USBS0); // Stop bit number - 0 one bit, 1 two bits
  UCSR0C |= (0 << UCPOL0); // clock polarity, used for synchronous mode only 0 disabled
  sei();
}

void uart_transmit(const char *str){
  // cli();
  UCSR0B &= ~(1<<UDRIE0); // disable UDRE interrupt before putting data inside
  char  dummy= UDR0; //clearing UDR0 register
  uint8_t i = 0; 
  uint8_t next_head;// = (tx_head + 1) % sizeof(tx_buffer);
  while (str[i] != '\0'){
    // uint8_t tx_head = (tx_head + 1) % sizeof(tx_buffer);
    // if (tx_head != tx_tail){
    next_head = (tx_head + 1) % sizeof(tx_buffer);
    if (next_head != tx_tail){
      tx_buffer[tx_head] = str[i];
      tx_head = (tx_head + 1) % sizeof(tx_buffer);
      i++;
      // if (!(UCSR0B & (1 << UDRIE0))){
        // cli();
        // UCSR0B |= (1<<UDRIE0); // enable UDRE interrupt to start transmitting data
        // sei();          
      // }
    }
    // cli();
    UCSR0B |= (1<<UDRIE0); // enable UDRE interrupt to start transmitting data
    // sei();  
  }   
  while(tx_head==tx_tail && (!(UCSR0A & (1 << UDRE0)))){}; // hard wat to complete transmission
}


void setup() {
  //setting the inputs/outputs pins
  // New function for timed interrupts rather time delays
  uart_init();
  init_time = millis();
}

// Main loop
void loop() {
  current_time=millis();
  if (current_time-init_time>1000){
  tmp_mili = millis() / 1000.0;
  dtostrf(tmp_mili, 20, 10, uart_write);
  uart_transmit(uart_write);
  init_time=millis();
  }
}
  

Are you aware that the UART serial code generated by the Arduino IDE is already fully interrupt-based?

If the processor resets, the first places I look are writing past array boundaries, and power supply brownout problems.

Welcome to the forum

When the Serial port is opened the Uno resets. This is normal behaviour. Can you open the Serial port just once and leave it open ?

There is a jumper on the UNO board that you can use to change that behaviour. But you need to change it back if you want to upload another sketch.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.