# Unnexpected Behaviour From Software UART On ATtiny84A AVR

I am trying to implement a software UART for the ATtiny84A, as it does not come with a UART out of the box.

The following is an example of the UART TX:

DDRB  |= (1 << DDB0); // Set the pin on Port B0 to be an output for UART TX.
PORTB |= (1 << PORTB0); // Default the pin to HIGH for the idle high of the UART

void uart_tx(uint8_t *transmit_data)
{
uint8_t string_length = strlen(transmit_data);
for (uint_8t character = 0; character < string_length; character++) // Separate the string into characters.
{
PORTB &=~ (1 << PORTB0); // Send a start bit by bringing the UART TX low.
timer_delay(); // Extra function that generates a delay to generate the appropriate baudrate.

for (uint8_t character_bit = 0; character_bit < 8; character_bit++) // Separate the character into bits.
{
if ((1 << character_bit) & transmit_data[character]) //
{
PORTB |= (1 << PORTB0); // Transmit a logical one
timer_delay(); // Aforementioned delay
} else {
PORTB &=~ (1 << PORTB0); // Transmit a logical 0
timer_delay(); // Aforementioned delay
}
}
PORTB |= (1 << PORTB0); // Transmit a stop bit by bringing UART tx High.
timer_delay(); // Aforementioned delay
}
}

uart_tx("ab");



What I would expect as an output is

0100001101 0010001101


however, what I am actually getting is shown in the following

which in terms of bits is

00001000011010010001101...


Taken as a whole, it has little meaning, but upon closer inspection, parts of it are correct. What is wrong about it is the 000 inserted at the beginning, so a more accurate way of looking at it is

?...000 0100001101 0010001101
^ start bit?


More specifically: The last two frames are accurate, but mystery data is being inserted at the beginning.

What is very strange, is that If I implement this in a regular C program, it works as I would expect:

#include <stdio.h>
#include <string.h>

void uart_tx(unsigned char *transmit_data)
{
for (unsigned char character = 0; character < strlen(transmit_data); character++)
{
printf("0");
for (unsigned char character_bit = 0; character_bit < 8; character_bit++)
{
if ((1 << character_bit) & transmit_data[character])
{
printf("1");
} else
{
printf("0");
}
}
printf("1");
printf(" ");
}
}

uart_tx("ab");


outputs

0100001101 0010001101


as expected, so I am very perplexed as to what is going on here.

EDIT: Here is the delay related code

// Initializing the timer
TCCR0A  |=  (1 << WGM01);
TIMSK0  |=  (1 << OCIE0A);
OCR0A   =   52;

// timer function
void timer_delay(void)
{
TCNT0   =   0;  // Reset the time
TCCR0B  |=  (1 << CS01); // start the timer with /8 prescaler.
while (!(TIFR0 & (1 << OCF0A)));    // Wait until the compare interrupt flag is set
TIFR0   &=~ (1 << OCF0A);   // Reset the Compare flag
TCCR0B  &=~ (1 << CS01);    // Stop the timer.
}
$$$$

• The idle state is HIGH. But why is the leftmost one third of the trace low ? If the start bit starts with a HIGH->LOW transition, your trigger (blue triangle) seems to be set for a LOW->HIGH transition. I think the extra 000 is coming from outside the function uart_tx. i.e., bet ween the line PORTB |= (1 << PORTB0); and the actual call to the uart_tx function. Can you show the lines in the code between the initial idle state setting and call to uart_tx ?
– AJN
May 5 at 8:13
• @AJN There's nothing in between those that would have any effect. In my code all there is is the initialization of a timer, and the timer_delay() function definition. I've even experimented with putting the idle state immediately before the function call, and still the same. May 5 at 8:16
• Is the observation persisting for multiple runs ? Perhaps some interrupt occurred just after the start bit was issued in the run where you captured the data ?
– AJN
May 5 at 8:19
• strlen(transmit_data); What if I want to send binary data instead of just text? May 5 at 13:59
• "// Initializing the timer TCCR0A |= ..." ... "TCCR0B = " I don't know this part but aren't those 2 different timer channels? It would seem that you init timer A then use timer B. May 5 at 14:11

The timer interrupt-flag is reset incorrectly. An interrupt flag is reset by writing a 1 to it, and not a 0.

TIFR0 &=~ (1 << OCF0A);
^ Incorrect


It should be

TIFR0 |= (1 << OCF0A);
`

See Section 11.9.7 of the ATtiny24A/44A/84A datasheet (2020 version - Revision A) listed here

...OCF0A is cleared by hardware when executing the cor- responding interrupt handling vector. Alternatively, OCF0A is cleared by writing a logic one to the flag...