Arduino Mega RX Recieve Interrupt stop working

I try to loop data through an Arduino Mega with an Atmega 2560. I use two different Interrupts, one for RX Recieve which recieve Data from a C-Programm running on my Laptop and a Timer Interrupt which is reading Data from a self written Ring-Buffer.

The program is running fine until I read Data from the Buffer, then the RX-Recieve interrupt stops fireing and the Buffer also don’t get Data. I test the Interrupts with toggled PIN.

The RX-Recieve interrupt also don’t work if I push the Timer interrupt to a higher frequency but without any work in the interrupt.

The Buffer size is 254 because if I set it higher the Arduino stops counting up at 254.
But basically the Interrupt stops working if Buffer.out() is used.

Here is my Code for the Arduino:

#include <avr/interrupt.h>
#include <avr/io.h>
#include <util/delay.h>
#include <stdio.h>

//#define BAUDRATE 921600L
#define BAUDRATE 9600L
#define SERIAL_FORMAT_8N1 0b00000110
#define sbi(port, bit) (port) |= (uint8_t)  (1 << (bit))
#define cbi(port, bit) (port) &= (uint8_t) ~(1 << (bit))

#define BUFFER_FAIL     0
#define BUFFER_SUCCESS  1

const uint32_t BUFFER_SIZE = 254;

struct Buffer {
  uint8_t data[BUFFER_SIZE];
  volatile uint8_t read; // zeigt auf das Feld mit dem ältesten Inhalt
  volatile uint8_t write; // zeigt immer auf leeres Feld
  volatile uint8_t runable;
} buffer = {{}, 0, 0, 0};

//https://www.mikrocontroller.net/articles/AVR-GCC-Tutorial/Der_UART UART Infos

//counter and compare value
const uint16_t t1_load = 0;
const uint16_t t1_comp = 64;

void setup() {
  DDRB |= _BV(DDB7); //Set Pin 13 to output
  DDRB |= _BV(DDB6); //Set Pin 13 to output
  serial_init(BAUDRATE, SERIAL_FORMAT_8N1);

  setup_timer1();
  sbi(UCSR0B, RXCIE0);         // rx complete interrupt enable
  sei();                       // enable interrupts, Global Interrupt Enable
}

void serial_init(uint32_t baudrate, uint8_t frame_format){
  // calculate baud rate settings
  uint8_t  u2x0 = 1;
  uint32_t ubbr0 = (F_CPU / 4 / baudrate - 1) / 2; // UART Baud Rate Register.
  //uint32_t ubbr0 = (F_CPU / (baudrate*16)) - 1;
  if (ubbr0 > 4095) {
    u2x0 = 0;
    ubbr0 = (F_CPU / 8 / baudrate -1) / 2;
  }
  // set baud rate
  UBRR0H = (uint8_t) (ubbr0 >> 8);
  UBRR0L = (uint8_t) (ubbr0 & 0xFF);
  if (u2x0) sbi(UCSR0A, U2X0);
  else      cbi(UCSR0A, U2X0);
  // enable receive / transmit
  UCSR0B |= _BV(RXEN0) | _BV(TXEN0);
  // set frame format
  UCSR0C = frame_format; // UART Control and Status Register C. URSEL   UMSEL   UPM1  UPM0  USBS  UCSZ1   UCSZ0   UCPOL // Set to 8bit Character Size
}

void setup_timer1(){
  TCCR1A = 0;

  //Set to prescaler of 1 (no prescaler)
  TCCR1B |= (1 << CS10);
  TCCR1B &= ~(1 << CS11);
  TCCR1B &= ~(1 << CS12); 

  //Reset Timer 1 and set compare value
  TCNT1 = t1_load;
  OCR1A = t1_comp;

  //Enable Timer1 compare interrupt
  TIMSK1 = (1 << OCIE1A);
}

int serial_write_byte(uint8_t data) {
   if (!bit_is_set(UCSR0A, UDRE0)){
    return EOF;
   }
   UDR0 = data;
   return data;
}


//READ
int serial_read_byte() {
  if (! bit_is_set(UCSR0A, RXC0))
    return EOF;
  uint8_t data = UDR0;
  return data;
}

//Timer1 write Data in Buffer
int  bit_pointer = -1;
ISR(TIMER1_COMPA_vect){
  TCNT1 = t1_load;
  
  if(buffer.runable){ //If BufferOut() is used, the Interrupt stops working
    //PORTB ^= _BV(PB7);
    bit_pointer++;
    uint8_t *c;
    BufferOut(c);
    char convert = *c;
    PORTB &= ((convert >> bit_pointer) & 0x01) << 7;
    if(buffer.read > 50 && buffer.read < 150){
      PORTB ^= _BV(PB7);
    }
    if(bit_pointer == 7){
      bit_pointer = -1;
      //serial_write_byte(test);
    }
      
  }
  
}

int serial_blocking_write_byte(uint8_t data) {
   loop_until_bit_is_set(UCSR0A, UDRE0);
   UDR0 = data;
   return data;
}

long count = 0;
//RX-Recieve Interrupt, Stops working after buffer.runable is set
ISR(USART0_RX_vect) {  
  PORTB ^= _BV(PB6);
  uint8_t data = UDR0;
  BufferIn(data);
  if(buffer.write > 200 && !buffer.runable){ //Starts reading from Buffer in Interrupt
    buffer.runable = 1;
  } 
  
  sbi(UCSR0B, RXCIE0); // UART Control and Status Register B
}


//
// Put 1 Byte to the Buffer
//
// Returns:
//     BUFFER_FAIL       Ringbuffer is full. It cant save another byte in it
//     BUFFER_SUCCESS    Byte saved
//
uint8_t BufferIn(uint8_t byte)
{
  if ( ( buffer.write + 1 == buffer.read ) ||
       ( buffer.read == 0 && buffer.write + 1 == BUFFER_SIZE ) ){
        return BUFFER_FAIL; // full
       }
    
  buffer.data[buffer.write] = byte;
  buffer.write++;
  
  if (buffer.write >= BUFFER_SIZE)
    buffer.write = 0;
  return BUFFER_SUCCESS;
}

//
// Takes 1 Byte out of the ringbuffer if one is ready
//
// Returns:
//     BUFFER_FAIL       Ringbuffer is empty
//     BUFFER_SUCCESS    1 Byte is dilivered
//    
uint8_t BufferOut(uint8_t *pByte)
{
  if (buffer.read == buffer.write){
    return BUFFER_FAIL;
  }
    
  *pByte = buffer.data[buffer.read];

  if(bit_pointer == 7){
    buffer.read++;
    if (buffer.read >= BUFFER_SIZE)
      buffer.read = 0;
  }
  return BUFFER_SUCCESS;
}


void loop(){}

Couple of questions:

Why use the Arduino IDE if you seem to dislike Arduino functions (aka mess with direct port manupulation and make your own serial handling).

Why is 'buffer' not volatile?

  1. I must use it as a frequency generator from higher Order not my decision =p And I also need it because the standard functions are to slow
  2. I havn't workes with volatile and C its my first program since 10 years but I will give it a try
  DDRB |= _BV(DDB7); //Set Pin 13 to output
  DDRB |= _BV(DDB6); //Set Pin 13 to output

At least one of those comments is wrong.

Diddling with the timer while the timer is running is a bad idea.

Ah yeah the lower comment is wrong but I use it right, forgot to change. I use this functions for toggling to see if the interrupt is working or not.

What do you mean, the timer isnt running in the setup or am I wrong?

I also have added volatile but without any success, the pin is toggling until the buffer has the needed values and buffer.runable is set, then the toggling stops.

ISR(USART0_RX_vect) {  
  PORTB ^= _BV(PB7);
  uint8_t data = UDR0;
  BufferIn(data);
  if(buffer.write > 200 && !buffer.runable){ //After buffer.runable the PORTB toggle dont do anything.
    buffer.runable = 1;
  } 
  
  sbi(UCSR0B, RXCIE0); 
}

Buffer.runable is then in Timer1 used for read from the Buffer:

//Timer1 write Data in Buffer
int  bit_pointer = -1;
ISR(TIMER1_COMPA_vect){
  TCNT1 = t1_load;
  if(buffer.runable){
    bit_pointer++;
    uint8_t *c;
    BufferOut(c);
    char test = *c;
    PORTB &= ((test >> bit_pointer) & 0x01) << 7;
    if(bit_pointer == 7){
      bit_pointer = -1;
      //serial_write_byte(test);
    }
  }
}

And then take the value from the Buffer:

//
// Takes 1 Byte out of the ringbuffer if one is ready
//
// Returns:
//     BUFFER_FAIL       Ringbuffer is empty
//     BUFFER_SUCCESS    1 Byte is dilivered
//    
uint8_t BufferOut(uint8_t *pByte)
{
  if (buffer.read == buffer.write){
    return BUFFER_FAIL;
  }
    
  *pByte = buffer.data[buffer.read];

  if(bit_pointer == 7){
    buffer.read++;
    if (buffer.read >= BUFFER_SIZE)
      buffer.read = 0;
  }
  return BUFFER_SUCCESS;
}

the timer isnt running in the setup or am I wrong?

You are wrong. The timer IS running when setup() is called.

But thats not the Problem, this Part was and is working fine for the whole time it only stops after buffer is available to read.

FoldFence:

  1. I must use it as a frequency generator from higher Order not my decision =p And I also need it because the standard functions are to slow

Then do yourself a favor and just stick with avr-g+ or avr-gcc even...

But really, as far as I can see you just mimic what's already in the HAL of the Arduino IDE...

septillion:
Then do yourself a favor and just stick with avr-g+ or avr-gcc even...

But really, as far as I can see you just mimic what's already in the HAL of the Arduino IDE...

I use the Datasheet of the Atmega 2560 and yeah a change would be possible but I must do it with the Arduino and I should use port/register manipulation what is working until I use the Buffer.

Do you have any Idea why the interrupt is blocking if I use the BufferOut function ?

FoldFence:
I must do it with the Arduino

Arduino hardware? Or Arduino IDE? Do note, they are two different and independent choices :wink:

Ah now I understand, yeah I use the Arduino IDE because the VS Code does not work but yeah you are right I could change but the IDE is not the Problem I can also write with Notepad I only use the IDE for the compilition. :smiley:

did you change this

struct Buffer {
 uint8_t data[BUFFER_SIZE];
 volatile uint8_t read; // zeigt auf das Feld mit dem ältesten Inhalt
 volatile uint8_t write; // zeigt immer auf leeres Feld
 volatile uint8_t runable;
} buffer = {{}, 0, 0, 0};

to

struct Buffer {
  volatile uint8_t data[BUFFER_SIZE];
  volatile uint16_t read; // zeigt auf das Feld mit dem ältesten Inhalt
  volatile uint16_t write; // zeigt immer auf leeres Feld
  volatile uint8_t runable;
} buffer = {{}, 0, 0, 0};

? (that should also give you a possibly bigger buffer size.)

Thing is, the IDE does a lot more then just compiling (and linking) it...

Yeah I have changed it, I think it worked now I made an Mutex for the buffer read/write with success!

I only have now the problem left if I set the timer to a t1_comp value < 32 the RX_Recieve interrupt dont work anymore…

What do you mean I thought the IDE just use a make file and the defined compiler ? Which IDE would you suggest for the programming part?

It merges tabs, tries to generate prototypes, includes a whole bunch of wrapper (init stuff, HAL etc), includes basic libraries, sets compiler flags, tries to find the correct library used, compiles everything and links.

And a large portion of it's power (to write code quick) is the whole wrapper part. Which would include a fine implementation of a Serial buffer. If you just want bare bones it would be more logical to just use AVR-G++.