Computing > Programming

[AVR UART] Sends out 7-data bits instead of 8-bits


Hello everyone!

Im having a very strange issue with an ATMega328P and I cant seem to solve it.

The issue is that the processor is sending 7 data bits instead of 8 data bits even though its configured to send 8-data bits.

I wrote this code a while back and prototyped it on the Arduino UNO but programmed it using Atmel Studio 7 and Atmel ICE, used the fuse settings for internal 8MHz clock with no "clock div 8". The code worked fine on this platform.

I recently received the final hardware after a very long delay due to Covid/semiconductor shortage. The strange thing is that the same code for the same processor is no longer working and I'm not sure why, ive never tested the code on this hardware but ive tested older unrelated code and everything seems to work except the UART. The RS485 enable pin goes low way before the UART transmission is completed, its about 1000 times faster than the baud rate and only shows up as a dot when zoomed to fit the transmission data on screen.

All the registers seem to be correctly configured according to the datasheet, maybe ive stared at the same code for too long and am going crazy, no idea. I do get frame errors (from the UCSR0A status register) whenever I try to send data larger than 7-bits so it seems that it understands that it is configured for 7-bits but according to the register debug overview it configured correctly.

Ive added the stripped UART code and output, captured on the scope below. The datasheet is attached and registers info I'm using can be found on page 159.
Have a nice weekend!

Sorry for the comment indentation, it doesn't want to indent correctly when posting it here.

--- Code: ---#define F_CPU 7372800UL
#define BAUD 9600
#define UBRR F_CPU/16/BAUD-1 // 47

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

int main(void){

UBRR0H = ((uint8_t)(UBRR >> 8)); // Set baud rate, 8Mhz UBRR -> 47
UBRR0L = ((uint8_t)(UBRR)); // Baud rate Low

UCSR0B = (1<< RXEN0) | (1 << TXEN0); // Enable RX/TX
UCSR0C = (1 << UCSZ01) | (1 << UCSZ00); // 8-data bits and 1 stop bit, no parity.

DDRD = (1 << PORTD4);         // Set PD4 as output, PD4 = RS485 control pin

    while (1){

PORTD = (1 << PORTD4); //Transmit enable for RS485
while(!(UCSR0A & (1<<UDRE0))); // While data register is empty.

UDR0 = 0xAA;
_delay_us(850); //Should not need this for the EN-pin. did not need it before...
PORTD = (0 << PORTD4); // Disable transmit


--- End code ---

Try sending 0x55 instead of 0xAA

8th bit (bit 7 counting 0 to 7) is there - but is not obvious because it is a high when sending AA and high is the same state as stop bit and rest state

I have no idea whats going on. Wiped the memory of the processor and reprogrammed it. It sort of works now.

The data is correct, im able to send a full byte (0xFF) and it displayed correctly in RealTerm.

The 850us delay to keep the control line for the RS485 is still needed. Not sure why the Arduino UNO didn't need the delay too keep the control line high but this does. Might have just been because of the "no load" on the Arduino Pins compared to my circuit board so it barely worked.


--- Quote from: Sudo_apt-get_install_yum on May 21, 2021, 01:45:22 pm ---

--- Code: ---...

while (1){

    PORTD = (1 << PORTD4);                 //Transmit enable for RS485
    while(!(UCSR0A & (1<<UDRE0)));     // While data register is empty.

    UDR0 = 0xAA;
    _delay_us(850);                               //Should not need this for the EN-pin. did not need it before...
    PORTD = (0 << PORTD4);                 // Disable transmit

--- End code ---

--- End quote ---

The reason you need a delay before clearing pin D4 is that some time is needed to transmit the data after you load UDR0.  A much better way of doing this is to wait for the TXC0 bit to be set, or maybe better still have it raise an interrupt and clear D4 in the interrupt handler.

You are right, it’s a way better approach.
I’m planning on switching to the ATMega808 which has a hardware controlled "control line" so I didn’t put much though into delay-based control. Il add the TXC0 blocker into the code.
Only reason I used the ATMega328 was because I had a few Arduinos at home and all micros were sold out with massive lead times.


[0] Message Index

There was an error while thanking
Go to full version