I only have some limited knowledge in interrupts.
This is what I understand about following ISR functions
ISR(USART_RX_vect)
will get called when a new data becomes available at the receive buffer (RXC0 of USCR0A will set to 1) and it gets cleared when data is read
ISR(USART_UDRE_vect)
will get called when UDRE0 becomes 1 indicating transmit buffer is empty and ready to receive data
I set up an UART interrupt code as below, not sure is this the proper way ISR function should look like but it works
/*
* uart_interrupt.c
*
* Created: 12-10-2018 04:54:04 PM
* Author : Athul
*/
#define F_CPU 1000000UL
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
//#include <util/setbaud.h>
#define BAUD 9600
#define SIZE 500
int i = 0, j = 0;
uint8_t data_int;
/* For U2X0 = 0 */
uint16_t UBRR0_value = ((F_CPU / (4L * BAUD)) - 1)/2;
/* For U2X0 = 1 */
//uint16_t UBRR0_value = ((F_CPU / (8L * BAUD)) - 1)/2;
void uart_init(void)
{
/* For a baud rate of 9600 (F_CPU = 1000000), error is 7% when U2X0 = 0. Writing this bit to one will
reduce the divisor of the baud rate divider from 16 to 8 effectively doubling the
transfer rate for asynchronous communication and reduce error to 0.2% */
UCSR0A |= (1 << U2X0);
/*set (global) interrupt enable bit*/
sei();
/* transmit enable, receive enable & RX Complete Interrupt Enable */
UCSR0B = (1 << RXEN0) | (1 << TXEN0) | (1 << RXCIE0);
/* 8 bit mode */
UCSR0C = (1 << UCSZ00) | (1 << UCSZ01);
/* Baud rate registers */
UBRR0H = UBRR0_value >> 8;
UBRR0L = UBRR0_value;
}
void uart_tx(uint8_t data)
{
/*wait till USART Receive Complete*/
loop_until_bit_is_set(UCSR0A, UDRE0); // same as while(!(UCSR0A & (1 << UDRE0)));
UDR0 = data;
}
uint8_t uart_rx(void) {
/*wait till USART Data Register Empty*/
loop_until_bit_is_set(UCSR0A, RXC0); // same as while(!(UCSR0A & (1 << RXC0)));
return UDR0;
}
void printString(uint8_t *ptr)
{
while(*ptr != '\0')
{
uart_tx(*ptr);
ptr++;
}
}
/*Interrupt sub-routine for RX Complete Interrupt Enable*/
ISR(USART_RX_vect)
{
data_int = UDR0;
loop_until_bit_is_set(UCSR0A, UDRE0);
UDR0 = data_int;
}
int main(void)
{
/*Initialize uart*/
uart_init();
/*Test*/
uint8_t *p = "Hello";
printString(p);
/*Set PORTB pins as output*/
DDRB = 0XFF;
/*event loop*/
while (1)
{
/*Toggle PORTB pins*/
PORTB = 0XFF;
_delay_ms(100);
PORTB = 0X00;
_delay_ms(100);
}
}
To know how to implement UDRIE0
, I made following changes,
//USART Data Register Empty Interrupt Enable
UCSR0B = (1 << RXEN0) | (1 << TXEN0) | (1 << RXCIE0) | (1 << UDRIE0);
ISR(USART_RX_vect)
{
data_int = UDR0;
}
ISR(USART_UDRE_vect)
{
UDR0 = data_int;
}
It keeps printing the data that I last entered
Then I decided to create an array and store received characters in it and the ISR(USART_UDRE_vect)
would read each character and transmit it.
#define SIZE 64
int i = 0, j = 0;
uint8_t data_int[SIZE];
ISR(USART_RX_vect)
{
data_int[i] = UDR0;
i++;
if(i > 64)
{
i = 0;
}
}
ISR(USART_UDRE_vect)
{
UDR0 = data_int[j];
j++;
if(j == 64)
{
UCSR0B &= ~(1 << UDRIE0); //disable UDRIE0 interrupt
}
}
It prints "hello" and nothing else.
Can anyone tell why isn't it working.
A small example of UDRIE0
if possible?
Also compiler gives a warning
pointer targets in initialization differ in signedness [-Wpointer-sign]
What does this mean?