I am developing a C application using avr-libc on an AVR ATmega328P microcontroller. Since I don't have an ICE debugger, I followed these instructions and this tutorial to create features stdio.hsuch as those printfcapable of using hardware UART like stdout.
This works, and I can see the output on the PC terminal connected to my target board, but the strange thing is: when I have only one printfon the main one, but before the main loop something causes the processor to reset, whereas if I have printfonly inside main loop or before the main loop And inside the loop it works great. Something like that:
#include <stdio.h>
FILE uart_output = FDEV_SETUP_STREAM(uart_drv_send_byte, NULL, _FDEV_SETUP_WRITE);
FILE uart_input = FDEV_SETUP_STREAM(NULL, uart_drv_read_byte, _FDEV_SETUP_READ);
int main() {
stdout = &uart_output;
stdin = &uart_input;
timer_init()
uart_drv_start(UBRRH_VALUE, UBRRL_VALUE, USE_2X, &PORTB, 2);
set_sleep_mode(SLEEP_MODE_IDLE);
printf("START ");
while(1) {
printf("LOOP ");
sleep_mode();
}
}
The above code produces the following output:
START LOOP LOOP LOOP LOOP LOOP LOOP ... LOOP
which is expected. If we comment on the line printf("START "), it will produce this:
LOOP LOOP LOOP LOOP LOOP LOOP LOOP ... LOOP
which is also wonderful. The problem is that if whileI don’t have in the loop printf, it will look like this:
START START START START START START ... START
, , START, , 1 & times; kHz. ? , ( , , LOOP, START).
GPIO
, GPIO print("START ") sleep_mode :
int main() {
GPIO1_ON;
printf("START ");
GPIO1_OFF;
while(1) {
GPIO2_ON;
sleep_mode();
GPIO2_OFF;
}
}
, GPIO1 132 μs (printf("START ") ), 6.6 ms - , 9600 / - GPIO2 12 ( : UART-ready-to-transfer UART-empty-data-register), 1,4 , GPIO1 , printf("START ") - , reset. , , UART, , UART , , printf , reset ( , reset , UART ).
(SOLVED!): , UART init TX **
UART AVR, , RS-232, RS-485, TX_ENABLE . , , ATmega328P ATmega644, , #define TX_VECTOR, . "TX_VECTOR" UDRE , USART0_TX_vect ( , ...)
(ISR) USART0_TX_vect, reset , @PeterGibson . !
#if defined(__AVR_ATmega328P__)
#define RX_VECTOR USART_RX_vect
#define TX_VECTOR USART_UDRE_vect
#elif defined(__AVR_ATmega644P__)
#define RX_VECTOR USART0_RX_vect
#define TX_VECTOR USART0_UDRE_vect
#endif
ISR(TX_VECTOR)
{
uint8_t byte;
if (!ringbuffer_read_byte(&txrb, &byte)) {
if (TX_ENABLE_PORT)
*TX_ENABLE_PORT |= _BV(TX_ENABLE_PIN);
UDR0 = byte;
}
else {
UCSR0B &= ~_BV(UDRIE0);
}
if ((TX_ENABLE_PORT) && (UCSR0A & _BV(TXC0) & _BV(UDR0))) {
*TX_ENABLE_PORT &= ~_BV(TX_ENABLE_PIN);
UCSR0B &= ~_BV(UDRIE0);
}
}
void uart_drv_start(uint8_t ubrrh, uint8_t ubrrl, uint8_t use2x,
volatile uint8_t* rs485_tx_enable_io_port,
uint8_t rs485_tx_enable_io_pin)
{
ringbuffer_init(&txrb, &tx_buffer[0], UART_TX_BUFSIZE);
ringbuffer_init(&rxrb, &rx_buffer[0], UART_RX_BUFSIZE);
UCSR0B = 0x00;
UBRR0H = ubrrh;
UBRR0L = ubrrl;
if (use2x)
UCSR0A |= _BV(U2X0);
else
UCSR0A &= ~_BV(U2X0);
UCSR0C = _BV(UCSZ00) | _BV(UCSZ01);
if (rs485_tx_enable_io_port) {
TX_ENABLE_PORT = rs485_tx_enable_io_port;
TX_ENABLE_PIN = rs485_tx_enable_io_pin;
*(TX_ENABLE_PORT-1) |= _BV(TX_ENABLE_PIN);
*TX_ENABLE_PORT &= ~_BV(TX_ENABLE_PIN);
UCSR0B = _BV(TXCIE0);
}
UCSR0B |= _BV(RXEN0) | _BV(TXEN0) | _BV(RXCIE0);
}
UART ( 100%!)
, UART, AVR ATmega, . , ISR!
#if defined(__AVR_ATmega328P__)
#define RX_BYTE_AVAILABLE USART_RX_vect
#define TX_FRAME_ENDED USART_TX_vect
#define TX_DATA_REGISTER_EMPTY USART_UDRE_vect
#elif defined(__AVR_ATmega644P__)
#define RX_BYTE_AVAILABLE USART0_RX_vect
#define TX_FRAME_ENDED USART0_TX_vect
#define TX_DATA_REGISTER_EMPTY USART0_UDRE_vect
#endif
static volatile uint8_t* TX_ENABLE_PORT = NULL;
static volatile uint8_t TX_ENABLE_PIN = 0;
ISR(RX_BYTE_AVAILABLE)
{
uint8_t status = UCSR0A;
if (status & _BV(FE0)) {
}
if (status & (_BV(DOR0) | _BV(UPE0))) {
}
ringbuffer_write_byte(&rxrb, UDR0);
}
ISR(TX_FRAME_ENDED)
{
*TX_ENABLE_PORT &= ~_BV(TX_ENABLE_PIN);
}
ISR(TX_DATA_REGISTER_EMPTY)
{
uint8_t byte;
if (!ringbuffer_read_byte(&txrb, &byte)) {
if (TX_ENABLE_PORT)
*TX_ENABLE_PORT |= _BV(TX_ENABLE_PIN);
UDR0 = byte;
}
else {
UCSR0B &= ~_BV(UDRIE0);
}
}
void uart_drv_start(uint8_t ubrrh, uint8_t ubrrl, uint8_t use2x,
volatile uint8_t* rs485_tx_enable_io_port,
uint8_t rs485_tx_enable_io_pin)
{
ringbuffer_init(&txrb, &tx_buffer[0], UART_TX_BUFSIZE);
ringbuffer_init(&rxrb, &rx_buffer[0], UART_RX_BUFSIZE);
cli();
UCSR0B = 0x00;
UBRR0H = ubrrh;
UBRR0L = ubrrl;
if (use2x)
UCSR0A |= _BV(U2X0);
else
UCSR0A &= ~_BV(U2X0);
UCSR0C = _BV(UCSZ00) | _BV(UCSZ01);
if (rs485_tx_enable_io_port) {
TX_ENABLE_PORT = rs485_tx_enable_io_port;
TX_ENABLE_PIN = rs485_tx_enable_io_pin;
*(TX_ENABLE_PORT-1) |= _BV(TX_ENABLE_PIN);
*TX_ENABLE_PORT &= ~_BV(TX_ENABLE_PIN);
UCSR0B = _BV(TXCIE0);
}
UCSR0B |= _BV(RXEN0) | _BV(TXEN0) | _BV(RXCIE0);
sei();
}
void uart_drv_send_byte(uint8_t byte, FILE *stream)
{
if (byte == '\n') {
uart_drv_send_byte('\r', stream);
}
uint8_t sreg = SREG;
cli();
while(ringbuffer_write_byte(&txrb, byte)) {
SREG = sreg;
_NOP();
sreg = SREG;
cli();
}
UCSR0B |= _BV(UDRIE0);
SREG = sreg;
}
uint8_t uart_drv_read_byte(FILE *stream)
{
uint8_t byte;
uint8_t sreg = SREG;
cli();
ringbuffer_read_byte(&rxrb, &byte);
SREG = sreg;
return byte;
}