Зеркало сайта: vivacious-stockings-frog.cyclic.app
Данная статья появилась случайно. Изначально я собирался написать что-то на тему программирования ARM Cortex®-M4 на связке ассемблера и Си. У меня уже давно валялись парочка плат с микроконтроллерами STM32F411CE и STMF407ZET6 и я уже было предвкушал, как вскоре запущу отладчик, но когда начал изучать и по ходу дела тут же описывать плату WeACT STM32F411CE, то сначала я наткнулся на DFU загрузчик, потом я изучал программу STM32CubeProgrammer, ну и в довершении, я обнаружил, что для платы существует прошивка MicroPython. Я не отбросил прошивку сразу в сторону, прежде всего мне хотелось составить свое мнение о микропитоне, и в конечном итоге я решил посвятить статью полностью этой теме.
Статья не претендует на всеобъемлющее руководство, это скорее краткий мануал для беглого ознакомления с системой MicroPython и навыками работы с платой WeACT STM32F411CE. Я не берусь сказать, будет ли у статьи продолжение. Микропитон мне понравился, но я считаю, что для того чтобы работать с ним серьезно, нужно освоить процесс добавления своих нативных модулей в прошивку. Т.е. драйвер дисплея лучше писать все-таки не на микропитоне, а на Си или ассемблере. В то время как основную логику программы можно писать и на MicroPython.
Полезная документация по теме статьи:
Содержание:
I. Обзор платы STM32F411CE (Black Pill V2.0)
II. Основы работы c MicroPython
В прошлом году на али появились недорогие платы в форм-факторе "Blue Pill", с чипам STM32F401CC и STM32F411CE. Это чипы с ядрами ARM Cortex®-M4, которые имеют аппаратную поддержку чисел с плавающей запятой одинарной точности и блоком DSP инструкций. На данный момент это самые доступные платы для тех, кто хочет оценить возможности микроконтролеров на ядрах ARM Cortex®-M4. Чип STM32F401CC имеет 256 КБайт флеш-памяти, 64 КБайт ОЗУ и может работать на частотах до 84 МГц включительно. Чип STM32F411CE имеет 512 КБайт флеш-памяти, 128 КБайт ОЗУ и он может работать на частоте до 100 МГц.
Сперва хочется сказать пару слов о чипе STM32F411CE. Если посмотреть на ключевые особенности (key features) данного микроконтроллера, что заявленны на сайте ST https://www.st.com/en/microcontrollers-microprocessors/stm32f411ce.html, то увидим следующее:
Arm® 32-bit Cortex®-M4 CPU with FPU, Adaptive real-time accelerator (ART Accelerator™) allowing 0-wait state execution from Flash memory, frequency up to 100 MHz
Здесь нам обещаются рабочие частоты до 100МГц включительно, некий ART-ускоритель (проприетарная технология ST), который позволит работать с флеш-памятью на частоте CPU, т.е. с "0-wait state" задержкой (читай "без задержки"). Ранее, я уже указывал на то, что флеш-память микроконтроллеров STM работает на меньшей частоте нежели ЦПУ и это существенно сказывается на работу небольших циклов. Если при линейном, т.е. последовательном выполнении программы, данное обстоятельство компенсируется двумя (для i-code bus и d-code bus) 128-битными буферами, то в случае ветвления конвейер сбрасывается, и процессору приходится ожидать флеш-память. В случае 0-wait state задержки ничего бы ждать не приходилось. Однако давайте заглянем в документацию на чип: STM32F411xC/E Reference Manual (RM0383):
Как видно, при частоте ЦПУ в 100 МГц и питании чипа 3.3 Вольт, нам придется работать с 3-wait state задержкой. Формально, вы конечно можете работать с 0-wait state задержкой на частотах порядка 16МГц или даже 24МГц.
Теперь поглядим на схему тактирования микроконтролера:
STM32F411CE имеет три коэффициента PLL: M, N и P. При тактировании от кварца 25МГц, если мы хотим использовать USB, через коэффициенты M, N и P мы можем выставить максимальную частоту ЦПУ не более 96 МГц.
Перейдем непосредственно к платам. Я заказывал свою плату с чипом STM32F411CEU6 пошлой осенью. Выглядит она так:
Вид снизу:
Заметьте, что снизу моей платы стоит номер версии платы - v1.3. Сейчас уже продаются более новые версии плат. На данный момент актуальная ревизия - это V3.0. Наиболее полную информацию об этой плате, так и о многих других, что продаются на ebay и ali, можно посмотреть на вики проекта STM32Duino , в разделе "Generic STM32F4 boards". Там эти платы обозначены как "WeAct Black Pill V2.0", и про них там имеется отдельная страничка WeAct Black Pill V2.0. На фотографиях там версия платы уже V2.0.
У одного из продавцов на али я нашел Changelog версий плат:
Платы версий начиная с 1.3 и выше, имеют три кнопки "BOOT", "FLASH" и "KEY". Один светодиод на питании, и один на выводе PC13. Два кварца, один на 25 MHz для HSE, и часовой кварц на LSE. Разъем для отладчика ST-Link V2 и разъем USB-C. На обратной стороне платы имеются контактные площадки для впайки SPI-флешки.
У компании WeAct имеется аккаунт на github: https://github.com/WeActTC/MiniF4-STM32F4x1, там также выложен Changelog, правда местами с китайскими иероглифами. Еще там есть ссылка на их официальный магазин на али, но если почитать отзывы в том магазине, то народ жалуется, что им присылают подделки. Как бы это не было печально, но факт. Также у них там написано, что платы с чипом STM32F401CC, т.е. что с 256KБ флеш-памяти, признаны устаревшими, и заменены платами с чипом STM32F401CE, т.е. с 512KБ флеш-памяти. Я правда не нашел таких плат на али, но имейте ввиду, если собираетесь использовать на плате микропитон, прошивка с ним может не влезть на чипы с 256KБ флеш-памяти.
В разделе документации, имеется распиновка плат:
Еще:
Там у них есть еще разные картинки, не поленитесь, зайдите и посмотрите.
В целом, я считаю, что преимущества платы с 411-м чипом - это невысокая цена (можно взять сразу десять), миниатюрность (большинство отладочных плат на чипах STM32F4xx выглядят монструозно), огромный объем флеш-памяти и приемлемый объем оперативной памяти (128 килобайт). Кроме того, на плате имеется посадочное место под флешку.
Существенным отличием от BluePill, явлется встроенный в чипы STM32F401/STM32F411 DFU-загрузчик. Это означает, что вы сможете прошить свой микроконтролер без программатора, прямо через USB-шнурок. В случае с BluePill, для прошивки платы через USB, сначала нужно было ставить DFU-загрузчик от STM32Duino, а затем наблюдать, как после каждой загрузки вашей программы, USB-порт постоянно переключался c устройства Virtual Serial Port на DFU-загрузчик и обратно. Кроме того, тот загрузчик элементарно затирался, стоило только прошить что-либо через ST-Link. Теперь все эти траблы остались в прошлом. DFU-загрузчик прошит в ПЗУ и останется там при любых условиях. Активируется он только специальной комбинацией нажатия кнопок, а не автоматически при каждом старте как было у Blue Pill.
Через DFU загрузчик STM32F411 можно не только загрузить свою прошивку, но и выставить нужные Option Bytes, прочитать флеш-память микроконтролера и т.д. Т.е. через USB-шнурок вы теперь можете сделать все то, что раньше было доступно только из флешера "STM32 ST-Link Utility", который требовал наличия программатора.
Для работы с DFU-загрузчиком микроконтролера нам понадобится флешер STM32CubeProgrammer. Данный флешер по функционалу примерно соответствует STM32 ST-Link Utility, но при этом работает в разных операционных системах, включая Linux.
На официальном сайте ST имеется книжка с документацией к программе: User Manual "STM32CubeProgrammer software description" (UM2237) . Настоятельно рекомендую полистать ее. Она кратенькая (80 страниц), и довольно доходчивая.
Скачать STM32CubeProgrammer можно также с официального сайта ST - https://www.st.com/en/development-tools/stm32cubeprog.html. После распаковки скачанного архива, перед нами появятся следующие файлы:
SetupSTM32CubeProgrammer-2.4.0.app SetupSTM32CubeProgrammer-2.4.0.exe SetupSTM32CubeProgrammer-2.4.0.linux
Здесь перед нами два инсталлятора, для Windows и для Linux. Но если посмотреть на линуксовый инсталлятор:
$ file ./SetupSTM32CubeProgrammer-2.4.0.linux ./SetupSTM32CubeProgrammer-2.4.0.linux: ELF 32-bit LSB executable, Intel 80386, version 1 (GNU/Linux), statically linke d, BuildID[sha1]=367c34dc0ca47b641c12116aaed8e2c741a6bae6, not stripped
то видно, что он является 32-битным приложением и будет работать только в 32-битных или мультибиблиотечных системах. Т.к. у меня теперь чистая 64-битная Slackware, то я по старинке воспользуюсь Windows инсталлятором:
$ java -jar ./SetupSTM32CubeProgrammer-2.4.0.exe
По умолчанию программа установится в директорию /usr/local/STMicroelectronics.
Программа STM32CubeProgrammer существует в двух ипостасях: в виде графической тулзы, и в виде утилиты с консольным, ака CLI-интерфейсом. Это означает, что теоретически мы можем использовать STM32CubeProgrammer_CLI в качестве флешера для его вызова из Makefile.
Графическая тулза выглядит как-то так:
Интерфейс консольной программы - это довольно длинный список опций, я спрятал его под спойлер:
посмотреть интерфейс STM32CubeProgrammer------------------------------------------------------------------- STM32CubeProgrammer v2.4.0 ------------------------------------------------------------------- Usage : STM32_Programmer_CLI.exe [command_1] [Arguments_1][[command_2] [Arguments_2]...] Generic commands: -?, -h, --help : Show this help -c, --connect : Establish connection to the device <port=<PortName> : Interface identifier. ex COM1, /dev/ttyS0, usb1, JTAG, SWD...) UART port optional parameters: [br=<baudrate>] : Baudrate. ex: 115200, 9600, etc, default 115200 [P=<parity>] : Parity bit, value in {NONE,ODD,EVEN}, default EVEN [db=<data_bits>] : Data bit, value in {6, 7, 8} ..., default 8 [sb=<stop_bits>] : Stop bit, value in {1, 1.5, 2} ..., default 1 [fc=<flowControl>] : Flow control Value in {OFF,Hardware,Software} ..., default OFF Not supported for STM32MP [noinit=noinit_bit]: Set No Init bits, value in {0,1} ..., default 0 [console] : Enter UART console mode JTAG/SWD debug port optional parameters: [freq=<frequency>] : Frequency in KHz. Default frequencies: 4000 SWD 9000 JTAG with STLINKv2 24000 SWD 21333 with STLINKv3 [index=<index>] : Index of the debug probe. default index 0 [sn=<serialNumber>]: Serial Number of the debug probe [ap=<accessPort>] : Access Port index to connect to. default ap 0 [mode=<mode>] : Connection mode. Value in {UR/HOTPLUG/NORMAL} default mode: NORMAL [reset=<mode>] : Reset modes: SWrst/HWrst/Crst. Default mode: SWrst Reset mode with UR connection mode is HWrst [shared] : Enable shared mode allowing connection of two or more instances of STM32CubeProgrammer or other debugger to the same ST-LINK probe. [tcpport=<Port>] : Port used for running ST-Link Server, default 7184 SPI port optional parameters: [br=<baudrate>] : Baudrate. [cpha=<cpha_val>] : 1Edge or 2Edge. default 1Edge [cpol=<cpol_val>] : low or high [crc=<crc_val>] : enable or disable (0/1). [crcpol=<crc_pol>] : crc polynom value. [datasize=<size>] : 8bit/16bit [direction=<val>] : Direction: 2LFullDuplex/2LRxOnly/1LRx/1LTx [firstbit=<val>] : First Bit: MSB/LSB [frameformat=<val>]: Frame Format: Motorola/TI [mode=<val>] : Mode: master/slave [nss=<val>] : NSS: soft/hard [nsspulse=<val>] : NSS pulse: Pulse/NoPulse [delay=<val>] : Delay: Delay/NoDelay, delay of few microseconds [noinit=noinit_bit]: Set No Init bits, value in {0,1} ..., default 0 CAN port optional parameters: [br=<rbaudrate>] : Baudrate : 125, 250, 500, 1000 Kbps, default 125 [mode=<canmode>] : CAN Mode : NORMAL, LOOPBACK..., default NORMAL [ide=<type>] : CAN Type : STANDARD or EXTENDED, default STANDARD [rtr=<format>] : Frame Format: DATA or REMOTE, default DATA [fifo=<afifo>] : Msg Receive : FIFO0 or FIFO1, default FIFO0 [fm=<fmode] : Filter Mode : MASK or LIST, default MASK [fs=<fscale>] : Filter Scale: 16 or 32, default 32 [fe=<fenable>] : Filter Activation : ENABLE or DISABLE, default ENABLE [fbn=<fbanknb>] : Filter Bank Number : 0 to 13, default 0 [noinit=noinit_bit]: Set No Init bits, value in {0,1} ..., default 0 I2C port optional parameters: [add=<ownadd>] : Slave address : address in hex format [br=<sbaudrate>] : Baudrate : 100 or 400 Kbps, default 400 [sm=<smode>] : Speed Mode : STANDARD or FAST, default FAST [am=<addmode>] : Address Mode : 7 or 10 bits, default 7 [af=<afilter>] : Analog filter : ENABLE or DISABLE, default ENABLE [df=<dfilter>] : Digital filter : ENABLE or DISABLE, default DISABLE [dnf=<dnfilter>] : Digital noise filter : 0 to 15, default 0 [rt=<rtime>] : Rise time : 0-1000(STANDARD), 0-300(FAST), default 0 [ft=<ftime>] : Fall time : 0-300 (STANDARD), 0-300(FAST), default 0 [noinit=noinit_bit]: Set No Init bits, value in {0,1} ..., default 0 -version, --version : Displays the tool's version -l, --list : List all available communication interfaces <uart> : UART interface <usb> : USB interface <st-link> : st-link interface -q, --quietMode : Enable quiet mode. No progress bar displayed -log, --log : Store the detailed output in log file [<file_Path.log>] : Path of the log file, default path = $HOME/.STM32Programmer/trace.log -vb, --verbosity : Specify verbosity level <Level> : Verbosity level, value in {1, 2, 3} Available commands for STM32 MCU: --skipErase : Skip sector erase before programming -sl, --safelib : Add a segment into a firmware file (elf,bin hex,srec) containing computed CRC values To use only with the safety lib component <file_path> : File path to be modified <start_address> : Flash memory start address <end_address> : Flash memory end address <slice_size> : Size of data per CRC value -ms, --mergesbsfu : Add a binary header and a sbsfu segment to an elf file <elf_file_path> : File path to be modified <header_file_path> : Header file path <sbsfu_file_path> : SBSFU file path -e, --erase : Erase memory pages/sectors devices: Not supported for STM32MP [all] : Erase all sectors [<sectorsCodes>] : Erase the specified sectors identified by sectors codes. ex: 0, 1, 2 to erase sectors 0, 1 and 2 [<[start end]>] : Erase the specified sectors starting from start code to end code, ex: -e [5 10] -w, --write -d, --download : Download the content of a file into device memory <file_path> : File path name to be downloaded: (bin, hex, srec, elf, stm32 or tsv file) [<address>] : Start address of download -w32 : Write a 32-bits data into device memory <address> : Start address of download <32-bit_data> : 32-bit data to be downloaded values should be separated by space -w16 : Write a 32-bits data into device memory <address> : Start address of download <16-bit_data> : 32-bit data to be downloaded values should be separated by space -w8 : Write a 32-bits data into device memory <address> : Start address of download <8-bit_data> : 32-bit data to be downloaded values should be separated by space -v, --verify : Verify if the programming operation is achieved successfully -r32 : Read a 32-bit data from device memory <address> : Read start address <size> : Size of data -r16 : Read a 16-bit data from device memory <address> : Read start address <size> : Size of data -r8 : Read a 8-bit data from device memory <address> : Read start address <size> : Size of data -rst : Reset system -hardRst : Hardware reset Available only with JTAG/SWD debug port -halt : Halt core -run : Run core -step : Step core Available only with JTAG/SWD debug port -score : Get core status Available only with JTAG/SWD debug port -coreReg : Read/Write core registers [<core_register>] R0/../R15/PC/LR/PSP/MSP/XPSR/APSR/IPSR/EPSR/ PRIMASK/BASEPRI/FAULTMASK/CONTROL [core_reg=<value>] value in case of write opration Note: multiple registers can be handled at once Available only with JTAG/SWD debug port -r, --read -u, --upload : Upload the device memory content to a .bin/.hex/.srec file <address> : Start address of read and upload <size> : Size of memory content to be read <file_path> : file path with .bin/.hex/.srec extension -el, --extload : Select a custom external memory-loader <file_path> : External memory-loader file path -s, --start -g, --go : Run the code at the specified address. [<address>] : Start address -rdu, --readunprotect: Remove memory's Read Protection by shifting the RDP level from level 1 to level 0. -tzenreg, --tzenregression: Remove TrustZone Protection by disabling the TZEN from 1 to 0. -ob, --optionbytes : This command allows the user to manipulate the device 's OptionBytes by displaying or modifying them. [displ] : This option allows the user to display the whole set of Option Bytes. [OptByte=<value>] : This option allows the user to program the given Option Byte. Available commands for STM32 MPU: -c, --connect : Establish connection to the device <port=<PortName> : Interface identifer. ex COM1, /dev/ttyS0, usb1) UART port optional parameters: [br=<baudrate>] : Baudrate. ex: 115200, 9600, etc, default 115200 [P=<parity>] : Parity bit, value in {NONE,ODD,EVEN}, default NONE [db=<data_bits>] : Data bit, value in {6, 7, 8} ..., default 8 [sb=<stop_bits>] : Stop bit, value in {1, 1.5, 2} ..., default 1 [fc=<flowControl>] : Flow control (Not yet supported for STM32MP) Value in {OFF,Hardware,Software} ..., default OFF [noinit=noinit_bit]: Set No Init bits, value in {0,1} ..., default 0 -s, --start -g, --go : Run the code at the specified partition ID. [<partitionID>] : Partition ID If not specified, last loaded partition will be started [<startAdress>] : Start address If not specified, last loaded segment address -otp program : This command allows the user to program SAFMEM memory by modifying the OTP words [wordID=<value>] : This field contains the OTP word number [value=<value>] : Loads value into the chosen OTP word [sha_rsl=<value>] : Loads value into the corresponding shadow read sticky lock bit [sha_wsl=<value>] : Loads value into the corresponding shadow write sticky lock bit [sl=<value>] : Loads value into the corresponding programming sticky lock bit [pl=<value>] : Loads value into the corresponding programming perma- nent lock bit -otp displ : This command allows the user to display all or parts of the OTP structure [upper] : Displays the loaded upper OTP shadow registers values and status [lower] : Displays the loaded lower OTP shadow registers values and status [ctrl] : Displays the loaded BSEC control registers -detach : Send detach command to DFU -wb : Write blob <blob_file_path> : Blob file path -pmic : Program PMIC NVM <PMIC file_path> : PMIC file_path -gc, --getcertificate : Get the chip Certificate, supported for devices with security features <file_path> : Certificate file path into which the chip certificate will be uploaded -p, --phaseID : Display the current partition ID to be loaded -w, --write -d, --download : Download the content of a file into device memory <file_path> : File path name to be downloaded: (bin, stm32 file <partition_id> : Partition ID to be downloaded -rp, --readPart : Upload a memory partion ID content to a .bin file <partionID> : Partion to be read [<offset address>] : Offset address of read and upload <size> : Size of partion content to be read <file_path> : Binary file path -ssp, --ssp : Program an ssp file <file_path> : Path of sfi file to be programmed <atf-ssp-path> : Path of atf specific to SSP [hsm=0|1] : Set user option for HSM use value in {0 (do not use HSM), 1 (use HSM)} Default value : hsm=0 <lic_path|slot=slotID> : Path to the license file (if hsm=0) or reader slot ID if HSM is used (hsm=1) MCU Secure programming specific commands: -sfi, --sfi : Program an sfi file [<protocol=Ptype>] : Protocol type to be used : static/live Only static protocol is supported so far Default value static <file_path> : Path of sfi file to be programmed [hsm=0|1] : Set user option for HSM use value in {0 (do not use HSM), 1 (use HSM)} Default value : hsm=0 <lic_path|slot=slotID> : Path to the SFI license file (if hsm=0) or reader slot ID if HSM is used (hsm=1) [<licMod_path>|slot=slotID]: list of the integrated SMI license files paths if HSM is not used (hsm=0) Or readers slot IDs list if HSM is used (hsm=1) Used only in combined case the list order should correspond to modules integration order within the SFI file -smi, --smi : Program an smi file <protocol=Ptype> : Protocol type to be used : static/live Only static protocol is supported so far Default value static <file_path> : Path of smi file to be programmed [hsm=0|1] : Set user option for HSM use value in {0 (do not use HSM), 1 (use HSM)} Default value : hsm=0 [<address>] : Destination address of the smi module needed only for relocatable SMI <lic_path|slot=slotID> : Path to the SMI license file (if hsm=0) or reader slot ID if HSM is used (hsm=1) -rsse, --rsse : Set the RSSe file path, supported for devices with security extension <file_path> : RSSe file path -a, --abort : This command allows the user to clean a not properly finished process. The currently ongoing operation will stop and the system will return to idle state HSM related commands: -hsmgetinfo : Read the HSM available information [slot=<SlotID>] : Slot ID of the Smart Card Reader Default value: slot=1 (the PC integrated SC reader) -hsmgetcounter : Read the current value of the license counter [slot=<SlotID>] : Slot ID of the Smart Card Reader Default value: slot=1 (the PC integrated SC reader) -hsmgetfwid : Read the Firmware/Module Identifier [slot=<SlotID>] : Slot ID of the Smart Card Reader Default value: slot=1 (the PC integrated SC reader) -hsmgetstatus : Read the current card life-cycle state [slot=<SlotID>] : Slot ID of the Smart Card Reader Default value: slot=1 (the PC integrated SC reader) -hsmgetlicense : Get a license for the current chip if counter is not null <file_path> : File path into which the recieved license will be stored [slot=<SlotID>] : Slot ID of the Smart Card Reader Default value: slot=1 (the PC integrated SC reader) [protocol=<Ptype>] : Protocol type to be used : static/live Only static protocol is supported so far Default value static STM32WBxx specific commands: -getuid64 : Read the device UID -fusgetstate : Read the FUS state Firmware Upgrade commands: -fwdelete : Delete the BLE stack firmware -fwupgrade : Upgrade the BLE stack firmware or the FUS firmware <file_path> : New firmware image file path <address> : Start address of download [firstinstall=0|1] : 1 if it is a first install otherwise 0 optional, Default value: firstinstall=0 [startstack=0|1] : 1 to start the stack after the upgrade otherwise 0 optional, Default value: startstack=1 -v : Verify if the download operation is achieved successfully before starting upgrade -startwirelessstack : Start the wireless stack Key management commands: -authkeyupdate : Authentication key update <file_path> : New authentication key file path. : This is the public key generated by : STM32TrustedPackageCreator using -sign command. -authkeylock : Authentication key lock : Once locked, it's no longuer possible to change it : using authkeyupdate command -wusrkey : Write user key <file_path> : User key file path <keytype=1|2|3> : User key type, values : 1, 2 or 3. : 1 = simple key, 2 = master key, 3 = encrypted key.
Хотя список опций CLI интерфейса довольно внушительный, нас касаться будет только та часть, что входит в раздел STM32 MCU.
Теперь подключим плату через USB-C шнурок к компьютеру. На github'е нам предлагается следующие способы для активации DFU (Device Firmware Upgrade) загрузчика:
How to enter ISP mode
- Method 1: When the power is on, press the BOOT0 key and the reset key, then release the reset key, and release the BOOT0 key after 0.5 seconds
- Method 2: When the power is off, hold down the BOOT0 key, and release the BOOT0 at 0.5s after the power is on
- DFU Mode: Use the data line to connect to the computer. If there is an unrecognized problem, you can heat the chip appropriately (25°C) and then re-enter the ISP mode
- Serial Port Mode: Connect PA9 and PA10 of core board with USB serial port
- Soft: STM32CubeProg
Нам предлагается два варианта. Второй вариант реализуется через отключение микроконтроллера от компьютера, он нам не подходит, т.к. это неудобно.
Если следовать первому варианту (метод 1), то сначала следует зажать кнопки BOOT0 и RESET, затем сперва отпустить кнопку RESET и через полсекунды так же отпустить кнопку BOOT0. Если все было сделано правильно, то в dmesg появится соответствующий лог:
[16081.551492] usb 4-1: new full-speed USB device number 3 using ohci-pci [16081.763546] usb 4-1: New USB device found, idVendor=0483, idProduct=df11, bcdDevice=22.00 [16081.763554] usb 4-1: New USB device strings: Mfr=1, Product=2, SerialNumber=3 [16081.763558] usb 4-1: Product: STM32 BOOTLOADER [16081.763562] usb 4-1: Manufacturer: STMicroelectronics [16081.763565] usb 4-1: SerialNumber: 389C37823039
У меня в микроконтроллер была залита простая мигалка (заливал сам). Когда я зажимал кнопки BOOT0 и RESET, и входил в режим загрузчика, то светодиод на плате переставал мигать. Чтобы выйти из режима загрузчика, достаточно начать RESET, светодиод снова начнет мигать (если вы не снесете прошивку в процессе, конечно).
Чтобы начать работать с DFU-загрузчиком в Linux, нужно сначала установить udev-правила. В каталоге с программой имеются несколько правил:
nostromo:~: ls -l /usr/local/STMicroelectronics/STM32Cube/STM32CubeProgrammer/Drivers/rules/ итого 28 -rw-r--r-- 1 flanker users 215 апр 11 2019 49-stlinkv1.rules -rw-r--r-- 1 flanker users 604 авг 7 2019 49-stlinkv2-1.rules -rw-r--r-- 1 flanker users 480 авг 7 2019 49-stlinkv2.rules -rw-r--r-- 1 flanker users 862 авг 7 2019 49-stlinkv3.rules -rw-r--r-- 1 flanker users 97 авг 7 2019 50-usb-conf.rules -rw-r--r-- 1 flanker users 217 авг 7 2019 Readme.txt -rw-r--r-- 1 flanker users 5 авг 7 2019 version.txt
Правила для ST-Link у меня уже есть, а вот правило 50-usb-conf.rules потребуется установить. Посмотрим, что там:
$ cat /usr/local/STMicroelectronics/STM32Cube/STM32CubeProgrammer/Drivers/rules/50-usb-conf.rules SUBSYSTEMS=="usb", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="df11", GROUP="users", MODE="0666"
Номера idVendor и idProduct соответствуют аналогичным номерам из нашего лога dmesg, следовательно - это то самое правило, которое нам и нужно. Копируем это udev-правило в /etc/udev/rules.d/ и перезагружаем правила командой из под рута:
# devadm control --reload-rules && udevadm trigger
Подключаем плату вновь (или перезагружаем если уже подключен) к компьютеру и заново активируем режим DFU-загрузчика.
Переключаемся на графическую тулзу. В вертикальной правой панели нужно будет нажать на кнопку обновления:
После этого там должен появиться порт USB1. После этого в выпадающем списке нужно выбрать тип соединения USB, и нажать на расположенную рядом желтую кнопку "Connect". Если все пройдет удачно, то у вас должно рабочее окно программы выглядеть как-то так:
Далее сориентироваться думаю не составит труда. Через программу можно загрузить прошивку в микроконтроллер, изменить Option Bytes (вкладка [OB]), посмотреть содержимое флеш-памяти в режиме дамп-вьювера. Ластик внизу позволяет очистить флеш от прошивки. Вкладка CPU доступна только при подключении через ST-Link. Хочу обратить внимание на переключение "Verbosity Level". Переключая его уровни можно регулировать уровень отладочной информации в окне лога.
Теперь вернемся к версии флешера с консольным интерфейсом. Запустим его с параметром "-l":
$ /usr/local/STMicroelectronics/STM32Cube/STM32CubeProgrammer/bin/STM32_Programmer_CLI -l ------------------------------------------------------------------- STM32CubeProgrammer v2.4.0 ------------------------------------------------------------------- ===== DFU Interface ===== Total number of available STM32 device in DFU mode: 1 Device Index : USB1 USB Bus Number : 004 USB Address Number : 001 Product ID : STM32 BOOTLOADER Serial number : 389C37823039 Firmware version : 0x011a Device ID : 0x0431 ===== STLink Interface ===== Error: No ST-Link detected! ===== UART Interface ===== Total number of serial ports available: 1 Port: ttyS0 Location: /dev/ttyS0 Description: N/A Manufacturer: N/A
Нам вывело наш подключенный через DFU микроконтроллер. Попробуем к нему подключиться:
$ /usr/local/STMicroelectronics/STM32Cube/STM32CubeProgrammer/bin/STM32_Programmer_CLI -c port=usb1
-------------------------------------------------------------------
STM32CubeProgrammer v2.4.0
-------------------------------------------------------------------
USB speed : Full Speed (12MBit/s)
Manuf. ID : STMicroelectronics
Product ID : STM32 BOOTLOADER
SN : 389C37823039
FW version : 0x011a
Device ID : 0x0431
Device name : STM32F411xC/E
Flash size : 512 KBytes (default)
Device type : MCU
Device CPU : Cortex-M4
Через опцию -vb можно регулировать уровнем отладочной информации. Например, с опцией -vb 2 та же команда выдаст такой лог:
$ /usr/local/STMicroelectronics/STM32Cube/STM32CubeProgrammer/bin/STM32_Programmer_CLI -vb 2 -c port=usb1
-------------------------------------------------------------------
STM32CubeProgrammer v2.4.0
-------------------------------------------------------------------
USB speed : Full Speed (12MBit/s)
Manuf. ID : STMicroelectronics
Product ID : STM32 BOOTLOADER
SN : 389C37823039
FW version : 0x011a
Device ID : 0x0431
AREA NAME SECT.NBR ADDRESS SIZE TYPE
Internal Flash 0000 0x08000000 0016 KB REW
0001 0x08004000 0016 KB REW
0002 0x08008000 0016 KB REW
0003 0x0800c000 0016 KB REW
0004 0x08010000 0064 KB REW
0005 0x08020000 0128 KB REW
0006 0x08040000 0128 KB REW
0007 0x08060000 0128 KB REW
Option Bytes 0000 0x1fffc000 0016 B RW
OTP Memory 0000 0x1fff7800 0512 B RW
0001 0x1fff7a00 0016 B RW
Device Feature 0000 0xffff0000 0004 B RW
sending an abort request
setting the address pointer to address: 0x08000000
sending an abort request
setting the address pointer to address: 0x08000000
setting the address pointer to address: 0x1fffc008
receiving packet nbr: 0
sending an abort request
UpLoading data
Database: Config 0 is active.
sending an abort request
setting the address pointer to address: 0x08000000
setting the address pointer to address: 0x1fffc008
receiving packet nbr: 0
sending an abort request
UpLoading data
Database: Config 0 is active.
Device name : STM32F411xC/E
Flash size : 512 KBytes (default)
Device type : MCU
Device CPU : Cortex-M4
Однако, когда я пытался подключиться к микроконтроллеру через ST-Link, то получил сообщение об ошибке, говорящее, что прошивка моего ST-Link устарела и не совместима с программой STM32CubeProgrammer:
$ /usr/local/STMicroelectronics/STM32Cube/STM32CubeProgrammer/bin/STM32_Programmer_CLI -l ------------------------------------------------------------------- STM32CubeProgrammer v2.4.0 ------------------------------------------------------------------- ===== DFU Interface ===== No STM32 device in DFU mode connected ===== STLink Interface =====Error: Old ST-LINK firmware version. Upgrade ST-LINK firmware -------- Connected ST-LINK Probes List -------- ST-Link Probe 0 : ST-LINK SN : 56FF6E064966504930072087 ST-LINK FW : V2J27S6 ----------------------------------------------- ===== UART Interface ===== Total number of serial ports available: 1 Port: ttyS0 Location: /dev/ttyS0 Description: N/A Manufacturer: N/A
В сети можно найти видеоролики о том, как через графическую тулзу прошивка ST-Link обновляется прямо тут же в STM32CubeProgrammer. Но видимо в Linux это не работает так просто. При попытке обновления прошивки из STM32CubeProgrammer я получил еще одно сообщение об ошибке:
Теперь уже мной ST-Link не в DFU-режиме! Опять пришлось все делать по старинке, т.е. скачать c сайта st.com утилиту "ST-Link Firmware Upgrade" и обновить прошивку из виртуалки:
Последний раз я обновлял прошивку ST-Link в 2016 году, тогда это была версия V2.J27.S6. Также как и тогда, обновление прошивки из виртуалки под Linux прошло успешно.
После этого, препятствия для подключения микроконтроллера к флешеру исчезнут:
Если в микроконтроллере имеется прошивка без поддержки отладки, как например в прошивке микропитона, то перед подключением к программе STM32CubeProgrammer (т.е. перед нажатием кнопки "Connect" в графической тулзе или перед нажатием Enter при вводе команды в случае использования консольной утилиты) необходимо будет будет нажать и отпустить кнопку Reset на плате, и примерно через полсекунды после отпускания кнопки подключаться программой. Второй способ заключается опять же в поочередном нажимании кнопок Reset и Boot.
В целом, каких-то преимуществ, по сравнению с подключением через USB-шнурок, в использовании ST-Link я не увидел.
Флеш-память микроконтроллера STM32F411CEU6 разбита на следующие сектора:
Очистка флеш-памяти через CLI-интерфейс осуществляется с помощью ключа "-e". Этот ключ с параметром "all" будет очищать все сектора. Но мы можем выбрать определенные сектора для очистки, в этом случае следует указать их через запятую. Или же мы можем задать диапазон секторов, для этого их номера достаточно будет разделить пробелом. В случае если после "-e" будет стоять одно число, то будет очищен соответствующий сектор:
Компания WeAct предлагает свои платы как бюджетную платформу для MircoPython. Оригинальная pyboard v1.1 c чипом STM32F405 стоит прилично - 33.9 фунтов + доставка.
Готовую прошивку с микропитоном для микроконтроллера STM32F411CE можно скачать с гитхаба компании WeACT https://github.com/WeActTC/MiniF4-STM32F4x1/tree/master/SDK/STM32F411CEU6/MicroPython:
Там есть прошивки для плат с различными флешками. Внешняя флешка позволит вам размешать ваш код на микропитоне непосредственно на этой самой флешке и быть т.о. по-сути не ограниченным в свободном пространстве. В прошивном случае вам придется довольствоваться 45 килобайтами под собственный код, т.к. остальное место будет занимать микропитон. Т.к. на нашей плате пока никакой флешки не установлено, нам нужна будет прошивка для "internal_rom":
Скачиваем raw-файл с прошивкой:
$ wget https://raw.githubusercontent.com/WeActTC/MiniF4-STM32F4x1/master/SDK/STM32F411CEU6/MicroPython/firmw are_internal_rom_stm32f411_v1.12-540.hex
Проверяем:
$ arm-none-eabi-size ./firmware_internal_rom_stm32f411_v1.12-540.hex text data bss dec hex filename 0 322404 0 322404 4eb64 ./firmware_internal_rom_stm32f411_v1.12-540.hex
Прошивка весит ~320КБ. Прошиваем с помощью команды:
$ STM32_Programmer_CLI -c port=swd -w /tmp/firmware_internal_rom_stm32f411_v1.12-540.hex
Отстыковываем ST-Link, если прошивка проводилась через него, а не через USB-шнурок, и подключаем плату к USB. В dmesg пойдет такой лог:
[32070.940976] usb 4-2: New USB device found, idVendor=f055, idProduct=9800, bcdDevice= 2.00 [32070.940983] usb 4-2: New USB device strings: Mfr=1, Product=2, SerialNumber=3 [32070.940988] usb 4-2: Product: Pyboard Virtual Comm Port in FS Mode [32070.940991] usb 4-2: Manufacturer: MicroPython [32070.940994] usb 4-2: SerialNumber: 389C37823039 [32071.352314] usb-storage 4-2:1.0: USB Mass Storage device detected [32071.353469] scsi host8: usb-storage 4-2:1.0 [32071.353558] usbcore: registered new interface driver usb-storage [32071.359817] cdc_acm 4-2:1.1: ttyACM0: USB ACM device [32071.361341] usbcore: registered new interface driver cdc_acm [32071.361344] cdc_acm: USB Abstract Control Model driver for USB modems and ISDN adapters [32071.368434] usbcore: registered new interface driver uas [32072.363046] scsi 8:0:0:0: Direct-Access MicroPy pyboard Flash 1.00 PQ: 0 ANSI: 2 [32072.374982] sd 8:0:0:0: [sdb] 384 512-byte logical blocks: (197 kB/192 KiB) [32072.382022] sd 8:0:0:0: [sdb] Write Protect is off [32072.382029] sd 8:0:0:0: [sdb] Mode Sense: 03 00 00 00 [32072.389035] sd 8:0:0:0: [sdb] No Caching mode page found [32072.389042] sd 8:0:0:0: [sdb] Assuming drive cache: write through [32072.443023] sdb: sdb1 [32072.494018] sd 8:0:0:0: [sdb] Attached SCSI removable disk
Здесь мы видим подключение двух устройств, последовательного порта и флеш-носителя. Монтируем флеш-носитель и смотрим его характеристики и содержимое:
$ df -h /mnt/tmp Файловая система Размер Использовано Дост Использовано% Cмонтировано в /dev/sdb1 47K 5,0K 42K 11% /mnt/tmp $ ls -l /mnt/tmp итого 5 -rwxr-xr-x 1 root root 528 янв 1 2015 README.txt -rwxr-xr-x 1 root root 366 янв 1 2015 boot.py -rwxr-xr-x 1 root root 34 янв 1 2015 main.py -rwxr-xr-x 1 root root 2999 янв 1 2015 pybcdc.inf
Здесь файл с расширением INF - это драйвер последовательно порта для Windows, его можно сразу стереть, освободится место. README.txt это хелло-файл:
This is a MicroPython board You can get started right away by writing your Python code in 'main.py'. For a serial prompt: - Windows: you need to go to 'Device manager', right click on the unknown device, then update the driver software, using the 'pybcdc.inf' file found on this drive. Then use a terminal program like Hyperterminal or putty. - Mac OS X: use the command: screen /dev/tty.usbmodem* - Linux: use the command: screen /dev/ttyACM0 Please visit http://micropython.org/help/ for further help.
Его тоже можно стереть.
boot.py - это надо думать автозагузочный файл:
# boot.py -- run on boot-up # can run arbitrary Python, but best to keep it minimal import machine import pyb pyb.country('US') # ISO 3166-1 Alpha-2 code, eg US, GB, DE, AU #pyb.main('main.py') # main script to run after this one #pyb.usb_mode('VCP+MSC') # act as a serial and a storage device #pyb.usb_mode('VCP+HID') # act as a serial device and a mouse
И main.py это пустой файл для вашего кода:
# main.py -- put your code here!
Напоминаю, что для своего кода у вас есть всего 45 килобайта.
На github'е компании WeAct имеется парочка примеров для микропитона: https://github.com/WeActTC/MiniF4-STM32F4x1/tree/master/SDK/MicroPython_Example. Нас будет интересовать содержимое Blink.py:
import pyb, micropython micropython.alloc_emergency_exception_buf(100) class Foo(object): def __init__(self, timer, led): self.led = led timer.callback(self.cb) def cb(self, tim): self.led.toggle() blue = Foo(pyb.Timer(1, freq=2), pyb.LED(1)) # LED(1) -> PC13
Размещаем эту программу в main.py, размонтируем флешку, жмем на кнопку Reset на плате, и наслаждаемся миганием синего светодиода.
Через последовательный порт у нас также есть доступ к режиму интерпретатора REPL. Там мы вручную сможем помигать светодиодом, но для этого сначала придется отчистить main.py от размещенного там ранее кода, и перезагрузить микроконтроллер, т.к. способа остановить через REPL запущенную из флешки программу, я пока не нашел. Итак входим к REPL с помощью команды:
$ screen /dev/ttyACM0
Нас должно встретить сообщение навроде этого:
MicroPython v1.12-540-gdd65eb920-dirty on 2020-07-05; WeAct_Core with STM32F411CE Type "help()" for more information. >>>
Словечко dirty в версии прошивки мне заранее не нравится ;) Вводим команду help() для вывода справки, и получаем следующий вывод:
Welcome to MicroPython! For online help please visit http://micropython.org/help/. Quick overview of commands for the board: pyb.info() -- print some general information pyb.delay(n) -- wait for n milliseconds pyb.millis() -- get number of milliseconds since hard reset pyb.Switch() -- create a switch object Switch methods: (), callback(f) pyb.LED(n) -- create an LED object for LED n (n=1,2,3,4) LED methods: on(), off(), toggle(), intensity() pyb.Pin(pin) -- get a pin, eg pyb.Pin('X1') pyb.Pin(pin, m, [p]) -- get a pin and configure it for IO mode m, pull mode p Pin methods: init(..), value([v]), high(), low() pyb.ExtInt(pin, m, p, callback) -- create an external interrupt object pyb.ADC(pin) -- make an analog object from a pin ADC methods: read(), read_timed(buf, freq) pyb.DAC(port) -- make a DAC object DAC methods: triangle(freq), write(n), write_timed(buf, freq) pyb.RTC() -- make an RTC object; methods: datetime([val]) pyb.rng() -- get a 30-bit hardware random number pyb.Servo(n) -- create Servo object for servo n (n=1,2,3,4) Servo methods: calibration(..), angle([x, [t]]), speed([x, [t]]) pyb.Accel() -- create an Accelerometer object Accelerometer methods: x(), y(), z(), tilt(), filtered_xyz() Pins are numbered X1-X12, X17-X22, Y1-Y12, or by their MCU name Pin IO modes are: pyb.Pin.IN, pyb.Pin.OUT_PP, pyb.Pin.OUT_OD Pin pull modes are: pyb.Pin.PULL_NONE, pyb.Pin.PULL_UP, pyb.Pin.PULL_DOWN Additional serial bus objects: pyb.I2C(n), pyb.SPI(n), pyb.UART(n) Control commands: CTRL-A -- on a blank line, enter raw REPL mode CTRL-B -- on a blank line, enter normal REPL mode CTRL-C -- interrupt a running program CTRL-D -- on a blank line, do a soft reset of the board CTRL-E -- on a blank line, enter paste mode For further help on a specific object, type help(obj) For a list of available modules, type help('modules')
Вводим команду help('modules') чтобы посмотреть список установленных по-умолчанию модулей:
>>> help('modules') __main__ math uasyncio/funcs umachine _onewire micropython uasyncio/lock uos _thread network uasyncio/stream urandom _uasyncio onewire ubinascii ure builtins pyb ucollections uselect cmath stm uctypes usocket dht sys uerrno ustruct framebuf uarray uhashlib utime gc uasyncio/__init__ uheapq utimeq lcd160cr uasyncio/core uio uzlib lcd160cr_test uasyncio/event ujson Plus any modules on the filesystem
В завершении вывода говорится, что дополнительные модули могут быть установлены на файловый носитель. Фактически это означает, что нам придется устанавливать на плату SPI-флешку.
Вводим команду pyb.info()
>>> pyb.info() ID=4a006700:19513930:38373538 S=96000000 H=96000000 P1=24000000 P2=48000000 _etext=806b184 _sidata=806b18c _sdata=20000000 _edata=2000001c _sbss=2000001c _ebss=20006494 _sstack=2001bff8 _estack=2001fff8 _ram_start=20000000 _heap_start=20006494 _heap_end=2001bff8 _ram_end=20020000 qstr: n_pool=1 n_qstr=3 n_str_data_bytes=28 n_total_bytes=124 GC: 86848 total 1536 : 85312 1=23 2=5 m=40 LFS free: 40960 bytes THREAD: only main thread
Эта информация на нас пока ничего не значит. Что бы управлять светодиодом, следует вводить команды pyb.LED(1).on(), pyb.LED(1).off(), pyb.LED(1).toggle(). При этом синий светодиод должен включаться и выключаться соответственно:
Также обратите внимание на командные комбинации клавиш. CTRL + D, к примеру, перезагружает микроконтроллер.
Установка SPI флешки позволит преодолеть досадное ограничение в 45 килобайт под вашу программу и дополнительные модули. Здесь: https://github.com/mcauser/WEACT_F411CEU6 утверждается, что платы успешно тестировались с флешками:
Замечу, что официальной поддержки 16 МБайтной флешки нет, в ее случае придется микропитон собирать из исходников. У меня под рукой была флешка Winbond W25Q64FVSIG. Запаять ее было делом пяти минут:
Кроме флешки, там есть еще посадочное место под конденсатор С15 на 0.1 мкФ:
Посадочное место под SMD конденсатор размера 0603, но у меня под рукой были только 0805. Усилием воли, я поставил тот, что был в наличии, но сел он кривовато. Флешка будет работать и без конденсатора, но его лучше будет все-таки поставить.
После промывки платы от следов пайки и последующей сушки, на микроконтроллере следует обновить прошивку, до версии, которая предназначена для работы с флешками на 8МБ https://github.com/WeActTC/MiniF4-STM32F4x1/tree/master/SDK/STM32F411CEU6/MicroPython:
Загружаем эту прошивку в чип:
Убираем ST-Link (если прошивка производилась через него) и подключаем плату через USB к компьютеру. В dmesg видим следующее:
[17748.129823] cdc_acm 4-2:1.1: ttyACM0: USB ACM device
[17748.131436] usbcore: registered new interface driver cdc_acm
[17748.131437] cdc_acm: USB Abstract Control Model driver for USB modems and ISDN adapters
[17748.136489] usb-storage 4-2:1.0: USB Mass Storage device detected
[17748.139756] scsi host8: usb-storage 4-2:1.0
[17748.139869] usbcore: registered new interface driver usb-storage
[17748.148136] usbcore: registered new interface driver uas
[17749.216339] scsi 8:0:0:0: Direct-Access MicroPy pyboard Flash 1.00 PQ: 0 ANSI: 2
[17749.227319] sd 8:0:0:0: [sdb] 16640 512-byte logical blocks: (8.52 MB/8.13 MiB)
[17749.234348] sd 8:0:0:0: [sdb] Write Protect is off
[17749.234355] sd 8:0:0:0: [sdb] Mode Sense: 03 00 00 00
[17749.241323] sd 8:0:0:0: [sdb] No Caching mode page found
[17749.241325] sd 8:0:0:0: [sdb] Assuming drive cache: write through
[17749.287331] sdb: sdb1
[17749.316331] sd 8:0:0:0: [sdb] Attached SCSI removable disk
У нас появилась флешка на 8 МБ. Ее даже можно открыть в файловом браузере:
Совсем не обязательно пользоваться готовыми прошивками микропитона, их можно собирать самому. Это может понадобиться, если вы решите поставить флешку на 16 МБ, или вам надо поставить микропитон на какую-то свою плату с микроконтроллером серии STM32F4xx. Или если спустя какое-то время, компания WeACT прекратит существование, и иного способа получить актуальную прошивку не будет.
На github'е https://github.com/WeActTC/MiniF4-STM32F4x1/tree/master/SDK/STM32F411CEU6/MicroPython/WeAct_F411CE выложен порядок сборки микропитона из исходников:
Следуя этим инструкциям, выполняем:
$ git clone https://github.com/micropython/micropython.git $ cd micropython/ $ git submodule update --init $ cd mpy-cross $ make -j4 $ cd ../ports/stm32/boards $ git clone https://github.com/WeActTC/WeAct_F411CE.git $ cd ..
Перед сборкой, нам нужно сконфигурировать прошивку на работу с нужной флешкой.
Согласно инструкции, в файле: ./boards/WeAct_F411CE/mpconfigboard.h находим строки:
#define MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE (1) #define MICROPY_HW_SPIFLASH_SIZE_BITS (32 * 1024 * 1024)
и заменяем их на следующие:
#define MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE (0) #define MICROPY_HW_SPIFLASH_SIZE_BITS (64 * 1024 * 1024)
Компилируем прошивку:
$ make -j4
После недолгой компиляции, мы получим прошивку в файле ./build-PYBV10/firmware.hex
$ arm-none-eabi-size ./build-PYBV10/firmware.hex text data bss dec hex filename 0 356852 0 356852 571f4 ./build-PYBV10/firmware.hex
Прошиваем ее в микроконтроллер, затем подключаем через USB к компьютеру, и заходим в REPL. Самым очевидным признаком того, что мы используем самосборную прошивку, будет изменившееся приветствие. Появится дата нашей сборки, замечаем, что версия микропитона сменилась с 1.12-540 до 1.12-648. Кроме того, из имени сборки исчезло слово "dirty":
Если ввести команду pyb.info(), то в строке "LFS free" появится размер нашей флешки.
Прежде всего, как я уже говорил ранее (возможно кто-то читает не все подряд с начала до конца), что бы управлять периферией из REPL (Read-Eval-Print Loop), нам следует очистить от программы файл main.py на флешке и перезапустить микроконтролер. Последнее можно сделать прямо из REPL нажав комбинацию клавиш CTRL+D.
В REPL можно вводить свою программу нажав комбинацию CTRL+E. Допустим только ввод, редактировать текст нельзя, даже затереть последние напечатанные символы не получится. Поэтому если вы вводите большой текст, то пишите его обычном редакторе, а затем используйте "Copy & Paste". Кроме CTRL+C и CTRL+V, мы можем использовать более хардкорное решение.
Т.к. мы уже работаем в screen, который является консольным мультиплексором, то мы можем использовать его встроенные возможности. Все команды в screen посылаются хоткеями "CTRL+Мета+Клавиша_команды". В качестве Мета-клавишы по-умолчанию выступает Alt. Т.о. жмем "CTL+ALT+C" и открываем новую консоль, между которыми можно переключаться через "CTL+ALT+SPACE". В новой консоли, в любом консольном редакторе вводим текст программы и выделяем его через "CTL+ALT+[". После последнего хоткея подводим курсор к началу выделения и нажатием пробела начинаем его выделять. Далее ведем курсор до окончания выделения и еще одним нажатием на пробел, заканчиваем выделение.
Внизу появится сообщение, что столько-то символов было скопировано в буфер. Далее снова переключаемся на REPL, вводим "CTR+E", затем "CTL+ALT+]", и наш текст вставился без малейшей ошибки.
Комбинация REPL "CTL+C" отменяет ввод программы. Комбинация "CTL+D" запускает программу на выполнение. Выполнения программы можно прервать комбинацией "CTL+C".
Теперь давайте напишем что-то полезное. Сделаем мигалку на обычном счетчике, и на нем приблизительно измерим быстродействие нашей MicroPython системы. Вводим в REPL такую программу:
while True: for i in range(60000): pass pyb.LED(1).toggle()
Запускаем ее комбинацией "CTL+D", и судя по частоте мигания синего светодиода, я бы сказал, что быстродействие нашего кода на python где-то на уровне нативного кода Arduino на 16-мегагерцовой меге. Но никто же не ждал чуда? Частоту работу микроконтроллере можно менять через команду: machine.freq(). Введите ее с пустыми скобками, чтобы узнать допустимые значения. Но микроконтроллер по умолчанию работает на частоте 96МГц, т.е. на максимальной производительности.
Можно использовать функцию pyb.delay() для указания задержки к миллисекундах:
import pyb while True: pyb.delay(1000) pyb.LED(1).toggle()
Следующий способ помигать светодиодом, на этот раз с помощью таймера, приведен как-раз в документации по этим таймерам - class Timer – control internal timers:
import pyb tim = pyb.Timer(1) # create a timer object using timer 1 tim.init(freq=1) # trigger at 1Hz tim.callback(lambda t:pyb.LED(1).toggle())
Здесь ключевое слово lambda несет то же значение, что в C++, т.е. указывает на безымянную функцию. Если то же самое сделать через именованную функцию, то получится немного длиннее:
import pyb def blink(timer): # we will receive the timer object when being called pyb.LED(1).toggle() # make blink tim = pyb.Timer(1, freq=2) # create a timer object using timer 1, trigger at 2Hz tim.callback(blink) # set the callback to our blink function
В качестве еще одного примера работы с таймерами можно рассмотреть реализацию бенчмарка, который я описывал в 2018 году: Простой бенчмарк на операции деления:
import pyb def blink(timer): # we will receive the timer object when being called global ms if (ms>0): ms = ms-1 tim = pyb.Timer(1, freq=1000) # create a timer object using timer 1, trigger at 1000Hz ms=50 tim.callback(blink) # set the callback to our blink function div_count=0 while (ms>0): result=ms/int(314) div_count=div_count+1 tim.callback(None) # stop timer print('div_count= ',div_count)
И ожидаемо, что результат его работы покажет производительность даже меньшую чем в Arduino:
Программу можно записать и другим способом. Например:
import pyb class check(object): def __init__(self,ms=50): self.ms=ms self.timer=pyb.Timer(1,freq=1000) def cb(self, tim): if (self.ms>0): self.ms-=1 def __call__(self): self.div_count=0 self.timer.callback(self.cb) while (self.ms>0): self.div_count+=1 self.timer.callback(None) return self.div_count r = check() print(r())
Любопытно, что такая, казалось бы, более замороченная программа, работает почти в два раза быстрее предыдущей:
Кстати, раз уж мы используем прерывания, а метод def cb(self, tim) в данном примере является обработчиком прерывания, в документации к микропитону есть рекомендация вставлять следующие строки в начало программы, для возможности генерации сообщения об ошибке, если они возникнут в обработчике прерывания:
import micropython micropython.alloc_emergency_exception_buf(100)
Если говорить конкретно об алгоритме, то его проще всего было бы реализовать без использования дополнительного таймера, через обычную функцию:
import pyb def check(ms): div_count=0 start=pyb.millis() while (pyb.elapsed_millis(start) < ms): div_count+=1 return div_count print(check(50))
И результат выполнения будет сопоставим с предыдущим случаем:
Теперь, допустим на нужно помигать светодиодом на произвольном пине. Для этого нужно обратиться к пину по его номеру, а не через LED(1).
Сначала зададим режим работы порта как PUSH PULL:
>>> blu=machine.Pin(pyb.Pin.cpu.C13,machine.Pin.OUT)
Теперь включаем светодиод:
>>> blu.off()
нет, это не ошибка, именно off(). Или выключаем:
>>> blu.on()
А можно и так. Включаем:
>>> blu.value(0)
Выключаем:
>>> blu.value(1)
Или меняем состояние:
>>> blu.value(not blu.value())
А сейчас самое время вспомнить, что на плате имеется кнопка "Key" висящая на PA0. Мы можем читать ее состояние, и использовать светодиод для индикации состояния кнопки. Для начала сделаем это самым простым способом - методом опроса состояния кнопки.
import pyb, machine led=machine.Pin(pyb.Pin.cpu.C13,machine.Pin.OUT) btn=machine.Pin(pyb.Pin.cpu.A0,machine.Pin.IN) while True: led.value(btn.value()) pyb.delay(100)
Теперь, когда мы будем нажимать кнопку "Key", синий светодиод будет загораться.
Переделать программу на внешнем прерывании не составляет большого труда. В данном случае у меня она получилось такой:
from machine import Pin import pyb, micropython micropython.alloc_emergency_exception_buf(100) btn=Pin(pyb.Pin.cpu.A0,Pin.IN) def btn_irq(pin): pyb.LED(1).toggle() global interrupt_pin interrupt_pin=pin print("press: ",interrupt_pin) btn.irq(trigger=Pin.IRQ_RISING,handler=btn_irq) while True: pyb.delay(100)
При каждом нажатии на кнопку "KEY" синий светодиод будет зажигаться или гаснуть, при этом в консоль пойдет идентификатор пина с кнопкой:
Замечу, что при нажатии на кнопку отсутствовал дребезг контакта, поэтому ставить какие-то задержки, для подавления дребезга, в обработчик внешнего прерывания я не стал.
Для редакторов кода VS Code и Atom возможна установка плагина Pymakr, который превращает работу в них, в приятную альтернативу использованию программы screen. Полагаю, что наиболее актуально это будет для пользователей Windows, у которых программы screen под рукой как правило нет, да и работать в консоли они не любят. Плагин Pymakr предоставляет вам консоль REPL, и позволяет автоматизировать оправку вашей программы в REPL на исполнение. Но Pymakr написан был для работы с платой Pyboard, и "из коробки" с нашей платой WeACT работать не будет. Его нужно будет настраивать. В принципе, это займет всего пару минут.
Проше всего, как мне показалось, настроить VS Code. Для начала нужно будет установить этот самый плагин Pymakr:
Затем надо будет заглянуть в лог dmesg и посмотреть, как там записан производитель (Manufacturer) последовательного порта.
[ 1709.050627] usb 4-2: New USB device found, idVendor=f055, idProduct=9800, bcdDevice= 2.00
[ 1709.050634] usb 4-2: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[ 1709.050639] usb 4-2: Product: Pyboard Virtual Comm Port in FS Mode
[ 1709.050642] usb 4-2: Manufacturer: MicroPython
[ 1709.050645] usb 4-2: SerialNumber: 389C37823039
[ 1709.466521] usb-storage 4-2:1.0: USB Mass Storage device detected
[ 1709.466639] scsi host8: usb-storage 4-2:1.0
[ 1709.466747] usbcore: registered new interface driver usb-storage
[ 1709.474206] cdc_acm 4-2:1.1: ttyACM0: USB ACM device
[ 1709.475847] usbcore: registered new interface driver cdc_acm
[ 1709.475850] cdc_acm: USB Abstract Control Model driver for USB modems and ISDN adapters
[ 1709.500918] usbcore: registered new interface driver uas
[ 1710.529689] scsi 8:0:0:0: Direct-Access MicroPy pyboard Flash 1.00 PQ: 0 ANSI: 2
[ 1710.541684] sd 8:0:0:0: [sdb] 16640 512-byte logical blocks: (8.52 MB/8.13 MiB)
[ 1710.548668] sd 8:0:0:0: [sdb] Write Protect is off
[ 1710.548676] sd 8:0:0:0: [sdb] Mode Sense: 03 00 00 00
[ 1710.555673] sd 8:0:0:0: [sdb] No Caching mode page found
[ 1710.555680] sd 8:0:0:0: [sdb] Assuming drive cache: write through
[ 1710.607667] sdb: sdb1
[ 1710.668669] sd 8:0:0:0: [sdb] Attached SCSI removable disk
Т.к. последовательный порт виртуальный, в качестве производителя можно в исходниках вписать что угодно, так что эта запись может измениться в будущих прошивках. В случае Windows, производителя нужно искать, я думаю, в диспечере устройств, в свойствах устройства.
После установки Pymakr сразу же откроется файл с настройками плагина - pymakr.json. Но даже если он не откроется автоматически, его можно найти в ~/.config/Code/User/pymakr.json. В этом файле настроек, нам нужно будет поменять адрес устройства с 192.168.4.1 на наш порт: "/dev/ttyACM0". Кроме этого добавить нашего производителя в список поддерживаемых для автосоединения. При этом автосоединения лучше будет сбросить в false, это только мешает.
После этого достаточно будет подключить плату к компьютеру и щелкнуть внизу по "Pymakr Console". В окне терминала появиться консоль REPL. Щелчок по "Run" запустит вашу программу в REPL.
Настройка Atom'а аналогична. Для начала нужно будет установить плагин Pymakr, после чего сразу зайти в настройки плагина:
В настройках нужно будет также изменить адрес устройства на свой порт, сбросить флажок с автосоединения, и добавить своего производителя в общий список:
После этого сверху, на окне Pymakr, нужно щелкнуть по "Connect Device", и из выпадающего списка выбрать свой порт. В окне появиться консоль REPL:
Клик по треугольнику слева загрузит вашу программу на выполнение в REPL.