Unix port and micro Python serial port

Posted by Calgaryalberta on Tue, 04 Jan 2022 01:04:03 +0100

Unix port and micro Python serial port

mpy on unix port is very convenient as a serial port test tool. In the first two chapters, we have transplanted mpy running on linux system of arm board. Students who have not seen it click the following link to view it. Now let's continue to learn about the use of serial port.
Link: Micro Python firmware compilation supporting LVGL (II) arm board transplantation

1. Install the serial port module

In python, we first think of installing pyserial. mpy can also be installed. In python, we install and manage the third-party module package through pip install. In mpy, we can use upip (many modules of mpy with u in front are distinguished by the same standard py), and the following instructions can be executed for installation:
Installation command:

./micropython-lvgl -m upip install micropython-serial

The default mod loading path of mpy is ~ / Micro Python / lib or / usr / lib / micro python, and the module code we just installed is placed in ~ / In the micro Python / lib path, the downloaded serial port module can be directly referenced. But there are some small problems, which will be discussed later and how to modify them.

2. Write code test

import serial
import time

def bytesToHexString(bytes):
    hex_list = ['%02X ' % b for b in bytes]
    str = ''
    for i in range(len(hex_list)):
        str += hex_list[i]
        if ((i+1) % 16) == 0:
            str +='\r\n'
    return str

# Serial port self transceiver test 0x00-0XFF
def uart_test(ser):
    list1 = []
    for i in range(0, 256):
        list1.append(i)
    ser.write(bytes(list1))
    print("send: 0x00...0xFF")
    print("Waiting to receive serial port data...")
    while ser.inWaiting() == 0:
        time.sleep(0.3)
    s = ser.read(ser.inWaiting())
    print(bytesToHexString(s))
    
# Initialize serial port, input parameters: serial port node, baud rate, timeout
ser=serial.Serial("/dev/ttyS5",9600,timeout=1)
ser.open()
uart_test(ser)
ser.close()

The above code is used for serial port loopback test, which needs to short circuit TX and RX of serial port. Test all data transmission and reception from 0x00 to 0XFF at 9600 baud rate. The test results are shown in the figure below:

After measuring 9600, you may also want to test whether all other baud rates can work normally and what is the upper limit of baud rate transmission. It is found that only 9600192057600115200 baud rates can be brought in. I think the arm board can not only support this baud rate, which must be limited by our serial module. In addition, the timeout unit should be s, but the decimal, such as 0.1, will report an error, indicating that the parameter needs an integer rather than a decimal. This should be a bug. The serial port timeout setting should be ms. Let's analyze the serial module code to solve the problem.

3. Increase the baud rate of serial port and optimize the timeout time

3.1 increase baud rate

At ~ / Find serial.exe in the microprython / lib directory Py open
See the following code:

    BAUD_MAP = {
        9600: termios.B9600,
        # From Linux asm-generic/termbits.h
        19200: 14,
        57600: termios.B57600,
        115200: termios.B115200
    }

Note the baud rate settable range is added here, and the baud rate value is provided by the termios module. The value provided by the termios module is essentially from ASM generic / termbits in the Linux kernel H file. Let's find out where the termios module is/ Micro Python lvgl enters repl and types help('modules') to see which modules are available

I found termios, a module built into mpy firmware, which can only be found in mpy source code.
Open the mpy source code project and find ports \ UNIX \ modtermios C file, which contains such a code:

#define C(name) { MP_ROM_QSTR(MP_QSTR_##name), MP_ROM_INT(name) }
    C(TCSANOW),

    C(B9600),
    #ifdef B57600
    C(B57600),
    #endif
    #ifdef B115200
    C(B115200),
    #endif

It can be seen that termios only provides three baud rates 96005760115200, which is similar to our serial Py, so you just need to add the baud rate you need here, but where can we find the baud rate you can choose? At this time, you need to find the kernel code of your arm board and find include \ UAPI \ ASM generic \ termbits Many baud rates have been defined in the H file (there may be some differences between arm and mips). Just add what we need. Here is the baud rate I added:

#define C(name) { MP_ROM_QSTR(MP_QSTR_##name), MP_ROM_INT(name) }
    C(TCSANOW),

    C(B9600),
    #ifdef B57600
    C(B57600),
    #endif
    #ifdef B115200
    C(B115200),
    #endif
    #ifdef B460800
    C(B460800),
    #endif
    #ifdef B921600
    C(B921600),
    #endif
    #ifdef B1152000
    C(B1152000),
    #endif
    #ifdef B1500000
    C(B1500000),
    #endif
    #ifdef B2000000
    C(B2000000),
    #endif
    #ifdef B2500000
    C(B2500000),
    #endif
    #ifdef B3000000
    C(B3000000),
    #endif
#undef C
};

Recompile the mpy firmware. In repl, you can check whether the baud rate we added is added. Type termios Press tab to complete it.

You can change serial at this time Py has added more baud rates

    BAUD_MAP = {
        9600: termios.B9600,
        # From Linux asm-generic/termbits.h
        19200: 14,
        57600: termios.B57600,
        115200: termios.B115200,
        460800: termios.B460800,
        921600: termios.B921600,
        1152000: termios.B1152000,
        1500000: termios.B1500000,
        2000000: termios.B2000000,
        2500000: termios.B2500000,
        3000000: termios.B3000000,
    }

3.2 optimize timeout

As mentioned in the previous test, the timeout input parameter unit is S. only the decimal can be set to ms level timeout, but the input parameter can only accept integers.
View serial Py code, find the following code:

    def __init__(self, port, baudrate, timeout=None, **kwargs):
        self.port = port
        self.baudrate = baudrate
        self.timeout = -1 if timeout is None else timeout * 1000
        self.open()

It will be found that the timeout input parameter is multiplied by 1000 when it is not empty, which means that the timeout sent to the underlying interface is in ms unit, and the decimal should be allowed to be passed in. We can forcibly convert it to int and pass it to the following interface. Modify this part of the code as follows:

    def __init__(self, port, baudrate, timeout=None, **kwargs):
        self.port = port
        self.baudrate = baudrate
        self.timeout = -1 if timeout is None else int(timeout * 1000)#Strong to int
        self.open()

You can modify our serial port test code timeout

ser=serial.Serial("/dev/ttyS5",9600,timeout=0.1)

Execute it again and it can work normally.

Topics: Python Linux ARM micropython