Demo of the usage USBDevice library with Blue Pill STM32F103C8T6 board.

Dependencies:   USBDevice

STM32F103C8T6 USBSerial Demo

This project contains demo of the USB serial usage for a cheap developer board Blue Pill with STM32F103C8T6 mcu.

/media/uploads/vznncv/stm32f103c8_usbserial.jpg

The USB serial port provides a good communication channel between PC and microcontroller. Especially it can be useful for a debug purposes.

Notes

  • by the specifications this board has only 64KB of the flash, but actually it can have 128KB, that will be useful for a debug builds as it requires about 100KB of the flash for this demo.
  • the board can have some problems with an USB because it has wrong value of the pull-up resistor
  • for steady reading of data from a serial port, the project contains python script serial_reader.py (it requires PySerial and six python libraries), that is steady to the board reloading
  • the project depends on the fork of the USBDevice library. This fork contains some fixes and support of the BLUE_PILL_STM32F103C8 target.
  • the mbed-os now contains correct code for a clock initialization of the BLUE_PILL_STM32F103C8 target, so you don't need to adjust the board clocks separately
Revision:
0:24604e97c40c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/serial_reader.py	Fri Aug 04 18:41:22 2017 +0300
@@ -0,0 +1,107 @@
+#!/usr/bin/env python
+from __future__ import print_function
+
+import argparse
+import sys
+from time import sleep
+
+import serial
+from serial.tools.list_ports import comports
+from six import binary_type
+
+_DEFAULT_BAUD_RATE = 115200
+
+
+def _reset_baud_drate(serial):
+    original_baudrate = serial.baudrate
+    i = serial.BAUDRATES.index(original_baudrate)
+    if i == -1:
+        raise ValueError("Unknown baudrate {}".format(original_baudrate))
+
+    if i > 1:
+        tmp_baud_rate = serial.BAUDRATES[i - 1]
+    elif len(serial.BAUDRATES) > 1:
+        tmp_baud_rate = serial.BAUDRATES[i + 1]
+    else:
+        raise ValueError("Only one baudreate is available")
+
+    serial.baudrate = tmp_baud_rate
+    serial.baudrate = original_baudrate
+
+
+def _read_from_serial_device(port, out=sys.stdout, reconnect_on_error=True, repeat_delay=2, **port_params):
+    print('Read from the serial port "{}" (use Ctrl+C to exit)'.format(port))
+    while True:
+        try:
+            with serial.Serial(port=port, **port_params) as com_port:
+                # hack:
+                # when you connect usb-com port of the stm32f1 first time, it will work
+                # but if you reconnect it, then it stop working, although com port readers doesn't show
+                # any error.
+                # However I found that it can be solved by 2 ways:
+                # - host rebooting (but it's very inconvenient)
+                # - changing baudrate. The new value doesn't matter, it should only be different than previous.
+                #   Moreover the old values without any problems can be reverted without any problems.
+                # TODO: find reason of such strange behavior
+                _reset_baud_drate(com_port)
+                for line in com_port:
+                    if isinstance(line, binary_type):
+                        line = line.decode('utf-8')
+                    out.write(line)
+                    out.flush()
+
+        except serial.SerialException as e:
+            print("Error: {}".format(e))
+            if not reconnect_on_error:
+                break
+            sleep(repeat_delay)
+
+
+def _guess_serial_device_name():
+    ports = list(comports())
+    if len(ports) == 1:
+        port = ports[0].device
+    elif len(ports) == 0:
+        raise ValueError("No serial devices found")
+    else:
+        print("Several serial devices are found. Please specify one of them explicitly:")
+        for port_info in ports:
+            print("- {}".format(port_info.device))
+        raise ValueError("Multiple serial devices are found.")
+
+    return port
+
+
+def main(args=None):
+    parser = argparse.ArgumentParser(prog='serial_reader',
+                                     description='Helper program that read text from a serial port. '
+                                                 'Unlike other com programs it automatically reconnect '
+                                                 'to serial port if any error occurs. It is useful for '
+                                                 'microcntrollers debugging when you want to reboot it and'
+                                                 'the connection will be lost for some time.')
+    parser.add_argument('port', nargs='?', help='Serial port device name. It it is not specifies, then'
+                                                'it will be found automatically if it is possible')
+    parser.add_argument('--baudrate', default=_DEFAULT_BAUD_RATE,
+                        help="baud rate. Default: {}".format(_DEFAULT_BAUD_RATE))
+    parsed_args = parser.parse_args(args)
+
+    if parsed_args.port is None:
+        try:
+            port = _guess_serial_device_name()
+        except Exception as e:
+            print(e)
+            sys.exit(1)
+    else:
+        port = parsed_args.port
+
+    try:
+        _read_from_serial_device(
+            port,
+            baudrate=parsed_args.baudrate
+        )
+    except KeyboardInterrupt:
+        print("Exit ...")
+
+
+if __name__ == '__main__':
+    main()