SerialPort Flow Control

I have been reading the code for the Cerb Family and I see a method signature in the file
C:\ghiopensource-29392\DeviceCode\Targets\Native\STM32F4\DeviceCode\STM32F4_USART\STM32F4_usart_functions.cpp

With the flow value parameter


BOOL CPU_USART_Initialize( int ComPortNum, int BaudRate, int Parity, int DataBits, int StopBits, int FlowValue )
{
    if (ComPortNum >= TOTAL_USART_PORT) return FALSE;
    if (Parity >= USART_PARITY_MARK) return FALSE;
    
    GLOBAL_LOCK(irq);
    
    ptr_USART_TypeDef uart = g_STM32F4_Uart_Ports[ComPortNum];
    UINT32 clk;
    
    // enable UART clock
    if (ComPortNum == 5) { // COM6 on APB2
        RCC->APB2ENR |= RCC_APB2ENR_USART6EN;
        clk = SYSTEM_APB2_CLOCK_HZ;
    } else if (ComPortNum) { // COM2-5 on APB1
        RCC->APB1ENR |= RCC_APB1ENR_USART2EN >> 1 << ComPortNum;
        clk = SYSTEM_APB1_CLOCK_HZ;
    } else { // COM1 on APB2
        // USART1 is not used on Cerberus but USART6 is used on Cerbuino.
        // This is just for Cerbuino. 
        //RCC->APB2ENR |= RCC_APB2ENR_USART1EN;
        //clk = SYSTEM_APB2_CLOCK_HZ;
        RCC->APB2ENR |= RCC_APB2ENR_USART6EN;
        clk = SYSTEM_APB2_CLOCK_HZ;
    }
    
    //  baudrate
    UINT16 div = (UINT16)((clk + (BaudRate >> 1)) / BaudRate); // rounded
    uart->BRR = div;
    
    // control
    UINT16 ctrl = USART_CR1_TE | USART_CR1_RE;
    if (DataBits == 9) ctrl |= USART_CR1_M;
    if (Parity) ctrl |= USART_CR1_PCE;
    if (Parity == USART_PARITY_ODD) ctrl |= USART_CR1_PS;
    uart->CR1 = ctrl;
    
    if (StopBits == USART_STOP_BITS_ONE)
		StopBits = 0;
    uart->CR2 = (UINT16)(StopBits << 12);
    //if (DataBits == USART_STOP_BITS_ONE) DataBits = 0;
    //uart->CR2 = (UINT16)(DataBits << 12);

    ctrl = 0;
    if (FlowValue & USART_FLOW_HW_OUT_EN) ctrl |= USART_CR3_CTSE;
    if (FlowValue & USART_FLOW_HW_IN_EN)  ctrl |= USART_CR3_RTSE;
    uart->CR3 = ctrl;

    GPIO_PIN rxPin, txPin, ctsPin, rtsPin;
    CPU_USART_GetPins(ComPortNum, rxPin, txPin, ctsPin, rtsPin);
    UINT32 alternate = 0x72; // AF7 = USART1-3
    //if (ComPortNum >= 3) alternate = 0x82; // AF8 = UART4-6
    if (ComPortNum == 0) alternate = 0x82; // AF8 = UART4-6 -->> Only because USART1 is really USART6
    CPU_GPIO_DisablePin(rxPin, RESISTOR_PULLUP, 0, (GPIO_ALT_MODE)alternate);
    CPU_GPIO_DisablePin(txPin, RESISTOR_DISABLED, 1, (GPIO_ALT_MODE)alternate);
    if (FlowValue & USART_FLOW_HW_OUT_EN)
        if (ctsPin == GPIO_PIN_NONE) return FALSE;
        CPU_GPIO_DisablePin(ctsPin, RESISTOR_DISABLED, 0, (GPIO_ALT_MODE)alternate);
    if (FlowValue & USART_FLOW_HW_IN_EN)
        if (rtsPin == GPIO_PIN_NONE) return FALSE;
        CPU_GPIO_DisablePin(rtsPin, RESISTOR_DISABLED, 1, (GPIO_ALT_MODE)alternate);

    CPU_USART_ProtectPins(ComPortNum, FALSE);
    
    switch (ComPortNum) {
    //case 0: CPU_INTC_ActivateInterrupt(USART1_IRQn, STM32F4_USART_Interrupt0, 0); break;
    case 0: CPU_INTC_ActivateInterrupt(USART6_IRQn, STM32F4_USART_Interrupt0, 0); break;
    case 1: CPU_INTC_ActivateInterrupt(USART2_IRQn, STM32F4_USART_Interrupt1, 0); break;
    case 2: CPU_INTC_ActivateInterrupt(USART3_IRQn, STM32F4_USART_Interrupt2, 0); break;
    case 3: CPU_INTC_ActivateInterrupt(UART4_IRQn, STM32F4_USART_Interrupt3, 0); break;
    case 4: CPU_INTC_ActivateInterrupt(UART5_IRQn, STM32F4_USART_Interrupt4, 0); break;
    case 5: CPU_INTC_ActivateInterrupt(USART6_IRQn, STM32F4_USART_Interrupt5, 0);
    }

    uart->CR1 |= USART_CR1_UE; // start uart


    return TRUE;
}

The method takes 6 parameters however the SerialPort class only takes 5


SerialPort("COM1", 9600, Parity.None, 8, StopBits.One);

Does anyone know how I can go about setting that parameter? Is it even possible?

[EDIT] Is it the handshake property?

The Handshake makes only sense, if the hardware can handle it.
On RS232 you need 4 more wires between both ends:
TRS, CTS, DSR, DTR.
It’s nothing more than 2 outputs of each side, which are inputs on the other side signaling if each side is ready to receive and/or wants to send data.

So if you have the source code open, you should check if these signals are handled some where.
Then you need hardware which supports these as well.

I don’t know where the code that does that handling is. I can’t seem to figure out how the uC knows that’s its buffer is full.

Hi,
hope that Im not too far from the topic again.
I suppose that, if the function is implemented, it must be handled in the interrupt routine of the UART, which perhaps can be found under e.g. STM32F4_USART_Interrupt0.

@ Ro, Which source file is that information in?

Sorry, I don’t know. Perhaps someone of GHI can tell.

Just for the reference, the hardware flow control is activated when the handshake property is set to Handshake.RequestToSend.

(from the file : C:\MicroFrameworkPK_v4_2\Framework\Core\Native_Hardware\Native_UART\SerialPort.cs)


if (m_config.Handshake == Handshake.RequestToSend)
                    {
                        if (CTSPin != Cpu.Pin.GPIO_NONE)
                        {
                            Port.ReservePin(CTSPin, fReserve);
                            exceptLevel = 3;
                        }

                        if (RTSPin != Cpu.Pin.GPIO_NONE)
                        {
                            Port.ReservePin(RTSPin, fReserve);
                            exceptLevel = 4;
                        }
                    }

It appears that the system will try to reserve the CTS and RTS pins for use. If not then later down it throws and exception and releases those pins.

I have concluded that GHI hasn’t implemented the hardware flow control for Fez Devices; so that aspect is a brick wall.

On the contrary, the Spider, the Raptor, and the Cobra I and II all have Handshaking. The OSHW has not been implemented. Premium libraries it is active.

@ Aron - thank you for the information. I think it should be mentioned in the specifications of the boards if UART supports hardware handshake or if it supports not. This could prevent customers from spending hours or even days to dig through the firmware code.

3 Likes

I’m just going to echo Ro here…

This is both sad and frustrating because it clearly says 2x on the website that the FEZ Cerbuino Bee supports the K socket type (handshaking image attached for details) Someone needs to have a serious discussion with the GHI Marketing team that put together this website because if it is indeed true then the website was flatly wrong and money (and time) was wasted due to these inaccuracies

but that won’t fix the problem…what I need is some firmware that supports handshaking… Since this seems to be a firmware issue are there instructions on how to recompile this firmware with this option enabled , the firmware source code or some beta version we could test? - See more at: https://www.ghielectronics.com/community/forum/topic?id=14308&page=3#msg146833 :open_mouth: :-[ :wall:

@ shanekirkbride - you might be able to turn on handshaking by manipulating processor registers.

If GHI isn’t willing to work with you on getting your money back, you probably have a solid case for false advertising.

@ godefroi - happy New year!

Lol, you too, Gus.

How’s this: GHI didn’t put flow control in because they knew beforehand that you wouldn’t need it. Better?

I took a look at the code and from my reading it looks like handshaking is definitely supported. I do not currently have a serial port on my new machine and I do not have a USB->Serial adapter so I wired a null modem link using two breakout modules and tested it between a CerbuinoBee and a Spider and it definitely seems to be working…

Here is how I initialized the Serial ports


_serial = new SerialPort("COM2", 9600, Parity.None, 8, StopBits.One);
_serial.Handshake = Handshake.RequestToSend;
_serial.Open();

I also checked the Gadgeteer implementation, I did not physically test it, but I do think there is a bug there. If you use the Gadgeteer interfaces you should pass Serial.HardwareFlowControl.UseIfAvailable, if you pass HardwareFlowControl.Required there looks to be a logic bug that will not enable hardware flow control.

Take a look
gadgeteer\Main\GadgeteerCore\Libraries\Core\Serial42\Serial.cs


 public Serial(Socket socket, int baudRate, SerialParity parity, SerialStopBits stopBits, int dataBits, HardwareFlowControl hardwareFlowControlRequirement, Module module)
        {
            bool hwFlowSupported = false; /// Watch this Variable

            if (hardwareFlowControlRequirement == HardwareFlowControl.Required)
                socket.EnsureTypeIsSupported('K', module); /// Here hwFlowSupported  is not set
            else
            {
                hwFlowSupported = socket.SupportsType('K'); /// Here the hwFlowSupported is set

                if (!hwFlowSupported)
                    socket.EnsureTypeIsSupported('U', module);
            }

            socket.ReservePin(Socket.Pin.Four, module);
            socket.ReservePin(Socket.Pin.Five, module);
            if (hardwareFlowControlRequirement != HardwareFlowControl.NotRequired)
            {
                // must reserve hardware flow control pins even if not using them, since they are electrically connected.
                socket.ReservePin(Socket.Pin.Six, module);
                socket.ReservePin(Socket.Pin.Seven, module);
            }

            string portName = socket.SerialPortName;

            if ((portName == null || portName == "") && socket.SerialIndirector != null)
                Interface = socket.SerialIndirector(socket, baudRate, (Socket.SocketInterfaces.SerialParity)parity, (Socket.SocketInterfaces.SerialStopBits)stopBits, dataBits, (Socket.SocketInterfaces.HardwareFlowControl)hardwareFlowControlRequirement, module);

            else
/// The next line uses hwFlowSupported, but it is still false if you had passed HardwareFlowControl.Required
                Interface = new NativeSerial(socket, baudRate, (Socket.SocketInterfaces.SerialParity)parity, (Socket.SocketInterfaces.SerialStopBits)stopBits, dataBits, (Socket.SocketInterfaces.HardwareFlowControl)hardwareFlowControlRequirement, module, portName, hwFlowSupported);

            Interface.NewLine = "\n";
            Interface.Encoding = System.Text.Encoding.UTF8;
            Interface.ReadTimeout = InfiniteTimeout;
            Interface.WriteTimeout = InfiniteTimeout;
        }

1 Like

I replied to the other thread saying I remember hand shaking being supported but we will double check in the future.

Assuming this is a reply to my post, I guess you misinterpreted what I said. I am confirming that it does in fact work with the OSHW.

@ taylorza - yes what I mean is that what I remember is correct. Thank you very much for checking the source code :slight_smile:

1 Like

@ Gus - It is a pleasure, I just wanted to make sure you guys were not being falsely accused of false advertising :slight_smile:

1 Like