SERIAL_8N2 Serial communication on the nano 33 BLE

For a current project, I have a nano 33 BLE that reads data from different sensors (mostly I2C and analog) and sends its results over Bluetooth to an app for further processing.

The problem I have encountered is that one of my sensors communicates over Serial with a SERIAL_8N2 configuration. However, I found out on the Serial.begin() reference page that Serial1 on the nano 33 BLE only supports SERIAL_8N1. Also, all the software serial implementations I've seen so far either don't work on the nano 33 BLE or don't support SERIAL_8N2.

So I'd appreciate any tips on how (or if) I can make the communication to the sensor work.

And somehow in most cases, when 8N2 is transmitted, a UART set to 8N1 will receive it without to much problems.
8N2 has 1 start bit (LOW) 8 data bits (LOW for a '1' and HIGH for a '0' ) and 2 stop bits (both HIGH).
8N1 only has 1 stop bit, but the UART won't start on the next byte until it receives a start bit again.

Try it, i think it should work for you as long as reception is all that you do,

Also from the datasheet

The amount of stop bits can also be configurated through the register CONFIG on page 511

Where it says that there is a bit in one of the registers that can be set to '1' for 2 stop bits and '0' for 1 stop bit.
So it is possible.

Thanks for the quick answer. Of course, you are correct that receiving is not an issue, and that definitely showed a lack of understanding of how exactly Serial communication works on my end.

However, a new issue has come up because I need to be able also to send data to the sensor, so if I'm not mistaken, now the 8N2 config is actually required. I've previously seen the datasheet of the nRF52840 chip you mentioned, but I couldn't get it to work on my own.

My current test code
Below, you can see my attempt to change the register value, which doesn't work, and I'm hoping that someone can tell me what I am doing wrong/how I can fix it.

The contents of the loop are just for testing and having control over when and what gets sent over the Serial1 port to check with an oscilloscope.

#define UARTE1_BASE 0x40028000 // Base address for UARTE1
#define CONFIG_OFFSET 0x56C    // Offset for the CONFIG register
#define UARTE1_CONFIG_REG (*(volatile uint32_t*)(UARTE1_BASE + CONFIG_OFFSET))

void setup() {
  Serial.begin(9600);
  delay(2000);
  Serial.println("start");
  // Configure the UARTE1 for 8 data bits, no parity, 2 stop bits (SERIAL_8N2)
  uint32_t configValue = UARTE1_CONFIG_REG; // Read current value
  Serial.println(configValue,BIN);  // Print the current value
  configValue |= (0x01 << 4);  // Set the STOP bit field to 1 for two stop bits
  UARTE1_CONFIG_REG = configValue; // Write back to the CONFIG register
  configValue = UARTE1_CONFIG_REG; // Read current value after the changes
  Serial.println(configValue,BIN);  // Print the current value after the changes

  Serial1.begin(9600);

  // Configure the UARTE1 for 8 data bits, no parity, 2 stop bits (SERIAL_8N2)
  configValue |= (0x01 << 4);  // Set the STOP bit field to 1 for two stop bits
  UARTE1_CONFIG_REG = configValue; // Write back to the CONFIG register
  configValue = UARTE1_CONFIG_REG; // Read current value
  Serial.println(configValue,BIN);
}

void loop() {
  if (Serial.available()) {        // If anything comes in Serial (USB),
    Serial1.write(Serial.read());  // read it and send it out Serial1 (pins 0 & 1)
  }
}

Some questions/things I am unsure about:

  • Are there any conflicts because I manually manipulate the register and also call Serial1.begin(), and if so, how would I avoid them/access the Serial/UART port without the Serial1 object?

  • Is it important where in the code I change the contents of the configuration register? For example, does it make a difference if I make the changes before or after the Serial1.begin() call?

  • Am I right to assume that UARTE1 is the right UART to configure (when I have the sensor connected to the RX and TX pins)? It is my understanding that UART0 is used for the USB connection and that UART (as described in section 6.33 in the datasheet) is not actually used as there is only a single UART, but the Arduino has two separate ones (USB and the set of pins or alternatively speaking Serial and Serial1).

Relevant information if you want to check against the datasheet:

  • nRF52840 datasheet
  • Information about the UARTE begins in section 6.34 (page 512)
  • The base addresses can be found under section "6.34.9 Registers" (page 516)
  • The config register is described in section "6.34.9.34 CONFIG" (page 529)

Yes i would say so.

which doesn't work because the result is what ?

yes there are. The config register gets set by the call to begin() The obvious is to change the config register afterwards. For more information you could probably investigate how the core handles the UART. Usually hardwareSerial.h is the place to look. It is quite a quest to find the code that actually sets the registers within the core, since it tends to be spread out over several header and .cpp and sometimes .c files, but it should be in there somewhere.

There i am not sure. Although if you get messages back on the Serial monitor, and those are the ones you send using 'Serial' then i guess the other port would be 'Serial1' But keep in mind the what is referenced as Serial & Serial1 in the Arduino core may refer to something else.

What bothers me a little is that if all these options or available, they have not been implemented in the core, or maybe they are ? Anyway.

Well yeah, though your response was so long ago i hardly remembered what my involvement was.

The result is that the serial signal still only has one stop bit.

Solution
I found out that UARTE1 corresponds to Serial. So, I was modifying the wrong UART object. After changing the base register address to that of UARTE0, which corresponds to Arduino's Serial1, everything works now (the signal now has two stop bits), as you can see in the two attached pictures.

The working code now looks like this:

#define UARTE0_BASE 0x40002000 // Base address for UARTE0
#define CONFIG_OFFSET 0x56C    // Offset for the CONFIG register
#define UARTE0_CONFIG_REG (*(volatile uint32_t*)(UARTE0_BASE + CONFIG_OFFSET))

void setup() {
  Serial.begin(9600);
  
  Serial1.begin(9600);

  // Configure the UARTE0 for 8 data bits, no parity, 2 stop bits (SERIAL_8N2)
  uint32_t configValue = UARTE0_CONFIG_REG; // Read current value
  configValue |= (0x01 << 4);  // Set the STOP bit field to 1 for two stop bits
  UARTE0_CONFIG_REG = configValue; // Write back to the CONFIG register
}

void loop() {
  if (Serial.available()) {        // If anything comes in Serial (USB),
    Serial1.write(Serial.read());  // read it and send it out Serial1 (pins 0 & 1)
  }
}

Not as far as I know. Putting SERIAL_8N2 as an additional argument into the Serial1.begin() function bricks the nano or stops it from continuing with the rest of the code.

Signal viewed with an oscilloscope
For testing, I just wrote two arbitrary characters ("1" and "2" which correspond to 00110001 and 00110010) over the serial monitor, which then were transmitted via Serial1 to be checked with an oscilloscope.

Before the config changes, one can see that after the first byte is transmitted, the signal line goes HIGH for one bit (STOP bit) before going LOW again (START bit) of the second data transfer.

After the config changes, the signal line stays HIGH for double the time (two STOP bits) between the two pieces of data being transmitted.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.