Main Site Documentation

FezCerb40 UART Parity Bit


#1

Hi, I have the problem that every time when I set the partiy bit on my FezCerb40 to Even the communication fails.

Is there a known issue?

I have tested it on COM1 and COM2 but same behaviour, I can’t receive any data.


this.port.BaudRate = 300;
this.port.Parity = Parity.Even;
this.port.StopBits = StopBits.One;
this.port.DataBits = 7;

this.port.Open();


#2

Do you need to use even parity checks?

try:


#3

What do you mean by “communication fails”.
Do you get an exception? Is the data corrupted?
If the 2nd one is the case, is the other end set for even parity as well for sure?


#4

@ Darko - yes I need parity check, I have to use it.

@ Reinhard - I use a optical probe to read out a smartmeter (IEC iec62056-21)

I send the initialization sequence “/?!”, but the smart meter do not response.

The optical probe has an RS232 interface, and I use the RS232 module from GHI to connect it to the FezCerb40 at COM1

If I do the same with the optical probe connected to the pc it works without a problem.

I have also an RN-XV wifi module connected to COM2, it was also configured to use parity, but it didn’t worked, so after trying everything I noticed, changing the parity made the trick.

The hole “code” works with an FezCobra II but its to big, I wanted to shrink the footprint.


#5

You have set 7 data bits. Been a very long time since any device has used 7 bits + parity. Maybe it should be 8 data bits?

Have you tried to do a loopback?


#6

@ Mike - In serial port connection default IEC62056-21 settings are: Bitrate 300, 7E1.


#7

there are even parity threads around if you look. Here’s one with what appears to be a solution - it’s a 4.2 discussion, not sure what you’re using nor if this is still relevant in 4.3 land…
https://www.ghielectronics.com/community/forum/topic?id=14700


#8

So now I have the mode 8E1 working:


private const uint USART_BASE_ADDRESS = 0x40004400;
private readonly Register USART_CR1 = new Register(USART_BASE_ADDRESS + 0x0C);

private const uint USART_CR1_PCE = 0x400;
private const uint USART_CR1_M = 0x1000;
private const uint USART_CR1_PE = 0x200;

private SerialPort port = new SerialPort("COM2");

public void Initialize()
{
this.port.BaudRate = 9600;
this.port.DataBits = 8;
this.port.StopBits = StopBits.One;
this.port.Parity = Parity.Even;
this.port.Handshake = Handshake.RequestToSend;

this.port.Open();

// setting length and parity bit
this.USART_CR1.Value |= USART_CR1_M;
this.USART_CR1.Value |= USART_CR1_PCE;
// set to even parity
this.USART_CR1.Value &= ~USART_CR1_PE;

}

So know its working with the RN-XV wifi module, but with my optical probe still no luck.


#9

I have worked out a solution for my problem.

This solution will work for all STM32F405XX µC.

In the code below 300 baud are only on UART’s (Com2, Com3) supported that are connected to the low speed bus APB1. If you want to use it with Com1 you have to modify RCC_CFGR_PPRE1_16 and RCC_CFGR_PPRE1_4.

If you want to run at 300 Baud 7E1 then you have to change the clock devider for APB1 from 4 to 16, now the bus is running with 10,5 Mhz.
**** Be carefull other peripherals also use this bus, never set the clock devider lower than 4 ********

When we calculate the baudrate as in the manual described, we get

10500000 / (16 * 300) = 2187,5 // this number must be smaler than 2^12, thats the reason why we have to adjust the clock devider

This value is devided into the integer and the fractional part, like in the manual discribed we get

UART_BRR = 0x88B8

// This section is only necessery because there is a bug in NETMF or in the porting code.
// So that the parity bit is set wrong
To get 7E1 working we have the set the M, PCE and PE Bit in the UART_CR1 register right. The STM32F4 supports 4 possible frame-formats:

=================================================
M bit | PCE bit | USART frame

0 | 0 | SB | 8 bit data | STB
0 | 1 | SB | 7-bit data | PB | STB
1 | 0 | SB | 9-bit data | STB
1 | 1 | SB | 8-bit data | PB | STB

The PE bit defines only if it is even (0) or odd (1)

Importend as I have observed if you use 7E1 and call Read or ReadByte you get the 7 data bits and the parity bit.

I have writen a wrapper class for the serialport for better handling:


namespace Pps.IO
{
    using System;
    using System.IO.Ports;
    using GHI.Processor;
    using Microsoft.SPOT;

    public class SerialPort : System.IO.Ports.SerialPort
    {
        // COM1
        private const uint USART6_BASE_ADDRESS = 0x40011400;
        // COM2
        private const uint USART2_BASE_ADDRESS = 0x40004400;
        // COM3
        private const uint USART3_BASE_ADDRESS = 0x40004800;

        private const uint RCC_BASE_ADDRESS = 0x40023800;


        private const uint USART_CR1_PCE = 0x400;
        private const uint USART_CR1_M = 0x1000;
        private const uint USART_CR1_PE = 0x200;

        private const uint RCC_CFGR_PPRE1_16 = 0x1C00;
        private const uint RCC_CFGR_PPRE1_4 = 0x1400;

        private const uint BAUD_300 = 0x88B8;

        private readonly Register USART_BRR;
        private readonly Register USART_CR1;

        private readonly Register RCC_CFGR;

        public SerialPort(string portName)
            : this(portName, 9600, Parity.None, 8)
        {
        }

        public SerialPort(string portName, int baudRate, Parity parity, int dataBits)
            : base(portName, baudRate, parity, dataBits)
        {
            uint baseAddress = 0;

            switch (portName.ToLower())
            {
                case "com1":
                    baseAddress = USART6_BASE_ADDRESS;
                    break;
                case "com2":
                    baseAddress = USART2_BASE_ADDRESS;
                    break;
                case "com3":
                    baseAddress = USART3_BASE_ADDRESS;
                    break;
                default:
                    throw new ArgumentException("invalid portname", "portName");
            }

            this.USART_BRR = new Register(baseAddress + 0x08);
            this.USART_CR1 = new Register(baseAddress + 0x0C);

            this.RCC_CFGR = new Register(RCC_BASE_ADDRESS + 0x08);

            this.RCC_CFGR.Value = (this.RCC_CFGR.Value & ~RCC_CFGR_PPRE1_16) | RCC_CFGR_PPRE1_4;
        }

        public new void Open()
        {
            uint cr1 = 0x0;

            base.Open();

            cr1 = this.USART_CR1.Value;

            if (this.BaudRate == 300)
            {
                this.RCC_CFGR.Value |= RCC_CFGR_PPRE1_16;

                this.USART_BRR.Value = BAUD_300;
            }
            else
            {
                this.RCC_CFGR.Value = (this.RCC_CFGR.Value & ~RCC_CFGR_PPRE1_16) | RCC_CFGR_PPRE1_4;
            }

            if (this.DataBits == 8 && this.Parity == Parity.None && this.StopBits != StopBits.None)
            {
                cr1 &= ~USART_CR1_PCE;
                cr1 &= ~USART_CR1_M;
                cr1 &= ~USART_CR1_PE;
            }
            else if (this.DataBits == 7 && (this.Parity == Parity.Even || this.Parity == Parity.Odd) && this.StopBits != StopBits.None)
            {
                cr1 |= USART_CR1_PCE;
                cr1 &= ~USART_CR1_M;

                if (this.Parity == Parity.Even)
                {
                    cr1 &= ~USART_CR1_PE;
                }
                else
                {
                    cr1 |= USART_CR1_PE;
                }
            }
            else if (this.DataBits == 9 && this.Parity == Parity.None && this.StopBits != StopBits.None)
            {
                cr1 &= ~USART_CR1_PCE;
                cr1 |= USART_CR1_M;
                cr1 &= ~USART_CR1_PE;
            }
            else if (this.DataBits == 8 && (this.Parity == Parity.Even || this.Parity == Parity.Odd) && this.StopBits != StopBits.None)
            {
                cr1 |= USART_CR1_PCE;
                cr1 |= USART_CR1_M;

                if (this.Parity == Parity.Even)
                {
                    cr1 &= ~USART_CR1_PE;
                }
                else
                {
                    cr1 |= USART_CR1_PE;
                }
            }
            else
            {
                throw new InvalidOperationException("no valid frame format");
            }


            this.USART_CR1.Value = cr1;
        }

        public override void Close()
        {
            base.Close();

            this.RCC_CFGR.Value = (this.RCC_CFGR.Value & ~RCC_CFGR_PPRE1_16) | RCC_CFGR_PPRE1_4;
        }

        public override int ReadByte()
        {
            if (this.Parity != System.IO.Ports.Parity.None)
            {
                return base.ReadByte() & ~0x80;
            }
            else
            {
                return base.ReadByte();
            }
        }
    }
}