AVR half duplex receiver interrupt error (ATTiny841)

Go To Last Post
5 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

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;
}

 

Last Edited: Thu. Oct 12, 2017 - 10:07 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The first thing is that the c variable in main() should be volatile and commsController should be pointer to volatile.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I managed to fix the code! Here is the working code. Would it have worked the same if I allocated the object to heap? instead of creating it in stack and using pointers.

 

#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;
}

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

And what was the issue?

BTW, cli() just before sei() is totally unnecessary.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Creating the object outside of main stack space seemed to solve it. I also needed to declare the object volatile as the character was being updated.

In terms of the echo, the receiver was listening to all transmitted information so I needed to ensure it was disabled. (It was also working even though I thought it wasn't...)