Serial using 9N1

Hi

Version v0.5.0-rc.1in beta provides the following enhancement

“Support for USART (Serial1/2/4/5) data bits, parity and stop bits1 #7576

I have tried to test using Serial9N1 between 2 photons.

I am sending the following from one photon
"Serial1.write(0x0100 | i);" Where i increments each loop
If I then on the receiving photon set Serial1 to listen to the sending photon and Serial to send over usb.
Using
Serial.println((c >> 8)& 0x00ff, HEX);
Serial.println(c & 0x00ff, HEX);

I don’t get anything for the high byte (the ninth bit). The low byte is fine, this increments between 0 and 255

I have tried a number of other iterations of code. Has anyone successfully got the high byte, i.e. bit 9 from a transmission?

Cheers
Michael

(I originally posted this under the firmware comments topic but think that was the wrong place so posting as a new topic)

I tried a quick test of SERIAL_9N1 mode and could not get it to work looping TX to RX on a Photon running 0.5.0-rc1. The lower 8 bits were fine but I never received a value with the 9th bit set. Here’s the code I used:

#include "Particle.h"

// Connect TX to RX (loopback)

int sendChar = 250;

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

	Serial1.begin(9600, SERIAL_9N1);
}

void loop() {
	Serial1.write(sendChar);
	Serial1.flush();


	unsigned long start = millis();
	int recvChar = Serial1.read();

	while (recvChar < 0 && millis() - start < 2000) {
		delay(1);
		recvChar = Serial1.read();
	}
	Serial.printlnf("sendChar=%d recvChar=%d", sendChar, recvChar);

	if (++sendChar >= 512) {
		sendChar = 0;
		delay(10000);
	}
}

I didn’t have a chance to really dig into it and find out why or even whether the problem is in transmit or receive, but I thought I’d let you know at least this much.

I’m pretty sure it’s a receive problem. This is the output from the TX pin sending 0xAA = 0b010101010 (9-bit). Since serial is LSB first, you can see the idle state (high), start bit (low), then the alternating data bits, and the 9th bit is low before the stop bit (high). I also compared it to the output from 0x155 and the output seems correct to me.

1 Like

Looking through the code, it looks as though the 9th bit is not supported on read (and there are no tests validating a 9-bit read.)

The culprit looks to be this line - the 16-bit data is cast to a char. I’m surprised the code compiles since all warnings are errors.

Changing the declaration from unsigned char to uint16_t might help.

Yes, changing that plus the implementation of store_char and the one place it’s called from fixes 9-bit reads for me.

3 Likes

It might be worth noting that this cast to char could have been done to ensure no random data is introduced into the 16-bit buffer[] when data was always interpreted as 8-bit in the past. With this being variable sizes now, we will need to pay a little more attention to the data read when set to the default 8-bit size… it may be worth adding a mask when not using 9-bits. CI tests will be reviewed to ensure 8-bit mode yields 8-bit data and similarly for 9-bit mode.

Tracking the issue here:

Hi

Thanks for your help confirming that this wasn’t working.

I am keen to get it up and going to test - appreciate that overall testing is required before it can be released.

@rickkas7 could you help in identifying exactly where you changed to get it to work

Also, I am trying to compile locally but get the message “Please note the develop branch contains untested, unreleased code. We recommend using the ‘latest’ branch which contains the latest released firmware code. To build the develop branch, please see the the build documentation at https://github.com/spark/firmware/blob/develop/docs/build.md#building-the-develop-branch. Stop.”

I have followed the link and see under the section “building the develop branch” it says

  1. export the environment variable PARTICLE_DEVELOP=1
  2. after pulling from the develop branch, be sure to build and flash the system firmware

This is foreign to me - what do I need to do to export the environment variable so I can build and flash

Cheers
Michael

Put the Photon in DFU mode (hold down both buttons, then release RESET continuing to hold down SETUP while it blinks magenta until it starts blinking yellow, then release).

I use a command sort of like this:

cd firmware/modules
make all program-dfu PLATFORM=photon APPDIR="~/src/ser9test" PARTICLE_DEVELOP=1

This is what I changed:

diff --git a/hal/src/stm32f2xx/usart_hal.c b/hal/src/stm32f2xx/usart_hal.c
index 8e20b8f..dd7d043 100644
--- a/hal/src/stm32f2xx/usart_hal.c
+++ b/hal/src/stm32f2xx/usart_hal.c
@@ -107,8 +107,8 @@ static STM32_USART_Info *usartMap[TOTAL_USARTS]; // pointer to USART_MAP[] conta
 
 /* Private function prototypes -----------------------------------------------*/
 
-inline void store_char(unsigned char c, Ring_Buffer *buffer) __attribute__((always_inline));
-inline void store_char(unsigned char c, Ring_Buffer *buffer)
+inline void store_value(uint16_t c, Ring_Buffer *buffer) __attribute__((always_inline));
+inline void store_value(uint16_t c, Ring_Buffer *buffer)
 {
        unsigned i = (unsigned int)(buffer->head + 1) % SERIAL_BUFFER_SIZE;
 
@@ -382,7 +382,7 @@ int32_t HAL_USART_Read_Data(HAL_USART_Serial serial)
        }
        else
        {
-               unsigned char c = usartMap[serial]->usart_rx_buffer->buffer[usartMap[serial]->usart_rx_buffer->tail];
+               uint16_t c = usartMap[serial]->usart_rx_buffer->buffer[usartMap[serial]->usart_rx_buffer->tail];
                usartMap[serial]->usart_rx_buffer->tail = (unsigned int)(usartMap[serial]->usart_rx_buffer->tail + 1) % SERIAL_BUFFER_SIZE;
                return c;
        }
@@ -426,8 +426,8 @@ static void HAL_USART_Handler(HAL_USART_Serial serial)
        if(USART_GetITStatus(usartMap[serial]->usart_peripheral, USART_IT_RXNE) != RESET)
        {
                // Read byte from the receive data register
-               unsigned char c = USART_ReceiveData(usartMap[serial]->usart_peripheral);
-               store_char(c, usartMap[serial]->usart_rx_buffer);
+               uint16_t c = USART_ReceiveData(usartMap[serial]->usart_peripheral);
+               store_value(c, usartMap[serial]->usart_rx_buffer);
        }
 
        if(USART_GetITStatus(usartMap[serial]->usart_peripheral, USART_IT_TXE) != RESET)

Good luck! It’s hard at first, but once you get the hang of it, it’s not so bad.

Hi

Thanks so much. It is working wonders now.

Thanks for the assistance with this!

Cheers
Michael

1 Like