Serial 7 bit Data Even Parity

I think I have hit a wall here, after looking at the extensive work that was done to implement parity and 9 bits into Serial I have picked up that the microprocessor does not support 7 bit characters on the USART. Can someone confirm that is so? It seems odd since 7 bit ASCII characters have been used forever.
If it is the case that the micro cannot handle 7 bit characters does anyone have suggestions as to how to get around it. My thinking is to write a dedicated bit banging TX and RX routine which uses pins to implement it, I would sooner not. I suspect that the Electron would not be up to the precise timing that would be necessary but may be able to do it at lower baud rates.
Any comments would be appreciated.
Thanks

Serial 7E1 is being worked on. I’m not positive the version it’s scheduled to go into, however.

That is good news!
However my customer is not going to wait for that so thinking around the problem I have decided that 7E1 is the same as 8N1 if the character I send has the parity embedded in it as the MSB. So I have done some changes to the character string going out and confirmed that works.
Only problem I have now is determining when the last character has actually been transmitted by Serial1.write(). I need to switch some circuitry around to enable the receive signal to be seen by the Electron. I have searched for an answer for this but there does not seem to be one. How does Serial1.halfduplex() determine that it is OK to switch to receive mode and is this available as a function? Alternatively it would seem that an serialEvent1 type function should be provided to indicate when the transmit buffer is fully sent?
Just putting in wait on delay(ms) is a very error prone way of achieving the result.
Thanks for your help.

Testing for all data sent should be be easy enough using Serial1.availableForWrite() but there’s a bug in the implementation so it doesn’t work. I haven’t found a workaround, other than building your own system firmware yet.

Yes I picked that up from the forums that Serial1.flush() etc did not work properly.However there seems to be a feeling that although flush() does not wait for the complete string to be sent it does wait for the current character to be sent. I tried doing flush() after every character and this does seem to be the case. It slows transmission slightly but gives a solution in my case. Providing I include the flush() after every character my main program does not get ahead of itself.
Thanks, Any update would be appreciated.
My application is writing a driver for SDI-12 communications, which is working with the above work arounds.It only uses the Serial functions and does not do any extra interrupt or bit banging processes so it is quite small. When I tidy it up I will put it in the library. It does require some simple external hardware to combine the TX and RX signals but you really need something there to do the level shifting to 5 volt anyway.

I just realised that if SERIAL_7E1 is implemented that there is currently no function or response that indicates that there is a parity or framing error in a received string? Am I wrong there? I cannot find anything in the firmware docs.
Certainly will need some detection of this if the units are to be used in robust applications.

Just raising this issue again. The Version 6 firmware has implemented SERIAL_7E1 etc, this is good. However there still does not seem to be any feedback as to whether the communication had parity, framing errors etc. Have I missed something there? It will be important to have these checks available to ascertain if the string picked up is valid.

Doesn't the E in there stand for Even parity?

The STM32F205 USART hardware supports detecting parity (and other) errors, either by polling or interrupts. I tried the following code which does not work but I’m not sure why. It doesn’t look like the HAL is grabbing the flags first, but maybe you have to initialize something. In any case, here’s the code in case someone else wants to take a look:

Sender: This sends a byte per second. It’s configured for 9N1, but it’s really sending out 8E1, with about 20 % of the bytes having a parity error.

#include "Particle.h"

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

	Serial1.begin(9600, SERIAL_9N1);

}

void loop() {

	// We're set to generate 9N1, but the receiver is set for 8E1. We do this so
	// can can generate both good and bad parity easily

	int value = rand() & 0xff;

	// Count the number of 1 bits in value
	int oneBitCount = 0;
	for(int ii = 0; ii < 8; ii++) {
		if ((value & (1 << ii)) != 0) {
			oneBitCount++;
		}
	}

	bool isError = false;

	if ((rand() % 5) == 0) {
		// About every 1 in 5 tries, generate a parity error
		oneBitCount++;
		isError = true;
	}

	// Generate even parity
	if (oneBitCount & 1) {
		value |= 0x100;
	}
	Serial1.write((uint16_t)value);

	Serial.printlnf("sending 0x%x isError=%d", value, isError);

	delay(1000);
}

Receiver: Set to receive 8E1, prints out bytes received. Should also print out parity error notifications, but doesn’t.

#include "Particle.h"

bool isSerial1ParityError(); // forward declaration

bool errorWarned = false;


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

	Serial1.begin(9600, SERIAL_8E1);

}

void loop() {
	if (isSerial1ParityError() && !errorWarned) {
		Serial.println("parity error");
		errorWarned = true;
	}
	if (Serial1.available()) {
		int incomingByte = Serial1.read();

		Serial.printlnf("received 0x%x", incomingByte);
		errorWarned = false;
	}
}


bool isSerial1ParityError() {
	// The error flag is automatically cleared after the flag is checked and a byte is read

	// Might also want to check USART_FLAG_NE (noise error) and USART_FLAG_FE (framing error) here
	return USART_GetFlagStatus(USART1, USART_FLAG_PE) != 0;
}

@ScruffR Yes the E stands for even parity but that is the point, if the firmware does not have a hook to determining if there is a parity error then the user does not know whether to trust the returned string or not, as @rickkas7 is pointing out. Essentially I will probably read a string from the appropriate port but if there is parity or framing errors in it then I am not informed. Am I missing something?

I see, that might be something for @avtolstoy & @BDub to look into then

Hi, interesting topic. I’m using a Spark Core to read out a Kamstrup Multical 66C. However the device dictates 7E2 at 300 baud.

What is the status of the 7 bits development?

Hmm, it looks like I have to put an Arduino between my device and the Spark Core. LOL!

I’m pretty sure 7E2 should work properly in 0.6.0, which is in development but should be out soon. 0.6.0rc2 is out and you can try with that. There’s a constant for SERIAL_7E2.

As a side note, I know baud rates under 1200 don’t work on the Photon and Electron, but I’m not sure about the Core. 300 baud may work on the Core, maybe not. It’s a clock divisor issue; the peripheral clock at least on the Photon is too fast for the size of the USART divider to go below 1200. But because the peripheral clock is shared it would slow down all peripherals to reduce the speed and needing 300 baud is pretty rare these days.

1 Like

Hi rickkas7,

Thank you for this information. I have strange enough a piece of code running on my Arduino Uno from a fellow developer that already read this device. I only use the 300 baud part. I can read the standard output information with 300 baud, SERIAL_8N1 (the default). However the Kamstrup Multical 66C (12 years old) documententation mentions “300,E,7,2”. So probably the doc is wrong. A few years ago they updated the Kamstrup and maybe the firmware in it too. When I port this code with minor changes to my Spark Core it does not work. It does send the data but the Kamstrup does not respond. So you might have right that the 300 baud is also on this device not working in a proper manner.
The minor changes I made to the code are not in the range it would influence the serial write and read proces. The changes are needed because otherwise it hangs up my Spark.

while(1);

doesn’t like the spark and turns the Spark into a green breathing mode and have to reset it to factory mode.

Removed a line.

If you do it that way the cloud will stay connected

while(1) Particle.process();

I did some low-baud-rate experiments, and what I discovered is on that the Core has a minimum of 600 baud. Specifying anything less than 600 gets you 600 baud.

Core

1200 baud, same for Photon and Core. Note that it says 600 Hz because each full cycle of the 0x55 value is two bits, so the baud rate in this case is twice that, or 1200 baud.

600 baud Core, correct. Same thing, 300 Hz = 600 baud.

300 baud Core. Not right. This is basically the same as 600 baud.

Photon

Photon, 1200 baud is as low as it will go. You can specify 300 or 600, but it picks weird values instead, I think 17600 baud and 1741 baud, respectively.

600 baud Photon (not right at all):

300 baud Photon (not right at all):

Test code

I tested with system version 0.5.3 and 8N1 serial.

#include "Particle.h"

const unsigned long SEND_PERIOD_MS = 250;

unsigned long lastSend = 0;
int state = 0;

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

	Serial1.begin(600);
}

void loop() {

	while(Serial1.available()) {
		char ch = Serial1.read();
		Serial.printlnf("%02x", ch);
	}

	if (millis() - lastSend >= SEND_PERIOD_MS) {
		lastSend = millis();

		if (state == 0) {
			Serial1.write(0x55);
			state = 1;
		}
		else {
			Serial1.write(0xAA);
			state = 0;
		}
	}

}

2 Likes

ScruffR, thanks for this tip.

2 Likes

Hello rickkas7,

Thanks for your effort to explain it in this short time. With this conclusion I’ll stick to the Arduino for just accessing the Kamstrup Multical 66C Heatwater meter. The other two devices, the water consumption meter (counts/liter) and the smart electricity meter will be processed by the Spark Core. The Spark will connect each hour to the Arduino to read the Kamstrup GJ data. I appreciate your effort to explore the lower baud boundary.

2 Likes

@BDub Brett, I noticed that you were dobbed in when I posted this request some months back. Since SERIAL_7E1 was introduced I have been allowing my code to use the Electron version of SERIAL_7E1 rather than my cluged version which uses SERIAL_8N1 and translates the characters to and from SERIAL_7E1 . The problem with the new code though is that if there is a comms error there does not seem to be a way of me picking that up if I am using the native SERIAL_7E1
I can pick it up in my cluged version because I am doing parity checks on the bits in the character as I translate them. Is there any thought that the parity checks, overrun, framing errors etc can be brought out as results for the user in all the native serial codes? Thanks. Robyn

Hello pNrie!

I am currently developing the same as you, an SDI-12 interface with the Electron. How did you get the SDI-12 communications working in the end?
I have just seen that firmware 0.60 fully supports SERIAL_7E1.
Would you mind sharing some of the code you made? I’m still figuring out the whole hardware/software solution :slight_smile:

Thanks!