Reading 9bit serial data problem

I need to make a program that use the serial in 9 bit data mode with an arduino mega.

Since that mode isn't supported natively, I start the USART writing directly in the registers (UBRRnL, UBRRnH, USCRnA, USCRnB and USCRnC) and I succesfully start the USART in 9 bit data mode.

The problem is that when I turn on that mode, the RXB8n bit (9 bit received) of the USCRnB change from 0 to 1, as if the mega received a byte.

Then, when I use the code to read the bytes received (mixing reading the registers and the Serial.read()), I discovered that the 9 bit is "moved" one position, because of that first phantom bit. But since is only actualized when it received a new byte, it's unusable.

Thats my code:

setup: //I use the Serial2
  UBRR2L=0x67;  
  UBRR2H=0x00;
  UCSR2A=0x20;
  UCSR2B=0x9C;
  UCSR2C=0x06;

reading:

  timeOut=millis();
  unsigned char estado, resh, resl;

while(Serial2.available()==0) 
 {
   
    if ((millis()-timeOut)> TimeOutByte)
    {
      Serial.println("TimeOut9bit Bytes");
      break;
    }
  }
  estado = UCSR2A;
  resh = UCSR2B;
  resl = UDR2;  //I've also tried without reading the UDR2
  
  resh = (resh >> 1) & 0x01;

  ninthbit=resh; //Global variable
  dataReceived=Serial2.read(); //Global variable

If I print the resl (UDR2), ninthbit and dataReceived, I can saw that the ninthbit is syncronized with the resl, but the dataReceived is one position advanced. Because the first read of the resl is always 0 and resh 1.

Anyone knows why is this happend?

Thanks, Er_Garry

could you not used "Serial.begin(speed, config)"? config sets the data, parity, and stop bits. (Default is 8 data bits, no parity, one stop bit)

https://www.arduino.cc/en/Serial/Begin

https://nvsl.github.io/PiDuino_Library/function/2000/02/02/Serial-begin-config.html

sherzaad: could you not used "Serial.begin(speed, config)"? config sets the data, parity, and stop bits. (Default is 8 data bits, no parity, one stop bit)

https://www.arduino.cc/en/Serial/Begin

https://nvsl.github.io/PiDuino_Library/function/2000/02/02/Serial-begin-config.html

As OP said, there is no 9 bit mode with serial.begin.

sherzaad: could you not used "Serial.begin(speed, config)"? config sets the data, parity, and stop bits. (Default is 8 data bits, no parity, one stop bit)

https://www.arduino.cc/en/Serial/Begin

https://nvsl.github.io/PiDuino_Library/function/2000/02/02/Serial-begin-config.html

The 9 bit mode cannot be achieved with the Serial.begin(), but with that registers I could enter the 9 bit mode at 9600 bauds. Because I can Write without problems (and that method works fine), and I could read 9 bits data, but the ninth bit is unsynced with the others (as I explain in the first post).

So I think that is something with the Serial Library buffer, because I also print the USCR2A after the Serial2.available() and the interrupt bit RXC2 was always 0.

Every time a character is received, the Arduino Serial library is grabbing the byte and stuffing it into the input buffer; it ignores the 9th bit, which wouldn't fit in the input buffer anyway, because that's an array of bytes. You would need to modify this isr (or disable it and make sure you never go more than ~1ms (assuming 9600 baud) between checking the serial port ;-) ) to retain the 9th bit. Among other things, that would mean making the datatype for the buffer bigger so it could store those 9th bits (ie, you're moving to int's, so that doubles the size of the array). This is presumably why the person writing the serial library used in the arduino core didn't support 9-bit serial.

DrAzzy: Every time a character is received, the Arduino Serial library is grabbing the byte and stuffing it into the input buffer; it ignores the 9th bit, which wouldn't fit in the input buffer anyway, because that's an array of bytes. You would need to modify this isr (or disable it and make sure you never go more than ~1ms (assuming 9600 baud) between checking the serial port ;-) ) to retain the 9th bit. Among other things, that would mean making the datatype for the buffer bigger so it could store those 9th bits (ie, you're moving to int's, so that doubles the size of the array). This is presumably why the person writing the serial library used in the arduino core didn't support 9-bit serial.

Yes, I know that, but I wanted to do without modify the library.

I don't mind to work with the registers instead of the Serial Functions, but I have the problem that the RXC2 flag never turn to 1 (maybe the serial library "steal" the received byte and empty the buffer?). That's why I made a mix of Serial functions and register reads.

The strange thing is that when I receive the first byte, if I checked the UDR and 9th bit there values are 0 and 1, and the Serial2.read() obtain the received byte correctly (only the 8 data bits). When the next byte is received, the UDR and 9th bit values are the values of the first byte (all the 9 bits correctly), instead of the values of the second byte.

So the UDR and 9th bit are always a byte behind the Serial2.read() and it only get updated when it received a new byte.

er_garry: maybe the serial library "steal" the received byte and empty the buffer?

This is exactly what's happening - you need to either disable the interrupt and make sure your code checks the serial registers at least once per ms (more if using higher baud rate), or modify the library.