Demo of the usage USBDevice library with Blue Pill STM32F103C8T6 board.
STM32F103C8T6 USBSerial Demo
This project contains demo of the USB serial usage for a cheap developer board Blue Pill with STM32F103C8T6 mcu.
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
Diff: serial_reader.py
- 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()