Is 9-bit Serial communication possible on Arduino?

Hello all, I hope you are having a great day as you read this.

I am currently working with the Arduino DUE and was wondering if it was possible to have 9-bit serial communication. I would like to use a 9th bit to serve as a wake up bit when continuously sending data. If anyone has any leads, please let me know. If it is possible even on a Mega or an Uno, that is perfectly fine and that information would be valuable to me as well.

The Arduino Due has a AT91SAM3X8E MCU.

The datasheet and CMSIS header files tell you all you need to know about that chip’s USART / serial peripheral. As you can see in

And in the datasheet

grafik


However, as you can see here in

the Arduino (USART/UART) serial classes do not expose the 9-bit mode to you, although it is there in hardware.

What you can of course do is either modify the Arduino core to support it, or write your own functions to configure and send 9-data, like

#include <Arduino.h>

//only for reference: Which Serials map to which U(S)ART peripherals
//USARTClass Serial1(USART0, USART0_IRQn, ID_USART0, &rx_buffer2, &tx_buffer2);
//USARTClass Serial2(USART1, USART1_IRQn, ID_USART1, &rx_buffer3, &tx_buffer3);
//USARTClass Serial3(USART3, USART3_IRQn, ID_USART3, &rx_buffer4, &tx_buffer4);

void setup() {
    Serial.begin(115200); // serial montitor uart
    Serial1.begin(115200);
    // enable 9-bit mode after general config has been done
    USART0->US_CR |= US_MR_MODE9; 
}

/* next bigger datatype capable of holding at least 9 bits is uint16_t  */
void send_9bit_data(uint16_t data) {
    // wait until possibly previous transmission is done
    while((USART0->US_CR & US_CSR_TXBUFE) != 0) { delay(1); }
    // write into Transmit Holding Register (THR). TXCHR is 9-bit wide!
    USART0->US_THR = data & 0x1ffu; // mask off any bits beyond 9 bit
    // wait until transmission is done again
    while((USART0->US_CR & US_CSR_TXBUFE) != 0) { delay(1); }
}

void loop() {
    // try and produce different pattern with 9th bit set or not
    send_9bit_data(0xFF | (1 << 8)); // also equal to 0x1ff
    send_9bit_data(0xFF); // also equal 0x0ff
}
2 Likes

Ahh I see! Wow, this is super helpful compared to what I have found online. I am going to try to figure out how to use this in my application. But in case I take a day or two in comparison to your hour or so I will share my application. I am continuously sending 9-bit data from another device, so on the DUE I would like to be able to read incoming data, detect a ‘stop’ bit, and then continue to read for the next set of 9-bit data. I am not the greatest with pointers but I will try to use the registers as you did.

I see. Well the MODE9 bit should also affect the UART RX path equally. For a very simply test, you could disbale the interrupt handler code that is enabled by the regular code so that it doesn’t snatch away the received data and wait and read the data yourself.

As in,

#include <Arduino.h>
#include <chip.h>

//only for reference: Which Serials map to which U(S)ART peripherals
//USARTClass Serial1(USART0, USART0_IRQn, ID_USART0, &rx_buffer2, &tx_buffer2);
//USARTClass Serial2(USART1, USART1_IRQn, ID_USART1, &rx_buffer3, &tx_buffer3);
//USARTClass Serial3(USART3, USART3_IRQn, ID_USART3, &rx_buffer4, &tx_buffer4);

void setup() {
    Serial.begin(115200); // serial montitor uart
    Serial1.begin(115200);
    // enable 9-bit mode after general config has been done
    USART0->US_CR |= US_MR_MODE9; 
    // disable RX interrupt so that the Arduino code doesn't steal the data
    NVIC_DisableIRQ(USART0_IRQn);
    // disable generation of RX (ready) interrupt in USART peripheral, we do a blocking test
    USART0->US_IER = /*UART_IER_RXRDY |*/ UART_IER_OVRE | UART_IER_FRAME;
}

void read_9bit_data_blocking() {
    // wait until RX ready (RX ready is not 0)
    while((USART0->US_CSR & US_CSR_RXRDY) == 0) {}
    // read data
    uint16_t data = USART0->US_RHR & 0x1ffu;
    // print back
    Serial.println("RECEIVED DATA: 0x" + String(data, HEX));
}

void loop() {
    read_9bit_data_blocking();
}

Of course all untested.

1 Like