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
serial_reader.py@0:24604e97c40c, 2017-08-04 (annotated)
- Committer:
- Konstantin Kochin
- Date:
- Fri Aug 04 18:41:22 2017 +0300
- Revision:
- 0:24604e97c40c
Initial release
The project contains autogenerated makefile for a debug build,
the program itself (main.cpp) and the helper python script
'serial_reader.py' to read a data from a serial port.
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
Konstantin Kochin |
0:24604e97c40c | 1 | #!/usr/bin/env python |
Konstantin Kochin |
0:24604e97c40c | 2 | from __future__ import print_function |
Konstantin Kochin |
0:24604e97c40c | 3 | |
Konstantin Kochin |
0:24604e97c40c | 4 | import argparse |
Konstantin Kochin |
0:24604e97c40c | 5 | import sys |
Konstantin Kochin |
0:24604e97c40c | 6 | from time import sleep |
Konstantin Kochin |
0:24604e97c40c | 7 | |
Konstantin Kochin |
0:24604e97c40c | 8 | import serial |
Konstantin Kochin |
0:24604e97c40c | 9 | from serial.tools.list_ports import comports |
Konstantin Kochin |
0:24604e97c40c | 10 | from six import binary_type |
Konstantin Kochin |
0:24604e97c40c | 11 | |
Konstantin Kochin |
0:24604e97c40c | 12 | _DEFAULT_BAUD_RATE = 115200 |
Konstantin Kochin |
0:24604e97c40c | 13 | |
Konstantin Kochin |
0:24604e97c40c | 14 | |
Konstantin Kochin |
0:24604e97c40c | 15 | def _reset_baud_drate(serial): |
Konstantin Kochin |
0:24604e97c40c | 16 | original_baudrate = serial.baudrate |
Konstantin Kochin |
0:24604e97c40c | 17 | i = serial.BAUDRATES.index(original_baudrate) |
Konstantin Kochin |
0:24604e97c40c | 18 | if i == -1: |
Konstantin Kochin |
0:24604e97c40c | 19 | raise ValueError("Unknown baudrate {}".format(original_baudrate)) |
Konstantin Kochin |
0:24604e97c40c | 20 | |
Konstantin Kochin |
0:24604e97c40c | 21 | if i > 1: |
Konstantin Kochin |
0:24604e97c40c | 22 | tmp_baud_rate = serial.BAUDRATES[i - 1] |
Konstantin Kochin |
0:24604e97c40c | 23 | elif len(serial.BAUDRATES) > 1: |
Konstantin Kochin |
0:24604e97c40c | 24 | tmp_baud_rate = serial.BAUDRATES[i + 1] |
Konstantin Kochin |
0:24604e97c40c | 25 | else: |
Konstantin Kochin |
0:24604e97c40c | 26 | raise ValueError("Only one baudreate is available") |
Konstantin Kochin |
0:24604e97c40c | 27 | |
Konstantin Kochin |
0:24604e97c40c | 28 | serial.baudrate = tmp_baud_rate |
Konstantin Kochin |
0:24604e97c40c | 29 | serial.baudrate = original_baudrate |
Konstantin Kochin |
0:24604e97c40c | 30 | |
Konstantin Kochin |
0:24604e97c40c | 31 | |
Konstantin Kochin |
0:24604e97c40c | 32 | def _read_from_serial_device(port, out=sys.stdout, reconnect_on_error=True, repeat_delay=2, **port_params): |
Konstantin Kochin |
0:24604e97c40c | 33 | print('Read from the serial port "{}" (use Ctrl+C to exit)'.format(port)) |
Konstantin Kochin |
0:24604e97c40c | 34 | while True: |
Konstantin Kochin |
0:24604e97c40c | 35 | try: |
Konstantin Kochin |
0:24604e97c40c | 36 | with serial.Serial(port=port, **port_params) as com_port: |
Konstantin Kochin |
0:24604e97c40c | 37 | # hack: |
Konstantin Kochin |
0:24604e97c40c | 38 | # when you connect usb-com port of the stm32f1 first time, it will work |
Konstantin Kochin |
0:24604e97c40c | 39 | # but if you reconnect it, then it stop working, although com port readers doesn't show |
Konstantin Kochin |
0:24604e97c40c | 40 | # any error. |
Konstantin Kochin |
0:24604e97c40c | 41 | # However I found that it can be solved by 2 ways: |
Konstantin Kochin |
0:24604e97c40c | 42 | # - host rebooting (but it's very inconvenient) |
Konstantin Kochin |
0:24604e97c40c | 43 | # - changing baudrate. The new value doesn't matter, it should only be different than previous. |
Konstantin Kochin |
0:24604e97c40c | 44 | # Moreover the old values without any problems can be reverted without any problems. |
Konstantin Kochin |
0:24604e97c40c | 45 | # TODO: find reason of such strange behavior |
Konstantin Kochin |
0:24604e97c40c | 46 | _reset_baud_drate(com_port) |
Konstantin Kochin |
0:24604e97c40c | 47 | for line in com_port: |
Konstantin Kochin |
0:24604e97c40c | 48 | if isinstance(line, binary_type): |
Konstantin Kochin |
0:24604e97c40c | 49 | line = line.decode('utf-8') |
Konstantin Kochin |
0:24604e97c40c | 50 | out.write(line) |
Konstantin Kochin |
0:24604e97c40c | 51 | out.flush() |
Konstantin Kochin |
0:24604e97c40c | 52 | |
Konstantin Kochin |
0:24604e97c40c | 53 | except serial.SerialException as e: |
Konstantin Kochin |
0:24604e97c40c | 54 | print("Error: {}".format(e)) |
Konstantin Kochin |
0:24604e97c40c | 55 | if not reconnect_on_error: |
Konstantin Kochin |
0:24604e97c40c | 56 | break |
Konstantin Kochin |
0:24604e97c40c | 57 | sleep(repeat_delay) |
Konstantin Kochin |
0:24604e97c40c | 58 | |
Konstantin Kochin |
0:24604e97c40c | 59 | |
Konstantin Kochin |
0:24604e97c40c | 60 | def _guess_serial_device_name(): |
Konstantin Kochin |
0:24604e97c40c | 61 | ports = list(comports()) |
Konstantin Kochin |
0:24604e97c40c | 62 | if len(ports) == 1: |
Konstantin Kochin |
0:24604e97c40c | 63 | port = ports[0].device |
Konstantin Kochin |
0:24604e97c40c | 64 | elif len(ports) == 0: |
Konstantin Kochin |
0:24604e97c40c | 65 | raise ValueError("No serial devices found") |
Konstantin Kochin |
0:24604e97c40c | 66 | else: |
Konstantin Kochin |
0:24604e97c40c | 67 | print("Several serial devices are found. Please specify one of them explicitly:") |
Konstantin Kochin |
0:24604e97c40c | 68 | for port_info in ports: |
Konstantin Kochin |
0:24604e97c40c | 69 | print("- {}".format(port_info.device)) |
Konstantin Kochin |
0:24604e97c40c | 70 | raise ValueError("Multiple serial devices are found.") |
Konstantin Kochin |
0:24604e97c40c | 71 | |
Konstantin Kochin |
0:24604e97c40c | 72 | return port |
Konstantin Kochin |
0:24604e97c40c | 73 | |
Konstantin Kochin |
0:24604e97c40c | 74 | |
Konstantin Kochin |
0:24604e97c40c | 75 | def main(args=None): |
Konstantin Kochin |
0:24604e97c40c | 76 | parser = argparse.ArgumentParser(prog='serial_reader', |
Konstantin Kochin |
0:24604e97c40c | 77 | description='Helper program that read text from a serial port. ' |
Konstantin Kochin |
0:24604e97c40c | 78 | 'Unlike other com programs it automatically reconnect ' |
Konstantin Kochin |
0:24604e97c40c | 79 | 'to serial port if any error occurs. It is useful for ' |
Konstantin Kochin |
0:24604e97c40c | 80 | 'microcntrollers debugging when you want to reboot it and' |
Konstantin Kochin |
0:24604e97c40c | 81 | 'the connection will be lost for some time.') |
Konstantin Kochin |
0:24604e97c40c | 82 | parser.add_argument('port', nargs='?', help='Serial port device name. It it is not specifies, then' |
Konstantin Kochin |
0:24604e97c40c | 83 | 'it will be found automatically if it is possible') |
Konstantin Kochin |
0:24604e97c40c | 84 | parser.add_argument('--baudrate', default=_DEFAULT_BAUD_RATE, |
Konstantin Kochin |
0:24604e97c40c | 85 | help="baud rate. Default: {}".format(_DEFAULT_BAUD_RATE)) |
Konstantin Kochin |
0:24604e97c40c | 86 | parsed_args = parser.parse_args(args) |
Konstantin Kochin |
0:24604e97c40c | 87 | |
Konstantin Kochin |
0:24604e97c40c | 88 | if parsed_args.port is None: |
Konstantin Kochin |
0:24604e97c40c | 89 | try: |
Konstantin Kochin |
0:24604e97c40c | 90 | port = _guess_serial_device_name() |
Konstantin Kochin |
0:24604e97c40c | 91 | except Exception as e: |
Konstantin Kochin |
0:24604e97c40c | 92 | print(e) |
Konstantin Kochin |
0:24604e97c40c | 93 | sys.exit(1) |
Konstantin Kochin |
0:24604e97c40c | 94 | else: |
Konstantin Kochin |
0:24604e97c40c | 95 | port = parsed_args.port |
Konstantin Kochin |
0:24604e97c40c | 96 | |
Konstantin Kochin |
0:24604e97c40c | 97 | try: |
Konstantin Kochin |
0:24604e97c40c | 98 | _read_from_serial_device( |
Konstantin Kochin |
0:24604e97c40c | 99 | port, |
Konstantin Kochin |
0:24604e97c40c | 100 | baudrate=parsed_args.baudrate |
Konstantin Kochin |
0:24604e97c40c | 101 | ) |
Konstantin Kochin |
0:24604e97c40c | 102 | except KeyboardInterrupt: |
Konstantin Kochin |
0:24604e97c40c | 103 | print("Exit ...") |
Konstantin Kochin |
0:24604e97c40c | 104 | |
Konstantin Kochin |
0:24604e97c40c | 105 | |
Konstantin Kochin |
0:24604e97c40c | 106 | if __name__ == '__main__': |
Konstantin Kochin |
0:24604e97c40c | 107 | main() |