Search code examples
cuartatmega9-bit-serial

Atmega Toggle Variable Too Slow For 9Bit UART


I've written some code to output to the usart a 9bit message.

The code is as follows:

bool_t SERIAL__TX_SEND_NINE(U8_t ch, bool_t nine)         // send a character
{

  bool_t result = SE_TRUE;              // assume OK

  // transceiver is on so send as soon as the buffer is ready
  while(SERIAL__TX_READY() == SE_FALSE)
  {                                     // make sure the Tx buffer is ready for another character
  }
  if (nine == TRUE)
  {   
    //SERIAL_USART_B |= 0x01;   
    UCSR0B &= ~(1<<TXB80);
    UCSR0B |= (1<<TXB80);
  }
  else
  {     
    //SERIAL_USART_B &= 0xFE;   
    UCSR0B &= ~(1<<TXB80);
  }

  SERIAL_UDR = ch;                      // then send the next character
  SERIAL_USART_A |= SERIAL_TX_DONE;     // clear the done flag
  return result;                        // OK
}

//! \brief  send a byte on the serial communications bus if ready - return TRUE if successful
//!
//! \param  ch the byte to transmit
//! \return SE_TRUE if the byte was sent, SE_FALSE can't happen for this device
bool_t serial_0_tx_send_if_ready_nine(U8_t ch, bool_t nine)         // send a character if able to
{
    // if buffer ready?
    if(SERIAL__TX_READY() == FALSE)
    {
        return FALSE;
    }

return SERIAL__TX_SEND_NINE(ch, nine);           // send the next character
}

SERIAL_UDR = UDR0

SERIAL_USART_A = UCSR0A

When I put in breakpoints for whenever the code is run, whether it is the start of the function or the end of the function, it works as expected. The ninth bit toggles on and off for each data packet. (5 data packets in total)

When I have no breakpoints, when the ninth bit toggles appear to be completely at random. When I only have one breakpoint within the if statement, it only hits once. So, I'm guessing the 'nine' value isn't setting quick enough to run the toggle at full speed.

The toggle bit is being set a function before hand.

// outgoing state machine
// only process it if the function pointer isn't NULL
if(handle->send != NULL)
{
  // try and get a byte to send
  if(RingBuffer_GetByte(&handle->out_rb, &data) == RINGBUFFER_OK)
  {
    // we got something to send
        if (nine_toggle == TRUE)
        {
            nine_toggle = FALSE;
        }
        else
        {
            nine_toggle = TRUE;
        }

  if(serial_0_tx_send_if_ready_nine(data, nine_toggle) == SE_FALSE)
  {
    // but couldn't send it so put it back
    RingBuffer_PutBackByte(&handle->out_rb, data);
  }
  // otherwise we sent another one. ringbuffer does all the data handling so nothing else to do
}
}

But I don't understand why that would happen.

Does the atemga324p have a timing delay when storing unsigned chars (bool_t)

Any ideas would be appreciate.

Additional details. MCU: Atmega324p. OS: Windows 10. Compiler: Atmel Studio 7.0. Optimization: None.


Solution

  • Figured it out.

    serial_0_tx_send_if_ready_nine(...) was returning false when running at full speed, because the comm port wasn't ready to send the data.

    Therefore it was holding onto that byte and re-running the send function, however, the toggle had already been changed, and I didnt reverse the toggle.

    I changed a part of the code to be the following:

      if(serial_0_tx_send_if_ready_nine(data, nine_toggle) == SE_FALSE)
      {
        // but couldn't send it so put it back
        RingBuffer8_PutBackByte(&handle->out_rb, data);
        nine_toggle ^= 1; //<== Added this line
      }