Search code examples
interruptavruart

AVR half duplex receiver interrupt error


I am attempting to implement half duplex UART with an ATTiny841. The idea of the code is that when I transmit anything but the character 'd' I receive nothing back and when I transmit the 'd' I get that letter back. After testing this out, with various characters, I always receive the same letter that I have transmitted. One of the major issues I am facing here is within the USART0_RX_vect. For some reason the if statement does not appear to work. Any suggestions on what I could do to solve this?

#include <avr/io.h>
#include <avr/interrupt.h>

class CommsController {
public:
    uint8_t data;
    bool bjsonComplete;

    CommsController(uint8_t ubrr) {
        UCSR0B |= (1<<RXEN0)|(1<<TXEN0)|(1<<RXCIE0); // Enable Rx and Rx Complete Interrupt.
        UBRR0H = (ubrr>>8);
        UBRR0L = ubrr;
        // Select 8-bit data frame, single stop bit and no parity using UCSR0C (Default values are what we want).

        this->bjsonComplete = false;
    }

    void transmit(unsigned char data) {
        UCSR0B &= ~(1<<RXEN0) & ~(1<<RXCIE0); // disable Rx and interrupt.
        /* Wait for empty transmit buffer */
        while ( !( UCSR0A & (1<<UDRE0)) )
        ;
        /* Put data into buffer, sends the data */
        UDR0 = data;
        while (!(UCSR0A & (1<<UDRE0) & (1<<TXC0))) {}; // Wait for empty transmit buffer.
        UCSR0B |= (1<<RXEN0)|(1<<RXCIE0); // Re-enable Rx and interrupt.
    }
};


volatile uint8_t data = 0;

CommsController* commsController;

ISR(USART0_RX_vect) {
    data = UDR0;
    if(data == 'd') {
        commsController->data = data;
        commsController->bjsonComplete = true;
    }
}

/* Replace with your library code */
int main(void)
{
    cli();
    CommsController c(51);
    commsController = &c;
    sei();

    while(1) {
        if(commsController->bjsonComplete) {
            commsController->transmit(commsController->data);
        }
    }

    return 0;
}

Solution

  • I later found out that the issue was actually because I did not declare the commsController volatile. I will post the full working code below for anyone who is facing similar issues:

    #define F_CPU 8000000UL
    
    #include <avr/io.h>
    #include <avr/interrupt.h>
    #include <avr/delay.h>
    
    class CommsController {
    public:
        volatile uint8_t data;
        volatile bool bjsonComplete;
    
        CommsController(uint8_t ubrr) {
            UCSR0B |= (1<<RXEN0)|(1<<RXCIE0); // Enable Rx and Rx Complete Interrupt.
            UBRR0H = (ubrr>>8);
            UBRR0L = ubrr;
            // Select 8-bit data frame, single stop bit and no parity using UCSR0C (Default values are what we want).
    
            this->bjsonComplete = false;
            this->data = 0;
        } 
    
        void transmit(unsigned char data) volatile {
            UCSR0B &= ~(1<<RXCIE0); // disable Rx interrupt.
            /* Wait for empty transmit buffer */
            while (!( UCSR0A & (1<<UDRE0)));
    
            /* Put data into buffer, sends the data */
            UDR0 = data;
            while (!(UCSR0A & (1<<TXC0))); // Wait for empty transmit buffer.
            UCSR0B |= (1<<RXCIE0); // Re-enable Rx interrupt.
        }
    };
    
    volatile CommsController c(51);
    
    ISR(USART0_RX_vect) {
        c.data = UDR0;
    }
    
    /* Replace with your library code */
    int main(void)
    {
        cli();
        sei();
        DDRB |= (1<<PORTB1);
        PORTB &= ~(1<<PORTB1);
    
        while(1) {
            if(c.data == 'd') {
                c.transmit('f');
                c.data = 0;
            }
        }
    
        return 0;
    }