summaryrefslogtreecommitdiff
path: root/ports
diff options
context:
space:
mode:
Diffstat (limited to 'ports')
-rw-r--r--ports/bare-arm/Makefile2
-rw-r--r--ports/cc3200/mods/modusocket.c15
-rw-r--r--ports/cc3200/mods/modusocket.h2
-rw-r--r--ports/cc3200/mods/modwlan.c10
-rw-r--r--ports/cc3200/mpconfigport.h4
-rw-r--r--ports/esp32/Makefile786
-rw-r--r--ports/esp32/README.md202
-rw-r--r--ports/esp32/README.ulp.md126
-rw-r--r--ports/esp32/esp32.custom_common.ld254
-rw-r--r--ports/esp32/esp32_ulp.c97
-rw-r--r--ports/esp32/espneopixel.c53
-rw-r--r--ports/esp32/esponewire.c80
-rw-r--r--ports/esp32/fatfs_port.c41
-rw-r--r--ports/esp32/gccollect.c66
-rw-r--r--ports/esp32/gccollect.h42
-rw-r--r--ports/esp32/help.c65
-rw-r--r--ports/esp32/machine_adc.c132
-rw-r--r--ports/esp32/machine_dac.c97
-rw-r--r--ports/esp32/machine_hw_spi.c390
-rw-r--r--ports/esp32/machine_pin.c414
-rw-r--r--ports/esp32/machine_pwm.c277
-rw-r--r--ports/esp32/machine_rtc.c162
-rw-r--r--ports/esp32/machine_rtc.h44
-rw-r--r--ports/esp32/machine_timer.c192
-rw-r--r--ports/esp32/machine_touchpad.c110
-rw-r--r--ports/esp32/machine_uart.c357
-rw-r--r--ports/esp32/machine_wdt.c78
-rw-r--r--ports/esp32/main.c146
-rw-r--r--ports/esp32/makeimg.py25
-rw-r--r--ports/esp32/memory.h2
-rw-r--r--ports/esp32/modesp.c157
-rw-r--r--ports/esp32/modesp.h1
-rw-r--r--ports/esp32/modesp32.c141
-rw-r--r--ports/esp32/modesp32.h31
-rw-r--r--ports/esp32/modmachine.c269
-rw-r--r--ports/esp32/modmachine.h26
-rw-r--r--ports/esp32/modnetwork.c646
-rw-r--r--ports/esp32/modnetwork.h36
-rw-r--r--ports/esp32/modsocket.c702
-rw-r--r--ports/esp32/modules/_boot.py12
-rw-r--r--ports/esp32/modules/apa106.py8
l---------ports/esp32/modules/dht.py1
l---------ports/esp32/modules/ds18x20.py1
-rw-r--r--ports/esp32/modules/flashbdev.py34
-rw-r--r--ports/esp32/modules/inisetup.py42
-rw-r--r--ports/esp32/modules/neopixel.py33
l---------ports/esp32/modules/ntptime.py1
l---------ports/esp32/modules/onewire.py1
l---------ports/esp32/modules/umqtt/robust.py1
l---------ports/esp32/modules/umqtt/simple.py1
l---------ports/esp32/modules/upip.py1
l---------ports/esp32/modules/upip_utarfile.py1
l---------ports/esp32/modules/upysh.py1
l---------ports/esp32/modules/urequests.py1
l---------ports/esp32/modules/webrepl.py1
l---------ports/esp32/modules/webrepl_setup.py1
l---------ports/esp32/modules/websocket_helper.py1
-rw-r--r--ports/esp32/moduos.c134
-rw-r--r--ports/esp32/modutime.c106
-rw-r--r--ports/esp32/mpconfigport.h268
-rw-r--r--ports/esp32/mphalport.c156
-rw-r--r--ports/esp32/mphalport.h86
-rw-r--r--ports/esp32/mpthreadport.c226
-rw-r--r--ports/esp32/mpthreadport.h45
-rw-r--r--ports/esp32/network_lan.c203
-rw-r--r--ports/esp32/partitions.csv5
-rw-r--r--ports/esp32/qstrdefsport.h30
-rw-r--r--ports/esp32/sdkconfig.h191
-rw-r--r--ports/esp32/uart.c65
-rw-r--r--ports/esp32/uart.h33
-rw-r--r--ports/esp8266/Makefile28
-rw-r--r--ports/esp8266/README.md26
-rw-r--r--ports/esp8266/common-hal/os/__init__.c15
-rw-r--r--ports/esp8266/esp8266_common.ld1
-rw-r--r--ports/esp8266/esp_mphal.c27
-rw-r--r--ports/esp8266/esp_mphal.h9
-rw-r--r--ports/esp8266/esppwm.c17
-rw-r--r--ports/esp8266/esppwm.h2
-rw-r--r--ports/esp8266/espuart.c31
-rw-r--r--ports/esp8266/machine_hspi.c7
-rw-r--r--ports/esp8266/main.c34
-rw-r--r--ports/esp8266/modmachine.c4
-rw-r--r--ports/esp8266/modnetwork.c50
-rw-r--r--ports/esp8266/modules/inisetup.py2
-rw-r--r--ports/esp8266/modules/ntptime.py1
-rw-r--r--ports/esp8266/modules/webrepl_setup.py14
-rw-r--r--ports/esp8266/mpconfigport.h11
-rw-r--r--ports/esp8266/mpconfigport_512k.h3
-rw-r--r--ports/esp8266/posix_helpers.c5
-rw-r--r--ports/minimal/Makefile3
-rw-r--r--ports/minimal/README.md2
-rw-r--r--ports/minimal/main.c2
-rw-r--r--ports/qemu-arm/Makefile24
-rw-r--r--ports/qemu-arm/Makefile.test24
-rw-r--r--ports/qemu-arm/README.md4
-rw-r--r--ports/qemu-arm/mpconfigport.h7
-rw-r--r--ports/qemu-arm/test_main.c36
-rw-r--r--ports/stm32/Makefile160
-rw-r--r--ports/stm32/README.md12
-rw-r--r--ports/stm32/accel.c61
-rw-r--r--ports/stm32/accel.h6
-rw-r--r--ports/stm32/adc.c372
-rw-r--r--ports/stm32/adc.h6
-rw-r--r--ports/stm32/boards/B_L475E_IOT01A/mpconfigboard.h13
-rw-r--r--ports/stm32/boards/B_L475E_IOT01A/mpconfigboard.mk5
-rw-r--r--ports/stm32/boards/B_L475E_IOT01A/stm32l4xx_hal_conf.h1
-rw-r--r--ports/stm32/boards/CERB40/mpconfigboard.h18
-rw-r--r--ports/stm32/boards/CERB40/mpconfigboard.mk4
-rw-r--r--ports/stm32/boards/CERB40/pins.csv4
-rw-r--r--ports/stm32/boards/CERB40/stm32f4xx_hal_conf.h2
-rw-r--r--ports/stm32/boards/ESPRUINO_PICO/mpconfigboard.h12
-rw-r--r--ports/stm32/boards/ESPRUINO_PICO/mpconfigboard.mk4
-rw-r--r--ports/stm32/boards/ESPRUINO_PICO/stm32f4xx_hal_conf.h2
-rw-r--r--ports/stm32/boards/HYDRABUS/mpconfigboard.h11
-rw-r--r--ports/stm32/boards/HYDRABUS/mpconfigboard.mk4
-rw-r--r--ports/stm32/boards/HYDRABUS/stm32f4xx_hal_conf.h2
-rw-r--r--ports/stm32/boards/LIMIFROG/board_init.c6
-rw-r--r--ports/stm32/boards/LIMIFROG/mpconfigboard.h10
-rw-r--r--ports/stm32/boards/LIMIFROG/mpconfigboard.mk5
-rw-r--r--ports/stm32/boards/LIMIFROG/stm32l4xx_hal_conf.h1
-rw-r--r--ports/stm32/boards/NETDUINO_PLUS_2/board_init.c4
-rw-r--r--ports/stm32/boards/NETDUINO_PLUS_2/mpconfigboard.h11
-rw-r--r--ports/stm32/boards/NETDUINO_PLUS_2/mpconfigboard.mk4
-rw-r--r--ports/stm32/boards/NETDUINO_PLUS_2/pins.csv2
-rw-r--r--ports/stm32/boards/NETDUINO_PLUS_2/stm32f4xx_hal_conf.h2
-rw-r--r--ports/stm32/boards/NUCLEO_F091RC/mpconfigboard.h59
-rw-r--r--ports/stm32/boards/NUCLEO_F091RC/mpconfigboard.mk7
-rw-r--r--ports/stm32/boards/NUCLEO_F091RC/pins.csv87
-rw-r--r--ports/stm32/boards/NUCLEO_F091RC/stm32f0xx_hal_conf.h312
-rw-r--r--ports/stm32/boards/NUCLEO_F401RE/mpconfigboard.mk4
-rw-r--r--ports/stm32/boards/NUCLEO_F401RE/stm32f4xx_hal_conf.h4
-rw-r--r--ports/stm32/boards/NUCLEO_F411RE/mpconfigboard.mk4
-rw-r--r--ports/stm32/boards/NUCLEO_F411RE/stm32f4xx_hal_conf.h4
-rw-r--r--ports/stm32/boards/NUCLEO_F429ZI/mpconfigboard.h20
-rw-r--r--ports/stm32/boards/NUCLEO_F429ZI/mpconfigboard.mk4
-rw-r--r--ports/stm32/boards/NUCLEO_F429ZI/stm32f4xx_hal_conf.h2
-rw-r--r--ports/stm32/boards/NUCLEO_F446RE/mpconfigboard.mk4
-rw-r--r--ports/stm32/boards/NUCLEO_F446RE/stm32f4xx_hal_conf.h4
-rw-r--r--ports/stm32/boards/NUCLEO_F746ZG/mpconfigboard.h77
-rw-r--r--ports/stm32/boards/NUCLEO_F746ZG/mpconfigboard.mk6
-rw-r--r--ports/stm32/boards/NUCLEO_F746ZG/pins.csv68
-rw-r--r--ports/stm32/boards/NUCLEO_F746ZG/stm32f7xx_hal_conf.h427
-rw-r--r--ports/stm32/boards/NUCLEO_F767ZI/board_init.c8
-rw-r--r--ports/stm32/boards/NUCLEO_F767ZI/mpconfigboard.h18
-rw-r--r--ports/stm32/boards/NUCLEO_F767ZI/mpconfigboard.mk4
-rw-r--r--ports/stm32/boards/NUCLEO_F767ZI/pins.csv6
-rw-r--r--ports/stm32/boards/NUCLEO_F767ZI/stm32f7xx_hal_conf.h2
-rw-r--r--ports/stm32/boards/NUCLEO_H743ZI/board_init.c8
-rw-r--r--ports/stm32/boards/NUCLEO_H743ZI/mpconfigboard.h65
-rw-r--r--ports/stm32/boards/NUCLEO_H743ZI/mpconfigboard.mk7
-rw-r--r--ports/stm32/boards/NUCLEO_H743ZI/pins.csv63
-rw-r--r--ports/stm32/boards/NUCLEO_H743ZI/stm32h7xx_hal_conf.h434
-rw-r--r--ports/stm32/boards/NUCLEO_L476RG/mpconfigboard.h6
-rw-r--r--ports/stm32/boards/NUCLEO_L476RG/mpconfigboard.mk5
-rwxr-xr-xports/stm32/boards/NUCLEO_L476RG/stm32l4xx_hal_conf.h1
-rw-r--r--ports/stm32/boards/OLIMEX_E407/mpconfigboard.h16
-rw-r--r--ports/stm32/boards/OLIMEX_E407/mpconfigboard.mk4
-rw-r--r--ports/stm32/boards/OLIMEX_E407/pins.csv3
-rw-r--r--ports/stm32/boards/OLIMEX_E407/stm32f4xx_hal_conf.h2
-rw-r--r--ports/stm32/boards/PYBLITEV10/mpconfigboard.h7
-rw-r--r--ports/stm32/boards/PYBLITEV10/mpconfigboard.mk4
-rw-r--r--ports/stm32/boards/PYBLITEV10/stm32f4xx_hal_conf.h2
-rw-r--r--ports/stm32/boards/PYBV10/mpconfigboard.h13
-rw-r--r--ports/stm32/boards/PYBV10/mpconfigboard.mk4
-rw-r--r--ports/stm32/boards/PYBV10/stm32f4xx_hal_conf.h2
-rw-r--r--ports/stm32/boards/PYBV11/mpconfigboard.h13
-rw-r--r--ports/stm32/boards/PYBV11/mpconfigboard.mk4
-rw-r--r--ports/stm32/boards/PYBV11/stm32f4xx_hal_conf.h2
-rw-r--r--ports/stm32/boards/PYBV3/mpconfigboard.h12
-rw-r--r--ports/stm32/boards/PYBV3/mpconfigboard.mk4
-rw-r--r--ports/stm32/boards/PYBV3/pins.csv2
-rw-r--r--ports/stm32/boards/PYBV3/stm32f4xx_hal_conf.h2
-rw-r--r--ports/stm32/boards/PYBV4/mpconfigboard.h13
-rw-r--r--ports/stm32/boards/PYBV4/mpconfigboard.mk4
-rw-r--r--ports/stm32/boards/PYBV4/stm32f4xx_hal_conf.h2
-rw-r--r--ports/stm32/boards/STM32F411DISC/mpconfigboard.h10
-rw-r--r--ports/stm32/boards/STM32F411DISC/mpconfigboard.mk4
-rw-r--r--ports/stm32/boards/STM32F411DISC/pins.csv2
-rw-r--r--ports/stm32/boards/STM32F411DISC/stm32f4xx_hal_conf.h2
-rw-r--r--ports/stm32/boards/STM32F429DISC/mpconfigboard.h17
-rw-r--r--ports/stm32/boards/STM32F429DISC/mpconfigboard.mk4
-rw-r--r--ports/stm32/boards/STM32F429DISC/stm32f4xx_hal_conf.h3
-rw-r--r--ports/stm32/boards/STM32F439/mpconfigboard.h19
-rw-r--r--ports/stm32/boards/STM32F439/mpconfigboard.mk4
-rw-r--r--ports/stm32/boards/STM32F439/stm32f4xx_hal_conf.h2
-rw-r--r--ports/stm32/boards/STM32F4DISC/mpconfigboard.h17
-rw-r--r--ports/stm32/boards/STM32F4DISC/mpconfigboard.mk4
-rw-r--r--ports/stm32/boards/STM32F4DISC/pins.csv3
-rw-r--r--ports/stm32/boards/STM32F4DISC/stm32f4xx_hal_conf.h2
-rw-r--r--ports/stm32/boards/STM32F769DISC/mpconfigboard.h16
-rw-r--r--ports/stm32/boards/STM32F769DISC/mpconfigboard.mk4
-rw-r--r--ports/stm32/boards/STM32F769DISC/pins.csv2
-rw-r--r--ports/stm32/boards/STM32F769DISC/stm32f7xx_hal_conf.h3
-rw-r--r--ports/stm32/boards/STM32F7DISC/board_init.c4
-rw-r--r--ports/stm32/boards/STM32F7DISC/mpconfigboard.h18
-rw-r--r--ports/stm32/boards/STM32F7DISC/mpconfigboard.mk4
-rw-r--r--ports/stm32/boards/STM32F7DISC/pins.csv2
-rw-r--r--ports/stm32/boards/STM32F7DISC/stm32f7xx_hal_conf.h2
-rw-r--r--ports/stm32/boards/STM32L476DISC/bdev.c24
-rw-r--r--ports/stm32/boards/STM32L476DISC/board_init.c9
-rw-r--r--ports/stm32/boards/STM32L476DISC/mpconfigboard.h26
-rw-r--r--ports/stm32/boards/STM32L476DISC/mpconfigboard.mk5
-rw-r--r--ports/stm32/boards/STM32L476DISC/stm32l4xx_hal_conf.h1
-rw-r--r--ports/stm32/boards/STM32L496GDISC/mpconfigboard.h52
-rw-r--r--ports/stm32/boards/STM32L496GDISC/mpconfigboard.mk7
-rw-r--r--ports/stm32/boards/STM32L496GDISC/pins.csv140
-rw-r--r--ports/stm32/boards/STM32L496GDISC/stm32l4xx_hal_conf.h421
-rw-r--r--ports/stm32/boards/common_basic.ld86
-rw-r--r--ports/stm32/boards/common_bl.ld86
-rw-r--r--ports/stm32/boards/common_ifs.ld (renamed from ports/stm32/boards/common.ld)13
-rwxr-xr-xports/stm32/boards/make-pins.py18
-rw-r--r--ports/stm32/boards/startup_stm32f0.s303
-rw-r--r--ports/stm32/boards/startup_stm32f4.s530
-rw-r--r--ports/stm32/boards/startup_stm32f7.s (renamed from ports/stm32/startup_stm32.S)220
-rw-r--r--ports/stm32/boards/startup_stm32h7.s763
-rw-r--r--ports/stm32/boards/startup_stm32l4.s549
-rw-r--r--ports/stm32/boards/stm32f091_af.csv89
-rw-r--r--ports/stm32/boards/stm32f091xc.ld26
-rw-r--r--ports/stm32/boards/stm32f401_af.csv6
-rw-r--r--ports/stm32/boards/stm32f401xd.ld3
-rw-r--r--ports/stm32/boards/stm32f401xe.ld3
-rw-r--r--ports/stm32/boards/stm32f405.ld3
-rw-r--r--ports/stm32/boards/stm32f405_af.csv4
-rw-r--r--ports/stm32/boards/stm32f411.ld3
-rw-r--r--ports/stm32/boards/stm32f411_af.csv6
-rw-r--r--ports/stm32/boards/stm32f429.ld3
-rw-r--r--ports/stm32/boards/stm32f429_af.csv4
-rw-r--r--ports/stm32/boards/stm32f439.ld3
-rw-r--r--ports/stm32/boards/stm32f439_af.csv16
-rw-r--r--ports/stm32/boards/stm32f4xx_prefix.c2
-rw-r--r--ports/stm32/boards/stm32f722.ld27
-rw-r--r--ports/stm32/boards/stm32f722_af.csv146
-rw-r--r--ports/stm32/boards/stm32f746.ld3
-rw-r--r--ports/stm32/boards/stm32f746_af.csv15
-rw-r--r--ports/stm32/boards/stm32f767.ld4
-rw-r--r--ports/stm32/boards/stm32f767_af.csv340
-rw-r--r--ports/stm32/boards/stm32f769.ld3
-rw-r--r--ports/stm32/boards/stm32h743.ld29
-rw-r--r--ports/stm32/boards/stm32h743_af.csv170
-rw-r--r--ports/stm32/boards/stm32l476_af.csv30
-rw-r--r--ports/stm32/boards/stm32l476xe.ld6
-rw-r--r--ports/stm32/boards/stm32l476xg.ld8
-rw-r--r--ports/stm32/boards/stm32l496_af.csv142
-rw-r--r--ports/stm32/boards/stm32l496xg.ld35
-rw-r--r--ports/stm32/bufhelper.h6
-rw-r--r--ports/stm32/can.c367
-rw-r--r--ports/stm32/can.h7
-rw-r--r--ports/stm32/dac.c76
-rw-r--r--ports/stm32/dac.h6
-rw-r--r--ports/stm32/dma.c188
-rw-r--r--ports/stm32/dma.h10
-rw-r--r--ports/stm32/extint.c100
-rw-r--r--ports/stm32/extint.h8
-rw-r--r--ports/stm32/fatfs_port.c4
-rw-r--r--ports/stm32/flash.c61
-rw-r--r--ports/stm32/flash.h8
-rw-r--r--ports/stm32/flashbdev.c269
-rw-r--r--ports/stm32/font_petme128_8x8.h6
-rw-r--r--ports/stm32/gccollect.h6
-rw-r--r--ports/stm32/gchelper_m0.s61
-rw-r--r--ports/stm32/i2c.c1221
-rw-r--r--ports/stm32/i2c.h22
-rw-r--r--ports/stm32/i2cslave.c101
-rw-r--r--ports/stm32/i2cslave.h60
-rw-r--r--ports/stm32/irq.h70
-rw-r--r--ports/stm32/lcd.c29
-rw-r--r--ports/stm32/lcd.h6
-rw-r--r--ports/stm32/led.c11
-rw-r--r--ports/stm32/led.h17
-rw-r--r--ports/stm32/lwip_inc/arch/cc.h8
-rw-r--r--ports/stm32/lwip_inc/arch/sys_arch.h1
-rw-r--r--ports/stm32/lwip_inc/lwipopts.h61
-rw-r--r--ports/stm32/machine_i2c.c424
-rw-r--r--ports/stm32/main.c247
-rw-r--r--ports/stm32/make-stmconst.py2
-rw-r--r--ports/stm32/mboot/Makefile189
-rw-r--r--ports/stm32/mboot/README.md78
-rw-r--r--ports/stm32/mboot/main.c1341
-rw-r--r--ports/stm32/mboot/mboot.py177
-rw-r--r--ports/stm32/mboot/mphalport.h155
-rw-r--r--ports/stm32/mboot/stm32_generic.ld77
-rw-r--r--ports/stm32/modmachine.c155
-rw-r--r--ports/stm32/modmachine.h7
-rw-r--r--ports/stm32/modnetwork.c84
-rw-r--r--ports/stm32/modnetwork.h24
-rw-r--r--ports/stm32/modnwcc3k.c7
-rw-r--r--ports/stm32/modnwwiznet5k.c36
-rw-r--r--ports/stm32/modpyb.c61
-rw-r--r--ports/stm32/modstm.c7
l---------ports/stm32/modules/dht.py1
-rw-r--r--ports/stm32/moduos.c18
-rw-r--r--ports/stm32/modusocket.c26
-rw-r--r--ports/stm32/modutime.c8
-rw-r--r--ports/stm32/mpconfigboard_common.h218
-rw-r--r--ports/stm32/mpconfigport.h67
-rw-r--r--ports/stm32/mphalport.c95
-rw-r--r--ports/stm32/mphalport.h42
-rw-r--r--ports/stm32/network_wiznet5k.c417
-rw-r--r--ports/stm32/pendsv.c2
-rw-r--r--ports/stm32/pendsv.h6
-rw-r--r--ports/stm32/pin.c2
-rw-r--r--ports/stm32/pin.h16
-rw-r--r--ports/stm32/pin_defs_stm32.h16
-rw-r--r--ports/stm32/portmodules.h6
-rw-r--r--ports/stm32/pyb_i2c.c1068
-rw-r--r--ports/stm32/pybthread.h6
-rw-r--r--ports/stm32/qspi.c282
-rw-r--r--ports/stm32/qspi.h36
-rw-r--r--ports/stm32/resethandler.s70
-rw-r--r--ports/stm32/resethandler_m0.s74
-rw-r--r--ports/stm32/rng.c76
-rw-r--r--ports/stm32/rng.h9
-rw-r--r--ports/stm32/rtc.c64
-rw-r--r--ports/stm32/rtc.h6
-rw-r--r--ports/stm32/sdcard.c85
-rw-r--r--ports/stm32/sdcard.h6
-rw-r--r--ports/stm32/servo.c19
-rw-r--r--ports/stm32/servo.h6
-rw-r--r--ports/stm32/spi.c371
-rw-r--r--ports/stm32/spi.h21
-rw-r--r--ports/stm32/spibdev.c85
-rw-r--r--ports/stm32/stm32_it.c147
-rw-r--r--ports/stm32/stm32_it.h10
-rw-r--r--ports/stm32/storage.c371
-rw-r--r--ports/stm32/storage.h29
-rw-r--r--ports/stm32/system_stm32.c208
-rw-r--r--ports/stm32/system_stm32f0.c203
-rw-r--r--ports/stm32/systick.h6
-rw-r--r--ports/stm32/timer.c144
-rw-r--r--ports/stm32/timer.h6
-rw-r--r--ports/stm32/uart.c196
-rw-r--r--ports/stm32/uart.h7
-rw-r--r--ports/stm32/usb.c144
-rw-r--r--ports/stm32/usb.h8
-rw-r--r--ports/stm32/usbd_cdc_interface.c45
-rw-r--r--ports/stm32/usbd_cdc_interface.h14
-rw-r--r--ports/stm32/usbd_conf.c1359
-rw-r--r--ports/stm32/usbd_conf.h141
-rw-r--r--ports/stm32/usbd_desc.c168
-rw-r--r--ports/stm32/usbd_desc.h6
-rw-r--r--ports/stm32/usbd_hid_interface.c20
-rw-r--r--ports/stm32/usbd_hid_interface.h8
-rw-r--r--ports/stm32/usbd_msc_storage.c2
-rw-r--r--ports/stm32/usbd_msc_storage.h6
-rw-r--r--ports/stm32/usbdev/Release_Notes.html974
-rw-r--r--ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid.h131
-rw-r--r--ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid0.h15
-rw-r--r--ports/stm32/usbdev/class/inc/usbd_msc_bot.h302
-rw-r--r--ports/stm32/usbdev/class/inc/usbd_msc_data.h208
-rw-r--r--ports/stm32/usbdev/class/inc/usbd_msc_scsi.h390
-rw-r--r--ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c517
-rw-r--r--ports/stm32/usbdev/class/src/usbd_msc_bot.c814
-rw-r--r--ports/stm32/usbdev/class/src/usbd_msc_data.c268
-rw-r--r--ports/stm32/usbdev/class/src/usbd_msc_scsi.c1622
-rw-r--r--ports/stm32/usbdev/core/inc/usbd_core.h318
-rw-r--r--ports/stm32/usbdev/core/inc/usbd_ctlreq.h212
-rw-r--r--ports/stm32/usbdev/core/inc/usbd_def.h634
-rw-r--r--ports/stm32/usbdev/core/inc/usbd_ioreq.h242
-rw-r--r--ports/stm32/usbdev/core/src/usbd_core.c1106
-rw-r--r--ports/stm32/usbdev/core/src/usbd_ctlreq.c1509
-rw-r--r--ports/stm32/usbdev/core/src/usbd_ioreq.c472
-rw-r--r--ports/stm32/usbhost/Release_Notes.html973
-rw-r--r--ports/stm32/usrsw.c7
-rw-r--r--ports/stm32/usrsw.h6
-rw-r--r--ports/stm32/wdt.c4
-rw-r--r--ports/stm32/wdt.h6
-rw-r--r--ports/teensy/hal_gpio.c2
-rw-r--r--ports/teensy/led.c2
-rw-r--r--ports/teensy/mk20dx256_prefix.c2
-rw-r--r--ports/teensy/pin_defs_teensy.h6
-rw-r--r--ports/teensy/teensy_hal.h8
-rw-r--r--ports/unix/Makefile4
-rw-r--r--ports/unix/coverage.c91
-rw-r--r--ports/unix/file.c24
-rw-r--r--ports/unix/main.c31
-rw-r--r--ports/unix/modffi.c2
-rw-r--r--ports/unix/modjni.c2
-rw-r--r--ports/unix/modos.c10
-rw-r--r--ports/unix/moduos_vfs.c18
-rw-r--r--ports/unix/moduselect.c24
-rw-r--r--ports/unix/modusocket.c34
-rw-r--r--ports/unix/mpconfigport.h15
-rw-r--r--ports/unix/mpconfigport_coverage.h14
-rw-r--r--ports/unix/mpthreadport.c4
-rw-r--r--ports/windows/Makefile4
-rw-r--r--ports/windows/mpconfigport.h8
-rw-r--r--ports/zephyr/CMakeLists.txt21
-rw-r--r--ports/zephyr/Makefile36
-rw-r--r--ports/zephyr/README.md4
-rw-r--r--ports/zephyr/main.c29
-rwxr-xr-xports/zephyr/make-bin-testsuite20
-rw-r--r--ports/zephyr/modusocket.c35
-rw-r--r--ports/zephyr/modzsensor.c146
-rw-r--r--ports/zephyr/mpconfigport.h11
-rw-r--r--ports/zephyr/mpconfigport_bin_testsuite.h31
-rw-r--r--ports/zephyr/prj_base.conf20
-rw-r--r--ports/zephyr/prj_disco_l475_iot1.conf5
397 files changed, 28192 insertions, 11002 deletions
diff --git a/ports/bare-arm/Makefile b/ports/bare-arm/Makefile
index 0fcd5d027..a515db80e 100644
--- a/ports/bare-arm/Makefile
+++ b/ports/bare-arm/Makefile
@@ -36,7 +36,7 @@ SRC_S = \
# startup_stm32f40xx.s \
gchelper.s \
-OBJ = $(PY_O) $(addprefix $(BUILD)/, $(SRC_C:.c=.o) $(SRC_S:.s=.o))
+OBJ = $(PY_CORE_O) $(addprefix $(BUILD)/, $(SRC_C:.c=.o) $(SRC_S:.s=.o))
all: $(BUILD)/firmware.elf
diff --git a/ports/cc3200/mods/modusocket.c b/ports/cc3200/mods/modusocket.c
index f587e765a..286b1fb02 100644
--- a/ports/cc3200/mods/modusocket.c
+++ b/ports/cc3200/mods/modusocket.c
@@ -336,6 +336,9 @@ STATIC int wlan_socket_ioctl (mod_network_socket_obj_t *s, mp_uint_t request, mp
if (SL_FD_ISSET(sd, &xfds)) {
ret |= MP_STREAM_POLL_HUP;
}
+ } else if (request == MP_STREAM_CLOSE) {
+ wlan_socket_close(s);
+ ret = 0;
} else {
*_errno = MP_EINVAL;
ret = MP_STREAM_ERROR;
@@ -466,14 +469,6 @@ STATIC mp_obj_t socket_make_new(const mp_obj_type_t *type, size_t n_args, size_t
return s;
}
-// method socket.close()
-STATIC mp_obj_t socket_close(mp_obj_t self_in) {
- mod_network_socket_obj_t *self = self_in;
- wlan_socket_close(self);
- return mp_const_none;
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_1(socket_close_obj, socket_close);
-
// method socket.bind(address)
STATIC mp_obj_t socket_bind(mp_obj_t self_in, mp_obj_t addr_in) {
mod_network_socket_obj_t *self = self_in;
@@ -704,8 +699,8 @@ STATIC mp_obj_t socket_makefile(size_t n_args, const mp_obj_t *args) {
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(socket_makefile_obj, 1, 6, socket_makefile);
STATIC const mp_rom_map_elem_t socket_locals_dict_table[] = {
- { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&socket_close_obj) },
- { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&socket_close_obj) },
+ { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mp_stream_close_obj) },
+ { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) },
{ MP_ROM_QSTR(MP_QSTR_bind), MP_ROM_PTR(&socket_bind_obj) },
{ MP_ROM_QSTR(MP_QSTR_listen), MP_ROM_PTR(&socket_listen_obj) },
{ MP_ROM_QSTR(MP_QSTR_accept), MP_ROM_PTR(&socket_accept_obj) },
diff --git a/ports/cc3200/mods/modusocket.h b/ports/cc3200/mods/modusocket.h
index 6e7758662..aaee04ce1 100644
--- a/ports/cc3200/mods/modusocket.h
+++ b/ports/cc3200/mods/modusocket.h
@@ -26,6 +26,8 @@
#ifndef MICROPY_INCLUDED_CC3200_MODS_MODUSOCKET_H
#define MICROPY_INCLUDED_CC3200_MODS_MODUSOCKET_H
+#include "py/stream.h"
+
extern const mp_obj_dict_t socket_locals_dict;
extern const mp_stream_p_t socket_stream_p;
diff --git a/ports/cc3200/mods/modwlan.c b/ports/cc3200/mods/modwlan.c
index 005334a79..c27e993bc 100644
--- a/ports/cc3200/mods/modwlan.c
+++ b/ports/cc3200/mods/modwlan.c
@@ -886,7 +886,7 @@ STATIC mp_obj_t wlan_scan(mp_obj_t self_in) {
}
mp_obj_t tuple[5];
- tuple[0] = mp_obj_new_str((const char *)wlanEntry.ssid, wlanEntry.ssid_len, false);
+ tuple[0] = mp_obj_new_str((const char *)wlanEntry.ssid, wlanEntry.ssid_len);
tuple[1] = mp_obj_new_bytes((const byte *)wlanEntry.bssid, SL_BSSID_LENGTH);
// 'normalize' the security type
if (wlanEntry.sec_type > 2) {
@@ -1076,7 +1076,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(wlan_mode_obj, 1, 2, wlan_mode);
STATIC mp_obj_t wlan_ssid(size_t n_args, const mp_obj_t *args) {
wlan_obj_t *self = args[0];
if (n_args == 1) {
- return mp_obj_new_str((const char *)self->ssid, strlen((const char *)self->ssid), false);
+ return mp_obj_new_str((const char *)self->ssid, strlen((const char *)self->ssid));
} else {
size_t len;
const char *ssid = mp_obj_str_get_data(args[1], &len);
@@ -1096,7 +1096,7 @@ STATIC mp_obj_t wlan_auth(size_t n_args, const mp_obj_t *args) {
} else {
mp_obj_t security[2];
security[0] = mp_obj_new_int(self->auth);
- security[1] = mp_obj_new_str((const char *)self->key, strlen((const char *)self->key), false);
+ security[1] = mp_obj_new_str((const char *)self->key, strlen((const char *)self->key));
return mp_obj_new_tuple(2, security);
}
} else {
@@ -1200,7 +1200,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_KW(wlan_irq_obj, 1, wlan_irq);
// mp_obj_t connections = mp_obj_new_list(0, NULL);
//
// if (wlan_is_connected()) {
-// device[0] = mp_obj_new_str((const char *)wlan_obj.ssid_o, strlen((const char *)wlan_obj.ssid_o), false);
+// device[0] = mp_obj_new_str((const char *)wlan_obj.ssid_o, strlen((const char *)wlan_obj.ssid_o));
// device[1] = mp_obj_new_bytes((const byte *)wlan_obj.bssid, SL_BSSID_LENGTH);
// // add the device to the list
// mp_obj_list_append(connections, mp_obj_new_tuple(MP_ARRAY_SIZE(device), device));
@@ -1233,7 +1233,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_KW(wlan_irq_obj, 1, wlan_irq);
// if (sl_NetAppGet(SL_NET_APP_DEVICE_CONFIG_ID, NETAPP_SET_GET_DEV_CONF_OPT_DEVICE_URN, &len, (uint8_t *)urn) < 0) {
// mp_raise_OSError(MP_EIO);
// }
-// return mp_obj_new_str(urn, (len - 1), false);
+// return mp_obj_new_str(urn, (len - 1));
// }
//
// return mp_const_none;
diff --git a/ports/cc3200/mpconfigport.h b/ports/cc3200/mpconfigport.h
index 29ae9092b..ee9a226e5 100644
--- a/ports/cc3200/mpconfigport.h
+++ b/ports/cc3200/mpconfigport.h
@@ -131,8 +131,8 @@
X(ETIMEDOUT) \
// TODO these should be generic, not bound to fatfs
-#define mp_type_fileio fatfs_type_fileio
-#define mp_type_textio fatfs_type_textio
+#define mp_type_fileio mp_type_vfs_fat_fileio
+#define mp_type_textio mp_type_vfs_fat_textio
// use vfs's functions for import stat and builtin open
#define mp_import_stat mp_vfs_import_stat
diff --git a/ports/esp32/Makefile b/ports/esp32/Makefile
new file mode 100644
index 000000000..b0baa0dca
--- /dev/null
+++ b/ports/esp32/Makefile
@@ -0,0 +1,786 @@
+include ../../py/mkenv.mk
+
+# qstr definitions (must come before including py.mk)
+QSTR_DEFS = qstrdefsport.h
+
+MICROPY_PY_USSL = 0
+MICROPY_SSL_AXTLS = 0
+MICROPY_FATFS = 1
+MICROPY_PY_BTREE = 1
+
+#FROZEN_DIR = scripts
+FROZEN_MPY_DIR = modules
+
+# include py core make definitions
+include $(TOP)/py/py.mk
+
+PORT ?= /dev/ttyUSB0
+BAUD ?= 460800
+FLASH_MODE ?= dio
+FLASH_FREQ ?= 40m
+FLASH_SIZE ?= 4MB
+CROSS_COMPILE ?= xtensa-esp32-elf-
+
+ESPIDF_SUPHASH := 9a55b42f0841b3d38a61089b1dda4bf28135decd
+
+# paths to ESP IDF and its components
+ifeq ($(ESPIDF),)
+ifneq ($(IDF_PATH),)
+ESPIDF = $(IDF_PATH)
+else
+$(info The ESPIDF variable has not been set, please set it to the root of the esp-idf repository.)
+$(info See README.md for installation instructions.)
+$(info Supported git hash: $(ESPIDF_SUPHASH))
+$(error ESPIDF not set)
+endif
+endif
+ESPCOMP = $(ESPIDF)/components
+ESPTOOL ?= $(ESPCOMP)/esptool_py/esptool/esptool.py
+
+# verify the ESP IDF version
+ESPIDF_CURHASH := $(shell git -C $(ESPIDF) show -s --pretty=format:'%H')
+ifneq ($(ESPIDF_CURHASH),$(ESPIDF_SUPHASH))
+$(info ** WARNING **)
+$(info The git hash of ESP IDF does not match the supported version)
+$(info The build may complete and the firmware may work but it is not guaranteed)
+$(info ESP IDF path: $(ESPIDF))
+$(info Current git hash: $(ESPIDF_CURHASH))
+$(info Supported git hash: $(ESPIDF_SUPHASH))
+endif
+
+# pretty format of ESP IDF version, used internally by the IDF
+IDF_VER := $(shell git -C $(ESPIDF) describe)
+
+INC += -I.
+INC += -I$(TOP)
+INC += -I$(TOP)/lib/mp-readline
+INC += -I$(TOP)/lib/netutils
+INC += -I$(TOP)/lib/timeutils
+INC += -I$(BUILD)
+
+INC_ESPCOMP += -I$(ESPCOMP)/bootloader_support/include
+INC_ESPCOMP += -I$(ESPCOMP)/driver/include
+INC_ESPCOMP += -I$(ESPCOMP)/driver/include/driver
+INC_ESPCOMP += -I$(ESPCOMP)/nghttp/port/include
+INC_ESPCOMP += -I$(ESPCOMP)/nghttp/nghttp2/lib/includes
+INC_ESPCOMP += -I$(ESPCOMP)/esp32/include
+INC_ESPCOMP += -I$(ESPCOMP)/soc/include
+INC_ESPCOMP += -I$(ESPCOMP)/soc/esp32/include
+INC_ESPCOMP += -I$(ESPCOMP)/ethernet/include
+INC_ESPCOMP += -I$(ESPCOMP)/expat/include/expat
+INC_ESPCOMP += -I$(ESPCOMP)/expat/port/include
+INC_ESPCOMP += -I$(ESPCOMP)/heap/include
+INC_ESPCOMP += -I$(ESPCOMP)/json/include
+INC_ESPCOMP += -I$(ESPCOMP)/json/port/include
+INC_ESPCOMP += -I$(ESPCOMP)/log/include
+INC_ESPCOMP += -I$(ESPCOMP)/newlib/include
+INC_ESPCOMP += -I$(ESPCOMP)/nvs_flash/include
+INC_ESPCOMP += -I$(ESPCOMP)/freertos/include
+INC_ESPCOMP += -I$(ESPCOMP)/tcpip_adapter/include
+INC_ESPCOMP += -I$(ESPCOMP)/lwip/include/lwip
+INC_ESPCOMP += -I$(ESPCOMP)/lwip/include/lwip/port
+INC_ESPCOMP += -I$(ESPCOMP)/lwip/include/lwip/posix
+INC_ESPCOMP += -I$(ESPCOMP)/mbedtls/mbedtls/include
+INC_ESPCOMP += -I$(ESPCOMP)/mbedtls/port/include
+INC_ESPCOMP += -I$(ESPCOMP)/spi_flash/include
+INC_ESPCOMP += -I$(ESPCOMP)/ulp/include
+INC_ESPCOMP += -I$(ESPCOMP)/vfs/include
+INC_ESPCOMP += -I$(ESPCOMP)/newlib/platform_include
+INC_ESPCOMP += -I$(ESPCOMP)/xtensa-debug-module/include
+INC_ESPCOMP += -I$(ESPCOMP)/wpa_supplicant/include
+INC_ESPCOMP += -I$(ESPCOMP)/wpa_supplicant/port/include
+INC_ESPCOMP += -I$(ESPCOMP)/ethernet/include
+INC_ESPCOMP += -I$(ESPCOMP)/app_trace/include
+INC_ESPCOMP += -I$(ESPCOMP)/app_update/include
+INC_ESPCOMP += -I$(ESPCOMP)/pthread/include
+INC_ESPCOMP += -I$(ESPCOMP)/smartconfig_ack/include
+
+# these flags are common to C and C++ compilation
+CFLAGS_COMMON = -Os -ffunction-sections -fdata-sections -fstrict-volatile-bitfields \
+ -mlongcalls -nostdlib \
+ -Wall -Werror -Wno-error=unused-function -Wno-error=unused-but-set-variable \
+ -Wno-error=unused-variable -Wno-error=deprecated-declarations \
+ -DESP_PLATFORM
+
+CFLAGS_BASE = -std=gnu99 $(CFLAGS_COMMON) -DMBEDTLS_CONFIG_FILE='"mbedtls/esp_config.h"' -DHAVE_CONFIG_H
+CFLAGS = $(CFLAGS_BASE) $(INC) $(INC_ESPCOMP)
+CFLAGS += -DIDF_VER=\"$(IDF_VER)\"
+CFLAGS += $(CFLAGS_MOD)
+
+# this is what ESPIDF uses for c++ compilation
+CXXFLAGS = -std=gnu++11 $(CFLAGS_COMMON) $(INC) $(INC_ESPCOMP)
+
+LDFLAGS = -nostdlib -Map=$(@:.elf=.map) --cref
+LDFLAGS += --gc-sections -static -EL
+LDFLAGS += -u call_user_start_cpu0 -u uxTopUsedPriority -u ld_include_panic_highint_hdl
+LDFLAGS += -u __cxa_guard_dummy # so that implementation of static guards is taken from cxx_guards.o instead of libstdc++.a
+LDFLAGS += -L$(ESPCOMP)/esp32/ld
+LDFLAGS += -T $(BUILD)/esp32_out.ld
+LDFLAGS += -T ./esp32.custom_common.ld
+LDFLAGS += -T esp32.rom.ld
+LDFLAGS += -T esp32.peripherals.ld
+
+LIBGCC_FILE_NAME = $(shell $(CC) $(CFLAGS) -print-libgcc-file-name)
+LIBSTDCXX_FILE_NAME = $(shell $(CXX) $(CXXFLAGS) -print-file-name=libstdc++.a)
+
+# Debugging/Optimization
+ifeq ($(DEBUG), 1)
+CFLAGS += -g
+COPT = -O0
+else
+#CFLAGS += -fdata-sections -ffunction-sections
+COPT += -Os -DNDEBUG
+#LDFLAGS += --gc-sections
+endif
+
+# Enable SPIRAM support if CONFIG_SPIRAM_SUPPORT=1
+ifeq ($(CONFIG_SPIRAM_SUPPORT),1)
+CFLAGS_COMMON += -mfix-esp32-psram-cache-issue -DCONFIG_SPIRAM_SUPPORT=1
+LIBC_LIBM = $(ESPCOMP)/newlib/lib/libc-psram-workaround.a $(ESPCOMP)/newlib/lib/libm-psram-workaround.a
+else
+LDFLAGS += -T esp32.rom.spiram_incompatible_fns.ld
+LIBC_LIBM = $(ESPCOMP)/newlib/lib/libc.a $(ESPCOMP)/newlib/lib/libm.a
+endif
+
+################################################################################
+# List of MicroPython source and object files
+
+SRC_C = \
+ main.c \
+ uart.c \
+ gccollect.c \
+ mphalport.c \
+ fatfs_port.c \
+ help.c \
+ modutime.c \
+ moduos.c \
+ machine_timer.c \
+ machine_pin.c \
+ machine_touchpad.c \
+ machine_adc.c \
+ machine_dac.c \
+ machine_pwm.c \
+ machine_uart.c \
+ modmachine.c \
+ modnetwork.c \
+ network_lan.c \
+ modsocket.c \
+ modesp.c \
+ esp32_ulp.c \
+ modesp32.c \
+ espneopixel.c \
+ machine_hw_spi.c \
+ machine_wdt.c \
+ mpthreadport.c \
+ machine_rtc.c \
+ $(SRC_MOD)
+
+EXTMOD_SRC_C = $(addprefix extmod/,\
+ modonewire.c \
+ )
+
+LIB_SRC_C = $(addprefix lib/,\
+ libm/math.c \
+ libm/fmodf.c \
+ libm/roundf.c \
+ libm/ef_sqrt.c \
+ libm/kf_rem_pio2.c \
+ libm/kf_sin.c \
+ libm/kf_cos.c \
+ libm/kf_tan.c \
+ libm/ef_rem_pio2.c \
+ libm/sf_sin.c \
+ libm/sf_cos.c \
+ libm/sf_tan.c \
+ libm/sf_frexp.c \
+ libm/sf_modf.c \
+ libm/sf_ldexp.c \
+ libm/asinfacosf.c \
+ libm/atanf.c \
+ libm/atan2f.c \
+ mp-readline/readline.c \
+ netutils/netutils.c \
+ timeutils/timeutils.c \
+ utils/pyexec.c \
+ utils/interrupt_char.c \
+ utils/sys_stdio_mphal.c \
+ )
+
+ifeq ($(MICROPY_FATFS), 1)
+LIB_SRC_C += \
+ lib/oofatfs/ff.c \
+ lib/oofatfs/option/unicode.c
+endif
+
+DRIVERS_SRC_C = $(addprefix drivers/,\
+ bus/softspi.c \
+ dht/dht.c \
+ )
+
+OBJ_MP =
+OBJ_MP += $(PY_O)
+OBJ_MP += $(addprefix $(BUILD)/, $(SRC_C:.c=.o))
+OBJ_MP += $(addprefix $(BUILD)/, $(EXTMOD_SRC_C:.c=.o))
+OBJ_MP += $(addprefix $(BUILD)/, $(LIB_SRC_C:.c=.o))
+OBJ_MP += $(addprefix $(BUILD)/, $(DRIVERS_SRC_C:.c=.o))
+
+# List of sources for qstr extraction
+SRC_QSTR += $(SRC_C) $(EXTMOD_SRC_C) $(LIB_SRC_C) $(DRIVERS_SRC_C)
+# Append any auto-generated sources that are needed by sources listed in SRC_QSTR
+SRC_QSTR_AUTO_DEPS +=
+
+################################################################################
+# List of object files from the ESP32 IDF components
+
+ESPIDF_DRIVER_O = $(addprefix $(ESPCOMP)/driver/,\
+ uart.o \
+ periph_ctrl.o \
+ ledc.o \
+ gpio.o \
+ timer.o \
+ spi_master.o \
+ spi_common.o \
+ rtc_module.o \
+ )
+
+$(BUILD)/$(ESPCOMP)/esp32/dport_access.o: CFLAGS += -Wno-array-bounds
+ESPIDF_ESP32_O = $(addprefix $(ESPCOMP)/esp32/,\
+ brownout.o \
+ panic.o \
+ esp_timer.o \
+ esp_timer_esp32.o \
+ ets_timer_legacy.o \
+ event_default_handlers.o \
+ fast_crypto_ops.o \
+ task_wdt.o \
+ cache_err_int.o \
+ clk.o \
+ core_dump.o \
+ cpu_start.o \
+ gdbstub.o \
+ crosscore_int.o \
+ ipc.o \
+ int_wdt.o \
+ event_loop.o \
+ hwcrypto/sha.o \
+ hwcrypto/aes.o \
+ lib_printf.o \
+ freertos_hooks.o \
+ system_api.o \
+ hw_random.o \
+ phy_init.o \
+ intr_alloc.o \
+ dport_access.o \
+ wifi_init.o \
+ wifi_os_adapter.o \
+ sleep_modes.o \
+ spiram.o \
+ spiram_psram.o \
+ )
+
+ESPIDF_HEAP_O = $(addprefix $(ESPCOMP)/heap/,\
+ heap_caps.o \
+ heap_caps_init.o \
+ multi_heap.o \
+ )
+
+ESPIDF_SOC_O = $(addprefix $(ESPCOMP)/soc/,\
+ esp32/cpu_util.o \
+ esp32/rtc_clk.o \
+ esp32/rtc_init.o \
+ esp32/rtc_pm.o \
+ esp32/rtc_sleep.o \
+ esp32/rtc_time.o \
+ esp32/soc_memory_layout.o \
+ esp32/spi_periph.o \
+ )
+
+ESPIDF_CXX_O = $(addprefix $(ESPCOMP)/cxx/,\
+ cxx_guards.o \
+ )
+
+ESPIDF_ETHERNET_O = $(addprefix $(ESPCOMP)/ethernet/,\
+ emac_dev.o \
+ emac_main.o \
+ eth_phy/phy_tlk110.o \
+ eth_phy/phy_lan8720.o \
+ eth_phy/phy_common.o \
+ )
+
+$(BUILD)/$(ESPCOMP)/expat/%.o: CFLAGS += -Wno-unused-function
+ESPIDF_EXPAT_O = $(addprefix $(ESPCOMP)/expat/,\
+ library/xmltok_ns.o \
+ library/xmltok.o \
+ library/xmlparse.o \
+ library/xmlrole.o \
+ library/xmltok_impl.o \
+ port/minicheck.o \
+ port/expat_element.o \
+ port/chardata.o \
+ )
+
+ESPIDF_PTHREAD_O = $(addprefix $(ESPCOMP)/pthread/,\
+ pthread.o \
+ pthread_local_storage.o \
+ )
+
+# Assembler .S files need only basic flags, and in particular should not have
+# -Os because that generates subtly different code.
+# We also need custom CFLAGS for .c files because FreeRTOS has headers with
+# generic names (eg queue.h) which can clash with other files in the port.
+CFLAGS_ASM = -I$(ESPCOMP)/esp32/include -I$(ESPCOMP)/soc/esp32/include -I$(ESPCOMP)/freertos/include/freertos -I.
+$(BUILD)/$(ESPCOMP)/freertos/portasm.o: CFLAGS = $(CFLAGS_ASM)
+$(BUILD)/$(ESPCOMP)/freertos/xtensa_context.o: CFLAGS = $(CFLAGS_ASM)
+$(BUILD)/$(ESPCOMP)/freertos/xtensa_intr_asm.o: CFLAGS = $(CFLAGS_ASM)
+$(BUILD)/$(ESPCOMP)/freertos/xtensa_vectors.o: CFLAGS = $(CFLAGS_ASM)
+$(BUILD)/$(ESPCOMP)/freertos/%.o: CFLAGS = $(CFLAGS_BASE) -I. $(INC_ESPCOMP) -I$(ESPCOMP)/freertos/include/freertos -D_ESP_FREERTOS_INTERNAL
+ESPIDF_FREERTOS_O = $(addprefix $(ESPCOMP)/freertos/,\
+ croutine.o \
+ event_groups.o \
+ FreeRTOS-openocd.o \
+ list.o \
+ portasm.o \
+ port.o \
+ queue.o \
+ ringbuf.o \
+ tasks.o \
+ timers.o \
+ xtensa_context.o \
+ xtensa_init.o \
+ xtensa_intr_asm.o \
+ xtensa_intr.o \
+ xtensa_overlay_os_hook.o \
+ xtensa_vector_defaults.o \
+ xtensa_vectors.o \
+ )
+
+ESPIDF_VFS_O = $(addprefix $(ESPCOMP)/vfs/,\
+ vfs_uart.o \
+ vfs.o \
+ )
+
+ESPIDF_JSON_O = $(addprefix $(ESPCOMP)/json/cJSON/,\
+ cJSON.o \
+ cJSON_Utils.o \
+ )
+
+ESPIDF_LOG_O = $(addprefix $(ESPCOMP)/log/,\
+ log.o \
+ )
+
+ESPIDF_XTENSA_DEBUG_MODULE_O = $(addprefix $(ESPCOMP)/xtensa-debug-module/,\
+ eri.o \
+ trax.o \
+ )
+
+ESPIDF_TCPIP_ADAPTER_O = $(addprefix $(ESPCOMP)/tcpip_adapter/,\
+ tcpip_adapter_lwip.o \
+ )
+
+ESPIDF_APP_TRACE_O = $(addprefix $(ESPCOMP)/app_trace/,\
+ app_trace.o \
+ )
+
+ESPIDF_APP_UPDATE_O = $(addprefix $(ESPCOMP)/app_update/,\
+ esp_ota_ops.o \
+ )
+
+ESPIDF_NEWLIB_O = $(addprefix $(ESPCOMP)/newlib/,\
+ time.o \
+ select.o \
+ syscalls.o \
+ syscall_table.o \
+ reent_init.o \
+ locks.o \
+ )
+
+ESPIDF_NGHTTP_O = $(addprefix $(ESPCOMP)/nghttp/,\
+ nghttp2/lib/nghttp2_http.o \
+ nghttp2/lib/nghttp2_version.o \
+ nghttp2/lib/nghttp2_mem.o \
+ nghttp2/lib/nghttp2_hd_huffman.o \
+ nghttp2/lib/nghttp2_rcbuf.o \
+ nghttp2/lib/nghttp2_callbacks.o \
+ nghttp2/lib/nghttp2_session.o \
+ nghttp2/lib/nghttp2_stream.o \
+ nghttp2/lib/nghttp2_hd.o \
+ nghttp2/lib/nghttp2_priority_spec.o \
+ nghttp2/lib/nghttp2_buf.o \
+ nghttp2/lib/nghttp2_option.o \
+ nghttp2/lib/nghttp2_npn.o \
+ nghttp2/lib/nghttp2_helper.o \
+ nghttp2/lib/nghttp2_frame.o \
+ nghttp2/lib/nghttp2_outbound_item.o \
+ nghttp2/lib/nghttp2_hd_huffman_data.o \
+ nghttp2/lib/nghttp2_pq.o \
+ nghttp2/lib/nghttp2_queue.o \
+ nghttp2/lib/nghttp2_submit.o \
+ nghttp2/lib/nghttp2_map.o \
+ port/http_parser.o \
+ )
+
+ESPIDF_NVS_FLASH_O = $(addprefix $(ESPCOMP)/nvs_flash/,\
+ src/nvs_types.o \
+ src/nvs_page.o \
+ src/nvs_item_hash_list.o \
+ src/nvs_pagemanager.o \
+ src/nvs_storage.o \
+ src/nvs_api.o \
+ )
+
+ESPIDF_OPENSSL_O = $(addprefix $(ESPCOMP)/openssl/,\
+ )
+
+ESPIDF_SMARTCONFIG_ACK_O = $(addprefix $(ESPCOMP)/smartconfig_ack/,\
+ smartconfig_ack.o \
+ )
+
+ESPIDF_SPI_FLASH_O = $(addprefix $(ESPCOMP)/spi_flash/,\
+ flash_mmap.o \
+ partition.o \
+ spi_flash_rom_patch.o \
+ cache_utils.o \
+ flash_ops.o \
+ )
+
+ESPIDF_ULP_O = $(addprefix $(ESPCOMP)/ulp/,\
+ ulp.o \
+ )
+
+$(BUILD)/$(ESPCOMP)/lwip/%.o: CFLAGS += -Wno-address -Wno-unused-variable -Wno-unused-but-set-variable
+ESPIDF_LWIP_O = $(addprefix $(ESPCOMP)/lwip/,\
+ api/pppapi.o \
+ api/netbuf.o \
+ api/api_lib.o \
+ api/netifapi.o \
+ api/tcpip.o \
+ api/netdb.o \
+ api/err.o \
+ api/api_msg.o \
+ api/sockets.o \
+ apps/sntp/sntp.o \
+ apps/dhcpserver.o \
+ core/ipv4/ip_frag.o \
+ core/ipv4/dhcp.o \
+ core/ipv4/ip4_addr.o \
+ core/ipv4/igmp.o \
+ core/ipv4/ip4.o \
+ core/ipv4/autoip.o \
+ core/ipv4/icmp.o \
+ core/ipv6/ip6_frag.o \
+ core/ipv6/dhcp6.o \
+ core/ipv6/inet6.o \
+ core/ipv6/ip6_addr.o \
+ core/ipv6/ip6.o \
+ core/ipv6/nd6.o \
+ core/ipv6/mld6.o \
+ core/ipv6/ethip6.o \
+ core/ipv6/icmp6.o \
+ core/mem.o \
+ core/init.o \
+ core/memp.o \
+ core/sys.o \
+ core/tcp_in.o \
+ core/dns.o \
+ core/ip.o \
+ core/pbuf.o \
+ core/raw.o \
+ core/tcp.o \
+ core/def.o \
+ core/netif.o \
+ core/stats.o \
+ core/timers.o \
+ core/inet_chksum.o \
+ core/udp.o \
+ core/tcp_out.o \
+ netif/slipif.o \
+ netif/etharp.o \
+ netif/ethernet.o \
+ netif/lowpan6.o \
+ netif/ethernetif.o \
+ port/freertos/sys_arch.o \
+ port/netif/wlanif.o \
+ port/netif/ethernetif.o \
+ port/vfs_lwip.o \
+ )
+
+ESPIDF_MBEDTLS_O = $(addprefix $(ESPCOMP)/mbedtls/,\
+ mbedtls/library/entropy.o \
+ mbedtls/library/pkcs12.o \
+ mbedtls/library/ccm.o \
+ mbedtls/library/pk.o \
+ mbedtls/library/sha1.o \
+ mbedtls/library/x509_csr.o \
+ mbedtls/library/ssl_cli.o \
+ mbedtls/library/ecp.o \
+ mbedtls/library/blowfish.o \
+ mbedtls/library/x509.o \
+ mbedtls/library/ecp_curves.o \
+ mbedtls/library/error.o \
+ mbedtls/library/ssl_ticket.o \
+ mbedtls/library/entropy_poll.o \
+ mbedtls/library/cipher.o \
+ mbedtls/library/version_features.o \
+ mbedtls/library/ripemd160.o \
+ mbedtls/library/rsa.o \
+ mbedtls/library/rsa_internal.o \
+ mbedtls/library/md.o \
+ mbedtls/library/md_wrap.o \
+ mbedtls/library/sha256.o \
+ mbedtls/library/dhm.o \
+ mbedtls/library/ssl_cache.o \
+ mbedtls/library/pkwrite.o \
+ mbedtls/library/base64.o \
+ mbedtls/library/asn1parse.o \
+ mbedtls/library/ssl_tls.o \
+ mbedtls/library/hmac_drbg.o \
+ mbedtls/library/pem.o \
+ mbedtls/library/version.o \
+ mbedtls/library/gcm.o \
+ mbedtls/library/memory_buffer_alloc.o \
+ mbedtls/library/md2.o \
+ mbedtls/library/ecdsa.o \
+ mbedtls/library/ssl_srv.o \
+ mbedtls/library/x509_crt.o \
+ mbedtls/library/ecdh.o \
+ mbedtls/library/asn1write.o \
+ mbedtls/library/md4.o \
+ mbedtls/library/debug.o \
+ mbedtls/library/x509_create.o \
+ mbedtls/library/ecjpake.o \
+ mbedtls/library/oid.o \
+ mbedtls/library/md5.o \
+ mbedtls/library/ssl_ciphersuites.o \
+ mbedtls/library/sha512.o \
+ mbedtls/library/xtea.o \
+ mbedtls/library/aes.o \
+ mbedtls/library/cipher_wrap.o \
+ mbedtls/library/arc4.o \
+ mbedtls/library/bignum.o \
+ mbedtls/library/pkparse.o \
+ mbedtls/library/padlock.o \
+ mbedtls/library/threading.o \
+ mbedtls/library/x509_crl.o \
+ mbedtls/library/pkcs11.o \
+ mbedtls/library/aesni.o \
+ mbedtls/library/timing.o \
+ mbedtls/library/certs.o \
+ mbedtls/library/pkcs5.o \
+ mbedtls/library/ssl_cookie.o \
+ mbedtls/library/camellia.o \
+ mbedtls/library/havege.o \
+ mbedtls/library/des.o \
+ mbedtls/library/x509write_csr.o \
+ mbedtls/library/platform.o \
+ mbedtls/library/ctr_drbg.o \
+ mbedtls/library/x509write_crt.o \
+ mbedtls/library/pk_wrap.o \
+ port/esp_bignum.o \
+ port/esp_hardware.o \
+ port/esp_sha1.o \
+ port/esp_sha256.o \
+ port/esp_sha512.o \
+ )
+
+$(BUILD)/$(ESPCOMP)/wpa_supplicant/%.o: CFLAGS += -DEMBEDDED_SUPP -DIEEE8021X_EAPOL -DEAP_PEER_METHOD -DEAP_MSCHAPv2 -DEAP_TTLS -DEAP_TLS -DEAP_PEAP -DUSE_WPA2_TASK -DCONFIG_WPS2 -DCONFIG_WPS_PIN -DUSE_WPS_TASK -DESPRESSIF_USE -DESP32_WORKAROUND -D__ets__ -Wno-strict-aliasing
+ESPIDF_WPA_SUPPLICANT_O = $(addprefix $(ESPCOMP)/wpa_supplicant/,\
+ src/crypto/aes-internal-enc.o \
+ src/crypto/sha256-internal.o \
+ src/crypto/md5-internal.o \
+ src/crypto/aes-internal.o \
+ src/crypto/sha1.o \
+ src/crypto/aes-internal-dec.o \
+ src/crypto/aes-unwrap.o \
+ src/crypto/crypto_internal-rsa.o \
+ src/crypto/dh_groups.o \
+ src/crypto/crypto_internal.o \
+ src/crypto/aes-wrap.o \
+ src/crypto/sha1-internal.o \
+ src/crypto/dh_group5.o \
+ src/crypto/sha256.o \
+ src/crypto/rc4.o \
+ src/crypto/md5.o \
+ src/crypto/aes-cbc.o \
+ src/crypto/sha1-pbkdf2.o \
+ src/crypto/bignum.o \
+ src/crypto/crypto_internal-modexp.o \
+ src/crypto/crypto_internal-cipher.o \
+ src/fast_crypto/fast_aes-unwrap.o \
+ src/fast_crypto/fast_aes-wrap.o \
+ src/fast_crypto/fast_sha256.o \
+ src/fast_crypto/fast_sha256-internal.o \
+ port/os_xtensa.o \
+ )
+
+OBJ_ESPIDF =
+OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_NEWLIB_O))
+OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_DRIVER_O))
+OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_ESP32_O))
+OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_HEAP_O))
+OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_SOC_O))
+OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_CXX_O))
+OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_ETHERNET_O))
+OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_EXPAT_O))
+OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_PTHREAD_O))
+OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_FREERTOS_O))
+OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_VFS_O))
+OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_JSON_O))
+OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_LOG_O))
+OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_LWIP_O))
+OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_MBEDTLS_O))
+OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_XTENSA_DEBUG_MODULE_O))
+OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_TCPIP_ADAPTER_O))
+OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_APP_TRACE_O))
+OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_APP_UPDATE_O))
+OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_NGHTTP_O))
+OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_NVS_FLASH_O))
+OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_OPENSSL_O))
+OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_SMARTCONFIG_ACK_O))
+OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_SPI_FLASH_O))
+OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_ULP_O))
+OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_WPA_SUPPLICANT_O))
+################################################################################
+# Main targets
+
+all: $(BUILD)/firmware.bin
+
+.PHONY: idf-version deploy erase
+
+idf-version:
+ $(ECHO) "ESP IDF supported hash: $(ESPIDF_SUPHASH)"
+
+$(BUILD)/firmware.bin: $(BUILD)/bootloader.bin $(BUILD)/partitions.bin $(BUILD)/application.bin
+ $(ECHO) "Create $@"
+ $(Q)$(PYTHON) makeimg.py $^ $@
+
+deploy: $(BUILD)/firmware.bin
+ $(ECHO) "Writing $^ to the board"
+ $(Q)$(ESPTOOL) --chip esp32 --port $(PORT) --baud $(BAUD) write_flash -z --flash_mode $(FLASH_MODE) --flash_freq $(FLASH_FREQ) 0x1000 $^
+
+erase:
+ $(ECHO) "Erasing flash"
+ $(Q)$(ESPTOOL) --chip esp32 --port $(PORT) --baud $(BAUD) erase_flash
+
+################################################################################
+# Declarations to build the application
+
+OBJ = $(OBJ_MP) $(OBJ_ESPIDF)
+
+APP_LD_ARGS =
+APP_LD_ARGS += $(LDFLAGS_MOD)
+APP_LD_ARGS += --start-group
+APP_LD_ARGS += -L$(dir $(LIBGCC_FILE_NAME)) -lgcc
+APP_LD_ARGS += -L$(dir $(LIBSTDCXX_FILE_NAME)) -lstdc++
+APP_LD_ARGS += $(LIBC_LIBM)
+APP_LD_ARGS += $(ESPCOMP)/esp32/libhal.a
+APP_LD_ARGS += -L$(ESPCOMP)/esp32/lib -lcore -lmesh -lnet80211 -lphy -lrtc -lpp -lwpa -lsmartconfig -lcoexist -lwps -lwpa2
+APP_LD_ARGS += $(OBJ)
+APP_LD_ARGS += --end-group
+
+$(BUILD)/esp32_out.ld: sdkconfig.h
+ $(Q)$(CC) -I. -C -P -x c -E $(ESPCOMP)/esp32/ld/esp32.ld -o $@
+
+$(BUILD)/application.bin: $(BUILD)/application.elf
+ $(ECHO) "Create $@"
+ $(Q)$(ESPTOOL) --chip esp32 elf2image --flash_mode $(FLASH_MODE) --flash_freq $(FLASH_FREQ) --flash_size $(FLASH_SIZE) $<
+
+$(BUILD)/application.elf: $(OBJ) $(BUILD)/esp32_out.ld
+ $(ECHO) "LINK $@"
+ $(Q)$(LD) $(LDFLAGS) -o $@ $(APP_LD_ARGS)
+ $(Q)$(SIZE) $@
+
+define compile_cxx
+$(ECHO) "CXX $<"
+$(Q)$(CXX) $(CXXFLAGS) -c -MD -o $@ $<
+@# The following fixes the dependency file.
+@# See http://make.paulandlesley.org/autodep.html for details.
+@# Regex adjusted from the above to play better with Windows paths, etc.
+@$(CP) $(@:.o=.d) $(@:.o=.P); \
+ $(SED) -e 's/#.*//' -e 's/^.*: *//' -e 's/ *\\$$//' \
+ -e '/^$$/ d' -e 's/$$/ :/' < $(@:.o=.d) >> $(@:.o=.P); \
+ $(RM) -f $(@:.o=.d)
+endef
+
+vpath %.cpp . $(TOP)
+$(BUILD)/%.o: %.cpp
+ $(call compile_cxx)
+
+################################################################################
+# Declarations to build the bootloader
+
+$(BUILD)/bootloader/$(ESPCOMP)/%.o: CFLAGS += -DBOOTLOADER_BUILD=1 -I$(ESPCOMP)/bootloader_support/include_priv -I$(ESPCOMP)/bootloader_support/include -I$(ESPCOMP)/micro-ecc/micro-ecc -I$(ESPCOMP)/esp32 -Wno-error=format
+BOOTLOADER_OBJ = $(addprefix $(BUILD)/bootloader/$(ESPCOMP)/,\
+ bootloader_support/src/bootloader_clock.o \
+ bootloader_support/src/bootloader_common.o \
+ bootloader_support/src/bootloader_flash.o \
+ bootloader_support/src/bootloader_init.o \
+ bootloader_support/src/bootloader_random.o \
+ bootloader_support/src/bootloader_sha.o \
+ bootloader_support/src/bootloader_utility.o \
+ bootloader_support/src/efuse.o \
+ bootloader_support/src/flash_qio_mode.o \
+ bootloader_support/src/secure_boot_signatures.o \
+ bootloader_support/src/secure_boot.o \
+ bootloader_support/src/esp_image_format.o \
+ bootloader_support/src/flash_encrypt.o \
+ bootloader_support/src/flash_partitions.o \
+ log/log.o \
+ spi_flash/spi_flash_rom_patch.o \
+ soc/esp32/rtc_clk.o \
+ soc/esp32/rtc_time.o \
+ soc/esp32/cpu_util.o \
+ micro-ecc/micro-ecc/uECC.o \
+ bootloader/subproject/main/bootloader_start.o \
+ )
+
+BOOTLOADER_LIBS =
+BOOTLOADER_LIBS += -Wl,--start-group
+BOOTLOADER_LIBS += $(BOOTLOADER_OBJ)
+BOOTLOADER_LIBS += -L$(ESPCOMP)/esp32/lib -lrtc
+BOOTLOADER_LIBS += -L$(dir $(LIBGCC_FILE_NAME)) -lgcc
+BOOTLOADER_LIBS += -Wl,--end-group
+
+BOOTLOADER_LDFLAGS =
+BOOTLOADER_LDFLAGS += -nostdlib
+BOOTLOADER_LDFLAGS += -L$(ESPIDF)/lib
+BOOTLOADER_LDFLAGS += -L$(ESPIDF)/ld
+BOOTLOADER_LDFLAGS += -u call_user_start_cpu0
+BOOTLOADER_LDFLAGS += -Wl,--gc-sections
+BOOTLOADER_LDFLAGS += -static
+BOOTLOADER_LDFLAGS += -Wl,-EL
+BOOTLOADER_LDFLAGS += -Wl,-Map=$(@:.elf=.map) -Wl,--cref
+BOOTLOADER_LDFLAGS += -T $(ESPCOMP)/bootloader/subproject/main/esp32.bootloader.ld
+BOOTLOADER_LDFLAGS += -T $(ESPCOMP)/bootloader/subproject/main/esp32.bootloader.rom.ld
+BOOTLOADER_LDFLAGS += -T $(ESPCOMP)/esp32/ld/esp32.rom.ld
+BOOTLOADER_LDFLAGS += -T $(ESPCOMP)/esp32/ld/esp32.rom.spiram_incompatible_fns.ld
+BOOTLOADER_LDFLAGS += -T $(ESPCOMP)/esp32/ld/esp32.peripherals.ld
+
+BOOTLOADER_OBJ_DIRS = $(sort $(dir $(BOOTLOADER_OBJ)))
+$(BOOTLOADER_OBJ): | $(BOOTLOADER_OBJ_DIRS)
+$(BOOTLOADER_OBJ_DIRS):
+ $(MKDIR) -p $@
+
+$(BUILD)/bootloader/%.o: %.c
+ $(call compile_c)
+
+$(BUILD)/bootloader.bin: $(BUILD)/bootloader.elf
+ $(ECHO) "Create $@"
+ $(Q)$(ESPTOOL) --chip esp32 elf2image --flash_mode $(FLASH_MODE) --flash_freq $(FLASH_FREQ) --flash_size $(FLASH_SIZE) $<
+
+$(BUILD)/bootloader.elf: $(BOOTLOADER_OBJ)
+ $(ECHO) "LINK $@"
+ $(Q)$(CC) $(BOOTLOADER_LDFLAGS) -o $@ $(BOOTLOADER_LIBS)
+
+################################################################################
+# Declarations to build the partitions
+
+PYTHON2 ?= python2
+PART_SRC = partitions.csv
+
+$(BUILD)/partitions.bin: $(PART_SRC)
+ $(ECHO) "Create $@"
+ $(Q)$(PYTHON2) $(ESPCOMP)/partition_table/gen_esp32part.py -q $< $@
+
+################################################################################
+
+include $(TOP)/py/mkrules.mk
diff --git a/ports/esp32/README.md b/ports/esp32/README.md
new file mode 100644
index 000000000..85df001e3
--- /dev/null
+++ b/ports/esp32/README.md
@@ -0,0 +1,202 @@
+MicroPython port to the ESP32
+=============================
+
+This is an experimental port of MicroPython to the Espressif ESP32
+microcontroller. It uses the ESP-IDF framework and MicroPython runs as
+a task under FreeRTOS.
+
+Supported features include:
+- REPL (Python prompt) over UART0.
+- 16k stack for the MicroPython task and 96k Python heap.
+- Many of MicroPython's features are enabled: unicode, arbitrary-precision
+ integers, single-precision floats, complex numbers, frozen bytecode, as
+ well as many of the internal modules.
+- Internal filesystem using the flash (currently 2M in size).
+- The machine module with GPIO, UART, SPI, software I2C, ADC, DAC, PWM,
+ TouchPad, WDT and Timer.
+- The network module with WLAN (WiFi) support.
+
+Development of this ESP32 port was sponsored in part by Microbric Pty Ltd.
+
+Setting up the toolchain and ESP-IDF
+------------------------------------
+
+There are two main components that are needed to build the firmware:
+- the Xtensa cross-compiler that targets the CPU in the ESP32 (this is
+ different to the compiler used by the ESP8266)
+- the Espressif IDF (IoT development framework, aka SDK)
+
+The ESP-IDF changes quickly and MicroPython only supports a certain version. The
+git hash of this version can be found by running `make` without a configured
+`ESPIDF`. Then you can fetch only the given esp-idf using the following command:
+
+ $ git clone https://github.com/espressif/esp-idf.git
+ $ git checkout <Current supported ESP-IDF commit hash>
+ $ git submodule update --init --recursive
+
+The binary toolchain (binutils, gcc, etc.) can be installed using the following
+guides:
+
+ * [Linux installation](https://esp-idf.readthedocs.io/en/latest/get-started/linux-setup.html)
+ * [MacOS installation](https://esp-idf.readthedocs.io/en/latest/get-started/macos-setup.html)
+ * [Windows installation](https://esp-idf.readthedocs.io/en/latest/get-started/windows-setup.html)
+
+If you are on a Windows machine then the
+[Windows Subsystem for Linux](https://msdn.microsoft.com/en-au/commandline/wsl/install_guide)
+is the most efficient way to install the ESP32 toolchain and build the project.
+If you use WSL then follow the
+[Linux guidelines](https://esp-idf.readthedocs.io/en/latest/get-started/linux-setup.html)
+for the ESP-IDF instead of the Windows ones.
+
+The Espressif ESP-IDF instructions above only install pyserial for Python 2,
+so if you're running Python 3 or a non-system Python you'll also need to
+install `pyserial` (or `esptool`) so that the Makefile can flash the board
+and set parameters:
+```bash
+$ pip install pyserial
+```
+
+Once everything is set up you should have a functioning toolchain with
+prefix xtensa-esp32-elf- (or otherwise if you configured it differently)
+as well as a copy of the ESP-IDF repository. You will need to update your `PATH`
+environment variable to include the ESP32 toolchain. For example, you can issue
+the following commands on (at least) Linux:
+
+ $ export PATH=$PATH:$HOME/esp/crosstool-NG/builds/xtensa-esp32-elf/bin
+
+You can put this command in your `.profile` or `.bash_login`.
+
+You then need to set the `ESPIDF` environment/makefile variable to point to
+the root of the ESP-IDF repository. You can set the variable in your PATH,
+or at the command line when calling make, or in your own custom `makefile`.
+The last option is recommended as it allows you to easily configure other
+variables for the build. In that case, create a new file in the esp32
+directory called `makefile` and add the following lines to that file:
+```
+ESPIDF = <path to root of esp-idf repository>
+#PORT = /dev/ttyUSB0
+#FLASH_MODE = qio
+#FLASH_SIZE = 4MB
+#CROSS_COMPILE = xtensa-esp32-elf-
+#CONFIG_SPIRAM_SUPPORT = 1
+
+include Makefile
+```
+Be sure to enter the correct path to your local copy of the IDF repository
+(and use `$(HOME)`, not tilde, to reference your home directory).
+If your filesystem is case-insensitive then you'll need to use `GNUmakefile`
+instead of `makefile`.
+If the Xtensa cross-compiler is not in your path you can use the
+`CROSS_COMPILE` variable to set its location. Other options of interest
+are `PORT` for the serial port of your esp32 module, and `FLASH_MODE`
+(which may need to be `dio` for some modules)
+and `FLASH_SIZE`. See the Makefile for further information.
+
+Building the firmware
+---------------------
+
+The MicroPython cross-compiler must be built to pre-compile some of the
+built-in scripts to bytecode. This can be done by (from the root of
+this repository):
+```bash
+$ make -C mpy-cross
+```
+
+The ESP32 port has a dependency on Berkeley DB, which is an external
+dependency (git submodule). You'll need to have git initialize that
+module using the commands:
+```bash
+$ git submodule init lib/berkeley-db-1.xx
+$ git submodule update
+```
+
+Then to build MicroPython for the ESP32 run:
+```bash
+$ cd ports/esp32
+$ make
+```
+This will produce binary firmware images in the `build/` subdirectory
+(three of them: bootloader.bin, partitions.bin and application.bin).
+
+To flash the firmware you must have your ESP32 module in the bootloader
+mode and connected to a serial port on your PC. Refer to the documentation
+for your particular ESP32 module for how to do this. The serial port and
+flash settings are set in the `Makefile`, and can be overridden in your
+local `makefile`; see above for more details.
+
+You will also need to have user permissions to access the /dev/ttyUSB0 device.
+On Linux, you can enable this by adding your user to the `dialout` group,
+and rebooting or logging out and in again.
+```bash
+$ sudo adduser <username> dialout
+```
+
+If you are installing MicroPython to your module for the first time, or
+after installing any other firmware, you should first erase the flash
+completely:
+```bash
+$ make erase
+```
+
+To flash the MicroPython firmware to your ESP32 use:
+```bash
+$ make deploy
+```
+This will use the `esptool.py` script (provided by ESP-IDF) to download the
+binary images.
+
+Getting a Python prompt
+-----------------------
+
+You can get a prompt via the serial port, via UART0, which is the same UART
+that is used for programming the firmware. The baudrate for the REPL is
+115200 and you can use a command such as:
+```bash
+$ picocom -b 115200 /dev/ttyUSB0
+```
+
+Configuring the WiFi and using the board
+----------------------------------------
+
+The ESP32 port is designed to be (almost) equivalent to the ESP8266 in
+terms of the modules and user-facing API. There are some small differences,
+notably that the ESP32 does not automatically connect to the last access
+point when booting up. But for the most part the documentation and tutorials
+for the ESP8266 should apply to the ESP32 (at least for the components that
+are implemented).
+
+See http://docs.micropython.org/en/latest/esp8266/esp8266/quickref.html for
+a quick reference, and http://docs.micropython.org/en/latest/esp8266/esp8266/tutorial/intro.html
+for a tutorial.
+
+The following function can be used to connect to a WiFi access point (you can
+either pass in your own SSID and password, or change the defaults so you can
+quickly call `wlan_connect()` and it just works):
+```python
+def wlan_connect(ssid='MYSSID', password='MYPASS'):
+ import network
+ wlan = network.WLAN(network.STA_IF)
+ if not wlan.active() or not wlan.isconnected():
+ wlan.active(True)
+ print('connecting to:', ssid)
+ wlan.connect(ssid, password)
+ while not wlan.isconnected():
+ pass
+ print('network config:', wlan.ifconfig())
+```
+
+Note that some boards require you to configure the WiFi antenna before using
+the WiFi. On Pycom boards like the LoPy and WiPy 2.0 you need to execute the
+following code to select the internal antenna (best to put this line in your
+boot.py file):
+```python
+import machine
+antenna = machine.Pin(16, machine.Pin.OUT, value=0)
+```
+
+Troubleshooting
+---------------
+
+* Continuous reboots after programming: Ensure FLASH_MODE is correct for your
+ board (e.g. ESP-WROOM-32 should be DIO). Then perform a `make clean`, rebuild,
+ redeploy.
diff --git a/ports/esp32/README.ulp.md b/ports/esp32/README.ulp.md
new file mode 100644
index 000000000..cbc5771a9
--- /dev/null
+++ b/ports/esp32/README.ulp.md
@@ -0,0 +1,126 @@
+# ULP
+
+To compile binarys for the ulp you need the ulp toolkit. Download it from https://github.com/espressif/binutils-esp32ulp/wiki#downloads
+Then extract it, then add ```esp32ulp-elf-binutils/bin``` to your PATH
+
+## Example Makefile
+
+```make
+ULP_S_SOURCES := main.S
+ULP_APP_NAME := test
+ULP_LD_SCRIPT := esp32.ulp.ld
+
+SRC_PATH := src
+BUILD_PATH := build
+
+include $(ESPIDF)/components/ulp/Makefile.projbuild
+
+ULP_ELF := $(ULP_APP_NAME).elf
+ULP_MAP := $(ULP_ELF:.elf=.map)
+ULP_SYM := $(ULP_ELF:.elf=.sym)
+ULP_BIN := $(ULP_ELF:.elf=.bin)
+ULP_EXPORTS_LD := $(ULP_ELF:.elf=.ld)
+ULP_EXPORTS_HEADER := $(ULP_ELF:.elf=.h)
+
+ULP_OBJECTS := $(notdir $(ULP_S_SOURCES:.S=.ulp.o))
+ULP_DEP := $(notdir $(ULP_S_SOURCES:.S=.ulp.d)) $(ULP_LD_SCRIPT:.ld=.d)
+ULP_PREPROCESSED := $(notdir $(ULP_S_SOURCES:.S=.ulp.pS))
+ULP_LISTINGS := $(notdir $(ULP_S_SOURCES:.S=.ulp.lst))
+
+.PHONY: all clean
+
+all: $(BUILD_PATH) $(BUILD_PATH)/$(ULP_BIN)
+
+clean:
+ rm -rf $(BUILD_PATH)
+
+$(BUILD_PATH):
+ mkdir $@
+
+# Generate preprocessed linker file.
+$(BUILD_PATH)/$(ULP_APP_NAME).ld: $(SRC_PATH)/$(ULP_LD_SCRIPT)
+ cpp -P $< -o $@
+
+# Generate preprocessed assembly files.
+# To inspect these preprocessed files, add a ".PRECIOUS: %.ulp.pS" rule.
+$(BUILD_PATH)/%.ulp.pS: $(SRC_PATH)/%.S
+ cpp $< -o $@
+
+# Compiled preprocessed files into object files.
+$(BUILD_PATH)/%.ulp.o: $(BUILD_PATH)/%.ulp.pS
+ $(ULP_AS) -al=$(patsubst %.ulp.o,%.ulp.lst,$@) -o $@ $<
+
+# Link object files and generate map file
+$(BUILD_PATH)/$(ULP_ELF): $(BUILD_PATH)/$(ULP_OBJECTS) $(BUILD_PATH)/$(ULP_APP_NAME).ld
+ $(ULP_LD) -o $@ -A elf32-esp32ulp -Map=$(BUILD_PATH)/$(ULP_MAP) -T $(BUILD_PATH)/$(ULP_APP_NAME).ld $<
+
+# Dump the list of global symbols in a convenient format.
+$(ULP_SYM): $(ULP_ELF)
+ $(ULP_NM) -g -f posix $< > $@
+
+# Dump the binary for inclusion into the project
+$(BUILD_PATH)/$(ULP_BIN): $(BUILD_PATH)/$(ULP_ELF)
+ $(ULP_OBJCOPY) -O binary $< $@
+```
+
+## Example linker script for the ulp
+```
+#define ULP_BIN_MAGIC 0x00706c75
+#define HEADER_SIZE 12
+#define CONFIG_ULP_COPROC_RESERVE_MEM 4096
+
+MEMORY
+{
+ ram(RW) : ORIGIN = 0, LENGTH = CONFIG_ULP_COPROC_RESERVE_MEM
+}
+
+SECTIONS
+{
+ .text : AT(HEADER_SIZE)
+ {
+ *(.text)
+ } >ram
+ .data :
+ {
+ . = ALIGN(4);
+ *(.data)
+ } >ram
+ .bss :
+ {
+ . = ALIGN(4);
+ *(.bss)
+ } >ram
+
+ .header : AT(0)
+ {
+ LONG(ULP_BIN_MAGIC)
+ SHORT(LOADADDR(.text))
+ SHORT(SIZEOF(.text))
+ SHORT(SIZEOF(.data))
+ SHORT(SIZEOF(.bss))
+ }
+}
+```
+
+## Example ulp code
+```asm
+move R3, 99
+move R0, 10
+
+# mem[R0+0] = R3
+st R3, R0, 0
+
+HALT
+```
+
+## Example python code using the ulp
+```python
+import esp32
+import time
+
+u = esp32.ULP()
+with open('test.bin', 'rb') as f:
+ b = f.read()
+u.load_binary(0,b)
+u.run(0)
+```
diff --git a/ports/esp32/esp32.custom_common.ld b/ports/esp32/esp32.custom_common.ld
new file mode 100644
index 000000000..716e9ac1d
--- /dev/null
+++ b/ports/esp32/esp32.custom_common.ld
@@ -0,0 +1,254 @@
+/* Default entry point: */
+ENTRY(call_start_cpu0);
+
+SECTIONS
+{
+ /* RTC fast memory holds RTC wake stub code,
+ including from any source file named rtc_wake_stub*.c
+ */
+ .rtc.text :
+ {
+ . = ALIGN(4);
+ *(.rtc.literal .rtc.text)
+ *rtc_wake_stub*.o(.literal .text .literal.* .text.*)
+ } > rtc_iram_seg
+
+ /* RTC slow memory holds RTC wake stub
+ data/rodata, including from any source file
+ named rtc_wake_stub*.c
+ */
+ .rtc.data :
+ {
+ _rtc_data_start = ABSOLUTE(.);
+ *(.rtc.data)
+ *(.rtc.rodata)
+ *rtc_wake_stub*.o(.data .rodata .data.* .rodata.* .bss .bss.*)
+ _rtc_data_end = ABSOLUTE(.);
+ } > rtc_slow_seg
+
+ /* RTC bss, from any source file named rtc_wake_stub*.c */
+ .rtc.bss (NOLOAD) :
+ {
+ _rtc_bss_start = ABSOLUTE(.);
+ *rtc_wake_stub*.o(.bss .bss.*)
+ *rtc_wake_stub*.o(COMMON)
+ _rtc_bss_end = ABSOLUTE(.);
+ } > rtc_slow_seg
+
+ /* This section holds data that should not be initialized at power up
+ and will be retained during deep sleep. The section located in
+ RTC SLOW Memory area. User data marked with RTC_NOINIT_ATTR will be placed
+ into this section. See the file "esp_attr.h" for more information.
+ */
+ .rtc_noinit (NOLOAD):
+ {
+ . = ALIGN(4);
+ _rtc_noinit_start = ABSOLUTE(.);
+ *(.rtc_noinit .rtc_noinit.*)
+ . = ALIGN(4) ;
+ _rtc_noinit_end = ABSOLUTE(.);
+ } > rtc_slow_seg
+
+ /* Send .iram0 code to iram */
+ .iram0.vectors :
+ {
+ /* Vectors go to IRAM */
+ _init_start = ABSOLUTE(.);
+ /* Vectors according to builds/RF-2015.2-win32/esp108_v1_2_s5_512int_2/config.html */
+ . = 0x0;
+ KEEP(*(.WindowVectors.text));
+ . = 0x180;
+ KEEP(*(.Level2InterruptVector.text));
+ . = 0x1c0;
+ KEEP(*(.Level3InterruptVector.text));
+ . = 0x200;
+ KEEP(*(.Level4InterruptVector.text));
+ . = 0x240;
+ KEEP(*(.Level5InterruptVector.text));
+ . = 0x280;
+ KEEP(*(.DebugExceptionVector.text));
+ . = 0x2c0;
+ KEEP(*(.NMIExceptionVector.text));
+ . = 0x300;
+ KEEP(*(.KernelExceptionVector.text));
+ . = 0x340;
+ KEEP(*(.UserExceptionVector.text));
+ . = 0x3C0;
+ KEEP(*(.DoubleExceptionVector.text));
+ . = 0x400;
+ *(.*Vector.literal)
+
+ *(.UserEnter.literal);
+ *(.UserEnter.text);
+ . = ALIGN (16);
+ *(.entry.text)
+ *(.init.literal)
+ *(.init)
+ _init_end = ABSOLUTE(.);
+
+ /* This goes here, not at top of linker script, so addr2line finds it last,
+ and uses it in preference to the first symbol in IRAM */
+ _iram_start = ABSOLUTE(0);
+ } > iram0_0_seg
+
+ .iram0.text :
+ {
+ /* Code marked as runnning out of IRAM */
+ _iram_text_start = ABSOLUTE(.);
+ *(.iram1 .iram1.*)
+ *freertos/*(.literal .text .literal.* .text.*)
+ *heap/multi_heap.o(.literal .text .literal.* .text.*)
+ *heap/multi_heap_poisoning.o(.literal .text .literal.* .text.*)
+ *esp32/panic.o(.literal .text .literal.* .text.*)
+ *esp32/core_dump.o(.literal .text .literal.* .text.*)
+ *app_trace/*(.literal .text .literal.* .text.*)
+ *xtensa-debug-module/eri.o(.literal .text .literal.* .text.*)
+ *librtc.a:(.literal .text .literal.* .text.*)
+ *soc/esp32/*(.literal .text .literal.* .text.*)
+ *libhal.a:(.literal .text .literal.* .text.*)
+ *libgcc.a:lib2funcs.o(.literal .text .literal.* .text.*)
+ *spi_flash/spi_flash_rom_patch.o(.literal .text .literal.* .text.*)
+ *libgcov.a:(.literal .text .literal.* .text.*)
+ INCLUDE esp32.spiram.rom-functions-iram.ld
+ *py/scheduler.o*(.literal .text .literal.* .text.*)
+ _iram_text_end = ABSOLUTE(.);
+ } > iram0_0_seg
+
+ .dram0.data :
+ {
+ _data_start = ABSOLUTE(.);
+ *(.data)
+ *(.data.*)
+ *(.gnu.linkonce.d.*)
+ *(.data1)
+ *(.sdata)
+ *(.sdata.*)
+ *(.gnu.linkonce.s.*)
+ *(.sdata2)
+ *(.sdata2.*)
+ *(.gnu.linkonce.s2.*)
+ *(.jcr)
+ *(.dram1 .dram1.*)
+ *esp32/panic.o(.rodata .rodata.*)
+ *libphy.a:(.rodata .rodata.*)
+ *soc/esp32/rtc_clk.o(.rodata .rodata.*)
+ *app_trace/app_trace.o(.rodata .rodata.*)
+ *libgcov.a:(.rodata .rodata.*)
+ *heap/multi_heap.o(.rodata .rodata.*)
+ *heap/multi_heap_poisoning.o(.rodata .rodata.*)
+ INCLUDE esp32.spiram.rom-functions-dram.ld
+ _data_end = ABSOLUTE(.);
+ . = ALIGN(4);
+ } > dram0_0_seg
+
+ /*This section holds data that should not be initialized at power up.
+ The section located in Internal SRAM memory region. The macro _NOINIT
+ can be used as attribute to place data into this section.
+ See the esp_attr.h file for more information.
+ */
+ .noinit (NOLOAD):
+ {
+ . = ALIGN(4);
+ _noinit_start = ABSOLUTE(.);
+ *(.noinit .noinit.*)
+ . = ALIGN(4) ;
+ _noinit_end = ABSOLUTE(.);
+ } > dram0_0_seg
+
+ /* Shared RAM */
+ .dram0.bss (NOLOAD) :
+ {
+ . = ALIGN (8);
+ _bss_start = ABSOLUTE(.);
+ *(.dynsbss)
+ *(.sbss)
+ *(.sbss.*)
+ *(.gnu.linkonce.sb.*)
+ *(.scommon)
+ *(.sbss2)
+ *(.sbss2.*)
+ *(.gnu.linkonce.sb2.*)
+ *(.dynbss)
+ *(.bss)
+ *(.bss.*)
+ *(.share.mem)
+ *(.gnu.linkonce.b.*)
+ *(COMMON)
+ . = ALIGN (8);
+ _bss_end = ABSOLUTE(.);
+ /* The heap starts right after end of this section */
+ _heap_start = ABSOLUTE(.);
+ } > dram0_0_seg
+
+ .flash.rodata :
+ {
+ _rodata_start = ABSOLUTE(.);
+ *(.rodata)
+ *(.rodata.*)
+ *(.irom1.text) /* catch stray ICACHE_RODATA_ATTR */
+ *(.gnu.linkonce.r.*)
+ *(.rodata1)
+ __XT_EXCEPTION_TABLE_ = ABSOLUTE(.);
+ *(.xt_except_table)
+ *(.gcc_except_table .gcc_except_table.*)
+ *(.gnu.linkonce.e.*)
+ *(.gnu.version_r)
+ . = (. + 3) & ~ 3;
+ __eh_frame = ABSOLUTE(.);
+ KEEP(*(.eh_frame))
+ . = (. + 7) & ~ 3;
+ /* C++ constructor and destructor tables, properly ordered: */
+ __init_array_start = ABSOLUTE(.);
+ KEEP (*crtbegin.o(.ctors))
+ KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors))
+ KEEP (*(SORT(.ctors.*)))
+ KEEP (*(.ctors))
+ __init_array_end = ABSOLUTE(.);
+ KEEP (*crtbegin.o(.dtors))
+ KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors))
+ KEEP (*(SORT(.dtors.*)))
+ KEEP (*(.dtors))
+ /* C++ exception handlers table: */
+ __XT_EXCEPTION_DESCS_ = ABSOLUTE(.);
+ *(.xt_except_desc)
+ *(.gnu.linkonce.h.*)
+ __XT_EXCEPTION_DESCS_END__ = ABSOLUTE(.);
+ *(.xt_except_desc_end)
+ *(.dynamic)
+ *(.gnu.version_d)
+ _rodata_end = ABSOLUTE(.);
+ /* Literals are also RO data. */
+ _lit4_start = ABSOLUTE(.);
+ *(*.lit4)
+ *(.lit4.*)
+ *(.gnu.linkonce.lit4.*)
+ _lit4_end = ABSOLUTE(.);
+ . = ALIGN(4);
+ _thread_local_start = ABSOLUTE(.);
+ *(.tdata)
+ *(.tdata.*)
+ *(.tbss)
+ *(.tbss.*)
+ _thread_local_end = ABSOLUTE(.);
+ . = ALIGN(4);
+ } >drom0_0_seg
+
+ .flash.text :
+ {
+ _stext = .;
+ _text_start = ABSOLUTE(.);
+ *(.literal .text .literal.* .text.* .stub .gnu.warning .gnu.linkonce.literal.* .gnu.linkonce.t.*.literal .gnu.linkonce.t.*)
+ *(.irom0.text) /* catch stray ICACHE_RODATA_ATTR */
+ *(.fini.literal)
+ *(.fini)
+ *(.gnu.version)
+ _text_end = ABSOLUTE(.);
+ _etext = .;
+
+ /* Similar to _iram_start, this symbol goes here so it is
+ resolved by addr2line in preference to the first symbol in
+ the flash.text segment.
+ */
+ _flash_cache_start = ABSOLUTE(0);
+ } >iram0_2_seg
+}
diff --git a/ports/esp32/esp32_ulp.c b/ports/esp32/esp32_ulp.c
new file mode 100644
index 000000000..3772639f4
--- /dev/null
+++ b/ports/esp32/esp32_ulp.c
@@ -0,0 +1,97 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018 "Andreas Valder" <andreas.valder@serioese.gmbh>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/runtime.h"
+
+#include "esp32/ulp.h"
+#include "esp_err.h"
+
+typedef struct _esp32_ulp_obj_t {
+ mp_obj_base_t base;
+} esp32_ulp_obj_t;
+
+const mp_obj_type_t esp32_ulp_type;
+
+// singleton ULP object
+STATIC const esp32_ulp_obj_t esp32_ulp_obj = {{&esp32_ulp_type}};
+
+STATIC mp_obj_t esp32_ulp_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
+ // check arguments
+ mp_arg_check_num(n_args, n_kw, 0, 0, false);
+
+ // return constant object
+ return (mp_obj_t)&esp32_ulp_obj;
+}
+
+STATIC mp_obj_t esp32_ulp_set_wakeup_period(mp_obj_t self_in, mp_obj_t period_index_in, mp_obj_t period_us_in) {
+ mp_uint_t period_index = mp_obj_get_int(period_index_in);
+ mp_uint_t period_us = mp_obj_get_int(period_us_in);
+ int _errno = ulp_set_wakeup_period(period_index, period_us);
+ if (_errno != ESP_OK) {
+ mp_raise_OSError(_errno);
+ }
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_3(esp32_ulp_set_wakeup_period_obj, esp32_ulp_set_wakeup_period);
+
+STATIC mp_obj_t esp32_ulp_load_binary(mp_obj_t self_in, mp_obj_t load_addr_in, mp_obj_t program_binary_in) {
+ mp_uint_t load_addr = mp_obj_get_int(load_addr_in);
+
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(program_binary_in, &bufinfo, MP_BUFFER_READ);
+
+ int _errno = ulp_load_binary(load_addr, bufinfo.buf, bufinfo.len/sizeof(uint32_t));
+ if (_errno != ESP_OK) {
+ mp_raise_OSError(_errno);
+ }
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_3(esp32_ulp_load_binary_obj, esp32_ulp_load_binary);
+
+STATIC mp_obj_t esp32_ulp_run(mp_obj_t self_in, mp_obj_t entry_point_in) {
+ mp_uint_t entry_point = mp_obj_get_int(entry_point_in);
+ int _errno = ulp_run(entry_point/sizeof(uint32_t));
+ if (_errno != ESP_OK) {
+ mp_raise_OSError(_errno);
+ }
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(esp32_ulp_run_obj, esp32_ulp_run);
+
+STATIC const mp_rom_map_elem_t esp32_ulp_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_set_wakeup_period), MP_ROM_PTR(&esp32_ulp_set_wakeup_period_obj) },
+ { MP_ROM_QSTR(MP_QSTR_load_binary), MP_ROM_PTR(&esp32_ulp_load_binary_obj) },
+ { MP_ROM_QSTR(MP_QSTR_run), MP_ROM_PTR(&esp32_ulp_run_obj) },
+ { MP_ROM_QSTR(MP_QSTR_RESERVE_MEM), MP_ROM_INT(CONFIG_ULP_COPROC_RESERVE_MEM) },
+};
+STATIC MP_DEFINE_CONST_DICT(esp32_ulp_locals_dict, esp32_ulp_locals_dict_table);
+
+const mp_obj_type_t esp32_ulp_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_ULP,
+ .make_new = esp32_ulp_make_new,
+ .locals_dict = (mp_obj_t)&esp32_ulp_locals_dict,
+};
diff --git a/ports/esp32/espneopixel.c b/ports/esp32/espneopixel.c
new file mode 100644
index 000000000..829c8b1c8
--- /dev/null
+++ b/ports/esp32/espneopixel.c
@@ -0,0 +1,53 @@
+// Original version from https://github.com/adafruit/Adafruit_NeoPixel
+// Modifications by dpgeorge to support auto-CPU-frequency detection
+
+// This is a mash-up of the Due show() code + insights from Michael Miller's
+// ESP8266 work for the NeoPixelBus library: github.com/Makuna/NeoPixelBus
+// Needs to be a separate .c file to enforce ICACHE_RAM_ATTR execution.
+
+#include "py/mpconfig.h"
+#include "py/mphal.h"
+#include "modesp.h"
+
+void IRAM_ATTR esp_neopixel_write(uint8_t pin, uint8_t *pixels, uint32_t numBytes, uint8_t timing) {
+ uint8_t *p, *end, pix, mask;
+ uint32_t t, time0, time1, period, c, startTime, pinMask;
+
+ pinMask = 1 << pin;
+ p = pixels;
+ end = p + numBytes;
+ pix = *p++;
+ mask = 0x80;
+ startTime = 0;
+
+ uint32_t fcpu = ets_get_cpu_frequency() * 1000000;
+
+ if (timing == 1) {
+ // 800 KHz
+ time0 = (fcpu * 0.35) / 1000000; // 0.35us
+ time1 = (fcpu * 0.8) / 1000000; // 0.8us
+ period = (fcpu * 1.25) / 1000000; // 1.25us per bit
+ } else {
+ // 400 KHz
+ time0 = (fcpu * 0.5) / 1000000; // 0.35us
+ time1 = (fcpu * 1.2) / 1000000; // 0.8us
+ period = (fcpu * 2.5) / 1000000; // 1.25us per bit
+ }
+
+ uint32_t irq_state = mp_hal_quiet_timing_enter();
+ for (t = time0;; t = time0) {
+ if (pix & mask) t = time1; // Bit high duration
+ while (((c = mp_hal_ticks_cpu()) - startTime) < period); // Wait for bit start
+ GPIO_REG_WRITE(GPIO_OUT_W1TS_REG, pinMask); // Set high
+ startTime = c; // Save start time
+ while (((c = mp_hal_ticks_cpu()) - startTime) < t); // Wait high duration
+ GPIO_REG_WRITE(GPIO_OUT_W1TC_REG, pinMask); // Set low
+ if (!(mask >>= 1)) { // Next bit/byte
+ if(p >= end) break;
+ pix = *p++;
+ mask = 0x80;
+ }
+ }
+ while ((mp_hal_ticks_cpu() - startTime) < period); // Wait for last bit
+ mp_hal_quiet_timing_exit(irq_state);
+}
diff --git a/ports/esp32/esponewire.c b/ports/esp32/esponewire.c
new file mode 100644
index 000000000..781616cbe
--- /dev/null
+++ b/ports/esp32/esponewire.c
@@ -0,0 +1,80 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2015-2017 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/mphal.h"
+#include "esp8266/esponewire.h"
+
+#define TIMING_RESET1 (0)
+#define TIMING_RESET2 (1)
+#define TIMING_RESET3 (2)
+#define TIMING_READ1 (3)
+#define TIMING_READ2 (4)
+#define TIMING_READ3 (5)
+#define TIMING_WRITE1 (6)
+#define TIMING_WRITE2 (7)
+#define TIMING_WRITE3 (8)
+
+uint16_t esp_onewire_timings[9] = {480, 40, 420, 5, 5, 40, 10, 50, 10};
+
+#define DELAY_US mp_hal_delay_us_fast
+
+int esp_onewire_reset(mp_hal_pin_obj_t pin) {
+ mp_hal_pin_write(pin, 0);
+ DELAY_US(esp_onewire_timings[TIMING_RESET1]);
+ uint32_t i = MICROPY_BEGIN_ATOMIC_SECTION();
+ mp_hal_pin_write(pin, 1);
+ DELAY_US(esp_onewire_timings[TIMING_RESET2]);
+ int status = !mp_hal_pin_read(pin);
+ MICROPY_END_ATOMIC_SECTION(i);
+ DELAY_US(esp_onewire_timings[TIMING_RESET3]);
+ return status;
+}
+
+int esp_onewire_readbit(mp_hal_pin_obj_t pin) {
+ mp_hal_pin_write(pin, 1);
+ uint32_t i = MICROPY_BEGIN_ATOMIC_SECTION();
+ mp_hal_pin_write(pin, 0);
+ DELAY_US(esp_onewire_timings[TIMING_READ1]);
+ mp_hal_pin_write(pin, 1);
+ DELAY_US(esp_onewire_timings[TIMING_READ2]);
+ int value = mp_hal_pin_read(pin);
+ MICROPY_END_ATOMIC_SECTION(i);
+ DELAY_US(esp_onewire_timings[TIMING_READ3]);
+ return value;
+}
+
+void esp_onewire_writebit(mp_hal_pin_obj_t pin, int value) {
+ uint32_t i = MICROPY_BEGIN_ATOMIC_SECTION();
+ mp_hal_pin_write(pin, 0);
+ DELAY_US(esp_onewire_timings[TIMING_WRITE1]);
+ if (value) {
+ mp_hal_pin_write(pin, 1);
+ }
+ DELAY_US(esp_onewire_timings[TIMING_WRITE2]);
+ mp_hal_pin_write(pin, 1);
+ DELAY_US(esp_onewire_timings[TIMING_WRITE3]);
+ MICROPY_END_ATOMIC_SECTION(i);
+}
diff --git a/ports/esp32/fatfs_port.c b/ports/esp32/fatfs_port.c
new file mode 100644
index 000000000..880324ed8
--- /dev/null
+++ b/ports/esp32/fatfs_port.c
@@ -0,0 +1,41 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * Development of the code in this file was sponsored by Microbric Pty Ltd
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2013, 2014, 2016 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <sys/time.h>
+#include "lib/oofatfs/ff.h"
+#include "timeutils.h"
+
+DWORD get_fattime(void) {
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ timeutils_struct_time_t tm;
+ timeutils_seconds_since_2000_to_struct_time(tv.tv_sec, &tm);
+
+ return (((DWORD)(tm.tm_year - 1980) << 25) | ((DWORD)tm.tm_mon << 21) | ((DWORD)tm.tm_mday << 16) |
+ ((DWORD)tm.tm_hour << 11) | ((DWORD)tm.tm_min << 5) | ((DWORD)tm.tm_sec >> 1));
+}
diff --git a/ports/esp32/gccollect.c b/ports/esp32/gccollect.c
new file mode 100644
index 000000000..9843cef00
--- /dev/null
+++ b/ports/esp32/gccollect.c
@@ -0,0 +1,66 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * Development of the code in this file was sponsored by Microbric Pty Ltd
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2014 Damien P. George
+ * Copyright (c) 2017 Pycom Limited
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdio.h>
+
+#include "py/mpconfig.h"
+#include "py/mpstate.h"
+#include "py/gc.h"
+#include "py/mpthread.h"
+#include "gccollect.h"
+#include "soc/cpu.h"
+#include "xtensa/hal.h"
+
+
+static void gc_collect_inner(int level) {
+ if (level < XCHAL_NUM_AREGS / 8) {
+ gc_collect_inner(level + 1);
+ if (level != 0) {
+ return;
+ }
+ }
+
+ if (level == XCHAL_NUM_AREGS / 8) {
+ // get the sp
+ volatile uint32_t sp = (uint32_t)get_sp();
+ gc_collect_root((void**)sp, ((mp_uint_t)MP_STATE_THREAD(stack_top) - sp) / sizeof(uint32_t));
+ return;
+ }
+
+ // trace root pointers from any threads
+ #if MICROPY_PY_THREAD
+ mp_thread_gc_others();
+ #endif
+}
+
+void gc_collect(void) {
+ gc_collect_start();
+ gc_collect_inner(0);
+ gc_collect_end();
+}
diff --git a/ports/esp32/gccollect.h b/ports/esp32/gccollect.h
new file mode 100644
index 000000000..fe02cc62b
--- /dev/null
+++ b/ports/esp32/gccollect.h
@@ -0,0 +1,42 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * Development of the code in this file was sponsored by Microbric Pty Ltd
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2014 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+extern uint32_t _text_start;
+extern uint32_t _text_end;
+extern uint32_t _irom0_text_start;
+extern uint32_t _irom0_text_end;
+extern uint32_t _data_start;
+extern uint32_t _data_end;
+extern uint32_t _rodata_start;
+extern uint32_t _rodata_end;
+extern uint32_t _bss_start;
+extern uint32_t _bss_end;
+extern uint32_t _heap_start;
+extern uint32_t _heap_end;
+
+void gc_collect(void);
diff --git a/ports/esp32/help.c b/ports/esp32/help.c
new file mode 100644
index 000000000..95d115c56
--- /dev/null
+++ b/ports/esp32/help.c
@@ -0,0 +1,65 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * Development of the code in this file was sponsored by Microbric Pty Ltd
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2013-2016 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/builtin.h"
+
+const char esp32_help_text[] =
+"Welcome to MicroPython on the ESP32!\n"
+"\n"
+"For generic online docs please visit http://docs.micropython.org/\n"
+"\n"
+"For access to the hardware use the 'machine' module:\n"
+"\n"
+"import machine\n"
+"pin12 = machine.Pin(12, machine.Pin.OUT)\n"
+"pin12.value(1)\n"
+"pin13 = machine.Pin(13, machine.Pin.IN, machine.Pin.PULL_UP)\n"
+"print(pin13.value())\n"
+"i2c = machine.I2C(scl=machine.Pin(21), sda=machine.Pin(22))\n"
+"i2c.scan()\n"
+"i2c.writeto(addr, b'1234')\n"
+"i2c.readfrom(addr, 4)\n"
+"\n"
+"Basic WiFi configuration:\n"
+"\n"
+"import network\n"
+"sta_if = network.WLAN(network.STA_IF); sta_if.active(True)\n"
+"sta_if.scan() # Scan for available access points\n"
+"sta_if.connect(\"<AP_name>\", \"<password>\") # Connect to an AP\n"
+"sta_if.isconnected() # Check for successful connection\n"
+"\n"
+"Control commands:\n"
+" CTRL-A -- on a blank line, enter raw REPL mode\n"
+" CTRL-B -- on a blank line, enter normal REPL mode\n"
+" CTRL-C -- interrupt a running program\n"
+" CTRL-D -- on a blank line, do a soft reset of the board\n"
+" CTRL-E -- on a blank line, enter paste mode\n"
+"\n"
+"For further help on a specific object, type help(obj)\n"
+"For a list of available modules, type help('modules')\n"
+;
diff --git a/ports/esp32/machine_adc.c b/ports/esp32/machine_adc.c
new file mode 100644
index 000000000..d62f362e9
--- /dev/null
+++ b/ports/esp32/machine_adc.c
@@ -0,0 +1,132 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Nick Moore
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+
+#include <stdio.h>
+
+#include "esp_log.h"
+
+#include "driver/gpio.h"
+#include "driver/adc.h"
+
+#include "py/runtime.h"
+#include "py/mphal.h"
+#include "modmachine.h"
+
+typedef struct _madc_obj_t {
+ mp_obj_base_t base;
+ gpio_num_t gpio_id;
+ adc1_channel_t adc1_id;
+} madc_obj_t;
+
+STATIC const madc_obj_t madc_obj[] = {
+ {{&machine_adc_type}, GPIO_NUM_36, ADC1_CHANNEL_0},
+ {{&machine_adc_type}, GPIO_NUM_37, ADC1_CHANNEL_1},
+ {{&machine_adc_type}, GPIO_NUM_38, ADC1_CHANNEL_2},
+ {{&machine_adc_type}, GPIO_NUM_39, ADC1_CHANNEL_3},
+ {{&machine_adc_type}, GPIO_NUM_32, ADC1_CHANNEL_4},
+ {{&machine_adc_type}, GPIO_NUM_33, ADC1_CHANNEL_5},
+ {{&machine_adc_type}, GPIO_NUM_34, ADC1_CHANNEL_6},
+ {{&machine_adc_type}, GPIO_NUM_35, ADC1_CHANNEL_7},
+};
+
+STATIC mp_obj_t madc_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw,
+ const mp_obj_t *args) {
+
+ static int initialized = 0;
+ if (!initialized) {
+ adc1_config_width(ADC_WIDTH_12Bit);
+ initialized = 1;
+ }
+
+ mp_arg_check_num(n_args, n_kw, 1, 1, true);
+ gpio_num_t pin_id = machine_pin_get_id(args[0]);
+ const madc_obj_t *self = NULL;
+ for (int i = 0; i < MP_ARRAY_SIZE(madc_obj); i++) {
+ if (pin_id == madc_obj[i].gpio_id) { self = &madc_obj[i]; break; }
+ }
+ if (!self) mp_raise_ValueError("invalid Pin for ADC");
+ esp_err_t err = adc1_config_channel_atten(self->adc1_id, ADC_ATTEN_0db);
+ if (err == ESP_OK) return MP_OBJ_FROM_PTR(self);
+ mp_raise_ValueError("Parameter Error");
+}
+
+STATIC void madc_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
+ madc_obj_t *self = self_in;
+ mp_printf(print, "ADC(Pin(%u))", self->gpio_id);
+}
+
+STATIC mp_obj_t madc_read(mp_obj_t self_in) {
+ madc_obj_t *self = self_in;
+ int val = adc1_get_raw(self->adc1_id);
+ if (val == -1) mp_raise_ValueError("Parameter Error");
+ return MP_OBJ_NEW_SMALL_INT(val);
+}
+MP_DEFINE_CONST_FUN_OBJ_1(madc_read_obj, madc_read);
+
+STATIC mp_obj_t madc_atten(mp_obj_t self_in, mp_obj_t atten_in) {
+ madc_obj_t *self = self_in;
+ adc_atten_t atten = mp_obj_get_int(atten_in);
+ esp_err_t err = adc1_config_channel_atten(self->adc1_id, atten);
+ if (err == ESP_OK) return mp_const_none;
+ mp_raise_ValueError("Parameter Error");
+}
+MP_DEFINE_CONST_FUN_OBJ_2(madc_atten_obj, madc_atten);
+
+STATIC mp_obj_t madc_width(mp_obj_t cls_in, mp_obj_t width_in) {
+ adc_bits_width_t width = mp_obj_get_int(width_in);
+ esp_err_t err = adc1_config_width(width);
+ if (err == ESP_OK) return mp_const_none;
+ mp_raise_ValueError("Parameter Error");
+}
+MP_DEFINE_CONST_FUN_OBJ_2(madc_width_fun_obj, madc_width);
+MP_DEFINE_CONST_CLASSMETHOD_OBJ(madc_width_obj, MP_ROM_PTR(&madc_width_fun_obj));
+
+STATIC const mp_rom_map_elem_t madc_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&madc_read_obj) },
+ { MP_ROM_QSTR(MP_QSTR_atten), MP_ROM_PTR(&madc_atten_obj) },
+ { MP_ROM_QSTR(MP_QSTR_width), MP_ROM_PTR(&madc_width_obj) },
+
+ { MP_ROM_QSTR(MP_QSTR_ATTN_0DB), MP_ROM_INT(ADC_ATTEN_0db) },
+ { MP_ROM_QSTR(MP_QSTR_ATTN_2_5DB), MP_ROM_INT(ADC_ATTEN_2_5db) },
+ { MP_ROM_QSTR(MP_QSTR_ATTN_6DB), MP_ROM_INT(ADC_ATTEN_6db) },
+ { MP_ROM_QSTR(MP_QSTR_ATTN_11DB), MP_ROM_INT(ADC_ATTEN_11db) },
+
+ { MP_ROM_QSTR(MP_QSTR_WIDTH_9BIT), MP_ROM_INT(ADC_WIDTH_9Bit) },
+ { MP_ROM_QSTR(MP_QSTR_WIDTH_10BIT), MP_ROM_INT(ADC_WIDTH_10Bit) },
+ { MP_ROM_QSTR(MP_QSTR_WIDTH_11BIT), MP_ROM_INT(ADC_WIDTH_11Bit) },
+ { MP_ROM_QSTR(MP_QSTR_WIDTH_12BIT), MP_ROM_INT(ADC_WIDTH_12Bit) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(madc_locals_dict, madc_locals_dict_table);
+
+const mp_obj_type_t machine_adc_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_ADC,
+ .print = madc_print,
+ .make_new = madc_make_new,
+ .locals_dict = (mp_obj_t)&madc_locals_dict,
+};
diff --git a/ports/esp32/machine_dac.c b/ports/esp32/machine_dac.c
new file mode 100644
index 000000000..bd0804ec4
--- /dev/null
+++ b/ports/esp32/machine_dac.c
@@ -0,0 +1,97 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Nick Moore
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+
+#include <stdio.h>
+
+#include "esp_log.h"
+
+#include "driver/gpio.h"
+#include "driver/dac.h"
+
+#include "py/runtime.h"
+#include "py/mphal.h"
+#include "modmachine.h"
+
+typedef struct _mdac_obj_t {
+ mp_obj_base_t base;
+ gpio_num_t gpio_id;
+ dac_channel_t dac_id;
+} mdac_obj_t;
+
+STATIC const mdac_obj_t mdac_obj[] = {
+ {{&machine_dac_type}, GPIO_NUM_25, DAC_CHANNEL_1},
+ {{&machine_dac_type}, GPIO_NUM_26, DAC_CHANNEL_2},
+};
+
+STATIC mp_obj_t mdac_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw,
+ const mp_obj_t *args) {
+
+ mp_arg_check_num(n_args, n_kw, 1, 1, true);
+ gpio_num_t pin_id = machine_pin_get_id(args[0]);
+ const mdac_obj_t *self = NULL;
+ for (int i = 0; i < MP_ARRAY_SIZE(mdac_obj); i++) {
+ if (pin_id == mdac_obj[i].gpio_id) { self = &mdac_obj[i]; break; }
+ }
+ if (!self) mp_raise_ValueError("invalid Pin for DAC");
+
+ esp_err_t err = dac_output_enable(self->dac_id);
+ if (err == ESP_OK) {
+ err = dac_output_voltage(self->dac_id, 0);
+ }
+ if (err == ESP_OK) return MP_OBJ_FROM_PTR(self);
+ mp_raise_ValueError("Parameter Error");
+}
+
+STATIC void mdac_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
+ mdac_obj_t *self = self_in;
+ mp_printf(print, "DAC(Pin(%u))", self->gpio_id);
+}
+
+STATIC mp_obj_t mdac_write(mp_obj_t self_in, mp_obj_t value_in) {
+ mdac_obj_t *self = self_in;
+ int value = mp_obj_get_int(value_in);
+ if (value < 0 || value > 255) mp_raise_ValueError("Value out of range");
+
+ esp_err_t err = dac_output_voltage(self->dac_id, value);
+ if (err == ESP_OK) return mp_const_none;
+ mp_raise_ValueError("Parameter Error");
+}
+MP_DEFINE_CONST_FUN_OBJ_2(mdac_write_obj, mdac_write);
+
+STATIC const mp_rom_map_elem_t mdac_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mdac_write_obj) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(mdac_locals_dict, mdac_locals_dict_table);
+
+const mp_obj_type_t machine_dac_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_DAC,
+ .print = mdac_print,
+ .make_new = mdac_make_new,
+ .locals_dict = (mp_obj_t)&mdac_locals_dict,
+};
diff --git a/ports/esp32/machine_hw_spi.c b/ports/esp32/machine_hw_spi.c
new file mode 100644
index 000000000..d011ce53e
--- /dev/null
+++ b/ports/esp32/machine_hw_spi.c
@@ -0,0 +1,390 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 "Eric Poulsen" <eric@zyxod.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+
+#include "py/runtime.h"
+#include "py/stream.h"
+#include "py/mphal.h"
+#include "extmod/machine_spi.h"
+#include "modmachine.h"
+
+#include "driver/spi_master.h"
+
+#define MP_HW_SPI_MAX_XFER_BYTES (4092)
+#define MP_HW_SPI_MAX_XFER_BITS (MP_HW_SPI_MAX_XFER_BYTES * 8) // Has to be an even multiple of 8
+
+typedef struct _machine_hw_spi_obj_t {
+ mp_obj_base_t base;
+ spi_host_device_t host;
+ uint32_t baudrate;
+ uint8_t polarity;
+ uint8_t phase;
+ uint8_t bits;
+ uint8_t firstbit;
+ int8_t sck;
+ int8_t mosi;
+ int8_t miso;
+ spi_device_handle_t spi;
+ enum {
+ MACHINE_HW_SPI_STATE_NONE,
+ MACHINE_HW_SPI_STATE_INIT,
+ MACHINE_HW_SPI_STATE_DEINIT
+ } state;
+} machine_hw_spi_obj_t;
+
+STATIC void machine_hw_spi_deinit_internal(machine_hw_spi_obj_t *self) {
+ switch (spi_bus_remove_device(self->spi)) {
+ case ESP_ERR_INVALID_ARG:
+ mp_raise_msg(&mp_type_OSError, "invalid configuration");
+ return;
+
+ case ESP_ERR_INVALID_STATE:
+ mp_raise_msg(&mp_type_OSError, "SPI device already freed");
+ return;
+ }
+
+ switch (spi_bus_free(self->host)) {
+ case ESP_ERR_INVALID_ARG:
+ mp_raise_msg(&mp_type_OSError, "invalid configuration");
+ return;
+
+ case ESP_ERR_INVALID_STATE:
+ mp_raise_msg(&mp_type_OSError, "SPI bus already freed");
+ return;
+ }
+
+ int8_t pins[3] = {self->miso, self->mosi, self->sck};
+
+ for (int i = 0; i < 3; i++) {
+ if (pins[i] != -1) {
+ gpio_pad_select_gpio(pins[i]);
+ gpio_matrix_out(pins[i], SIG_GPIO_OUT_IDX, false, false);
+ gpio_set_direction(pins[i], GPIO_MODE_INPUT);
+ }
+ }
+}
+
+STATIC void machine_hw_spi_init_internal(
+ machine_hw_spi_obj_t *self,
+ int8_t host,
+ int32_t baudrate,
+ int8_t polarity,
+ int8_t phase,
+ int8_t bits,
+ int8_t firstbit,
+ int8_t sck,
+ int8_t mosi,
+ int8_t miso) {
+
+ // if we're not initialized, then we're
+ // implicitly 'changed', since this is the init routine
+ bool changed = self->state != MACHINE_HW_SPI_STATE_INIT;
+
+ esp_err_t ret;
+
+ machine_hw_spi_obj_t old_self = *self;
+
+ if (host != -1 && host != self->host) {
+ self->host = host;
+ changed = true;
+ }
+
+ if (baudrate != -1 && baudrate != self->baudrate) {
+ self->baudrate = baudrate;
+ changed = true;
+ }
+
+ if (polarity != -1 && polarity != self->polarity) {
+ self->polarity = polarity;
+ changed = true;
+ }
+
+ if (phase != -1 && phase != self->phase) {
+ self->phase = phase;
+ changed = true;
+ }
+
+ if (bits != -1 && bits != self->bits) {
+ self->bits = bits;
+ changed = true;
+ }
+
+ if (firstbit != -1 && firstbit != self->firstbit) {
+ self->firstbit = firstbit;
+ changed = true;
+ }
+
+ if (sck != -2 && sck != self->sck) {
+ self->sck = sck;
+ changed = true;
+ }
+
+ if (mosi != -2 && mosi != self->mosi) {
+ self->mosi = mosi;
+ changed = true;
+ }
+
+ if (miso != -2 && miso != self->miso) {
+ self->miso = miso;
+ changed = true;
+ }
+
+ if (self->host != HSPI_HOST && self->host != VSPI_HOST) {
+ mp_raise_ValueError("SPI ID must be either HSPI(1) or VSPI(2)");
+ }
+
+ if (changed) {
+ if (self->state == MACHINE_HW_SPI_STATE_INIT) {
+ self->state = MACHINE_HW_SPI_STATE_DEINIT;
+ machine_hw_spi_deinit_internal(&old_self);
+ }
+ } else {
+ return; // no changes
+ }
+
+ spi_bus_config_t buscfg = {
+ .miso_io_num = self->miso,
+ .mosi_io_num = self->mosi,
+ .sclk_io_num = self->sck,
+ .quadwp_io_num = -1,
+ .quadhd_io_num = -1
+ };
+
+ spi_device_interface_config_t devcfg = {
+ .clock_speed_hz = self->baudrate,
+ .mode = self->phase | (self->polarity << 1),
+ .spics_io_num = -1, // No CS pin
+ .queue_size = 1,
+ .flags = self->firstbit == MICROPY_PY_MACHINE_SPI_LSB ? SPI_DEVICE_TXBIT_LSBFIRST | SPI_DEVICE_RXBIT_LSBFIRST : 0,
+ .pre_cb = NULL
+ };
+
+ //Initialize the SPI bus
+ // FIXME: Does the DMA matter? There are two
+
+ ret = spi_bus_initialize(self->host, &buscfg, 1);
+ switch (ret) {
+ case ESP_ERR_INVALID_ARG:
+ mp_raise_msg(&mp_type_OSError, "invalid configuration");
+ return;
+
+ case ESP_ERR_INVALID_STATE:
+ mp_raise_msg(&mp_type_OSError, "SPI device already in use");
+ return;
+ }
+
+ ret = spi_bus_add_device(self->host, &devcfg, &self->spi);
+ switch (ret) {
+ case ESP_ERR_INVALID_ARG:
+ mp_raise_msg(&mp_type_OSError, "invalid configuration");
+ spi_bus_free(self->host);
+ return;
+
+ case ESP_ERR_NO_MEM:
+ mp_raise_msg(&mp_type_OSError, "out of memory");
+ spi_bus_free(self->host);
+ return;
+
+ case ESP_ERR_NOT_FOUND:
+ mp_raise_msg(&mp_type_OSError, "no free slots");
+ spi_bus_free(self->host);
+ return;
+ }
+ self->state = MACHINE_HW_SPI_STATE_INIT;
+}
+
+STATIC void machine_hw_spi_deinit(mp_obj_base_t *self_in) {
+ machine_hw_spi_obj_t *self = (machine_hw_spi_obj_t *) self_in;
+ if (self->state == MACHINE_HW_SPI_STATE_INIT) {
+ self->state = MACHINE_HW_SPI_STATE_DEINIT;
+ machine_hw_spi_deinit_internal(self);
+ }
+}
+
+STATIC void machine_hw_spi_transfer(mp_obj_base_t *self_in, size_t len, const uint8_t *src, uint8_t *dest) {
+ machine_hw_spi_obj_t *self = MP_OBJ_TO_PTR(self_in);
+
+ if (self->state == MACHINE_HW_SPI_STATE_DEINIT) {
+ mp_raise_msg(&mp_type_OSError, "transfer on deinitialized SPI");
+ return;
+ }
+
+ struct spi_transaction_t transaction = { 0 };
+
+ // Round to nearest whole set of bits
+ int bits_to_send = len * 8 / self->bits * self->bits;
+
+
+ if (len <= 4) {
+ if (src != NULL) {
+ memcpy(&transaction.tx_data, src, len);
+ }
+
+ transaction.flags = SPI_TRANS_USE_TXDATA | SPI_TRANS_USE_RXDATA;
+ transaction.length = bits_to_send;
+ spi_device_transmit(self->spi, &transaction);
+
+ if (dest != NULL) {
+ memcpy(dest, &transaction.rx_data, len);
+ }
+ } else {
+ int offset = 0;
+ int bits_remaining = bits_to_send;
+
+ while (bits_remaining) {
+ memset(&transaction, 0, sizeof(transaction));
+
+ transaction.length =
+ bits_remaining > MP_HW_SPI_MAX_XFER_BITS ? MP_HW_SPI_MAX_XFER_BITS : bits_remaining;
+
+ if (src != NULL) {
+ transaction.tx_buffer = src + offset;
+ }
+ if (dest != NULL) {
+ transaction.rx_buffer = dest + offset;
+ }
+
+ spi_device_transmit(self->spi, &transaction);
+ bits_remaining -= transaction.length;
+
+ // doesn't need ceil(); loop ends when bits_remaining is 0
+ offset += transaction.length / 8;
+ }
+ }
+}
+
+/******************************************************************************/
+// MicroPython bindings for hw_spi
+
+STATIC void machine_hw_spi_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
+ machine_hw_spi_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ mp_printf(print, "SPI(id=%u, baudrate=%u, polarity=%u, phase=%u, bits=%u, firstbit=%u, sck=%d, mosi=%d, miso=%d)",
+ self->host, self->baudrate, self->polarity,
+ self->phase, self->bits, self->firstbit,
+ self->sck, self->mosi, self->miso);
+}
+
+STATIC void machine_hw_spi_init(mp_obj_base_t *self_in, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ machine_hw_spi_obj_t *self = (machine_hw_spi_obj_t *) self_in;
+
+ enum { ARG_id, ARG_baudrate, ARG_polarity, ARG_phase, ARG_bits, ARG_firstbit, ARG_sck, ARG_mosi, ARG_miso };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_id, MP_ARG_INT, {.u_int = -1} },
+ { MP_QSTR_baudrate, MP_ARG_INT, {.u_int = -1} },
+ { MP_QSTR_polarity, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
+ { MP_QSTR_phase, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
+ { MP_QSTR_bits, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
+ { MP_QSTR_firstbit, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
+ { MP_QSTR_sck, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+ { MP_QSTR_mosi, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+ { MP_QSTR_miso, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+ };
+
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args),
+ allowed_args, args);
+ int8_t sck, mosi, miso;
+
+ if (args[ARG_sck].u_obj == MP_OBJ_NULL) {
+ sck = -2;
+ } else if (args[ARG_sck].u_obj == mp_const_none) {
+ sck = -1;
+ } else {
+ sck = machine_pin_get_id(args[ARG_sck].u_obj);
+ }
+
+ if (args[ARG_miso].u_obj == MP_OBJ_NULL) {
+ miso = -2;
+ } else if (args[ARG_miso].u_obj == mp_const_none) {
+ miso = -1;
+ } else {
+ miso = machine_pin_get_id(args[ARG_miso].u_obj);
+ }
+
+ if (args[ARG_mosi].u_obj == MP_OBJ_NULL) {
+ mosi = -2;
+ } else if (args[ARG_mosi].u_obj == mp_const_none) {
+ mosi = -1;
+ } else {
+ mosi = machine_pin_get_id(args[ARG_mosi].u_obj);
+ }
+
+ machine_hw_spi_init_internal(self, args[ARG_id].u_int, args[ARG_baudrate].u_int,
+ args[ARG_polarity].u_int, args[ARG_phase].u_int, args[ARG_bits].u_int,
+ args[ARG_firstbit].u_int, sck, mosi, miso);
+}
+
+mp_obj_t machine_hw_spi_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
+ enum { ARG_id, ARG_baudrate, ARG_polarity, ARG_phase, ARG_bits, ARG_firstbit, ARG_sck, ARG_mosi, ARG_miso };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_id, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = -1} },
+ { MP_QSTR_baudrate, MP_ARG_INT, {.u_int = 500000} },
+ { MP_QSTR_polarity, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
+ { MP_QSTR_phase, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
+ { MP_QSTR_bits, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 8} },
+ { MP_QSTR_firstbit, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = MICROPY_PY_MACHINE_SPI_MSB} },
+ { MP_QSTR_sck, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+ { MP_QSTR_mosi, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+ { MP_QSTR_miso, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ machine_hw_spi_obj_t *self = m_new_obj(machine_hw_spi_obj_t);
+ self->base.type = &machine_hw_spi_type;
+
+ machine_hw_spi_init_internal(
+ self,
+ args[ARG_id].u_int,
+ args[ARG_baudrate].u_int,
+ args[ARG_polarity].u_int,
+ args[ARG_phase].u_int,
+ args[ARG_bits].u_int,
+ args[ARG_firstbit].u_int,
+ args[ARG_sck].u_obj == MP_OBJ_NULL ? -1 : machine_pin_get_id(args[ARG_sck].u_obj),
+ args[ARG_mosi].u_obj == MP_OBJ_NULL ? -1 : machine_pin_get_id(args[ARG_mosi].u_obj),
+ args[ARG_miso].u_obj == MP_OBJ_NULL ? -1 : machine_pin_get_id(args[ARG_miso].u_obj));
+
+ return MP_OBJ_FROM_PTR(self);
+}
+
+STATIC const mp_machine_spi_p_t machine_hw_spi_p = {
+ .init = machine_hw_spi_init,
+ .deinit = machine_hw_spi_deinit,
+ .transfer = machine_hw_spi_transfer,
+};
+
+const mp_obj_type_t machine_hw_spi_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_SPI,
+ .print = machine_hw_spi_print,
+ .make_new = machine_hw_spi_make_new,
+ .protocol = &machine_hw_spi_p,
+ .locals_dict = (mp_obj_dict_t *) &mp_machine_spi_locals_dict,
+};
diff --git a/ports/esp32/machine_pin.c b/ports/esp32/machine_pin.c
new file mode 100644
index 000000000..2a26d6bfb
--- /dev/null
+++ b/ports/esp32/machine_pin.c
@@ -0,0 +1,414 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * Development of the code in this file was sponsored by Microbric Pty Ltd
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include "driver/gpio.h"
+
+#include "py/runtime.h"
+#include "py/mphal.h"
+#include "modmachine.h"
+#include "extmod/virtpin.h"
+#include "machine_rtc.h"
+#include "modesp32.h"
+
+typedef struct _machine_pin_obj_t {
+ mp_obj_base_t base;
+ gpio_num_t id;
+} machine_pin_obj_t;
+
+typedef struct _machine_pin_irq_obj_t {
+ mp_obj_base_t base;
+ gpio_num_t id;
+} machine_pin_irq_obj_t;
+
+STATIC const machine_pin_obj_t machine_pin_obj[] = {
+ {{&machine_pin_type}, GPIO_NUM_0},
+ {{&machine_pin_type}, GPIO_NUM_1},
+ {{&machine_pin_type}, GPIO_NUM_2},
+ {{&machine_pin_type}, GPIO_NUM_3},
+ {{&machine_pin_type}, GPIO_NUM_4},
+ {{&machine_pin_type}, GPIO_NUM_5},
+ {{&machine_pin_type}, GPIO_NUM_6},
+ {{&machine_pin_type}, GPIO_NUM_7},
+ {{&machine_pin_type}, GPIO_NUM_8},
+ {{&machine_pin_type}, GPIO_NUM_9},
+ {{&machine_pin_type}, GPIO_NUM_10},
+ {{&machine_pin_type}, GPIO_NUM_11},
+ {{&machine_pin_type}, GPIO_NUM_12},
+ {{&machine_pin_type}, GPIO_NUM_13},
+ {{&machine_pin_type}, GPIO_NUM_14},
+ {{&machine_pin_type}, GPIO_NUM_15},
+ {{&machine_pin_type}, GPIO_NUM_16},
+ {{&machine_pin_type}, GPIO_NUM_17},
+ {{&machine_pin_type}, GPIO_NUM_18},
+ {{&machine_pin_type}, GPIO_NUM_19},
+ {{NULL}, -1},
+ {{&machine_pin_type}, GPIO_NUM_21},
+ {{&machine_pin_type}, GPIO_NUM_22},
+ {{&machine_pin_type}, GPIO_NUM_23},
+ {{NULL}, -1},
+ {{&machine_pin_type}, GPIO_NUM_25},
+ {{&machine_pin_type}, GPIO_NUM_26},
+ {{&machine_pin_type}, GPIO_NUM_27},
+ {{NULL}, -1},
+ {{NULL}, -1},
+ {{NULL}, -1},
+ {{NULL}, -1},
+ {{&machine_pin_type}, GPIO_NUM_32},
+ {{&machine_pin_type}, GPIO_NUM_33},
+ {{&machine_pin_type}, GPIO_NUM_34},
+ {{&machine_pin_type}, GPIO_NUM_35},
+ {{&machine_pin_type}, GPIO_NUM_36},
+ {{&machine_pin_type}, GPIO_NUM_37},
+ {{&machine_pin_type}, GPIO_NUM_38},
+ {{&machine_pin_type}, GPIO_NUM_39},
+};
+
+// forward declaration
+STATIC const machine_pin_irq_obj_t machine_pin_irq_object[];
+
+void machine_pins_init(void) {
+ static bool did_install = false;
+ if (!did_install) {
+ gpio_install_isr_service(0);
+ did_install = true;
+ }
+ memset(&MP_STATE_PORT(machine_pin_irq_handler[0]), 0, sizeof(MP_STATE_PORT(machine_pin_irq_handler)));
+}
+
+void machine_pins_deinit(void) {
+ for (int i = 0; i < MP_ARRAY_SIZE(machine_pin_obj); ++i) {
+ if (machine_pin_obj[i].id != (gpio_num_t)-1) {
+ gpio_isr_handler_remove(machine_pin_obj[i].id);
+ }
+ }
+}
+
+STATIC void IRAM_ATTR machine_pin_isr_handler(void *arg) {
+ machine_pin_obj_t *self = arg;
+ mp_obj_t handler = MP_STATE_PORT(machine_pin_irq_handler)[self->id];
+ mp_sched_schedule(handler, MP_OBJ_FROM_PTR(self));
+}
+
+gpio_num_t machine_pin_get_id(mp_obj_t pin_in) {
+ if (mp_obj_get_type(pin_in) != &machine_pin_type) {
+ mp_raise_ValueError("expecting a pin");
+ }
+ machine_pin_obj_t *self = pin_in;
+ return self->id;
+}
+
+STATIC void machine_pin_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
+ machine_pin_obj_t *self = self_in;
+ mp_printf(print, "Pin(%u)", self->id);
+}
+
+// pin.init(mode, pull=None, *, value)
+STATIC mp_obj_t machine_pin_obj_init_helper(const machine_pin_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum { ARG_mode, ARG_pull, ARG_value };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_mode, MP_ARG_OBJ, {.u_obj = mp_const_none}},
+ { MP_QSTR_pull, MP_ARG_OBJ, {.u_obj = mp_const_none}},
+ { MP_QSTR_value, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL}},
+ };
+
+ // parse args
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ // configure the pin for gpio
+ gpio_pad_select_gpio(self->id);
+
+ // set initial value (do this before configuring mode/pull)
+ if (args[ARG_value].u_obj != MP_OBJ_NULL) {
+ gpio_set_level(self->id, mp_obj_is_true(args[ARG_value].u_obj));
+ }
+
+ // configure mode
+ if (args[ARG_mode].u_obj != mp_const_none) {
+ mp_int_t pin_io_mode = mp_obj_get_int(args[ARG_mode].u_obj);
+ if (self->id >= 34 && (pin_io_mode & GPIO_MODE_DEF_OUTPUT)) {
+ mp_raise_ValueError("pin can only be input");
+ } else {
+ gpio_set_direction(self->id, pin_io_mode);
+ }
+ }
+
+ // configure pull
+ if (args[ARG_pull].u_obj != mp_const_none) {
+ gpio_set_pull_mode(self->id, mp_obj_get_int(args[ARG_pull].u_obj));
+ }
+
+ return mp_const_none;
+}
+
+// constructor(id, ...)
+mp_obj_t mp_pin_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
+ mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true);
+
+ // get the wanted pin object
+ int wanted_pin = mp_obj_get_int(args[0]);
+ const machine_pin_obj_t *self = NULL;
+ if (0 <= wanted_pin && wanted_pin < MP_ARRAY_SIZE(machine_pin_obj)) {
+ self = (machine_pin_obj_t*)&machine_pin_obj[wanted_pin];
+ }
+ if (self == NULL || self->base.type == NULL) {
+ mp_raise_ValueError("invalid pin");
+ }
+
+ if (n_args > 1 || n_kw > 0) {
+ // pin mode given, so configure this GPIO
+ mp_map_t kw_args;
+ mp_map_init_fixed_table(&kw_args, n_kw, args + n_args);
+ machine_pin_obj_init_helper(self, n_args - 1, args + 1, &kw_args);
+ }
+
+ return MP_OBJ_FROM_PTR(self);
+}
+
+// fast method for getting/setting pin value
+STATIC mp_obj_t machine_pin_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {
+ mp_arg_check_num(n_args, n_kw, 0, 1, false);
+ machine_pin_obj_t *self = self_in;
+ if (n_args == 0) {
+ // get pin
+ return MP_OBJ_NEW_SMALL_INT(gpio_get_level(self->id));
+ } else {
+ // set pin
+ gpio_set_level(self->id, mp_obj_is_true(args[0]));
+ return mp_const_none;
+ }
+}
+
+// pin.init(mode, pull)
+STATIC mp_obj_t machine_pin_obj_init(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
+ return machine_pin_obj_init_helper(args[0], n_args - 1, args + 1, kw_args);
+}
+MP_DEFINE_CONST_FUN_OBJ_KW(machine_pin_init_obj, 1, machine_pin_obj_init);
+
+// pin.value([value])
+STATIC mp_obj_t machine_pin_value(size_t n_args, const mp_obj_t *args) {
+ return machine_pin_call(args[0], n_args - 1, 0, args + 1);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_pin_value_obj, 1, 2, machine_pin_value);
+
+// pin.irq(handler=None, trigger=IRQ_FALLING|IRQ_RISING)
+STATIC mp_obj_t machine_pin_irq(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum { ARG_handler, ARG_trigger, ARG_wake };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_handler, MP_ARG_OBJ, {.u_obj = mp_const_none} },
+ { MP_QSTR_trigger, MP_ARG_INT, {.u_int = GPIO_PIN_INTR_POSEDGE | GPIO_PIN_INTR_NEGEDGE} },
+ { MP_QSTR_wake, MP_ARG_OBJ, {.u_obj = mp_const_none} },
+ };
+ machine_pin_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ if (n_args > 1 || kw_args->used != 0) {
+ // configure irq
+ mp_obj_t handler = args[ARG_handler].u_obj;
+ uint32_t trigger = args[ARG_trigger].u_int;
+ mp_obj_t wake_obj = args[ARG_wake].u_obj;
+
+ if ((trigger == GPIO_PIN_INTR_LOLEVEL || trigger == GPIO_PIN_INTR_HILEVEL) && wake_obj != mp_const_none) {
+ mp_int_t wake;
+ if (mp_obj_get_int_maybe(wake_obj, &wake)) {
+ if (wake < 2 || wake > 7) {
+ mp_raise_ValueError("bad wake value");
+ }
+ } else {
+ mp_raise_ValueError("bad wake value");
+ }
+
+ if (machine_rtc_config.wake_on_touch) { // not compatible
+ mp_raise_ValueError("no resources");
+ }
+
+ if (!RTC_IS_VALID_EXT_PIN(self->id)) {
+ mp_raise_ValueError("invalid pin for wake");
+ }
+
+ if (machine_rtc_config.ext0_pin == -1) {
+ machine_rtc_config.ext0_pin = self->id;
+ } else if (machine_rtc_config.ext0_pin != self->id) {
+ mp_raise_ValueError("no resources");
+ }
+
+ machine_rtc_config.ext0_level = trigger == GPIO_PIN_INTR_LOLEVEL ? 0 : 1;
+ machine_rtc_config.ext0_wake_types = wake;
+ } else {
+ if (machine_rtc_config.ext0_pin == self->id) {
+ machine_rtc_config.ext0_pin = -1;
+ }
+
+ if (handler == mp_const_none) {
+ handler = MP_OBJ_NULL;
+ trigger = 0;
+ }
+ gpio_isr_handler_remove(self->id);
+ MP_STATE_PORT(machine_pin_irq_handler)[self->id] = handler;
+ gpio_set_intr_type(self->id, trigger);
+ gpio_isr_handler_add(self->id, machine_pin_isr_handler, (void*)self);
+ }
+ }
+
+ // return the irq object
+ return MP_OBJ_FROM_PTR(&machine_pin_irq_object[self->id]);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_pin_irq_obj, 1, machine_pin_irq);
+
+STATIC const mp_rom_map_elem_t machine_pin_locals_dict_table[] = {
+ // instance methods
+ { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&machine_pin_init_obj) },
+ { MP_ROM_QSTR(MP_QSTR_value), MP_ROM_PTR(&machine_pin_value_obj) },
+ { MP_ROM_QSTR(MP_QSTR_irq), MP_ROM_PTR(&machine_pin_irq_obj) },
+
+ // class constants
+ { MP_ROM_QSTR(MP_QSTR_IN), MP_ROM_INT(GPIO_MODE_INPUT) },
+ { MP_ROM_QSTR(MP_QSTR_OUT), MP_ROM_INT(GPIO_MODE_INPUT_OUTPUT) },
+ { MP_ROM_QSTR(MP_QSTR_OPEN_DRAIN), MP_ROM_INT(GPIO_MODE_INPUT_OUTPUT_OD) },
+ { MP_ROM_QSTR(MP_QSTR_PULL_UP), MP_ROM_INT(GPIO_PULLUP_ONLY) },
+ { MP_ROM_QSTR(MP_QSTR_PULL_DOWN), MP_ROM_INT(GPIO_PULLDOWN_ONLY) },
+ { MP_ROM_QSTR(MP_QSTR_IRQ_RISING), MP_ROM_INT(GPIO_PIN_INTR_POSEDGE) },
+ { MP_ROM_QSTR(MP_QSTR_IRQ_FALLING), MP_ROM_INT(GPIO_PIN_INTR_NEGEDGE) },
+ { MP_ROM_QSTR(MP_QSTR_WAKE_LOW), MP_ROM_INT(GPIO_PIN_INTR_LOLEVEL) },
+ { MP_ROM_QSTR(MP_QSTR_WAKE_HIGH), MP_ROM_INT(GPIO_PIN_INTR_HILEVEL) },
+};
+
+STATIC mp_uint_t pin_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) {
+ (void)errcode;
+ machine_pin_obj_t *self = self_in;
+
+ switch (request) {
+ case MP_PIN_READ: {
+ return gpio_get_level(self->id);
+ }
+ case MP_PIN_WRITE: {
+ gpio_set_level(self->id, arg);
+ return 0;
+ }
+ }
+ return -1;
+}
+
+STATIC MP_DEFINE_CONST_DICT(machine_pin_locals_dict, machine_pin_locals_dict_table);
+
+STATIC const mp_pin_p_t pin_pin_p = {
+ .ioctl = pin_ioctl,
+};
+
+const mp_obj_type_t machine_pin_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_Pin,
+ .print = machine_pin_print,
+ .make_new = mp_pin_make_new,
+ .call = machine_pin_call,
+ .protocol = &pin_pin_p,
+ .locals_dict = (mp_obj_t)&machine_pin_locals_dict,
+};
+
+/******************************************************************************/
+// Pin IRQ object
+
+STATIC const mp_obj_type_t machine_pin_irq_type;
+
+STATIC const machine_pin_irq_obj_t machine_pin_irq_object[] = {
+ {{&machine_pin_irq_type}, GPIO_NUM_0},
+ {{&machine_pin_irq_type}, GPIO_NUM_1},
+ {{&machine_pin_irq_type}, GPIO_NUM_2},
+ {{&machine_pin_irq_type}, GPIO_NUM_3},
+ {{&machine_pin_irq_type}, GPIO_NUM_4},
+ {{&machine_pin_irq_type}, GPIO_NUM_5},
+ {{&machine_pin_irq_type}, GPIO_NUM_6},
+ {{&machine_pin_irq_type}, GPIO_NUM_7},
+ {{&machine_pin_irq_type}, GPIO_NUM_8},
+ {{&machine_pin_irq_type}, GPIO_NUM_9},
+ {{&machine_pin_irq_type}, GPIO_NUM_10},
+ {{&machine_pin_irq_type}, GPIO_NUM_11},
+ {{&machine_pin_irq_type}, GPIO_NUM_12},
+ {{&machine_pin_irq_type}, GPIO_NUM_13},
+ {{&machine_pin_irq_type}, GPIO_NUM_14},
+ {{&machine_pin_irq_type}, GPIO_NUM_15},
+ {{&machine_pin_irq_type}, GPIO_NUM_16},
+ {{&machine_pin_irq_type}, GPIO_NUM_17},
+ {{&machine_pin_irq_type}, GPIO_NUM_18},
+ {{&machine_pin_irq_type}, GPIO_NUM_19},
+ {{NULL}, -1},
+ {{&machine_pin_irq_type}, GPIO_NUM_21},
+ {{&machine_pin_irq_type}, GPIO_NUM_22},
+ {{&machine_pin_irq_type}, GPIO_NUM_23},
+ {{NULL}, -1},
+ {{&machine_pin_irq_type}, GPIO_NUM_25},
+ {{&machine_pin_irq_type}, GPIO_NUM_26},
+ {{&machine_pin_irq_type}, GPIO_NUM_27},
+ {{NULL}, -1},
+ {{NULL}, -1},
+ {{NULL}, -1},
+ {{NULL}, -1},
+ {{&machine_pin_irq_type}, GPIO_NUM_32},
+ {{&machine_pin_irq_type}, GPIO_NUM_33},
+ {{&machine_pin_irq_type}, GPIO_NUM_34},
+ {{&machine_pin_irq_type}, GPIO_NUM_35},
+ {{&machine_pin_irq_type}, GPIO_NUM_36},
+ {{&machine_pin_irq_type}, GPIO_NUM_37},
+ {{&machine_pin_irq_type}, GPIO_NUM_38},
+ {{&machine_pin_irq_type}, GPIO_NUM_39},
+};
+
+STATIC mp_obj_t machine_pin_irq_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {
+ machine_pin_irq_obj_t *self = self_in;
+ mp_arg_check_num(n_args, n_kw, 0, 0, false);
+ machine_pin_isr_handler((void*)&machine_pin_obj[self->id]);
+ return mp_const_none;
+}
+
+STATIC mp_obj_t machine_pin_irq_trigger(size_t n_args, const mp_obj_t *args) {
+ machine_pin_irq_obj_t *self = args[0];
+ uint32_t orig_trig = GPIO.pin[self->id].int_type;
+ if (n_args == 2) {
+ // set trigger
+ gpio_set_intr_type(self->id, mp_obj_get_int(args[1]));
+ }
+ // return original trigger value
+ return MP_OBJ_NEW_SMALL_INT(orig_trig);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_pin_irq_trigger_obj, 1, 2, machine_pin_irq_trigger);
+
+STATIC const mp_rom_map_elem_t machine_pin_irq_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_trigger), MP_ROM_PTR(&machine_pin_irq_trigger_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(machine_pin_irq_locals_dict, machine_pin_irq_locals_dict_table);
+
+STATIC const mp_obj_type_t machine_pin_irq_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_IRQ,
+ .call = machine_pin_irq_call,
+ .locals_dict = (mp_obj_dict_t*)&machine_pin_irq_locals_dict,
+};
diff --git a/ports/esp32/machine_pwm.c b/ports/esp32/machine_pwm.c
new file mode 100644
index 000000000..4d6c59f0f
--- /dev/null
+++ b/ports/esp32/machine_pwm.c
@@ -0,0 +1,277 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include <stdio.h>
+#include "driver/ledc.h"
+#include "esp_err.h"
+
+#include "py/nlr.h"
+#include "py/runtime.h"
+#include "modmachine.h"
+#include "mphalport.h"
+
+// Forward dec'l
+extern const mp_obj_type_t machine_pwm_type;
+
+typedef struct _esp32_pwm_obj_t {
+ mp_obj_base_t base;
+ gpio_num_t pin;
+ uint8_t active;
+ uint8_t channel;
+} esp32_pwm_obj_t;
+
+// Which channel has which GPIO pin assigned?
+// (-1 if not assigned)
+STATIC int chan_gpio[LEDC_CHANNEL_MAX];
+
+// Params for PW operation
+// 5khz
+#define PWFREQ (5000)
+// High speed mode
+#define PWMODE (LEDC_HIGH_SPEED_MODE)
+// 10-bit resolution (compatible with esp8266 PWM)
+#define PWRES (LEDC_TIMER_10_BIT)
+// Timer 1
+#define PWTIMER (LEDC_TIMER_1)
+
+// Config of timer upon which we run all PWM'ed GPIO pins
+STATIC bool pwm_inited = false;
+STATIC ledc_timer_config_t timer_cfg = {
+ .bit_num = PWRES,
+ .freq_hz = PWFREQ,
+ .speed_mode = PWMODE,
+ .timer_num = PWTIMER
+};
+
+STATIC void pwm_init(void) {
+
+ // Initial condition: no channels assigned
+ for (int x = 0; x < LEDC_CHANNEL_MAX; ++x) {
+ chan_gpio[x] = -1;
+ }
+
+ // Init with default timer params
+ ledc_timer_config(&timer_cfg);
+}
+
+STATIC int set_freq(int newval) {
+ int oval = timer_cfg.freq_hz;
+
+ timer_cfg.freq_hz = newval;
+ if (ledc_timer_config(&timer_cfg) != ESP_OK) {
+ timer_cfg.freq_hz = oval;
+ return 0;
+ }
+ return 1;
+}
+
+/******************************************************************************/
+
+// MicroPython bindings for PWM
+
+STATIC void esp32_pwm_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
+ esp32_pwm_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ mp_printf(print, "PWM(%u", self->pin);
+ if (self->active) {
+ mp_printf(print, ", freq=%u, duty=%u", timer_cfg.freq_hz,
+ ledc_get_duty(PWMODE, self->channel));
+ }
+ mp_printf(print, ")");
+}
+
+STATIC void esp32_pwm_init_helper(esp32_pwm_obj_t *self,
+ size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum { ARG_freq, ARG_duty };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_freq, MP_ARG_INT, {.u_int = -1} },
+ { MP_QSTR_duty, MP_ARG_INT, {.u_int = -1} },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args, pos_args, kw_args,
+ MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ int channel;
+ int avail = -1;
+
+ // Find a free PWM channel, also spot if our pin is
+ // already mentioned.
+ for (channel = 0; channel < LEDC_CHANNEL_MAX; ++channel) {
+ if (chan_gpio[channel] == self->pin) {
+ break;
+ }
+ if ((avail == -1) && (chan_gpio[channel] == -1)) {
+ avail = channel;
+ }
+ }
+ if (channel >= LEDC_CHANNEL_MAX) {
+ if (avail == -1) {
+ mp_raise_ValueError("out of PWM channels");
+ }
+ channel = avail;
+ }
+ self->channel = channel;
+
+ // New PWM assignment
+ self->active = 1;
+ if (chan_gpio[channel] == -1) {
+ ledc_channel_config_t cfg = {
+ .channel = channel,
+ .duty = (1 << PWRES) / 2,
+ .gpio_num = self->pin,
+ .intr_type = LEDC_INTR_DISABLE,
+ .speed_mode = PWMODE,
+ .timer_sel = PWTIMER,
+ };
+ if (ledc_channel_config(&cfg) != ESP_OK) {
+ nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError,
+ "PWM not supported on pin %d", self->pin));
+ }
+ chan_gpio[channel] = self->pin;
+ }
+
+ // Maybe change PWM timer
+ int tval = args[ARG_freq].u_int;
+ if (tval != -1) {
+ if (tval != timer_cfg.freq_hz) {
+ if (!set_freq(tval)) {
+ nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError,
+ "Bad frequency %d", tval));
+ }
+ }
+ }
+
+ // Set duty cycle?
+ int dval = args[ARG_duty].u_int;
+ if (dval != -1) {
+ dval &= ((1 << PWRES)-1);
+ ledc_set_duty(PWMODE, channel, dval);
+ ledc_update_duty(PWMODE, channel);
+ }
+}
+
+STATIC mp_obj_t esp32_pwm_make_new(const mp_obj_type_t *type,
+ size_t n_args, size_t n_kw, const mp_obj_t *args) {
+ mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true);
+ gpio_num_t pin_id = machine_pin_get_id(args[0]);
+
+ // create PWM object from the given pin
+ esp32_pwm_obj_t *self = m_new_obj(esp32_pwm_obj_t);
+ self->base.type = &machine_pwm_type;
+ self->pin = pin_id;
+ self->active = 0;
+ self->channel = -1;
+
+ // start the PWM subsystem if it's not already running
+ if (!pwm_inited) {
+ pwm_init();
+ pwm_inited = true;
+ }
+
+ // start the PWM running for this channel
+ mp_map_t kw_args;
+ mp_map_init_fixed_table(&kw_args, n_kw, args + n_args);
+ esp32_pwm_init_helper(self, n_args - 1, args + 1, &kw_args);
+
+ return MP_OBJ_FROM_PTR(self);
+}
+
+STATIC mp_obj_t esp32_pwm_init(size_t n_args,
+ const mp_obj_t *args, mp_map_t *kw_args) {
+ esp32_pwm_init_helper(args[0], n_args - 1, args + 1, kw_args);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_KW(esp32_pwm_init_obj, 1, esp32_pwm_init);
+
+STATIC mp_obj_t esp32_pwm_deinit(mp_obj_t self_in) {
+ esp32_pwm_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ int chan = self->channel;
+
+ // Valid channel?
+ if ((chan >= 0) && (chan < LEDC_CHANNEL_MAX)) {
+ // Mark it unused, and tell the hardware to stop routing
+ chan_gpio[chan] = -1;
+ ledc_stop(PWMODE, chan, 0);
+ self->active = 0;
+ self->channel = -1;
+ }
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp32_pwm_deinit_obj, esp32_pwm_deinit);
+
+STATIC mp_obj_t esp32_pwm_freq(size_t n_args, const mp_obj_t *args) {
+ if (n_args == 1) {
+ // get
+ return MP_OBJ_NEW_SMALL_INT(timer_cfg.freq_hz);
+ }
+
+ // set
+ int tval = mp_obj_get_int(args[1]);
+ if (!set_freq(tval)) {
+ nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError,
+ "Bad frequency %d", tval));
+ }
+ return mp_const_none;
+}
+
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp32_pwm_freq_obj, 1, 2, esp32_pwm_freq);
+
+STATIC mp_obj_t esp32_pwm_duty(size_t n_args, const mp_obj_t *args) {
+ esp32_pwm_obj_t *self = MP_OBJ_TO_PTR(args[0]);
+ int duty;
+
+ if (n_args == 1) {
+ // get
+ duty = ledc_get_duty(PWMODE, self->channel);
+ return MP_OBJ_NEW_SMALL_INT(duty);
+ }
+
+ // set
+ duty = mp_obj_get_int(args[1]);
+ duty &= ((1 << PWRES)-1);
+ ledc_set_duty(PWMODE, self->channel, duty);
+ ledc_update_duty(PWMODE, self->channel);
+
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp32_pwm_duty_obj,
+ 1, 2, esp32_pwm_duty);
+
+STATIC const mp_rom_map_elem_t esp32_pwm_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&esp32_pwm_init_obj) },
+ { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&esp32_pwm_deinit_obj) },
+ { MP_ROM_QSTR(MP_QSTR_freq), MP_ROM_PTR(&esp32_pwm_freq_obj) },
+ { MP_ROM_QSTR(MP_QSTR_duty), MP_ROM_PTR(&esp32_pwm_duty_obj) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(esp32_pwm_locals_dict,
+ esp32_pwm_locals_dict_table);
+
+const mp_obj_type_t machine_pwm_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_PWM,
+ .print = esp32_pwm_print,
+ .make_new = esp32_pwm_make_new,
+ .locals_dict = (mp_obj_dict_t*)&esp32_pwm_locals_dict,
+};
diff --git a/ports/esp32/machine_rtc.c b/ports/esp32/machine_rtc.c
new file mode 100644
index 000000000..b17932da5
--- /dev/null
+++ b/ports/esp32/machine_rtc.c
@@ -0,0 +1,162 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 "Eric Poulsen" <eric@zyxod.com>
+ * Copyright (c) 2017 "Tom Manning" <tom@manningetal.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include <time.h>
+#include <sys/time.h>
+#include "driver/gpio.h"
+
+#include "py/nlr.h"
+#include "py/obj.h"
+#include "py/runtime.h"
+#include "py/mphal.h"
+#include "timeutils.h"
+#include "modmachine.h"
+#include "machine_rtc.h"
+
+typedef struct _machine_rtc_obj_t {
+ mp_obj_base_t base;
+} machine_rtc_obj_t;
+
+#define MEM_MAGIC 0x75507921
+/* There is 8K of rtc_slow_memory, but some is used by the system software
+ If the USER_MAXLEN is set to high, the following compile error will happen:
+ region `rtc_slow_seg' overflowed by N bytes
+ The current system software allows almost 4096 to be used.
+ To avoid running into issues if the system software uses more, 2048 was picked as a max length
+*/
+#define MEM_USER_MAXLEN 2048
+RTC_DATA_ATTR uint32_t rtc_user_mem_magic;
+RTC_DATA_ATTR uint32_t rtc_user_mem_len;
+RTC_DATA_ATTR uint8_t rtc_user_mem_data[MEM_USER_MAXLEN];
+
+// singleton RTC object
+STATIC const machine_rtc_obj_t machine_rtc_obj = {{&machine_rtc_type}};
+
+machine_rtc_config_t machine_rtc_config = {
+ .ext1_pins = 0,
+ .ext0_pin = -1
+ };
+
+STATIC mp_obj_t machine_rtc_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
+ // check arguments
+ mp_arg_check_num(n_args, n_kw, 0, 0, false);
+
+ // return constant object
+ return (mp_obj_t)&machine_rtc_obj;
+}
+
+STATIC mp_obj_t machine_rtc_datetime_helper(mp_uint_t n_args, const mp_obj_t *args) {
+ if (n_args == 1) {
+ // Get time
+
+ struct timeval tv;
+
+ gettimeofday(&tv, NULL);
+ timeutils_struct_time_t tm;
+
+ timeutils_seconds_since_2000_to_struct_time(tv.tv_sec, &tm);
+
+ mp_obj_t tuple[8] = {
+ mp_obj_new_int(tm.tm_year),
+ mp_obj_new_int(tm.tm_mon),
+ mp_obj_new_int(tm.tm_mday),
+ mp_obj_new_int(tm.tm_wday),
+ mp_obj_new_int(tm.tm_hour),
+ mp_obj_new_int(tm.tm_min),
+ mp_obj_new_int(tm.tm_sec),
+ mp_obj_new_int(tv.tv_usec)
+ };
+
+ return mp_obj_new_tuple(8, tuple);
+ } else {
+ // Set time
+
+ mp_obj_t *items;
+ mp_obj_get_array_fixed_n(args[1], 8, &items);
+
+ struct timeval tv = {0};
+ tv.tv_sec = timeutils_seconds_since_2000(mp_obj_get_int(items[0]), mp_obj_get_int(items[1]), mp_obj_get_int(items[2]), mp_obj_get_int(items[4]), mp_obj_get_int(items[5]), mp_obj_get_int(items[6]));
+ settimeofday(&tv, NULL);
+
+ return mp_const_none;
+ }
+}
+STATIC mp_obj_t machine_rtc_datetime(mp_uint_t n_args, const mp_obj_t *args) {
+ return machine_rtc_datetime_helper(n_args, args);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_rtc_datetime_obj, 1, 2, machine_rtc_datetime);
+
+STATIC mp_obj_t machine_rtc_init(mp_obj_t self_in, mp_obj_t date) {
+ mp_obj_t args[2] = {self_in, date};
+ machine_rtc_datetime_helper(2, args);
+
+ if (rtc_user_mem_magic != MEM_MAGIC) {
+ rtc_user_mem_magic = MEM_MAGIC;
+ rtc_user_mem_len = 0;
+ }
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(machine_rtc_init_obj, machine_rtc_init);
+
+STATIC mp_obj_t machine_rtc_memory(mp_uint_t n_args, const mp_obj_t *args) {
+ if (n_args == 1) {
+ // read RTC memory
+ uint32_t len = rtc_user_mem_len;
+ uint8_t rtcram[MEM_USER_MAXLEN];
+ memcpy( (char *) rtcram, (char *) rtc_user_mem_data, len);
+ return mp_obj_new_bytes(rtcram, len);
+ } else {
+ // write RTC memory
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_READ);
+
+ if (bufinfo.len > MEM_USER_MAXLEN) {
+ mp_raise_ValueError("buffer too long");
+ }
+ memcpy( (char *) rtc_user_mem_data, (char *) bufinfo.buf, bufinfo.len);
+ rtc_user_mem_len = bufinfo.len;
+ return mp_const_none;
+ }
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_rtc_memory_obj, 1, 2, machine_rtc_memory);
+
+STATIC const mp_rom_map_elem_t machine_rtc_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&machine_rtc_datetime_obj) },
+ { MP_ROM_QSTR(MP_QSTR_datetime), MP_ROM_PTR(&machine_rtc_datetime_obj) },
+ { MP_ROM_QSTR(MP_QSTR_memory), MP_ROM_PTR(&machine_rtc_memory_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(machine_rtc_locals_dict, machine_rtc_locals_dict_table);
+
+const mp_obj_type_t machine_rtc_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_RTC,
+ .make_new = machine_rtc_make_new,
+ .locals_dict = (mp_obj_t)&machine_rtc_locals_dict,
+};
diff --git a/ports/esp32/machine_rtc.h b/ports/esp32/machine_rtc.h
new file mode 100644
index 000000000..e34deb9be
--- /dev/null
+++ b/ports/esp32/machine_rtc.h
@@ -0,0 +1,44 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 "Eric Poulsen" <eric@zyxod.com>
+ * Copyright (c) 2017 "Tom Manning" <tom@manningetal.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_ESP32_MACHINE_RTC_H
+#define MICROPY_INCLUDED_ESP32_MACHINE_RTC_H
+
+#include "modmachine.h"
+
+typedef struct {
+ uint64_t ext1_pins; // set bit == pin#
+ int8_t ext0_pin; // just the pin#, -1 == None
+ bool wake_on_touch : 1;
+ bool ext0_level : 1;
+ wake_type_t ext0_wake_types;
+ bool ext1_level : 1;
+} machine_rtc_config_t;
+
+extern machine_rtc_config_t machine_rtc_config;
+
+#endif
diff --git a/ports/esp32/machine_timer.c b/ports/esp32/machine_timer.c
new file mode 100644
index 000000000..235a502bd
--- /dev/null
+++ b/ports/esp32/machine_timer.c
@@ -0,0 +1,192 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * Development of the code in this file was sponsored by Microbric Pty Ltd
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2013-2015 Damien P. George
+ * Copyright (c) 2016 Paul Sokolovsky
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+
+#include "driver/timer.h"
+#include "py/obj.h"
+#include "py/runtime.h"
+#include "modmachine.h"
+
+#define TIMER_INTR_SEL TIMER_INTR_LEVEL
+#define TIMER_DIVIDER 40000
+#define TIMER_SCALE (TIMER_BASE_CLK / TIMER_DIVIDER)
+
+#define TIMER_FLAGS 0
+
+typedef struct _machine_timer_obj_t {
+ mp_obj_base_t base;
+ mp_uint_t group;
+ mp_uint_t index;
+
+ mp_uint_t repeat;
+ mp_uint_t period;
+
+ mp_obj_t callback;
+
+ intr_handle_t handle;
+} machine_timer_obj_t;
+
+const mp_obj_type_t machine_timer_type;
+
+STATIC esp_err_t check_esp_err(esp_err_t code) {
+ if (code) {
+ mp_raise_OSError(code);
+ }
+
+ return code;
+}
+
+STATIC void machine_timer_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
+ machine_timer_obj_t *self = self_in;
+
+ timer_config_t config;
+ mp_printf(print, "Timer(%p; ", self);
+
+ timer_get_config(self->group, self->index, &config);
+
+ mp_printf(print, "alarm_en=%d, ", config.alarm_en);
+ mp_printf(print, "auto_reload=%d, ", config.auto_reload);
+ mp_printf(print, "counter_en=%d)", config.counter_en);
+}
+
+STATIC mp_obj_t machine_timer_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
+ mp_arg_check_num(n_args, n_kw, 1, 1, false);
+ machine_timer_obj_t *self = m_new_obj(machine_timer_obj_t);
+ self->base.type = &machine_timer_type;
+
+ self->group = (mp_obj_get_int(args[0]) >> 1) & 1;
+ self->index = mp_obj_get_int(args[0]) & 1;
+
+ return self;
+}
+
+STATIC void machine_timer_disable(machine_timer_obj_t *self) {
+ if (self->handle) {
+ timer_pause(self->group, self->index);
+ esp_intr_free(self->handle);
+ self->handle = NULL;
+ }
+}
+
+STATIC void machine_timer_isr(void *self_in) {
+ machine_timer_obj_t *self = self_in;
+ timg_dev_t *device = self->group ? &(TIMERG1) : &(TIMERG0);
+
+ device->hw_timer[self->index].update = 1;
+ if (self->index) {
+ device->int_clr_timers.t1 = 1;
+ } else {
+ device->int_clr_timers.t0 = 1;
+ }
+ device->hw_timer[self->index].config.alarm_en = self->repeat;
+
+ mp_sched_schedule(self->callback, self);
+}
+
+STATIC void machine_timer_enable(machine_timer_obj_t *self) {
+ timer_config_t config;
+ config.alarm_en = TIMER_ALARM_EN;
+ config.auto_reload = self->repeat;
+ config.counter_dir = TIMER_COUNT_UP;
+ config.divider = TIMER_DIVIDER;
+ config.intr_type = TIMER_INTR_LEVEL;
+ config.counter_en = TIMER_PAUSE;
+
+ check_esp_err(timer_init(self->group, self->index, &config));
+ check_esp_err(timer_set_counter_value(self->group, self->index, 0x00000000));
+ check_esp_err(timer_set_alarm_value(self->group, self->index, self->period));
+ check_esp_err(timer_enable_intr(self->group, self->index));
+ check_esp_err(timer_isr_register(self->group, self->index, machine_timer_isr, (void*)self, TIMER_FLAGS, &self->handle));
+ check_esp_err(timer_start(self->group, self->index));
+}
+
+STATIC mp_obj_t machine_timer_init_helper(machine_timer_obj_t *self, mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_period, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0xffffffff} },
+ { MP_QSTR_mode, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1} },
+ { MP_QSTR_callback, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
+ };
+
+ machine_timer_disable(self);
+
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ // Timer uses an 80MHz base clock, which is divided by the divider/scalar, we then convert to ms.
+ self->period = (args[0].u_int * TIMER_BASE_CLK) / (1000 * TIMER_DIVIDER);
+ self->repeat = args[1].u_int;
+ self->callback = args[2].u_obj;
+ self->handle = NULL;
+
+ machine_timer_enable(self);
+
+ return mp_const_none;
+}
+
+STATIC mp_obj_t machine_timer_deinit(mp_obj_t self_in) {
+ machine_timer_disable(self_in);
+
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_timer_deinit_obj, machine_timer_deinit);
+
+STATIC mp_obj_t machine_timer_init(mp_uint_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
+ return machine_timer_init_helper(args[0], n_args - 1, args + 1, kw_args);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_timer_init_obj, 1, machine_timer_init);
+
+STATIC mp_obj_t machine_timer_value(mp_obj_t self_in) {
+ machine_timer_obj_t *self = self_in;
+ double result;
+
+ timer_get_counter_time_sec(self->group, self->index, &result);
+
+ return MP_OBJ_NEW_SMALL_INT((mp_uint_t)(result * 1000)); // value in ms
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_timer_value_obj, machine_timer_value);
+
+STATIC const mp_rom_map_elem_t machine_timer_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&machine_timer_deinit_obj) },
+ { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&machine_timer_deinit_obj) },
+ { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&machine_timer_init_obj) },
+ { MP_ROM_QSTR(MP_QSTR_value), MP_ROM_PTR(&machine_timer_value_obj) },
+ { MP_ROM_QSTR(MP_QSTR_ONE_SHOT), MP_ROM_INT(false) },
+ { MP_ROM_QSTR(MP_QSTR_PERIODIC), MP_ROM_INT(true) },
+};
+STATIC MP_DEFINE_CONST_DICT(machine_timer_locals_dict, machine_timer_locals_dict_table);
+
+const mp_obj_type_t machine_timer_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_Timer,
+ .print = machine_timer_print,
+ .make_new = machine_timer_make_new,
+ .locals_dict = (mp_obj_t)&machine_timer_locals_dict,
+};
diff --git a/ports/esp32/machine_touchpad.c b/ports/esp32/machine_touchpad.c
new file mode 100644
index 000000000..96de1a2a1
--- /dev/null
+++ b/ports/esp32/machine_touchpad.c
@@ -0,0 +1,110 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Nick Moore
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+
+#include <stdio.h>
+
+#include "esp_log.h"
+
+#include "driver/gpio.h"
+#include "driver/touch_pad.h"
+
+#include "py/runtime.h"
+#include "py/mphal.h"
+#include "modmachine.h"
+
+typedef struct _mtp_obj_t {
+ mp_obj_base_t base;
+ gpio_num_t gpio_id;
+ touch_pad_t touchpad_id;
+} mtp_obj_t;
+
+STATIC const mtp_obj_t touchpad_obj[] = {
+ {{&machine_touchpad_type}, GPIO_NUM_4, TOUCH_PAD_NUM0},
+ {{&machine_touchpad_type}, GPIO_NUM_0, TOUCH_PAD_NUM1},
+ {{&machine_touchpad_type}, GPIO_NUM_2, TOUCH_PAD_NUM2},
+ {{&machine_touchpad_type}, GPIO_NUM_15, TOUCH_PAD_NUM3},
+ {{&machine_touchpad_type}, GPIO_NUM_13, TOUCH_PAD_NUM4},
+ {{&machine_touchpad_type}, GPIO_NUM_12, TOUCH_PAD_NUM5},
+ {{&machine_touchpad_type}, GPIO_NUM_14, TOUCH_PAD_NUM6},
+ {{&machine_touchpad_type}, GPIO_NUM_27, TOUCH_PAD_NUM7},
+ {{&machine_touchpad_type}, GPIO_NUM_33, TOUCH_PAD_NUM8},
+ {{&machine_touchpad_type}, GPIO_NUM_32, TOUCH_PAD_NUM9},
+};
+
+STATIC mp_obj_t mtp_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw,
+ const mp_obj_t *args) {
+
+ mp_arg_check_num(n_args, n_kw, 1, 1, true);
+ gpio_num_t pin_id = machine_pin_get_id(args[0]);
+ const mtp_obj_t *self = NULL;
+ for (int i = 0; i < MP_ARRAY_SIZE(touchpad_obj); i++) {
+ if (pin_id == touchpad_obj[i].gpio_id) { self = &touchpad_obj[i]; break; }
+ }
+ if (!self) mp_raise_ValueError("invalid pin for touchpad");
+
+ static int initialized = 0;
+ if (!initialized) {
+ touch_pad_init();
+ initialized = 1;
+ }
+ esp_err_t err = touch_pad_config(self->touchpad_id, 0);
+ if (err == ESP_OK) return MP_OBJ_FROM_PTR(self);
+ mp_raise_ValueError("Touch pad error");
+}
+
+STATIC mp_obj_t mtp_config(mp_obj_t self_in, mp_obj_t value_in) {
+ mtp_obj_t *self = self_in;
+ uint16_t value = mp_obj_get_int(value_in);
+ esp_err_t err = touch_pad_config(self->touchpad_id, value);
+ if (err == ESP_OK) return mp_const_none;
+ mp_raise_ValueError("Touch pad error");
+}
+MP_DEFINE_CONST_FUN_OBJ_2(mtp_config_obj, mtp_config);
+
+STATIC mp_obj_t mtp_read(mp_obj_t self_in) {
+ mtp_obj_t *self = self_in;
+ uint16_t value;
+ esp_err_t err = touch_pad_read(self->touchpad_id, &value);
+ if (err == ESP_OK) return MP_OBJ_NEW_SMALL_INT(value);
+ mp_raise_ValueError("Touch pad error");
+}
+MP_DEFINE_CONST_FUN_OBJ_1(mtp_read_obj, mtp_read);
+
+STATIC const mp_rom_map_elem_t mtp_locals_dict_table[] = {
+ // instance methods
+ { MP_ROM_QSTR(MP_QSTR_config), MP_ROM_PTR(&mtp_config_obj) },
+ { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mtp_read_obj) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(mtp_locals_dict, mtp_locals_dict_table);
+
+const mp_obj_type_t machine_touchpad_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_TouchPad,
+ .make_new = mtp_make_new,
+ .locals_dict = (mp_obj_t)&mtp_locals_dict,
+};
diff --git a/ports/esp32/machine_uart.c b/ports/esp32/machine_uart.c
new file mode 100644
index 000000000..474764b1b
--- /dev/null
+++ b/ports/esp32/machine_uart.c
@@ -0,0 +1,357 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+
+#include "driver/uart.h"
+#include "freertos/FreeRTOS.h"
+
+#include "py/runtime.h"
+#include "py/stream.h"
+#include "py/mperrno.h"
+#include "modmachine.h"
+
+typedef struct _machine_uart_obj_t {
+ mp_obj_base_t base;
+ uart_port_t uart_num;
+ uint8_t bits;
+ uint8_t parity;
+ uint8_t stop;
+ int8_t tx;
+ int8_t rx;
+ int8_t rts;
+ int8_t cts;
+ uint16_t timeout; // timeout waiting for first char (in ms)
+ uint16_t timeout_char; // timeout waiting between chars (in ms)
+} machine_uart_obj_t;
+
+STATIC const char *_parity_name[] = {"None", "1", "0"};
+
+/******************************************************************************/
+// MicroPython bindings for UART
+
+STATIC void machine_uart_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
+ machine_uart_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ uint32_t baudrate;
+ uart_get_baudrate(self->uart_num, &baudrate);
+ mp_printf(print, "UART(%u, baudrate=%u, bits=%u, parity=%s, stop=%u, tx=%d, rx=%d, rts=%d, cts=%d, timeout=%u, timeout_char=%u)",
+ self->uart_num, baudrate, self->bits, _parity_name[self->parity],
+ self->stop, self->tx, self->rx, self->rts, self->cts, self->timeout, self->timeout_char);
+}
+
+STATIC void machine_uart_init_helper(machine_uart_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum { ARG_baudrate, ARG_bits, ARG_parity, ARG_stop, ARG_tx, ARG_rx, ARG_rts, ARG_cts, ARG_timeout, ARG_timeout_char };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_baudrate, MP_ARG_INT, {.u_int = 0} },
+ { MP_QSTR_bits, MP_ARG_INT, {.u_int = 0} },
+ { MP_QSTR_parity, MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+ { MP_QSTR_stop, MP_ARG_INT, {.u_int = 0} },
+ { MP_QSTR_tx, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = UART_PIN_NO_CHANGE} },
+ { MP_QSTR_rx, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = UART_PIN_NO_CHANGE} },
+ { MP_QSTR_rts, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = UART_PIN_NO_CHANGE} },
+ { MP_QSTR_cts, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = UART_PIN_NO_CHANGE} },
+ { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
+ { MP_QSTR_timeout_char, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ // wait for all data to be transmitted before changing settings
+ uart_wait_tx_done(self->uart_num, pdMS_TO_TICKS(1000));
+
+ // set baudrate
+ uint32_t baudrate = 115200;
+ if (args[ARG_baudrate].u_int > 0) {
+ uart_set_baudrate(self->uart_num, args[ARG_baudrate].u_int);
+ uart_get_baudrate(self->uart_num, &baudrate);
+ }
+
+ uart_set_pin(self->uart_num, args[ARG_tx].u_int, args[ARG_rx].u_int, args[ARG_rts].u_int, args[ARG_cts].u_int);
+ if (args[ARG_tx].u_int != UART_PIN_NO_CHANGE) {
+ self->tx = args[ARG_tx].u_int;
+ }
+
+ if (args[ARG_rx].u_int != UART_PIN_NO_CHANGE) {
+ self->rx = args[ARG_rx].u_int;
+ }
+
+ if (args[ARG_rts].u_int != UART_PIN_NO_CHANGE) {
+ self->rts = args[ARG_rts].u_int;
+ }
+
+ if (args[ARG_cts].u_int != UART_PIN_NO_CHANGE) {
+ self->cts = args[ARG_cts].u_int;
+ }
+
+ // set data bits
+ switch (args[ARG_bits].u_int) {
+ case 0:
+ break;
+ case 5:
+ uart_set_word_length(self->uart_num, UART_DATA_5_BITS);
+ self->bits = 5;
+ break;
+ case 6:
+ uart_set_word_length(self->uart_num, UART_DATA_6_BITS);
+ self->bits = 6;
+ break;
+ case 7:
+ uart_set_word_length(self->uart_num, UART_DATA_7_BITS);
+ self->bits = 7;
+ break;
+ case 8:
+ uart_set_word_length(self->uart_num, UART_DATA_8_BITS);
+ self->bits = 8;
+ break;
+ default:
+ mp_raise_ValueError("invalid data bits");
+ break;
+ }
+
+ // set parity
+ if (args[ARG_parity].u_obj != MP_OBJ_NULL) {
+ if (args[ARG_parity].u_obj == mp_const_none) {
+ uart_set_parity(self->uart_num, UART_PARITY_DISABLE);
+ self->parity = 0;
+ } else {
+ mp_int_t parity = mp_obj_get_int(args[ARG_parity].u_obj);
+ if (parity & 1) {
+ uart_set_parity(self->uart_num, UART_PARITY_ODD);
+ self->parity = 1;
+ } else {
+ uart_set_parity(self->uart_num, UART_PARITY_EVEN);
+ self->parity = 2;
+ }
+ }
+ }
+
+ // set stop bits
+ switch (args[ARG_stop].u_int) {
+ // FIXME: ESP32 also supports 1.5 stop bits
+ case 0:
+ break;
+ case 1:
+ uart_set_stop_bits(self->uart_num, UART_STOP_BITS_1);
+ self->stop = 1;
+ break;
+ case 2:
+ uart_set_stop_bits(self->uart_num, UART_STOP_BITS_2);
+ self->stop = 2;
+ break;
+ default:
+ mp_raise_ValueError("invalid stop bits");
+ break;
+ }
+
+ // set timeout
+ self->timeout = args[ARG_timeout].u_int;
+
+ // set timeout_char
+ // make sure it is at least as long as a whole character (13 bits to be safe)
+ self->timeout_char = args[ARG_timeout_char].u_int;
+ uint32_t min_timeout_char = 13000 / baudrate + 1;
+ if (self->timeout_char < min_timeout_char) {
+ self->timeout_char = min_timeout_char;
+ }
+}
+
+STATIC mp_obj_t machine_uart_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
+ mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true);
+
+ // get uart id
+ mp_int_t uart_num = mp_obj_get_int(args[0]);
+ if (uart_num < 0 || uart_num >= UART_NUM_MAX) {
+ nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "UART(%d) does not exist", uart_num));
+ }
+
+ // Attempts to use UART0 from Python has resulted in all sorts of fun errors.
+ // FIXME: UART0 is disabled for now.
+ if (uart_num == UART_NUM_0) {
+ nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "UART(%d) is disabled (dedicated to REPL)", uart_num));
+ }
+
+ // Defaults
+ uart_config_t uartcfg = {
+ .baud_rate = 115200,
+ .data_bits = UART_DATA_8_BITS,
+ .parity = UART_PARITY_DISABLE,
+ .stop_bits = UART_STOP_BITS_1,
+ .flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
+ .rx_flow_ctrl_thresh = 0
+ };
+
+ // create instance
+ machine_uart_obj_t *self = m_new_obj(machine_uart_obj_t);
+ self->base.type = &machine_uart_type;
+ self->uart_num = uart_num;
+ self->bits = 8;
+ self->parity = 0;
+ self->stop = 1;
+ self->rts = UART_PIN_NO_CHANGE;
+ self->cts = UART_PIN_NO_CHANGE;
+ self->timeout = 0;
+ self->timeout_char = 0;
+
+ switch (uart_num) {
+ case UART_NUM_0:
+ self->rx = UART_PIN_NO_CHANGE; // GPIO 3
+ self->tx = UART_PIN_NO_CHANGE; // GPIO 1
+ break;
+ case UART_NUM_1:
+ self->rx = 9;
+ self->tx = 10;
+ break;
+ case UART_NUM_2:
+ self->rx = 16;
+ self->tx = 17;
+ break;
+ }
+
+ // Remove any existing configuration
+ uart_driver_delete(self->uart_num);
+
+ // init the peripheral
+ // Setup
+ uart_param_config(self->uart_num, &uartcfg);
+
+ // RX and TX buffers are currently hardcoded at 256 bytes each (IDF minimum).
+ uart_driver_install(uart_num, 256, 256, 0, NULL, 0);
+
+ mp_map_t kw_args;
+ mp_map_init_fixed_table(&kw_args, n_kw, args + n_args);
+ machine_uart_init_helper(self, n_args - 1, args + 1, &kw_args);
+
+ // Make sure pins are connected.
+ uart_set_pin(self->uart_num, self->tx, self->rx, self->rts, self->cts);
+
+ return MP_OBJ_FROM_PTR(self);
+}
+
+STATIC mp_obj_t machine_uart_init(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
+ machine_uart_init_helper(args[0], n_args - 1, args + 1, kw_args);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_KW(machine_uart_init_obj, 1, machine_uart_init);
+
+STATIC mp_obj_t machine_uart_any(mp_obj_t self_in) {
+ machine_uart_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ size_t rxbufsize;
+ uart_get_buffered_data_len(self->uart_num, &rxbufsize);
+ return MP_OBJ_NEW_SMALL_INT(rxbufsize);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_uart_any_obj, machine_uart_any);
+
+STATIC const mp_rom_map_elem_t machine_uart_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&machine_uart_init_obj) },
+
+ { MP_ROM_QSTR(MP_QSTR_any), MP_ROM_PTR(&machine_uart_any_obj) },
+ { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) },
+ { MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) },
+ { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) },
+ { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(machine_uart_locals_dict, machine_uart_locals_dict_table);
+
+STATIC mp_uint_t machine_uart_read(mp_obj_t self_in, void *buf_in, mp_uint_t size, int *errcode) {
+ machine_uart_obj_t *self = MP_OBJ_TO_PTR(self_in);
+
+ // make sure we want at least 1 char
+ if (size == 0) {
+ return 0;
+ }
+
+ TickType_t time_to_wait;
+ if (self->timeout == 0) {
+ time_to_wait = 0;
+ } else {
+ time_to_wait = pdMS_TO_TICKS(self->timeout);
+ }
+
+ int bytes_read = uart_read_bytes(self->uart_num, buf_in, size, time_to_wait);
+
+ if (bytes_read <= 0) {
+ *errcode = MP_EAGAIN;
+ return MP_STREAM_ERROR;
+ }
+
+ return bytes_read;
+}
+
+STATIC mp_uint_t machine_uart_write(mp_obj_t self_in, const void *buf_in, mp_uint_t size, int *errcode) {
+ machine_uart_obj_t *self = MP_OBJ_TO_PTR(self_in);
+
+ int bytes_written = uart_write_bytes(self->uart_num, buf_in, size);
+
+ if (bytes_written < 0) {
+ *errcode = MP_EAGAIN;
+ return MP_STREAM_ERROR;
+ }
+
+ // return number of bytes written
+ return bytes_written;
+}
+
+STATIC mp_uint_t machine_uart_ioctl(mp_obj_t self_in, mp_uint_t request, mp_uint_t arg, int *errcode) {
+ machine_uart_obj_t *self = self_in;
+ mp_uint_t ret;
+ if (request == MP_STREAM_POLL) {
+ mp_uint_t flags = arg;
+ ret = 0;
+ size_t rxbufsize;
+ uart_get_buffered_data_len(self->uart_num, &rxbufsize);
+ if ((flags & MP_STREAM_POLL_RD) && rxbufsize > 0) {
+ ret |= MP_STREAM_POLL_RD;
+ }
+ if ((flags & MP_STREAM_POLL_WR) && 1) { // FIXME: uart_tx_any_room(self->uart_num)
+ ret |= MP_STREAM_POLL_WR;
+ }
+ } else {
+ *errcode = MP_EINVAL;
+ ret = MP_STREAM_ERROR;
+ }
+ return ret;
+}
+
+STATIC const mp_stream_p_t uart_stream_p = {
+ .read = machine_uart_read,
+ .write = machine_uart_write,
+ .ioctl = machine_uart_ioctl,
+ .is_text = false,
+};
+
+const mp_obj_type_t machine_uart_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_UART,
+ .print = machine_uart_print,
+ .make_new = machine_uart_make_new,
+ .getiter = mp_identity_getiter,
+ .iternext = mp_stream_unbuffered_iter,
+ .protocol = &uart_stream_p,
+ .locals_dict = (mp_obj_dict_t*)&machine_uart_locals_dict,
+};
diff --git a/ports/esp32/machine_wdt.c b/ports/esp32/machine_wdt.c
new file mode 100644
index 000000000..88a58f056
--- /dev/null
+++ b/ports/esp32/machine_wdt.c
@@ -0,0 +1,78 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016 Paul Sokolovsky
+ * Copyright (c) 2017 Eric Poulsen
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <string.h>
+
+#include "py/nlr.h"
+#include "py/obj.h"
+#include "py/runtime.h"
+
+#include "esp_task_wdt.h"
+
+const mp_obj_type_t machine_wdt_type;
+
+typedef struct _machine_wdt_obj_t {
+ mp_obj_base_t base;
+} machine_wdt_obj_t;
+
+STATIC machine_wdt_obj_t wdt_default = {{&machine_wdt_type}};
+
+STATIC mp_obj_t machine_wdt_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {
+ mp_arg_check_num(n_args, n_kw, 0, 1, false);
+
+ mp_int_t id = 0;
+ if (n_args > 0) {
+ id = mp_obj_get_int(args[0]);
+ }
+
+ switch (id) {
+ case 0:
+ esp_task_wdt_add(NULL);
+ return &wdt_default;
+ default:
+ mp_raise_ValueError(NULL);
+ }
+}
+
+STATIC mp_obj_t machine_wdt_feed(mp_obj_t self_in) {
+ (void)self_in;
+ esp_task_wdt_reset();
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_wdt_feed_obj, machine_wdt_feed);
+
+STATIC const mp_rom_map_elem_t machine_wdt_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_feed), MP_ROM_PTR(&machine_wdt_feed_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(machine_wdt_locals_dict, machine_wdt_locals_dict_table);
+
+const mp_obj_type_t machine_wdt_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_WDT,
+ .make_new = machine_wdt_make_new,
+ .locals_dict = (mp_obj_t)&machine_wdt_locals_dict,
+};
diff --git a/ports/esp32/main.c b/ports/esp32/main.c
new file mode 100644
index 000000000..acbbfdccc
--- /dev/null
+++ b/ports/esp32/main.c
@@ -0,0 +1,146 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * Development of the code in this file was sponsored by Microbric Pty Ltd
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include "esp_system.h"
+#include "nvs_flash.h"
+#include "esp_task.h"
+#include "soc/cpu.h"
+#include "esp_log.h"
+
+#include "py/stackctrl.h"
+#include "py/nlr.h"
+#include "py/compile.h"
+#include "py/runtime.h"
+#include "py/repl.h"
+#include "py/gc.h"
+#include "py/mphal.h"
+#include "lib/mp-readline/readline.h"
+#include "lib/utils/pyexec.h"
+#include "uart.h"
+#include "modmachine.h"
+#include "modnetwork.h"
+#include "mpthreadport.h"
+
+// MicroPython runs as a task under FreeRTOS
+#define MP_TASK_PRIORITY (ESP_TASK_PRIO_MIN + 1)
+#define MP_TASK_STACK_SIZE (16 * 1024)
+#define MP_TASK_STACK_LEN (MP_TASK_STACK_SIZE / sizeof(StackType_t))
+
+STATIC StaticTask_t mp_task_tcb;
+STATIC StackType_t mp_task_stack[MP_TASK_STACK_LEN] __attribute__((aligned (8)));
+
+int vprintf_null(const char *format, va_list ap) {
+ // do nothing: this is used as a log target during raw repl mode
+ return 0;
+}
+
+void mp_task(void *pvParameter) {
+ volatile uint32_t sp = (uint32_t)get_sp();
+ #if MICROPY_PY_THREAD
+ mp_thread_init(&mp_task_stack[0], MP_TASK_STACK_LEN);
+ #endif
+ uart_init();
+
+ // Allocate the uPy heap using malloc and get the largest available region
+ size_t mp_task_heap_size = heap_caps_get_largest_free_block(MALLOC_CAP_8BIT);
+ void *mp_task_heap = malloc(mp_task_heap_size);
+
+soft_reset:
+ // initialise the stack pointer for the main thread
+ mp_stack_set_top((void *)sp);
+ mp_stack_set_limit(MP_TASK_STACK_SIZE - 1024);
+ gc_init(mp_task_heap, mp_task_heap + mp_task_heap_size);
+ mp_init();
+ mp_obj_list_init(mp_sys_path, 0);
+ mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR_));
+ mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR__slash_lib));
+ mp_obj_list_init(mp_sys_argv, 0);
+ readline_init0();
+
+ // initialise peripherals
+ machine_pins_init();
+
+ // run boot-up scripts
+ pyexec_frozen_module("_boot.py");
+ pyexec_file("boot.py");
+ if (pyexec_mode_kind == PYEXEC_MODE_FRIENDLY_REPL) {
+ pyexec_file("main.py");
+ }
+
+ for (;;) {
+ if (pyexec_mode_kind == PYEXEC_MODE_RAW_REPL) {
+ vprintf_like_t vprintf_log = esp_log_set_vprintf(vprintf_null);
+ if (pyexec_raw_repl() != 0) {
+ break;
+ }
+ esp_log_set_vprintf(vprintf_log);
+ } else {
+ if (pyexec_friendly_repl() != 0) {
+ break;
+ }
+ }
+ }
+
+ #if MICROPY_PY_THREAD
+ mp_thread_deinit();
+ #endif
+
+ gc_sweep_all();
+
+ mp_hal_stdout_tx_str("PYB: soft reboot\r\n");
+
+ // deinitialise peripherals
+ machine_pins_deinit();
+ usocket_events_deinit();
+
+ mp_deinit();
+ fflush(stdout);
+ goto soft_reset;
+}
+
+void app_main(void) {
+ nvs_flash_init();
+ xTaskCreateStaticPinnedToCore(mp_task, "mp_task", MP_TASK_STACK_LEN, NULL, MP_TASK_PRIORITY,
+ &mp_task_stack[0], &mp_task_tcb, 0);
+}
+
+void nlr_jump_fail(void *val) {
+ printf("NLR jump failed, val=%p\n", val);
+ esp_restart();
+}
+
+// modussl_mbedtls uses this function but it's not enabled in ESP IDF
+void mbedtls_debug_set_threshold(int threshold) {
+ (void)threshold;
+}
diff --git a/ports/esp32/makeimg.py b/ports/esp32/makeimg.py
new file mode 100644
index 000000000..aeedbff7e
--- /dev/null
+++ b/ports/esp32/makeimg.py
@@ -0,0 +1,25 @@
+import sys
+
+OFFSET_BOOTLOADER = 0x1000
+OFFSET_PARTITIONS = 0x8000
+OFFSET_APPLICATION = 0x10000
+
+files_in = [
+ ('bootloader', OFFSET_BOOTLOADER, sys.argv[1]),
+ ('partitions', OFFSET_PARTITIONS, sys.argv[2]),
+ ('application', OFFSET_APPLICATION, sys.argv[3]),
+]
+file_out = sys.argv[4]
+
+cur_offset = OFFSET_BOOTLOADER
+with open(file_out, 'wb') as fout:
+ for name, offset, file_in in files_in:
+ assert offset >= cur_offset
+ fout.write(b'\xff' * (offset - cur_offset))
+ cur_offset = offset
+ with open(file_in, 'rb') as fin:
+ data = fin.read()
+ fout.write(data)
+ cur_offset += len(data)
+ print('%-12s% 8d' % (name, len(data)))
+ print('%-12s% 8d' % ('total', cur_offset))
diff --git a/ports/esp32/memory.h b/ports/esp32/memory.h
new file mode 100644
index 000000000..f3777b0e3
--- /dev/null
+++ b/ports/esp32/memory.h
@@ -0,0 +1,2 @@
+// this is needed for extmod/crypto-algorithms/sha256.c
+#include <string.h>
diff --git a/ports/esp32/modesp.c b/ports/esp32/modesp.c
new file mode 100644
index 000000000..e614f77a6
--- /dev/null
+++ b/ports/esp32/modesp.c
@@ -0,0 +1,157 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * Development of the code in this file was sponsored by Microbric Pty Ltd
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2015 Paul Sokolovsky
+ * Copyright (c) 2016 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdio.h>
+
+#include "rom/gpio.h"
+#include "esp_log.h"
+#include "esp_spi_flash.h"
+
+#include "py/runtime.h"
+#include "py/mperrno.h"
+#include "py/mphal.h"
+#include "drivers/dht/dht.h"
+#include "modesp.h"
+
+STATIC mp_obj_t esp_osdebug(size_t n_args, const mp_obj_t *args) {
+ esp_log_level_t level = LOG_LOCAL_LEVEL;
+ if (n_args == 2) {
+ level = mp_obj_get_int(args[1]);
+ }
+ if (args[0] == mp_const_none) {
+ // Disable logging
+ esp_log_level_set("*", ESP_LOG_ERROR);
+ } else {
+ // Enable logging at the given level
+ // TODO args[0] should set the UART to which debug is sent
+ esp_log_level_set("*", level);
+ }
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp_osdebug_obj, 1, 2, esp_osdebug);
+
+STATIC mp_obj_t esp_flash_read(mp_obj_t offset_in, mp_obj_t buf_in) {
+ mp_int_t offset = mp_obj_get_int(offset_in);
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_WRITE);
+ esp_err_t res = spi_flash_read(offset, bufinfo.buf, bufinfo.len);
+ if (res != ESP_OK) {
+ mp_raise_OSError(MP_EIO);
+ }
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(esp_flash_read_obj, esp_flash_read);
+
+STATIC mp_obj_t esp_flash_write(mp_obj_t offset_in, mp_obj_t buf_in) {
+ mp_int_t offset = mp_obj_get_int(offset_in);
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_READ);
+ esp_err_t res = spi_flash_write(offset, bufinfo.buf, bufinfo.len);
+ if (res != ESP_OK) {
+ mp_raise_OSError(MP_EIO);
+ }
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(esp_flash_write_obj, esp_flash_write);
+
+STATIC mp_obj_t esp_flash_erase(mp_obj_t sector_in) {
+ mp_int_t sector = mp_obj_get_int(sector_in);
+ esp_err_t res = spi_flash_erase_sector(sector);
+ if (res != ESP_OK) {
+ mp_raise_OSError(MP_EIO);
+ }
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp_flash_erase_obj, esp_flash_erase);
+
+STATIC mp_obj_t esp_flash_size(void) {
+ return mp_obj_new_int_from_uint(spi_flash_get_chip_size());
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_0(esp_flash_size_obj, esp_flash_size);
+
+STATIC mp_obj_t esp_flash_user_start(void) {
+ return MP_OBJ_NEW_SMALL_INT(0x200000);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_0(esp_flash_user_start_obj, esp_flash_user_start);
+
+STATIC mp_obj_t esp_gpio_matrix_in(mp_obj_t pin, mp_obj_t sig, mp_obj_t inv) {
+ gpio_matrix_in(mp_obj_get_int(pin), mp_obj_get_int(sig), mp_obj_get_int(inv));
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_3(esp_gpio_matrix_in_obj, esp_gpio_matrix_in);
+
+STATIC mp_obj_t esp_gpio_matrix_out(size_t n_args, const mp_obj_t *args) {
+ (void)n_args;
+ gpio_matrix_out(mp_obj_get_int(args[0]), mp_obj_get_int(args[1]), mp_obj_get_int(args[2]), mp_obj_get_int(args[3]));
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp_gpio_matrix_out_obj, 4, 4, esp_gpio_matrix_out);
+
+STATIC mp_obj_t esp_neopixel_write_(mp_obj_t pin, mp_obj_t buf, mp_obj_t timing) {
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(buf, &bufinfo, MP_BUFFER_READ);
+ esp_neopixel_write(mp_hal_get_pin_obj(pin),
+ (uint8_t*)bufinfo.buf, bufinfo.len, mp_obj_get_int(timing));
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_3(esp_neopixel_write_obj, esp_neopixel_write_);
+
+STATIC const mp_rom_map_elem_t esp_module_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_esp) },
+
+ { MP_ROM_QSTR(MP_QSTR_osdebug), MP_ROM_PTR(&esp_osdebug_obj) },
+
+ { MP_ROM_QSTR(MP_QSTR_flash_read), MP_ROM_PTR(&esp_flash_read_obj) },
+ { MP_ROM_QSTR(MP_QSTR_flash_write), MP_ROM_PTR(&esp_flash_write_obj) },
+ { MP_ROM_QSTR(MP_QSTR_flash_erase), MP_ROM_PTR(&esp_flash_erase_obj) },
+ { MP_ROM_QSTR(MP_QSTR_flash_size), MP_ROM_PTR(&esp_flash_size_obj) },
+ { MP_ROM_QSTR(MP_QSTR_flash_user_start), MP_ROM_PTR(&esp_flash_user_start_obj) },
+
+ { MP_ROM_QSTR(MP_QSTR_gpio_matrix_in), MP_ROM_PTR(&esp_gpio_matrix_in_obj) },
+ { MP_ROM_QSTR(MP_QSTR_gpio_matrix_out), MP_ROM_PTR(&esp_gpio_matrix_out_obj) },
+
+ { MP_ROM_QSTR(MP_QSTR_neopixel_write), MP_ROM_PTR(&esp_neopixel_write_obj) },
+ { MP_ROM_QSTR(MP_QSTR_dht_readinto), MP_ROM_PTR(&dht_readinto_obj) },
+
+ // Constants for second arg of osdebug()
+ { MP_ROM_QSTR(MP_QSTR_LOG_NONE), MP_ROM_INT((mp_uint_t)ESP_LOG_NONE)},
+ { MP_ROM_QSTR(MP_QSTR_LOG_ERROR), MP_ROM_INT((mp_uint_t)ESP_LOG_ERROR)},
+ { MP_ROM_QSTR(MP_QSTR_LOG_WARNING), MP_ROM_INT((mp_uint_t)ESP_LOG_WARN)},
+ { MP_ROM_QSTR(MP_QSTR_LOG_INFO), MP_ROM_INT((mp_uint_t)ESP_LOG_INFO)},
+ { MP_ROM_QSTR(MP_QSTR_LOG_DEBUG), MP_ROM_INT((mp_uint_t)ESP_LOG_DEBUG)},
+ { MP_ROM_QSTR(MP_QSTR_LOG_VERBOSE), MP_ROM_INT((mp_uint_t)ESP_LOG_VERBOSE)},
+};
+
+STATIC MP_DEFINE_CONST_DICT(esp_module_globals, esp_module_globals_table);
+
+const mp_obj_module_t esp_module = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t*)&esp_module_globals,
+};
+
diff --git a/ports/esp32/modesp.h b/ports/esp32/modesp.h
new file mode 100644
index 000000000..a822c02ec
--- /dev/null
+++ b/ports/esp32/modesp.h
@@ -0,0 +1 @@
+void esp_neopixel_write(uint8_t pin, uint8_t *pixels, uint32_t numBytes, uint8_t timing);
diff --git a/ports/esp32/modesp32.c b/ports/esp32/modesp32.c
new file mode 100644
index 000000000..bab78e954
--- /dev/null
+++ b/ports/esp32/modesp32.c
@@ -0,0 +1,141 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 "Eric Poulsen" <eric@zyxod.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include <time.h>
+#include <sys/time.h>
+#include "driver/gpio.h"
+
+#include "py/nlr.h"
+#include "py/obj.h"
+#include "py/runtime.h"
+#include "py/mphal.h"
+#include "timeutils.h"
+#include "modmachine.h"
+#include "machine_rtc.h"
+#include "modesp32.h"
+
+STATIC mp_obj_t esp32_wake_on_touch(const mp_obj_t wake) {
+
+ if (machine_rtc_config.ext0_pin != -1) {
+ mp_raise_ValueError("no resources");
+ }
+ //nlr_raise(mp_obj_new_exception_msg(&mp_type_RuntimeError, "touchpad wakeup not available for this version of ESP-IDF"));
+
+ machine_rtc_config.wake_on_touch = mp_obj_is_true(wake);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp32_wake_on_touch_obj, esp32_wake_on_touch);
+
+STATIC mp_obj_t esp32_wake_on_ext0(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+
+ if (machine_rtc_config.wake_on_touch) {
+ mp_raise_ValueError("no resources");
+ }
+ enum {ARG_pin, ARG_level};
+ const mp_arg_t allowed_args[] = {
+ { MP_QSTR_pin, MP_ARG_OBJ, {.u_obj = mp_obj_new_int(machine_rtc_config.ext0_pin)} },
+ { MP_QSTR_level, MP_ARG_BOOL, {.u_bool = machine_rtc_config.ext0_level} },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ if (args[ARG_pin].u_obj == mp_const_none) {
+ machine_rtc_config.ext0_pin = -1; // "None"
+ } else {
+ gpio_num_t pin_id = machine_pin_get_id(args[ARG_pin].u_obj);
+ if (pin_id != machine_rtc_config.ext0_pin) {
+ if (!RTC_IS_VALID_EXT_PIN(pin_id)) {
+ nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "invalid pin"));
+ }
+ machine_rtc_config.ext0_pin = pin_id;
+ }
+ }
+
+ machine_rtc_config.ext0_level = args[ARG_level].u_bool;
+ machine_rtc_config.ext0_wake_types = MACHINE_WAKE_SLEEP | MACHINE_WAKE_DEEPSLEEP;
+
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(esp32_wake_on_ext0_obj, 0, esp32_wake_on_ext0);
+
+STATIC mp_obj_t esp32_wake_on_ext1(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum {ARG_pins, ARG_level};
+ const mp_arg_t allowed_args[] = {
+ { MP_QSTR_pins, MP_ARG_OBJ, {.u_obj = mp_const_none} },
+ { MP_QSTR_level, MP_ARG_BOOL, {.u_bool = machine_rtc_config.ext1_level} },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+ uint64_t ext1_pins = machine_rtc_config.ext1_pins;
+
+
+ // Check that all pins are allowed
+ if (args[ARG_pins].u_obj != mp_const_none) {
+ mp_uint_t len = 0;
+ mp_obj_t *elem;
+ mp_obj_get_array(args[ARG_pins].u_obj, &len, &elem);
+ ext1_pins = 0;
+
+ for (int i = 0; i < len; i++) {
+
+ gpio_num_t pin_id = machine_pin_get_id(elem[i]);
+ if (!RTC_IS_VALID_EXT_PIN(pin_id)) {
+ nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "invalid pin"));
+ break;
+ }
+ ext1_pins |= (1ll << pin_id);
+ }
+ }
+
+ machine_rtc_config.ext1_level = args[ARG_level].u_bool;
+ machine_rtc_config.ext1_pins = ext1_pins;
+
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(esp32_wake_on_ext1_obj, 0, esp32_wake_on_ext1);
+
+STATIC const mp_rom_map_elem_t esp32_module_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_esp32) },
+
+ { MP_OBJ_NEW_QSTR(MP_QSTR_wake_on_touch), (mp_obj_t)&esp32_wake_on_touch_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_wake_on_ext0), (mp_obj_t)&esp32_wake_on_ext0_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_wake_on_ext1), (mp_obj_t)&esp32_wake_on_ext1_obj },
+
+ { MP_ROM_QSTR(MP_QSTR_ULP), MP_ROM_PTR(&esp32_ulp_type) },
+
+ { MP_OBJ_NEW_QSTR(MP_QSTR_WAKEUP_ALL_LOW), mp_const_false },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_WAKEUP_ANY_HIGH), mp_const_true },
+};
+
+STATIC MP_DEFINE_CONST_DICT(esp32_module_globals, esp32_module_globals_table);
+
+const mp_obj_module_t esp32_module = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t*)&esp32_module_globals,
+};
diff --git a/ports/esp32/modesp32.h b/ports/esp32/modesp32.h
new file mode 100644
index 000000000..1d18cb41f
--- /dev/null
+++ b/ports/esp32/modesp32.h
@@ -0,0 +1,31 @@
+#ifndef MICROPY_INCLUDED_ESP32_MODESP32_H
+#define MICROPY_INCLUDED_ESP32_MODESP32_H
+
+#define RTC_VALID_EXT_PINS \
+( \
+ (1ll << 0) | \
+ (1ll << 2) | \
+ (1ll << 4) | \
+ (1ll << 12) | \
+ (1ll << 13) | \
+ (1ll << 14) | \
+ (1ll << 15) | \
+ (1ll << 25) | \
+ (1ll << 26) | \
+ (1ll << 27) | \
+ (1ll << 32) | \
+ (1ll << 33) | \
+ (1ll << 34) | \
+ (1ll << 35) | \
+ (1ll << 36) | \
+ (1ll << 37) | \
+ (1ll << 38) | \
+ (1ll << 39) \
+)
+
+#define RTC_LAST_EXT_PIN 39
+#define RTC_IS_VALID_EXT_PIN(pin_id) ((1ll << (pin_id)) & RTC_VALID_EXT_PINS)
+
+extern const mp_obj_type_t esp32_ulp_type;
+
+#endif // MICROPY_INCLUDED_ESP32_MODESP32_H
diff --git a/ports/esp32/modmachine.c b/ports/esp32/modmachine.c
new file mode 100644
index 000000000..2d59e137e
--- /dev/null
+++ b/ports/esp32/modmachine.c
@@ -0,0 +1,269 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * Development of the code in this file was sponsored by Microbric Pty Ltd
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2013-2015 Damien P. George
+ * Copyright (c) 2016 Paul Sokolovsky
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include "rom/ets_sys.h"
+#include "rom/rtc.h"
+#include "esp_system.h"
+#include "driver/touch_pad.h"
+
+#include "py/obj.h"
+#include "py/runtime.h"
+#include "extmod/machine_mem.h"
+#include "extmod/machine_signal.h"
+#include "extmod/machine_pulse.h"
+#include "extmod/machine_i2c.h"
+#include "extmod/machine_spi.h"
+#include "modmachine.h"
+#include "machine_rtc.h"
+
+#if MICROPY_PY_MACHINE
+
+typedef enum {
+ MP_PWRON_RESET = 1,
+ MP_HARD_RESET,
+ MP_WDT_RESET,
+ MP_DEEPSLEEP_RESET,
+ MP_SOFT_RESET
+} reset_reason_t;
+
+STATIC mp_obj_t machine_freq(size_t n_args, const mp_obj_t *args) {
+ if (n_args == 0) {
+ // get
+ return mp_obj_new_int(ets_get_cpu_frequency() * 1000000);
+ } else {
+ // set
+ mp_int_t freq = mp_obj_get_int(args[0]) / 1000000;
+ if (freq != 80 && freq != 160 && freq != 240) {
+ mp_raise_ValueError("frequency can only be either 80Mhz, 160MHz or 240MHz");
+ }
+ /*
+ system_update_cpu_freq(freq);
+ */
+ return mp_const_none;
+ }
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_freq_obj, 0, 1, machine_freq);
+
+STATIC mp_obj_t machine_sleep_helper(wake_type_t wake_type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+
+ enum {ARG_sleep_ms};
+ const mp_arg_t allowed_args[] = {
+ { MP_QSTR_sleep_ms, MP_ARG_INT, { .u_int = 0 } },
+ };
+
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+
+ mp_int_t expiry = args[ARG_sleep_ms].u_int;
+
+ if (expiry != 0) {
+ esp_sleep_enable_timer_wakeup(expiry * 1000);
+ }
+
+ if (machine_rtc_config.ext0_pin != -1 && (machine_rtc_config.ext0_wake_types & wake_type)) {
+ esp_sleep_enable_ext0_wakeup(machine_rtc_config.ext0_pin, machine_rtc_config.ext0_level ? 1 : 0);
+ }
+
+ if (machine_rtc_config.ext1_pins != 0) {
+ esp_sleep_enable_ext1_wakeup(
+ machine_rtc_config.ext1_pins,
+ machine_rtc_config.ext1_level ? ESP_EXT1_WAKEUP_ANY_HIGH : ESP_EXT1_WAKEUP_ALL_LOW);
+ }
+
+ if (machine_rtc_config.wake_on_touch) {
+ if (esp_sleep_enable_touchpad_wakeup() != ESP_OK) {
+ nlr_raise(mp_obj_new_exception_msg(&mp_type_RuntimeError, "esp_sleep_enable_touchpad_wakeup() failed"));
+ }
+ }
+
+ switch(wake_type) {
+ case MACHINE_WAKE_SLEEP:
+ esp_light_sleep_start();
+ break;
+ case MACHINE_WAKE_DEEPSLEEP:
+ esp_deep_sleep_start();
+ break;
+ }
+ return mp_const_none;
+}
+
+STATIC mp_obj_t machine_sleep(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ nlr_raise(mp_obj_new_exception_msg(&mp_type_RuntimeError, "light sleep not available for this version of ESP-IDF"));
+ return machine_sleep_helper(MACHINE_WAKE_SLEEP, n_args, pos_args, kw_args);
+};
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_sleep_obj, 0, machine_sleep);
+
+STATIC mp_obj_t machine_deepsleep(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ return machine_sleep_helper(MACHINE_WAKE_DEEPSLEEP, n_args, pos_args, kw_args);
+};
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_deepsleep_obj, 0, machine_deepsleep);
+
+STATIC mp_obj_t machine_reset_cause(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ switch(rtc_get_reset_reason(0)) {
+ case POWERON_RESET:
+ return MP_OBJ_NEW_SMALL_INT(MP_PWRON_RESET);
+ break;
+ case SW_RESET:
+ case SW_CPU_RESET:
+ return MP_OBJ_NEW_SMALL_INT(MP_SOFT_RESET);
+ break;
+ case OWDT_RESET:
+ case TG0WDT_SYS_RESET:
+ case TG1WDT_SYS_RESET:
+ case RTCWDT_SYS_RESET:
+ case RTCWDT_BROWN_OUT_RESET:
+ case RTCWDT_CPU_RESET:
+ case RTCWDT_RTC_RESET:
+ case TGWDT_CPU_RESET:
+ return MP_OBJ_NEW_SMALL_INT(MP_WDT_RESET);
+ break;
+
+ case DEEPSLEEP_RESET:
+ return MP_OBJ_NEW_SMALL_INT(MP_DEEPSLEEP_RESET);
+ break;
+
+ case EXT_CPU_RESET:
+ return MP_OBJ_NEW_SMALL_INT(MP_HARD_RESET);
+ break;
+
+ case NO_MEAN:
+ case SDIO_RESET:
+ case INTRUSION_RESET:
+ default:
+ return MP_OBJ_NEW_SMALL_INT(0);
+ break;
+ }
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_reset_cause_obj, 0, machine_reset_cause);
+
+STATIC mp_obj_t machine_wake_reason(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ return MP_OBJ_NEW_SMALL_INT(esp_sleep_get_wakeup_cause());
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_wake_reason_obj, 0, machine_wake_reason);
+
+STATIC mp_obj_t machine_reset(void) {
+ esp_restart();
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_reset_obj, machine_reset);
+
+STATIC mp_obj_t machine_unique_id(void) {
+ uint8_t chipid[6];
+ esp_efuse_mac_get_default(chipid);
+ return mp_obj_new_bytes(chipid, 6);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_unique_id_obj, machine_unique_id);
+
+STATIC mp_obj_t machine_idle(void) {
+ taskYIELD();
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_idle_obj, machine_idle);
+
+STATIC mp_obj_t machine_disable_irq(void) {
+ uint32_t state = MICROPY_BEGIN_ATOMIC_SECTION();
+ return mp_obj_new_int(state);
+}
+MP_DEFINE_CONST_FUN_OBJ_0(machine_disable_irq_obj, machine_disable_irq);
+
+STATIC mp_obj_t machine_enable_irq(mp_obj_t state_in) {
+ uint32_t state = mp_obj_get_int(state_in);
+ MICROPY_END_ATOMIC_SECTION(state);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_1(machine_enable_irq_obj, machine_enable_irq);
+
+STATIC const mp_rom_map_elem_t machine_module_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_umachine) },
+
+ { MP_ROM_QSTR(MP_QSTR_mem8), MP_ROM_PTR(&machine_mem8_obj) },
+ { MP_ROM_QSTR(MP_QSTR_mem16), MP_ROM_PTR(&machine_mem16_obj) },
+ { MP_ROM_QSTR(MP_QSTR_mem32), MP_ROM_PTR(&machine_mem32_obj) },
+
+ { MP_ROM_QSTR(MP_QSTR_freq), MP_ROM_PTR(&machine_freq_obj) },
+ { MP_ROM_QSTR(MP_QSTR_reset), MP_ROM_PTR(&machine_reset_obj) },
+ { MP_ROM_QSTR(MP_QSTR_unique_id), MP_ROM_PTR(&machine_unique_id_obj) },
+ { MP_ROM_QSTR(MP_QSTR_sleep), MP_ROM_PTR(&machine_sleep_obj) },
+ { MP_ROM_QSTR(MP_QSTR_deepsleep), MP_ROM_PTR(&machine_deepsleep_obj) },
+ { MP_ROM_QSTR(MP_QSTR_idle), MP_ROM_PTR(&machine_idle_obj) },
+
+ { MP_ROM_QSTR(MP_QSTR_disable_irq), MP_ROM_PTR(&machine_disable_irq_obj) },
+ { MP_ROM_QSTR(MP_QSTR_enable_irq), MP_ROM_PTR(&machine_enable_irq_obj) },
+
+ { MP_ROM_QSTR(MP_QSTR_time_pulse_us), MP_ROM_PTR(&machine_time_pulse_us_obj) },
+
+ { MP_ROM_QSTR(MP_QSTR_Timer), MP_ROM_PTR(&machine_timer_type) },
+ { MP_ROM_QSTR(MP_QSTR_WDT), MP_ROM_PTR(&machine_wdt_type) },
+
+ // wake abilities
+ { MP_ROM_QSTR(MP_QSTR_SLEEP), MP_ROM_INT(MACHINE_WAKE_SLEEP) },
+ { MP_ROM_QSTR(MP_QSTR_DEEPSLEEP), MP_ROM_INT(MACHINE_WAKE_DEEPSLEEP) },
+ { MP_ROM_QSTR(MP_QSTR_Pin), MP_ROM_PTR(&machine_pin_type) },
+ { MP_ROM_QSTR(MP_QSTR_Signal), MP_ROM_PTR(&machine_signal_type) },
+ { MP_ROM_QSTR(MP_QSTR_TouchPad), MP_ROM_PTR(&machine_touchpad_type) },
+ { MP_ROM_QSTR(MP_QSTR_ADC), MP_ROM_PTR(&machine_adc_type) },
+ { MP_ROM_QSTR(MP_QSTR_DAC), MP_ROM_PTR(&machine_dac_type) },
+ { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&machine_i2c_type) },
+ { MP_ROM_QSTR(MP_QSTR_PWM), MP_ROM_PTR(&machine_pwm_type) },
+ { MP_ROM_QSTR(MP_QSTR_RTC), MP_ROM_PTR(&machine_rtc_type) },
+ { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&mp_machine_soft_spi_type) },
+ { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&machine_uart_type) },
+
+ // Reset reasons
+ { MP_ROM_QSTR(MP_QSTR_reset_cause), MP_ROM_PTR(&machine_reset_cause_obj) },
+ { MP_ROM_QSTR(MP_QSTR_HARD_RESET), MP_ROM_INT(MP_HARD_RESET) },
+ { MP_ROM_QSTR(MP_QSTR_PWRON_RESET), MP_ROM_INT(MP_PWRON_RESET) },
+ { MP_ROM_QSTR(MP_QSTR_WDT_RESET), MP_ROM_INT(MP_WDT_RESET) },
+ { MP_ROM_QSTR(MP_QSTR_DEEPSLEEP_RESET), MP_ROM_INT(MP_DEEPSLEEP_RESET) },
+ { MP_ROM_QSTR(MP_QSTR_SOFT_RESET), MP_ROM_INT(MP_SOFT_RESET) },
+
+ // Wake reasons
+ { MP_ROM_QSTR(MP_QSTR_wake_reason), MP_ROM_PTR(&machine_wake_reason_obj) },
+ { MP_ROM_QSTR(MP_QSTR_PIN_WAKE), MP_ROM_INT(ESP_SLEEP_WAKEUP_EXT0) },
+ { MP_ROM_QSTR(MP_QSTR_EXT0_WAKE), MP_ROM_INT(ESP_SLEEP_WAKEUP_EXT0) },
+ { MP_ROM_QSTR(MP_QSTR_EXT1_WAKE), MP_ROM_INT(ESP_SLEEP_WAKEUP_EXT1) },
+ { MP_ROM_QSTR(MP_QSTR_TIMER_WAKE), MP_ROM_INT(ESP_SLEEP_WAKEUP_TIMER) },
+ { MP_ROM_QSTR(MP_QSTR_TOUCHPAD_WAKE), MP_ROM_INT(ESP_SLEEP_WAKEUP_TOUCHPAD) },
+ { MP_ROM_QSTR(MP_QSTR_ULP_WAKE), MP_ROM_INT(ESP_SLEEP_WAKEUP_ULP) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(machine_module_globals, machine_module_globals_table);
+
+const mp_obj_module_t mp_module_machine = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t*)&machine_module_globals,
+};
+
+#endif // MICROPY_PY_MACHINE
diff --git a/ports/esp32/modmachine.h b/ports/esp32/modmachine.h
new file mode 100644
index 000000000..c8513a471
--- /dev/null
+++ b/ports/esp32/modmachine.h
@@ -0,0 +1,26 @@
+#ifndef MICROPY_INCLUDED_ESP32_MODMACHINE_H
+#define MICROPY_INCLUDED_ESP32_MODMACHINE_H
+
+#include "py/obj.h"
+
+typedef enum {
+ //MACHINE_WAKE_IDLE=0x01,
+ MACHINE_WAKE_SLEEP=0x02,
+ MACHINE_WAKE_DEEPSLEEP=0x04
+} wake_type_t;
+
+extern const mp_obj_type_t machine_timer_type;
+extern const mp_obj_type_t machine_wdt_type;
+extern const mp_obj_type_t machine_pin_type;
+extern const mp_obj_type_t machine_touchpad_type;
+extern const mp_obj_type_t machine_adc_type;
+extern const mp_obj_type_t machine_dac_type;
+extern const mp_obj_type_t machine_pwm_type;
+extern const mp_obj_type_t machine_hw_spi_type;
+extern const mp_obj_type_t machine_uart_type;
+extern const mp_obj_type_t machine_rtc_type;
+
+void machine_pins_init(void);
+void machine_pins_deinit(void);
+
+#endif // MICROPY_INCLUDED_ESP32_MODMACHINE_H
diff --git a/ports/esp32/modnetwork.c b/ports/esp32/modnetwork.c
new file mode 100644
index 000000000..fdcb6d3cf
--- /dev/null
+++ b/ports/esp32/modnetwork.c
@@ -0,0 +1,646 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * Development of the code in this file was sponsored by Microbric Pty Ltd
+ * and Mnemote Pty Ltd
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016, 2017 Nick Moore @mnemote
+ * Copyright (c) 2017 "Eric Poulsen" <eric@zyxod.com>
+ *
+ * Based on esp8266/modnetwork.c which is Copyright (c) 2015 Paul Sokolovsky
+ * And the ESP IDF example code which is Public Domain / CC0
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+
+#include "py/nlr.h"
+#include "py/objlist.h"
+#include "py/runtime.h"
+#include "py/mphal.h"
+#include "py/mperrno.h"
+#include "netutils.h"
+#include "esp_wifi.h"
+#include "esp_wifi_types.h"
+#include "esp_log.h"
+#include "esp_event_loop.h"
+#include "esp_log.h"
+#include "lwip/dns.h"
+#include "tcpip_adapter.h"
+
+#include "modnetwork.h"
+
+#define MODNETWORK_INCLUDE_CONSTANTS (1)
+
+NORETURN void _esp_exceptions(esp_err_t e) {
+ switch (e) {
+ case ESP_ERR_WIFI_NOT_INIT:
+ mp_raise_msg(&mp_type_OSError, "Wifi Not Initialized");
+ case ESP_ERR_WIFI_NOT_STARTED:
+ mp_raise_msg(&mp_type_OSError, "Wifi Not Started");
+ case ESP_ERR_WIFI_NOT_STOPPED:
+ mp_raise_msg(&mp_type_OSError, "Wifi Not Stopped");
+ case ESP_ERR_WIFI_IF:
+ mp_raise_msg(&mp_type_OSError, "Wifi Invalid Interface");
+ case ESP_ERR_WIFI_MODE:
+ mp_raise_msg(&mp_type_OSError, "Wifi Invalid Mode");
+ case ESP_ERR_WIFI_STATE:
+ mp_raise_msg(&mp_type_OSError, "Wifi Internal State Error");
+ case ESP_ERR_WIFI_CONN:
+ mp_raise_msg(&mp_type_OSError, "Wifi Internal Error");
+ case ESP_ERR_WIFI_NVS:
+ mp_raise_msg(&mp_type_OSError, "Wifi Internal NVS Error");
+ case ESP_ERR_WIFI_MAC:
+ mp_raise_msg(&mp_type_OSError, "Wifi Invalid MAC Address");
+ case ESP_ERR_WIFI_SSID:
+ mp_raise_msg(&mp_type_OSError, "Wifi SSID Invalid");
+ case ESP_ERR_WIFI_PASSWORD:
+ mp_raise_msg(&mp_type_OSError, "Wifi Invalid Password");
+ case ESP_ERR_WIFI_TIMEOUT:
+ mp_raise_OSError(MP_ETIMEDOUT);
+ case ESP_ERR_WIFI_WAKE_FAIL:
+ mp_raise_msg(&mp_type_OSError, "Wifi Wakeup Failure");
+ case ESP_ERR_WIFI_WOULD_BLOCK:
+ mp_raise_msg(&mp_type_OSError, "Wifi Would Block");
+ case ESP_ERR_WIFI_NOT_CONNECT:
+ mp_raise_msg(&mp_type_OSError, "Wifi Not Connected");
+ case ESP_ERR_TCPIP_ADAPTER_INVALID_PARAMS:
+ mp_raise_msg(&mp_type_OSError, "TCP/IP Invalid Parameters");
+ case ESP_ERR_TCPIP_ADAPTER_IF_NOT_READY:
+ mp_raise_msg(&mp_type_OSError, "TCP/IP IF Not Ready");
+ case ESP_ERR_TCPIP_ADAPTER_DHCPC_START_FAILED:
+ mp_raise_msg(&mp_type_OSError, "TCP/IP DHCP Client Start Failed");
+ case ESP_ERR_TCPIP_ADAPTER_NO_MEM:
+ mp_raise_OSError(MP_ENOMEM);
+ default:
+ nlr_raise(mp_obj_new_exception_msg_varg(
+ &mp_type_RuntimeError, "Wifi Unknown Error 0x%04x", e
+ ));
+ }
+}
+
+static inline void esp_exceptions(esp_err_t e) {
+ if (e != ESP_OK) _esp_exceptions(e);
+}
+
+#define ESP_EXCEPTIONS(x) do { esp_exceptions(x); } while (0);
+
+typedef struct _wlan_if_obj_t {
+ mp_obj_base_t base;
+ int if_id;
+} wlan_if_obj_t;
+
+const mp_obj_type_t wlan_if_type;
+STATIC const wlan_if_obj_t wlan_sta_obj = {{&wlan_if_type}, WIFI_IF_STA};
+STATIC const wlan_if_obj_t wlan_ap_obj = {{&wlan_if_type}, WIFI_IF_AP};
+
+//static wifi_config_t wifi_ap_config = {{{0}}};
+static wifi_config_t wifi_sta_config = {{{0}}};
+
+// Set to "true" if esp_wifi_start() was called
+static bool wifi_started = false;
+
+// Set to "true" if the STA interface is requested to be connected by the
+// user, used for automatic reassociation.
+static bool wifi_sta_connect_requested = false;
+
+// Set to "true" if the STA interface is connected to wifi and has IP address.
+static bool wifi_sta_connected = false;
+
+// This function is called by the system-event task and so runs in a different
+// thread to the main MicroPython task. It must not raise any Python exceptions.
+static esp_err_t event_handler(void *ctx, system_event_t *event) {
+ switch(event->event_id) {
+ case SYSTEM_EVENT_STA_START:
+ ESP_LOGI("wifi", "STA_START");
+ break;
+ case SYSTEM_EVENT_STA_CONNECTED:
+ ESP_LOGI("network", "CONNECTED");
+ break;
+ case SYSTEM_EVENT_STA_GOT_IP:
+ ESP_LOGI("network", "GOT_IP");
+ wifi_sta_connected = true;
+ break;
+ case SYSTEM_EVENT_STA_DISCONNECTED: {
+ // This is a workaround as ESP32 WiFi libs don't currently
+ // auto-reassociate.
+ system_event_sta_disconnected_t *disconn = &event->event_info.disconnected;
+ char *message = "";
+ switch (disconn->reason) {
+ case WIFI_REASON_BEACON_TIMEOUT:
+ // AP has dropped out; try to reconnect.
+ message = "\nbeacon timeout";
+ break;
+ case WIFI_REASON_NO_AP_FOUND:
+ // AP may not exist, or it may have momentarily dropped out; try to reconnect.
+ message = "\nno AP found";
+ break;
+ case WIFI_REASON_AUTH_FAIL:
+ message = "\nauthentication failed";
+ wifi_sta_connect_requested = false;
+ break;
+ default:
+ // Let other errors through and try to reconnect.
+ break;
+ }
+ ESP_LOGI("wifi", "STA_DISCONNECTED, reason:%d%s", disconn->reason, message);
+
+ bool reconnected = false;
+ if (wifi_sta_connect_requested) {
+ wifi_mode_t mode;
+ if (esp_wifi_get_mode(&mode) == ESP_OK) {
+ if (mode & WIFI_MODE_STA) {
+ // STA is active so attempt to reconnect.
+ esp_err_t e = esp_wifi_connect();
+ if (e != ESP_OK) {
+ ESP_LOGI("wifi", "error attempting to reconnect: 0x%04x", e);
+ } else {
+ reconnected = true;
+ }
+ }
+ }
+ }
+ if (wifi_sta_connected && !reconnected) {
+ // If already connected and we fail to reconnect
+ wifi_sta_connected = false;
+ }
+ break;
+ }
+ default:
+ ESP_LOGI("network", "event %d", event->event_id);
+ break;
+ }
+ return ESP_OK;
+}
+
+/*void error_check(bool status, const char *msg) {
+ if (!status) {
+ nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, msg));
+ }
+}
+*/
+
+STATIC void require_if(mp_obj_t wlan_if, int if_no) {
+ wlan_if_obj_t *self = MP_OBJ_TO_PTR(wlan_if);
+ if (self->if_id != if_no) {
+ mp_raise_msg(&mp_type_OSError, if_no == WIFI_IF_STA ? "STA required" : "AP required");
+ }
+}
+
+STATIC mp_obj_t get_wlan(size_t n_args, const mp_obj_t *args) {
+ static int initialized = 0;
+ if (!initialized) {
+ wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
+ ESP_LOGD("modnetwork", "Initializing WiFi");
+ ESP_EXCEPTIONS( esp_wifi_init(&cfg) );
+ ESP_EXCEPTIONS( esp_wifi_set_storage(WIFI_STORAGE_RAM) );
+ ESP_LOGD("modnetwork", "Initialized");
+ initialized = 1;
+ }
+
+ int idx = (n_args > 0) ? mp_obj_get_int(args[0]) : WIFI_IF_STA;
+ if (idx == WIFI_IF_STA) {
+ return MP_OBJ_FROM_PTR(&wlan_sta_obj);
+ } else if (idx == WIFI_IF_AP) {
+ return MP_OBJ_FROM_PTR(&wlan_ap_obj);
+ } else {
+ mp_raise_ValueError("invalid WLAN interface identifier");
+ }
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(get_wlan_obj, 0, 1, get_wlan);
+
+STATIC mp_obj_t esp_initialize() {
+ static int initialized = 0;
+ if (!initialized) {
+ ESP_LOGD("modnetwork", "Initializing TCP/IP");
+ tcpip_adapter_init();
+ ESP_LOGD("modnetwork", "Initializing Event Loop");
+ ESP_EXCEPTIONS( esp_event_loop_init(event_handler, NULL) );
+ ESP_LOGD("modnetwork", "esp_event_loop_init done");
+ initialized = 1;
+ }
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_0(esp_initialize_obj, esp_initialize);
+
+#if (WIFI_MODE_STA & WIFI_MODE_AP != WIFI_MODE_NULL || WIFI_MODE_STA | WIFI_MODE_AP != WIFI_MODE_APSTA)
+#error WIFI_MODE_STA and WIFI_MODE_AP are supposed to be bitfields!
+#endif
+
+STATIC mp_obj_t esp_active(size_t n_args, const mp_obj_t *args) {
+ wlan_if_obj_t *self = MP_OBJ_TO_PTR(args[0]);
+
+ wifi_mode_t mode;
+ if (!wifi_started) {
+ mode = WIFI_MODE_NULL;
+ } else {
+ ESP_EXCEPTIONS(esp_wifi_get_mode(&mode));
+ }
+
+ int bit = (self->if_id == WIFI_IF_STA) ? WIFI_MODE_STA : WIFI_MODE_AP;
+
+ if (n_args > 1) {
+ bool active = mp_obj_is_true(args[1]);
+ mode = active ? (mode | bit) : (mode & ~bit);
+ if (mode == WIFI_MODE_NULL) {
+ if (wifi_started) {
+ ESP_EXCEPTIONS(esp_wifi_stop());
+ wifi_started = false;
+ }
+ } else {
+ ESP_EXCEPTIONS(esp_wifi_set_mode(mode));
+ if (!wifi_started) {
+ ESP_EXCEPTIONS(esp_wifi_start());
+ wifi_started = true;
+ }
+ }
+ }
+
+ return (mode & bit) ? mp_const_true : mp_const_false;
+}
+
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp_active_obj, 1, 2, esp_active);
+
+STATIC mp_obj_t esp_connect(size_t n_args, const mp_obj_t *args) {
+
+ mp_uint_t len;
+ const char *p;
+ if (n_args > 1) {
+ memset(&wifi_sta_config, 0, sizeof(wifi_sta_config));
+ p = mp_obj_str_get_data(args[1], &len);
+ memcpy(wifi_sta_config.sta.ssid, p, MIN(len, sizeof(wifi_sta_config.sta.ssid)));
+ p = (n_args > 2) ? mp_obj_str_get_data(args[2], &len) : "";
+ memcpy(wifi_sta_config.sta.password, p, MIN(len, sizeof(wifi_sta_config.sta.password)));
+ ESP_EXCEPTIONS( esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_sta_config) );
+ }
+ MP_THREAD_GIL_EXIT();
+ ESP_EXCEPTIONS( esp_wifi_connect() );
+ MP_THREAD_GIL_ENTER();
+ wifi_sta_connect_requested = true;
+
+ return mp_const_none;
+}
+
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp_connect_obj, 1, 7, esp_connect);
+
+STATIC mp_obj_t esp_disconnect(mp_obj_t self_in) {
+ wifi_sta_connect_requested = false;
+ ESP_EXCEPTIONS( esp_wifi_disconnect() );
+ return mp_const_none;
+}
+
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp_disconnect_obj, esp_disconnect);
+
+STATIC mp_obj_t esp_status(size_t n_args, const mp_obj_t *args) {
+ if (n_args == 1) {
+ // no arguments: return None until link status is implemented
+ return mp_const_none;
+ }
+
+ // one argument: return status based on query parameter
+ switch ((uintptr_t)args[1]) {
+ case (uintptr_t)MP_OBJ_NEW_QSTR(MP_QSTR_stations): {
+ // return list of connected stations, only if in soft-AP mode
+ require_if(args[0], WIFI_IF_AP);
+ wifi_sta_list_t station_list;
+ ESP_EXCEPTIONS(esp_wifi_ap_get_sta_list(&station_list));
+ wifi_sta_info_t *stations = (wifi_sta_info_t*)station_list.sta;
+ mp_obj_t list = mp_obj_new_list(0, NULL);
+ for (int i = 0; i < station_list.num; ++i) {
+ mp_obj_tuple_t *t = mp_obj_new_tuple(1, NULL);
+ t->items[0] = mp_obj_new_bytes(stations[i].mac, sizeof(stations[i].mac));
+ mp_obj_list_append(list, t);
+ }
+ return list;
+ }
+
+ default:
+ mp_raise_ValueError("unknown status param");
+ }
+
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp_status_obj, 1, 2, esp_status);
+
+STATIC mp_obj_t esp_scan(mp_obj_t self_in) {
+ // check that STA mode is active
+ wifi_mode_t mode;
+ ESP_EXCEPTIONS(esp_wifi_get_mode(&mode));
+ if ((mode & WIFI_MODE_STA) == 0) {
+ nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "STA must be active"));
+ }
+
+ mp_obj_t list = mp_obj_new_list(0, NULL);
+ wifi_scan_config_t config = { 0 };
+ // XXX how do we scan hidden APs (and if we can scan them, are they really hidden?)
+ MP_THREAD_GIL_EXIT();
+ esp_err_t status = esp_wifi_scan_start(&config, 1);
+ MP_THREAD_GIL_ENTER();
+ if (status == 0) {
+ uint16_t count = 0;
+ ESP_EXCEPTIONS( esp_wifi_scan_get_ap_num(&count) );
+ wifi_ap_record_t *wifi_ap_records = calloc(count, sizeof(wifi_ap_record_t));
+ ESP_EXCEPTIONS( esp_wifi_scan_get_ap_records(&count, wifi_ap_records) );
+ for (uint16_t i = 0; i < count; i++) {
+ mp_obj_tuple_t *t = mp_obj_new_tuple(6, NULL);
+ uint8_t *x = memchr(wifi_ap_records[i].ssid, 0, sizeof(wifi_ap_records[i].ssid));
+ int ssid_len = x ? x - wifi_ap_records[i].ssid : sizeof(wifi_ap_records[i].ssid);
+ t->items[0] = mp_obj_new_bytes(wifi_ap_records[i].ssid, ssid_len);
+ t->items[1] = mp_obj_new_bytes(wifi_ap_records[i].bssid, sizeof(wifi_ap_records[i].bssid));
+ t->items[2] = MP_OBJ_NEW_SMALL_INT(wifi_ap_records[i].primary);
+ t->items[3] = MP_OBJ_NEW_SMALL_INT(wifi_ap_records[i].rssi);
+ t->items[4] = MP_OBJ_NEW_SMALL_INT(wifi_ap_records[i].authmode);
+ t->items[5] = mp_const_false; // XXX hidden?
+ mp_obj_list_append(list, MP_OBJ_FROM_PTR(t));
+ }
+ free(wifi_ap_records);
+ }
+ return list;
+}
+
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp_scan_obj, esp_scan);
+
+STATIC mp_obj_t esp_isconnected(mp_obj_t self_in) {
+ wlan_if_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ if (self->if_id == WIFI_IF_STA) {
+ return mp_obj_new_bool(wifi_sta_connected);
+ } else {
+ wifi_sta_list_t sta;
+ esp_wifi_ap_get_sta_list(&sta);
+ return mp_obj_new_bool(sta.num != 0);
+ }
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp_isconnected_obj, esp_isconnected);
+
+STATIC mp_obj_t esp_ifconfig(size_t n_args, const mp_obj_t *args) {
+ wlan_if_obj_t *self = MP_OBJ_TO_PTR(args[0]);
+ tcpip_adapter_ip_info_t info;
+ tcpip_adapter_dns_info_t dns_info;
+ tcpip_adapter_get_ip_info(self->if_id, &info);
+ tcpip_adapter_get_dns_info(self->if_id, TCPIP_ADAPTER_DNS_MAIN, &dns_info);
+ if (n_args == 1) {
+ // get
+ mp_obj_t tuple[4] = {
+ netutils_format_ipv4_addr((uint8_t*)&info.ip, NETUTILS_BIG),
+ netutils_format_ipv4_addr((uint8_t*)&info.netmask, NETUTILS_BIG),
+ netutils_format_ipv4_addr((uint8_t*)&info.gw, NETUTILS_BIG),
+ netutils_format_ipv4_addr((uint8_t*)&dns_info.ip, NETUTILS_BIG),
+ };
+ return mp_obj_new_tuple(4, tuple);
+ } else {
+ // set
+ mp_obj_t *items;
+ mp_obj_get_array_fixed_n(args[1], 4, &items);
+ netutils_parse_ipv4_addr(items[0], (void*)&info.ip, NETUTILS_BIG);
+ if (mp_obj_is_integer(items[1])) {
+ // allow numeric netmask, i.e.:
+ // 24 -> 255.255.255.0
+ // 16 -> 255.255.0.0
+ // etc...
+ uint32_t* m = (uint32_t*)&info.netmask;
+ *m = htonl(0xffffffff << (32 - mp_obj_get_int(items[1])));
+ } else {
+ netutils_parse_ipv4_addr(items[1], (void*)&info.netmask, NETUTILS_BIG);
+ }
+ netutils_parse_ipv4_addr(items[2], (void*)&info.gw, NETUTILS_BIG);
+ netutils_parse_ipv4_addr(items[3], (void*)&dns_info.ip, NETUTILS_BIG);
+ // To set a static IP we have to disable DHCP first
+ if (self->if_id == WIFI_IF_STA || self->if_id == ESP_IF_ETH) {
+ esp_err_t e = tcpip_adapter_dhcpc_stop(self->if_id);
+ if (e != ESP_OK && e != ESP_ERR_TCPIP_ADAPTER_DHCP_ALREADY_STOPPED) _esp_exceptions(e);
+ ESP_EXCEPTIONS(tcpip_adapter_set_ip_info(self->if_id, &info));
+ ESP_EXCEPTIONS(tcpip_adapter_set_dns_info(self->if_id, TCPIP_ADAPTER_DNS_MAIN, &dns_info));
+ } else if (self->if_id == WIFI_IF_AP) {
+ esp_err_t e = tcpip_adapter_dhcps_stop(WIFI_IF_AP);
+ if (e != ESP_OK && e != ESP_ERR_TCPIP_ADAPTER_DHCP_ALREADY_STOPPED) _esp_exceptions(e);
+ ESP_EXCEPTIONS(tcpip_adapter_set_ip_info(WIFI_IF_AP, &info));
+ ESP_EXCEPTIONS(tcpip_adapter_set_dns_info(WIFI_IF_AP, TCPIP_ADAPTER_DNS_MAIN, &dns_info));
+ ESP_EXCEPTIONS(tcpip_adapter_dhcps_start(WIFI_IF_AP));
+ }
+ return mp_const_none;
+ }
+}
+
+MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp_ifconfig_obj, 1, 2, esp_ifconfig);
+
+STATIC mp_obj_t esp_config(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) {
+ if (n_args != 1 && kwargs->used != 0) {
+ mp_raise_TypeError("either pos or kw args are allowed");
+ }
+
+ wlan_if_obj_t *self = MP_OBJ_TO_PTR(args[0]);
+
+ // get the config for the interface
+ wifi_config_t cfg;
+ ESP_EXCEPTIONS(esp_wifi_get_config(self->if_id, &cfg));
+
+ if (kwargs->used != 0) {
+
+ for (size_t i = 0; i < kwargs->alloc; i++) {
+ if (MP_MAP_SLOT_IS_FILLED(kwargs, i)) {
+ int req_if = -1;
+
+ #define QS(x) (uintptr_t)MP_OBJ_NEW_QSTR(x)
+ switch ((uintptr_t)kwargs->table[i].key) {
+ case QS(MP_QSTR_mac): {
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(kwargs->table[i].value, &bufinfo, MP_BUFFER_READ);
+ if (bufinfo.len != 6) {
+ mp_raise_ValueError("invalid buffer length");
+ }
+ ESP_EXCEPTIONS(esp_wifi_set_mac(self->if_id, bufinfo.buf));
+ break;
+ }
+ case QS(MP_QSTR_essid): {
+ req_if = WIFI_IF_AP;
+ mp_uint_t len;
+ const char *s = mp_obj_str_get_data(kwargs->table[i].value, &len);
+ len = MIN(len, sizeof(cfg.ap.ssid));
+ memcpy(cfg.ap.ssid, s, len);
+ cfg.ap.ssid_len = len;
+ break;
+ }
+ case QS(MP_QSTR_hidden): {
+ req_if = WIFI_IF_AP;
+ cfg.ap.ssid_hidden = mp_obj_is_true(kwargs->table[i].value);
+ break;
+ }
+ case QS(MP_QSTR_authmode): {
+ req_if = WIFI_IF_AP;
+ cfg.ap.authmode = mp_obj_get_int(kwargs->table[i].value);
+ break;
+ }
+ case QS(MP_QSTR_password): {
+ req_if = WIFI_IF_AP;
+ mp_uint_t len;
+ const char *s = mp_obj_str_get_data(kwargs->table[i].value, &len);
+ len = MIN(len, sizeof(cfg.ap.password) - 1);
+ memcpy(cfg.ap.password, s, len);
+ cfg.ap.password[len] = 0;
+ break;
+ }
+ case QS(MP_QSTR_channel): {
+ req_if = WIFI_IF_AP;
+ cfg.ap.channel = mp_obj_get_int(kwargs->table[i].value);
+ break;
+ }
+ case QS(MP_QSTR_dhcp_hostname): {
+ const char *s = mp_obj_str_get_str(kwargs->table[i].value);
+ ESP_EXCEPTIONS(tcpip_adapter_set_hostname(self->if_id, s));
+ break;
+ }
+ default:
+ goto unknown;
+ }
+ #undef QS
+
+ // We post-check interface requirements to save on code size
+ if (req_if >= 0) {
+ require_if(args[0], req_if);
+ }
+ }
+ }
+
+ ESP_EXCEPTIONS(esp_wifi_set_config(self->if_id, &cfg));
+
+ return mp_const_none;
+ }
+
+ // Get config
+
+ if (n_args != 2) {
+ mp_raise_TypeError("can query only one param");
+ }
+
+ int req_if = -1;
+ mp_obj_t val;
+
+ #define QS(x) (uintptr_t)MP_OBJ_NEW_QSTR(x)
+ switch ((uintptr_t)args[1]) {
+ case QS(MP_QSTR_mac): {
+ uint8_t mac[6];
+ ESP_EXCEPTIONS(esp_wifi_get_mac(self->if_id, mac));
+ return mp_obj_new_bytes(mac, sizeof(mac));
+ }
+ case QS(MP_QSTR_essid):
+ if (self->if_id == WIFI_IF_STA) {
+ val = mp_obj_new_str((char*)cfg.sta.ssid, strlen((char*)cfg.sta.ssid));
+ } else {
+ val = mp_obj_new_str((char*)cfg.ap.ssid, cfg.ap.ssid_len);
+ }
+ break;
+ case QS(MP_QSTR_hidden):
+ req_if = WIFI_IF_AP;
+ val = mp_obj_new_bool(cfg.ap.ssid_hidden);
+ break;
+ case QS(MP_QSTR_authmode):
+ req_if = WIFI_IF_AP;
+ val = MP_OBJ_NEW_SMALL_INT(cfg.ap.authmode);
+ break;
+ case QS(MP_QSTR_channel):
+ req_if = WIFI_IF_AP;
+ val = MP_OBJ_NEW_SMALL_INT(cfg.ap.channel);
+ break;
+ case QS(MP_QSTR_dhcp_hostname): {
+ const char *s;
+ ESP_EXCEPTIONS(tcpip_adapter_get_hostname(self->if_id, &s));
+ val = mp_obj_new_str(s, strlen(s));
+ break;
+ }
+ default:
+ goto unknown;
+ }
+ #undef QS
+
+ // We post-check interface requirements to save on code size
+ if (req_if >= 0) {
+ require_if(args[0], req_if);
+ }
+
+ return val;
+
+unknown:
+ mp_raise_ValueError("unknown config param");
+}
+
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(esp_config_obj, 1, esp_config);
+
+STATIC const mp_rom_map_elem_t wlan_if_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_active), MP_ROM_PTR(&esp_active_obj) },
+ { MP_ROM_QSTR(MP_QSTR_connect), MP_ROM_PTR(&esp_connect_obj) },
+ { MP_ROM_QSTR(MP_QSTR_disconnect), MP_ROM_PTR(&esp_disconnect_obj) },
+ { MP_ROM_QSTR(MP_QSTR_status), MP_ROM_PTR(&esp_status_obj) },
+ { MP_ROM_QSTR(MP_QSTR_scan), MP_ROM_PTR(&esp_scan_obj) },
+ { MP_ROM_QSTR(MP_QSTR_isconnected), MP_ROM_PTR(&esp_isconnected_obj) },
+ { MP_ROM_QSTR(MP_QSTR_config), MP_ROM_PTR(&esp_config_obj) },
+ { MP_ROM_QSTR(MP_QSTR_ifconfig), MP_ROM_PTR(&esp_ifconfig_obj) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(wlan_if_locals_dict, wlan_if_locals_dict_table);
+
+const mp_obj_type_t wlan_if_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_WLAN,
+ .locals_dict = (mp_obj_t)&wlan_if_locals_dict,
+};
+
+STATIC mp_obj_t esp_phy_mode(size_t n_args, const mp_obj_t *args) {
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp_phy_mode_obj, 0, 1, esp_phy_mode);
+
+
+STATIC const mp_rom_map_elem_t mp_module_network_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_network) },
+ { MP_ROM_QSTR(MP_QSTR___init__), MP_ROM_PTR(&esp_initialize_obj) },
+ { MP_ROM_QSTR(MP_QSTR_WLAN), MP_ROM_PTR(&get_wlan_obj) },
+ { MP_ROM_QSTR(MP_QSTR_LAN), MP_ROM_PTR(&get_lan_obj) },
+ { MP_ROM_QSTR(MP_QSTR_phy_mode), MP_ROM_PTR(&esp_phy_mode_obj) },
+
+#if MODNETWORK_INCLUDE_CONSTANTS
+ { MP_ROM_QSTR(MP_QSTR_STA_IF), MP_ROM_INT(WIFI_IF_STA)},
+ { MP_ROM_QSTR(MP_QSTR_AP_IF), MP_ROM_INT(WIFI_IF_AP)},
+
+ { MP_ROM_QSTR(MP_QSTR_MODE_11B), MP_ROM_INT(WIFI_PROTOCOL_11B) },
+ { MP_ROM_QSTR(MP_QSTR_MODE_11G), MP_ROM_INT(WIFI_PROTOCOL_11G) },
+ { MP_ROM_QSTR(MP_QSTR_MODE_11N), MP_ROM_INT(WIFI_PROTOCOL_11N) },
+
+ { MP_ROM_QSTR(MP_QSTR_AUTH_OPEN), MP_ROM_INT(WIFI_AUTH_OPEN) },
+ { MP_ROM_QSTR(MP_QSTR_AUTH_WEP), MP_ROM_INT(WIFI_AUTH_WEP) },
+ { MP_ROM_QSTR(MP_QSTR_AUTH_WPA_PSK), MP_ROM_INT(WIFI_AUTH_WPA_PSK) },
+ { MP_ROM_QSTR(MP_QSTR_AUTH_WPA2_PSK), MP_ROM_INT(WIFI_AUTH_WPA2_PSK) },
+ { MP_ROM_QSTR(MP_QSTR_AUTH_WPA_WPA2_PSK), MP_ROM_INT(WIFI_AUTH_WPA_WPA2_PSK) },
+ { MP_ROM_QSTR(MP_QSTR_AUTH_MAX), MP_ROM_INT(WIFI_AUTH_MAX) },
+
+ { MP_ROM_QSTR(MP_QSTR_PHY_LAN8720), MP_ROM_INT(PHY_LAN8720) },
+ { MP_ROM_QSTR(MP_QSTR_PHY_TLK110), MP_ROM_INT(PHY_TLK110) },
+#endif
+};
+
+STATIC MP_DEFINE_CONST_DICT(mp_module_network_globals, mp_module_network_globals_table);
+
+const mp_obj_module_t mp_module_network = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t*)&mp_module_network_globals,
+};
diff --git a/ports/esp32/modnetwork.h b/ports/esp32/modnetwork.h
new file mode 100644
index 000000000..b8dc1b852
--- /dev/null
+++ b/ports/esp32/modnetwork.h
@@ -0,0 +1,36 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 "Eric Poulsen" <eric@zyxod.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#ifndef MICROPY_INCLUDED_ESP32_MODNETWORK_H
+#define MICROPY_INCLUDED_ESP32_MODNETWORK_H
+
+enum { PHY_LAN8720, PHY_TLK110 };
+
+MP_DECLARE_CONST_FUN_OBJ_KW(get_lan_obj);
+MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(esp_ifconfig_obj);
+
+void usocket_events_deinit(void);
+
+#endif
diff --git a/ports/esp32/modsocket.c b/ports/esp32/modsocket.c
new file mode 100644
index 000000000..daa77f581
--- /dev/null
+++ b/ports/esp32/modsocket.c
@@ -0,0 +1,702 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * Development of the code in this file was sponsored by Microbric Pty Ltd
+ * and Mnemote Pty Ltd
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016, 2017 Nick Moore @mnemote
+ *
+ * Based on extmod/modlwip.c
+ * Copyright (c) 2013, 2014 Damien P. George
+ * Copyright (c) 2015 Galen Hazelwood
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "py/runtime0.h"
+#include "py/nlr.h"
+#include "py/objlist.h"
+#include "py/objstr.h"
+#include "py/runtime.h"
+#include "py/mperrno.h"
+#include "py/mphal.h"
+#include "py/stream.h"
+#include "py/mperrno.h"
+#include "lib/netutils/netutils.h"
+#include "tcpip_adapter.h"
+#include "modnetwork.h"
+
+#include "lwip/sockets.h"
+#include "lwip/netdb.h"
+#include "lwip/ip4.h"
+#include "lwip/igmp.h"
+#include "esp_log.h"
+
+#define SOCKET_POLL_US (100000)
+
+typedef struct _socket_obj_t {
+ mp_obj_base_t base;
+ int fd;
+ uint8_t domain;
+ uint8_t type;
+ uint8_t proto;
+ bool peer_closed;
+ unsigned int retries;
+ #if MICROPY_PY_USOCKET_EVENTS
+ mp_obj_t events_callback;
+ struct _socket_obj_t *events_next;
+ #endif
+} socket_obj_t;
+
+void _socket_settimeout(socket_obj_t *sock, uint64_t timeout_ms);
+
+#if MICROPY_PY_USOCKET_EVENTS
+// Support for callbacks on asynchronous socket events (when socket becomes readable)
+
+// This divisor is used to reduce the load on the system, so it doesn't poll sockets too often
+#define USOCKET_EVENTS_DIVISOR (8)
+
+STATIC uint8_t usocket_events_divisor;
+STATIC socket_obj_t *usocket_events_head;
+
+void usocket_events_deinit(void) {
+ usocket_events_head = NULL;
+}
+
+// Assumes the socket is not already in the linked list, and adds it
+STATIC void usocket_events_add(socket_obj_t *sock) {
+ sock->events_next = usocket_events_head;
+ usocket_events_head = sock;
+}
+
+// Assumes the socket is already in the linked list, and removes it
+STATIC void usocket_events_remove(socket_obj_t *sock) {
+ for (socket_obj_t **s = &usocket_events_head;; s = &(*s)->events_next) {
+ if (*s == sock) {
+ *s = (*s)->events_next;
+ return;
+ }
+ }
+}
+
+// Polls all registered sockets for readability and calls their callback if they are readable
+void usocket_events_handler(void) {
+ if (usocket_events_head == NULL) {
+ return;
+ }
+ if (--usocket_events_divisor) {
+ return;
+ }
+ usocket_events_divisor = USOCKET_EVENTS_DIVISOR;
+
+ fd_set rfds;
+ FD_ZERO(&rfds);
+ int max_fd = 0;
+
+ for (socket_obj_t *s = usocket_events_head; s != NULL; s = s->events_next) {
+ FD_SET(s->fd, &rfds);
+ max_fd = MAX(max_fd, s->fd);
+ }
+
+ // Poll the sockets
+ struct timeval timeout = { .tv_sec = 0, .tv_usec = 0 };
+ int r = select(max_fd + 1, &rfds, NULL, NULL, &timeout);
+ if (r <= 0) {
+ return;
+ }
+
+ // Call the callbacks
+ for (socket_obj_t *s = usocket_events_head; s != NULL; s = s->events_next) {
+ if (FD_ISSET(s->fd, &rfds)) {
+ mp_call_function_1_protected(s->events_callback, s);
+ }
+ }
+}
+
+#endif // MICROPY_PY_USOCKET_EVENTS
+
+NORETURN static void exception_from_errno(int _errno) {
+ // Here we need to convert from lwip errno values to MicroPython's standard ones
+ if (_errno == EINPROGRESS) {
+ _errno = MP_EINPROGRESS;
+ }
+ mp_raise_OSError(_errno);
+}
+
+static inline void check_for_exceptions(void) {
+ mp_handle_pending();
+}
+
+static int _socket_getaddrinfo2(const mp_obj_t host, const mp_obj_t portx, struct addrinfo **resp) {
+ const struct addrinfo hints = {
+ .ai_family = AF_INET,
+ .ai_socktype = SOCK_STREAM,
+ };
+
+ mp_obj_t port = portx;
+ if (MP_OBJ_IS_SMALL_INT(port)) {
+ // This is perverse, because lwip_getaddrinfo promptly converts it back to an int, but
+ // that's the API we have to work with ...
+ port = mp_obj_str_binary_op(MP_BINARY_OP_MODULO, mp_obj_new_str_via_qstr("%s", 2), port);
+ }
+
+ const char *host_str = mp_obj_str_get_str(host);
+ const char *port_str = mp_obj_str_get_str(port);
+
+ if (host_str[0] == '\0') {
+ // a host of "" is equivalent to the default/all-local IP address
+ host_str = "0.0.0.0";
+ }
+
+ MP_THREAD_GIL_EXIT();
+ int res = lwip_getaddrinfo(host_str, port_str, &hints, resp);
+ MP_THREAD_GIL_ENTER();
+
+ return res;
+}
+
+int _socket_getaddrinfo(const mp_obj_t addrtuple, struct addrinfo **resp) {
+ mp_uint_t len = 0;
+ mp_obj_t *elem;
+ mp_obj_get_array(addrtuple, &len, &elem);
+ if (len != 2) return -1;
+ return _socket_getaddrinfo2(elem[0], elem[1], resp);
+}
+
+STATIC mp_obj_t socket_bind(const mp_obj_t arg0, const mp_obj_t arg1) {
+ socket_obj_t *self = MP_OBJ_TO_PTR(arg0);
+ struct addrinfo *res;
+ _socket_getaddrinfo(arg1, &res);
+ int r = lwip_bind_r(self->fd, res->ai_addr, res->ai_addrlen);
+ lwip_freeaddrinfo(res);
+ if (r < 0) exception_from_errno(errno);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_bind_obj, socket_bind);
+
+STATIC mp_obj_t socket_listen(const mp_obj_t arg0, const mp_obj_t arg1) {
+ socket_obj_t *self = MP_OBJ_TO_PTR(arg0);
+ int backlog = mp_obj_get_int(arg1);
+ int r = lwip_listen_r(self->fd, backlog);
+ if (r < 0) exception_from_errno(errno);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_listen_obj, socket_listen);
+
+STATIC mp_obj_t socket_accept(const mp_obj_t arg0) {
+ socket_obj_t *self = MP_OBJ_TO_PTR(arg0);
+
+ struct sockaddr addr;
+ socklen_t addr_len = sizeof(addr);
+
+ int new_fd = -1;
+ for (int i=0; i<=self->retries; i++) {
+ MP_THREAD_GIL_EXIT();
+ new_fd = lwip_accept_r(self->fd, &addr, &addr_len);
+ MP_THREAD_GIL_ENTER();
+ if (new_fd >= 0) break;
+ if (errno != EAGAIN) exception_from_errno(errno);
+ check_for_exceptions();
+ }
+ if (new_fd < 0) mp_raise_OSError(MP_ETIMEDOUT);
+
+ // create new socket object
+ socket_obj_t *sock = m_new_obj_with_finaliser(socket_obj_t);
+ sock->base.type = self->base.type;
+ sock->fd = new_fd;
+ sock->domain = self->domain;
+ sock->type = self->type;
+ sock->proto = self->proto;
+ sock->peer_closed = false;
+ _socket_settimeout(sock, UINT64_MAX);
+
+ // make the return value
+ uint8_t *ip = (uint8_t*)&((struct sockaddr_in*)&addr)->sin_addr;
+ mp_uint_t port = lwip_ntohs(((struct sockaddr_in*)&addr)->sin_port);
+ mp_obj_tuple_t *client = mp_obj_new_tuple(2, NULL);
+ client->items[0] = sock;
+ client->items[1] = netutils_format_inet_addr(ip, port, NETUTILS_BIG);
+
+ return client;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(socket_accept_obj, socket_accept);
+
+STATIC mp_obj_t socket_connect(const mp_obj_t arg0, const mp_obj_t arg1) {
+ socket_obj_t *self = MP_OBJ_TO_PTR(arg0);
+ struct addrinfo *res;
+ _socket_getaddrinfo(arg1, &res);
+ MP_THREAD_GIL_EXIT();
+ int r = lwip_connect_r(self->fd, res->ai_addr, res->ai_addrlen);
+ MP_THREAD_GIL_ENTER();
+ lwip_freeaddrinfo(res);
+ if (r != 0) {
+ exception_from_errno(errno);
+ }
+
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_connect_obj, socket_connect);
+
+STATIC mp_obj_t socket_setsockopt(size_t n_args, const mp_obj_t *args) {
+ (void)n_args; // always 4
+ socket_obj_t *self = MP_OBJ_TO_PTR(args[0]);
+
+ int opt = mp_obj_get_int(args[2]);
+
+ switch (opt) {
+ // level: SOL_SOCKET
+ case SO_REUSEADDR: {
+ int val = mp_obj_get_int(args[3]);
+ int ret = lwip_setsockopt_r(self->fd, SOL_SOCKET, opt, &val, sizeof(int));
+ if (ret != 0) {
+ exception_from_errno(errno);
+ }
+ break;
+ }
+
+ #if MICROPY_PY_USOCKET_EVENTS
+ // level: SOL_SOCKET
+ // special "register callback" option
+ case 20: {
+ if (args[3] == mp_const_none) {
+ if (self->events_callback != MP_OBJ_NULL) {
+ usocket_events_remove(self);
+ self->events_callback = MP_OBJ_NULL;
+ }
+ } else {
+ if (self->events_callback == MP_OBJ_NULL) {
+ usocket_events_add(self);
+ }
+ self->events_callback = args[3];
+ }
+ break;
+ }
+ #endif
+
+ // level: IPPROTO_IP
+ case IP_ADD_MEMBERSHIP: {
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(args[3], &bufinfo, MP_BUFFER_READ);
+ if (bufinfo.len != sizeof(ip4_addr_t) * 2) {
+ mp_raise_ValueError(NULL);
+ }
+
+ // POSIX setsockopt has order: group addr, if addr, lwIP has it vice-versa
+ err_t err = igmp_joingroup((const ip4_addr_t*)bufinfo.buf + 1, bufinfo.buf);
+ if (err != ERR_OK) {
+ mp_raise_OSError(-err);
+ }
+ break;
+ }
+
+ default:
+ mp_printf(&mp_plat_print, "Warning: lwip.setsockopt() option not implemented\n");
+ }
+
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(socket_setsockopt_obj, 4, 4, socket_setsockopt);
+
+void _socket_settimeout(socket_obj_t *sock, uint64_t timeout_ms) {
+ // Rather than waiting for the entire timeout specified, we wait sock->retries times
+ // for SOCKET_POLL_US each, checking for a MicroPython interrupt between timeouts.
+ // with SOCKET_POLL_MS == 100ms, sock->retries allows for timeouts up to 13 years.
+ // if timeout_ms == UINT64_MAX, wait forever.
+ sock->retries = (timeout_ms == UINT64_MAX) ? UINT_MAX : timeout_ms * 1000 / SOCKET_POLL_US;
+
+ struct timeval timeout = {
+ .tv_sec = 0,
+ .tv_usec = timeout_ms ? SOCKET_POLL_US : 0
+ };
+ lwip_setsockopt_r(sock->fd, SOL_SOCKET, SO_SNDTIMEO, (const void *)&timeout, sizeof(timeout));
+ lwip_setsockopt_r(sock->fd, SOL_SOCKET, SO_RCVTIMEO, (const void *)&timeout, sizeof(timeout));
+ lwip_fcntl_r(sock->fd, F_SETFL, timeout_ms ? 0 : O_NONBLOCK);
+}
+
+STATIC mp_obj_t socket_settimeout(const mp_obj_t arg0, const mp_obj_t arg1) {
+ socket_obj_t *self = MP_OBJ_TO_PTR(arg0);
+ if (arg1 == mp_const_none) _socket_settimeout(self, UINT64_MAX);
+ else _socket_settimeout(self, mp_obj_get_float(arg1) * 1000L);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_settimeout_obj, socket_settimeout);
+
+STATIC mp_obj_t socket_setblocking(const mp_obj_t arg0, const mp_obj_t arg1) {
+ socket_obj_t *self = MP_OBJ_TO_PTR(arg0);
+ if (mp_obj_is_true(arg1)) _socket_settimeout(self, UINT64_MAX);
+ else _socket_settimeout(self, 0);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_setblocking_obj, socket_setblocking);
+
+// XXX this can end up waiting a very long time if the content is dribbled in one character
+// at a time, as the timeout resets each time a recvfrom succeeds ... this is probably not
+// good behaviour.
+STATIC mp_uint_t _socket_read_data(mp_obj_t self_in, void *buf, size_t size,
+ struct sockaddr *from, socklen_t *from_len, int *errcode) {
+ socket_obj_t *sock = MP_OBJ_TO_PTR(self_in);
+
+ // If the peer closed the connection then the lwIP socket API will only return "0" once
+ // from lwip_recvfrom_r and then block on subsequent calls. To emulate POSIX behaviour,
+ // which continues to return "0" for each call on a closed socket, we set a flag when
+ // the peer closed the socket.
+ if (sock->peer_closed) {
+ return 0;
+ }
+
+ // XXX Would be nicer to use RTC to handle timeouts
+ for (int i = 0; i <= sock->retries; ++i) {
+ MP_THREAD_GIL_EXIT();
+ int r = lwip_recvfrom_r(sock->fd, buf, size, 0, from, from_len);
+ MP_THREAD_GIL_ENTER();
+ if (r == 0) {
+ sock->peer_closed = true;
+ }
+ if (r >= 0) {
+ return r;
+ }
+ if (errno != EWOULDBLOCK) {
+ *errcode = errno;
+ return MP_STREAM_ERROR;
+ }
+ check_for_exceptions();
+ }
+
+ *errcode = sock->retries == 0 ? MP_EWOULDBLOCK : MP_ETIMEDOUT;
+ return MP_STREAM_ERROR;
+}
+
+mp_obj_t _socket_recvfrom(mp_obj_t self_in, mp_obj_t len_in,
+ struct sockaddr *from, socklen_t *from_len) {
+ size_t len = mp_obj_get_int(len_in);
+ vstr_t vstr;
+ vstr_init_len(&vstr, len);
+
+ int errcode;
+ mp_uint_t ret = _socket_read_data(self_in, vstr.buf, len, from, from_len, &errcode);
+ if (ret == MP_STREAM_ERROR) {
+ exception_from_errno(errcode);
+ }
+
+ vstr.len = ret;
+ return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
+}
+
+STATIC mp_obj_t socket_recv(mp_obj_t self_in, mp_obj_t len_in) {
+ return _socket_recvfrom(self_in, len_in, NULL, NULL);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_recv_obj, socket_recv);
+
+STATIC mp_obj_t socket_recvfrom(mp_obj_t self_in, mp_obj_t len_in) {
+ struct sockaddr from;
+ socklen_t fromlen = sizeof(from);
+
+ mp_obj_t tuple[2];
+ tuple[0] = _socket_recvfrom(self_in, len_in, &from, &fromlen);
+
+ uint8_t *ip = (uint8_t*)&((struct sockaddr_in*)&from)->sin_addr;
+ mp_uint_t port = lwip_ntohs(((struct sockaddr_in*)&from)->sin_port);
+ tuple[1] = netutils_format_inet_addr(ip, port, NETUTILS_BIG);
+
+ return mp_obj_new_tuple(2, tuple);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_recvfrom_obj, socket_recvfrom);
+
+int _socket_send(socket_obj_t *sock, const char *data, size_t datalen) {
+ int sentlen = 0;
+ for (int i=0; i<=sock->retries && sentlen < datalen; i++) {
+ MP_THREAD_GIL_EXIT();
+ int r = lwip_write_r(sock->fd, data+sentlen, datalen-sentlen);
+ MP_THREAD_GIL_ENTER();
+ if (r < 0 && errno != EWOULDBLOCK) exception_from_errno(errno);
+ if (r > 0) sentlen += r;
+ check_for_exceptions();
+ }
+ if (sentlen == 0) mp_raise_OSError(MP_ETIMEDOUT);
+ return sentlen;
+}
+
+STATIC mp_obj_t socket_send(const mp_obj_t arg0, const mp_obj_t arg1) {
+ socket_obj_t *sock = MP_OBJ_TO_PTR(arg0);
+ mp_uint_t datalen;
+ const char *data = mp_obj_str_get_data(arg1, &datalen);
+ int r = _socket_send(sock, data, datalen);
+ return mp_obj_new_int(r);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_send_obj, socket_send);
+
+STATIC mp_obj_t socket_sendall(const mp_obj_t arg0, const mp_obj_t arg1) {
+ // XXX behaviour when nonblocking (see extmod/modlwip.c)
+ // XXX also timeout behaviour.
+ socket_obj_t *sock = MP_OBJ_TO_PTR(arg0);
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(arg1, &bufinfo, MP_BUFFER_READ);
+ int r = _socket_send(sock, bufinfo.buf, bufinfo.len);
+ if (r < bufinfo.len) mp_raise_OSError(MP_ETIMEDOUT);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_sendall_obj, socket_sendall);
+
+STATIC mp_obj_t socket_sendto(mp_obj_t self_in, mp_obj_t data_in, mp_obj_t addr_in) {
+ socket_obj_t *self = MP_OBJ_TO_PTR(self_in);
+
+ // get the buffer to send
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(data_in, &bufinfo, MP_BUFFER_READ);
+
+ // create the destination address
+ struct sockaddr_in to;
+ to.sin_len = sizeof(to);
+ to.sin_family = AF_INET;
+ to.sin_port = lwip_htons(netutils_parse_inet_addr(addr_in, (uint8_t*)&to.sin_addr, NETUTILS_BIG));
+
+ // send the data
+ for (int i=0; i<=self->retries; i++) {
+ MP_THREAD_GIL_EXIT();
+ int ret = lwip_sendto_r(self->fd, bufinfo.buf, bufinfo.len, 0, (struct sockaddr*)&to, sizeof(to));
+ MP_THREAD_GIL_ENTER();
+ if (ret > 0) return mp_obj_new_int_from_uint(ret);
+ if (ret == -1 && errno != EWOULDBLOCK) {
+ exception_from_errno(errno);
+ }
+ check_for_exceptions();
+ }
+ mp_raise_OSError(MP_ETIMEDOUT);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_3(socket_sendto_obj, socket_sendto);
+
+STATIC mp_obj_t socket_fileno(const mp_obj_t arg0) {
+ socket_obj_t *self = MP_OBJ_TO_PTR(arg0);
+ return mp_obj_new_int(self->fd);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(socket_fileno_obj, socket_fileno);
+
+STATIC mp_obj_t socket_makefile(size_t n_args, const mp_obj_t *args) {
+ (void)n_args;
+ return args[0];
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(socket_makefile_obj, 1, 3, socket_makefile);
+
+STATIC mp_uint_t socket_stream_read(mp_obj_t self_in, void *buf, mp_uint_t size, int *errcode) {
+ return _socket_read_data(self_in, buf, size, NULL, NULL, errcode);
+}
+
+STATIC mp_uint_t socket_stream_write(mp_obj_t self_in, const void *buf, mp_uint_t size, int *errcode) {
+ socket_obj_t *sock = self_in;
+ for (int i=0; i<=sock->retries; i++) {
+ MP_THREAD_GIL_EXIT();
+ int r = lwip_write_r(sock->fd, buf, size);
+ MP_THREAD_GIL_ENTER();
+ if (r > 0) return r;
+ if (r < 0 && errno != EWOULDBLOCK) { *errcode = errno; return MP_STREAM_ERROR; }
+ check_for_exceptions();
+ }
+ *errcode = sock->retries == 0 ? MP_EWOULDBLOCK : MP_ETIMEDOUT;
+ return MP_STREAM_ERROR;
+}
+
+STATIC mp_uint_t socket_stream_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) {
+ socket_obj_t * socket = self_in;
+ if (request == MP_STREAM_POLL) {
+
+ fd_set rfds; FD_ZERO(&rfds);
+ fd_set wfds; FD_ZERO(&wfds);
+ fd_set efds; FD_ZERO(&efds);
+ struct timeval timeout = { .tv_sec = 0, .tv_usec = 0 };
+ if (arg & MP_STREAM_POLL_RD) FD_SET(socket->fd, &rfds);
+ if (arg & MP_STREAM_POLL_WR) FD_SET(socket->fd, &wfds);
+ if (arg & MP_STREAM_POLL_HUP) FD_SET(socket->fd, &efds);
+
+ int r = select((socket->fd)+1, &rfds, &wfds, &efds, &timeout);
+ if (r < 0) {
+ *errcode = MP_EIO;
+ return MP_STREAM_ERROR;
+ }
+
+ mp_uint_t ret = 0;
+ if (FD_ISSET(socket->fd, &rfds)) ret |= MP_STREAM_POLL_RD;
+ if (FD_ISSET(socket->fd, &wfds)) ret |= MP_STREAM_POLL_WR;
+ if (FD_ISSET(socket->fd, &efds)) ret |= MP_STREAM_POLL_HUP;
+ return ret;
+ } else if (request == MP_STREAM_CLOSE) {
+ if (socket->fd >= 0) {
+ #if MICROPY_PY_USOCKET_EVENTS
+ if (socket->events_callback != MP_OBJ_NULL) {
+ usocket_events_remove(socket);
+ socket->events_callback = MP_OBJ_NULL;
+ }
+ #endif
+ int ret = lwip_close_r(socket->fd);
+ if (ret != 0) {
+ *errcode = errno;
+ return MP_STREAM_ERROR;
+ }
+ socket->fd = -1;
+ }
+ return 0;
+ }
+
+ *errcode = MP_EINVAL;
+ return MP_STREAM_ERROR;
+}
+
+STATIC const mp_rom_map_elem_t socket_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mp_stream_close_obj) },
+ { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) },
+ { MP_ROM_QSTR(MP_QSTR_bind), MP_ROM_PTR(&socket_bind_obj) },
+ { MP_ROM_QSTR(MP_QSTR_listen), MP_ROM_PTR(&socket_listen_obj) },
+ { MP_ROM_QSTR(MP_QSTR_accept), MP_ROM_PTR(&socket_accept_obj) },
+ { MP_ROM_QSTR(MP_QSTR_connect), MP_ROM_PTR(&socket_connect_obj) },
+ { MP_ROM_QSTR(MP_QSTR_send), MP_ROM_PTR(&socket_send_obj) },
+ { MP_ROM_QSTR(MP_QSTR_sendall), MP_ROM_PTR(&socket_sendall_obj) },
+ { MP_ROM_QSTR(MP_QSTR_sendto), MP_ROM_PTR(&socket_sendto_obj) },
+ { MP_ROM_QSTR(MP_QSTR_recv), MP_ROM_PTR(&socket_recv_obj) },
+ { MP_ROM_QSTR(MP_QSTR_recvfrom), MP_ROM_PTR(&socket_recvfrom_obj) },
+ { MP_ROM_QSTR(MP_QSTR_setsockopt), MP_ROM_PTR(&socket_setsockopt_obj) },
+ { MP_ROM_QSTR(MP_QSTR_settimeout), MP_ROM_PTR(&socket_settimeout_obj) },
+ { MP_ROM_QSTR(MP_QSTR_setblocking), MP_ROM_PTR(&socket_setblocking_obj) },
+ { MP_ROM_QSTR(MP_QSTR_makefile), MP_ROM_PTR(&socket_makefile_obj) },
+ { MP_ROM_QSTR(MP_QSTR_fileno), MP_ROM_PTR(&socket_fileno_obj) },
+
+ { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) },
+ { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) },
+ { MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) },
+ { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(socket_locals_dict, socket_locals_dict_table);
+
+STATIC const mp_stream_p_t socket_stream_p = {
+ .read = socket_stream_read,
+ .write = socket_stream_write,
+ .ioctl = socket_stream_ioctl
+};
+
+STATIC const mp_obj_type_t socket_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_socket,
+ .protocol = &socket_stream_p,
+ .locals_dict = (mp_obj_t)&socket_locals_dict,
+};
+
+STATIC mp_obj_t get_socket(size_t n_args, const mp_obj_t *args) {
+ socket_obj_t *sock = m_new_obj_with_finaliser(socket_obj_t);
+ sock->base.type = &socket_type;
+ sock->domain = AF_INET;
+ sock->type = SOCK_STREAM;
+ sock->proto = 0;
+ sock->peer_closed = false;
+ if (n_args > 0) {
+ sock->domain = mp_obj_get_int(args[0]);
+ if (n_args > 1) {
+ sock->type = mp_obj_get_int(args[1]);
+ if (n_args > 2) {
+ sock->proto = mp_obj_get_int(args[2]);
+ }
+ }
+ }
+
+ sock->fd = lwip_socket(sock->domain, sock->type, sock->proto);
+ if (sock->fd < 0) {
+ exception_from_errno(errno);
+ }
+ _socket_settimeout(sock, UINT64_MAX);
+
+ return MP_OBJ_FROM_PTR(sock);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(get_socket_obj, 0, 3, get_socket);
+
+STATIC mp_obj_t esp_socket_getaddrinfo(size_t n_args, const mp_obj_t *args) {
+ // TODO support additional args beyond the first two
+
+ struct addrinfo *res = NULL;
+ _socket_getaddrinfo2(args[0], args[1], &res);
+ mp_obj_t ret_list = mp_obj_new_list(0, NULL);
+
+ for (struct addrinfo *resi = res; resi; resi = resi->ai_next) {
+ mp_obj_t addrinfo_objs[5] = {
+ mp_obj_new_int(resi->ai_family),
+ mp_obj_new_int(resi->ai_socktype),
+ mp_obj_new_int(resi->ai_protocol),
+ mp_obj_new_str(resi->ai_canonname, strlen(resi->ai_canonname)),
+ mp_const_none
+ };
+
+ if (resi->ai_family == AF_INET) {
+ struct sockaddr_in *addr = (struct sockaddr_in *)resi->ai_addr;
+ // This looks odd, but it's really just a u32_t
+ ip4_addr_t ip4_addr = { .addr = addr->sin_addr.s_addr };
+ char buf[16];
+ ip4addr_ntoa_r(&ip4_addr, buf, sizeof(buf));
+ mp_obj_t inaddr_objs[2] = {
+ mp_obj_new_str(buf, strlen(buf)),
+ mp_obj_new_int(ntohs(addr->sin_port))
+ };
+ addrinfo_objs[4] = mp_obj_new_tuple(2, inaddr_objs);
+ }
+ mp_obj_list_append(ret_list, mp_obj_new_tuple(5, addrinfo_objs));
+ }
+
+ if (res) lwip_freeaddrinfo(res);
+ return ret_list;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp_socket_getaddrinfo_obj, 2, 6, esp_socket_getaddrinfo);
+
+STATIC mp_obj_t esp_socket_initialize() {
+ static int initialized = 0;
+ if (!initialized) {
+ ESP_LOGI("modsocket", "Initializing");
+ tcpip_adapter_init();
+ initialized = 1;
+ }
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_0(esp_socket_initialize_obj, esp_socket_initialize);
+
+STATIC const mp_rom_map_elem_t mp_module_socket_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_usocket) },
+ { MP_ROM_QSTR(MP_QSTR___init__), MP_ROM_PTR(&esp_socket_initialize_obj) },
+ { MP_ROM_QSTR(MP_QSTR_socket), MP_ROM_PTR(&get_socket_obj) },
+ { MP_ROM_QSTR(MP_QSTR_getaddrinfo), MP_ROM_PTR(&esp_socket_getaddrinfo_obj) },
+
+ { MP_ROM_QSTR(MP_QSTR_AF_INET), MP_ROM_INT(AF_INET) },
+ { MP_ROM_QSTR(MP_QSTR_AF_INET6), MP_ROM_INT(AF_INET6) },
+ { MP_ROM_QSTR(MP_QSTR_SOCK_STREAM), MP_ROM_INT(SOCK_STREAM) },
+ { MP_ROM_QSTR(MP_QSTR_SOCK_DGRAM), MP_ROM_INT(SOCK_DGRAM) },
+ { MP_ROM_QSTR(MP_QSTR_SOCK_RAW), MP_ROM_INT(SOCK_RAW) },
+ { MP_ROM_QSTR(MP_QSTR_IPPROTO_TCP), MP_ROM_INT(IPPROTO_TCP) },
+ { MP_ROM_QSTR(MP_QSTR_IPPROTO_UDP), MP_ROM_INT(IPPROTO_UDP) },
+ { MP_ROM_QSTR(MP_QSTR_IPPROTO_IP), MP_ROM_INT(IPPROTO_IP) },
+ { MP_ROM_QSTR(MP_QSTR_SOL_SOCKET), MP_ROM_INT(SOL_SOCKET) },
+ { MP_ROM_QSTR(MP_QSTR_SO_REUSEADDR), MP_ROM_INT(SO_REUSEADDR) },
+ { MP_ROM_QSTR(MP_QSTR_IP_ADD_MEMBERSHIP), MP_ROM_INT(IP_ADD_MEMBERSHIP) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(mp_module_socket_globals, mp_module_socket_globals_table);
+
+const mp_obj_module_t mp_module_usocket = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t*)&mp_module_socket_globals,
+};
diff --git a/ports/esp32/modules/_boot.py b/ports/esp32/modules/_boot.py
new file mode 100644
index 000000000..bf40ea3a9
--- /dev/null
+++ b/ports/esp32/modules/_boot.py
@@ -0,0 +1,12 @@
+import gc
+import uos
+from flashbdev import bdev
+
+try:
+ if bdev:
+ uos.mount(bdev, '/')
+except OSError:
+ import inisetup
+ vfs = inisetup.setup()
+
+gc.collect()
diff --git a/ports/esp32/modules/apa106.py b/ports/esp32/modules/apa106.py
new file mode 100644
index 000000000..ef971d78b
--- /dev/null
+++ b/ports/esp32/modules/apa106.py
@@ -0,0 +1,8 @@
+# APA106driver for MicroPython on ESP32
+# MIT license; Copyright (c) 2016 Damien P. George
+
+from neopixel import NeoPixel
+
+
+class APA106(NeoPixel):
+ ORDER = (0, 1, 2, 3)
diff --git a/ports/esp32/modules/dht.py b/ports/esp32/modules/dht.py
new file mode 120000
index 000000000..2aa2f5cbf
--- /dev/null
+++ b/ports/esp32/modules/dht.py
@@ -0,0 +1 @@
+../../../drivers/dht/dht.py \ No newline at end of file
diff --git a/ports/esp32/modules/ds18x20.py b/ports/esp32/modules/ds18x20.py
new file mode 120000
index 000000000..9721929a3
--- /dev/null
+++ b/ports/esp32/modules/ds18x20.py
@@ -0,0 +1 @@
+../../esp8266/modules/ds18x20.py \ No newline at end of file
diff --git a/ports/esp32/modules/flashbdev.py b/ports/esp32/modules/flashbdev.py
new file mode 100644
index 000000000..935f5342f
--- /dev/null
+++ b/ports/esp32/modules/flashbdev.py
@@ -0,0 +1,34 @@
+import esp
+
+class FlashBdev:
+
+ SEC_SIZE = 4096
+ START_SEC = esp.flash_user_start() // SEC_SIZE
+
+ def __init__(self, blocks):
+ self.blocks = blocks
+
+ def readblocks(self, n, buf):
+ #print("readblocks(%s, %x(%d))" % (n, id(buf), len(buf)))
+ esp.flash_read((n + self.START_SEC) * self.SEC_SIZE, buf)
+
+ def writeblocks(self, n, buf):
+ #print("writeblocks(%s, %x(%d))" % (n, id(buf), len(buf)))
+ #assert len(buf) <= self.SEC_SIZE, len(buf)
+ esp.flash_erase(n + self.START_SEC)
+ esp.flash_write((n + self.START_SEC) * self.SEC_SIZE, buf)
+
+ def ioctl(self, op, arg):
+ #print("ioctl(%d, %r)" % (op, arg))
+ if op == 4: # BP_IOCTL_SEC_COUNT
+ return self.blocks
+ if op == 5: # BP_IOCTL_SEC_SIZE
+ return self.SEC_SIZE
+
+size = esp.flash_size()
+if size < 1024*1024:
+ # flash too small for a filesystem
+ bdev = None
+else:
+ # for now we use a fixed size for the filesystem
+ bdev = FlashBdev(2048 * 1024 // FlashBdev.SEC_SIZE)
diff --git a/ports/esp32/modules/inisetup.py b/ports/esp32/modules/inisetup.py
new file mode 100644
index 000000000..0e9c72fe8
--- /dev/null
+++ b/ports/esp32/modules/inisetup.py
@@ -0,0 +1,42 @@
+import uos
+from flashbdev import bdev
+
+def check_bootsec():
+ buf = bytearray(bdev.SEC_SIZE)
+ bdev.readblocks(0, buf)
+ empty = True
+ for b in buf:
+ if b != 0xff:
+ empty = False
+ break
+ if empty:
+ return True
+ fs_corrupted()
+
+def fs_corrupted():
+ import time
+ while 1:
+ print("""\
+FAT filesystem appears to be corrupted. If you had important data there, you
+may want to make a flash snapshot to try to recover it. Otherwise, perform
+factory reprogramming of MicroPython firmware (completely erase flash, followed
+by firmware programming).
+""")
+ time.sleep(3)
+
+def setup():
+ check_bootsec()
+ print("Performing initial setup")
+ uos.VfsFat.mkfs(bdev)
+ vfs = uos.VfsFat(bdev)
+ uos.mount(vfs, '/flash')
+ uos.chdir('/flash')
+ with open("boot.py", "w") as f:
+ f.write("""\
+# This file is executed on every boot (including wake-boot from deepsleep)
+#import esp
+#esp.osdebug(None)
+#import webrepl
+#webrepl.start()
+""")
+ return vfs
diff --git a/ports/esp32/modules/neopixel.py b/ports/esp32/modules/neopixel.py
new file mode 100644
index 000000000..86c1586cd
--- /dev/null
+++ b/ports/esp32/modules/neopixel.py
@@ -0,0 +1,33 @@
+# NeoPixel driver for MicroPython on ESP32
+# MIT license; Copyright (c) 2016 Damien P. George
+
+from esp import neopixel_write
+
+
+class NeoPixel:
+ ORDER = (1, 0, 2, 3)
+
+ def __init__(self, pin, n, bpp=3, timing=0):
+ self.pin = pin
+ self.n = n
+ self.bpp = bpp
+ self.buf = bytearray(n * bpp)
+ self.pin.init(pin.OUT)
+ self.timing = timing
+
+ def __setitem__(self, index, val):
+ offset = index * self.bpp
+ for i in range(self.bpp):
+ self.buf[offset + self.ORDER[i]] = val[i]
+
+ def __getitem__(self, index):
+ offset = index * self.bpp
+ return tuple(self.buf[offset + self.ORDER[i]]
+ for i in range(self.bpp))
+
+ def fill(self, color):
+ for i in range(self.n):
+ self[i] = color
+
+ def write(self):
+ neopixel_write(self.pin, self.buf, self.timing)
diff --git a/ports/esp32/modules/ntptime.py b/ports/esp32/modules/ntptime.py
new file mode 120000
index 000000000..e90900d5a
--- /dev/null
+++ b/ports/esp32/modules/ntptime.py
@@ -0,0 +1 @@
+../../esp8266/modules/ntptime.py \ No newline at end of file
diff --git a/ports/esp32/modules/onewire.py b/ports/esp32/modules/onewire.py
new file mode 120000
index 000000000..091629488
--- /dev/null
+++ b/ports/esp32/modules/onewire.py
@@ -0,0 +1 @@
+../../esp8266/modules/onewire.py \ No newline at end of file
diff --git a/ports/esp32/modules/umqtt/robust.py b/ports/esp32/modules/umqtt/robust.py
new file mode 120000
index 000000000..6bfbbcf55
--- /dev/null
+++ b/ports/esp32/modules/umqtt/robust.py
@@ -0,0 +1 @@
+../../../../../micropython-lib/umqtt.robust/umqtt/robust.py \ No newline at end of file
diff --git a/ports/esp32/modules/umqtt/simple.py b/ports/esp32/modules/umqtt/simple.py
new file mode 120000
index 000000000..6419a4664
--- /dev/null
+++ b/ports/esp32/modules/umqtt/simple.py
@@ -0,0 +1 @@
+../../../../../micropython-lib/umqtt.simple/umqtt/simple.py \ No newline at end of file
diff --git a/ports/esp32/modules/upip.py b/ports/esp32/modules/upip.py
new file mode 120000
index 000000000..130eb6901
--- /dev/null
+++ b/ports/esp32/modules/upip.py
@@ -0,0 +1 @@
+../../../tools/upip.py \ No newline at end of file
diff --git a/ports/esp32/modules/upip_utarfile.py b/ports/esp32/modules/upip_utarfile.py
new file mode 120000
index 000000000..d9653d6a6
--- /dev/null
+++ b/ports/esp32/modules/upip_utarfile.py
@@ -0,0 +1 @@
+../../../tools/upip_utarfile.py \ No newline at end of file
diff --git a/ports/esp32/modules/upysh.py b/ports/esp32/modules/upysh.py
new file mode 120000
index 000000000..12d100c29
--- /dev/null
+++ b/ports/esp32/modules/upysh.py
@@ -0,0 +1 @@
+../../../../micropython-lib/upysh/upysh.py \ No newline at end of file
diff --git a/ports/esp32/modules/urequests.py b/ports/esp32/modules/urequests.py
new file mode 120000
index 000000000..76661112e
--- /dev/null
+++ b/ports/esp32/modules/urequests.py
@@ -0,0 +1 @@
+../../../../micropython-lib/urequests/urequests.py \ No newline at end of file
diff --git a/ports/esp32/modules/webrepl.py b/ports/esp32/modules/webrepl.py
new file mode 120000
index 000000000..2a3987a72
--- /dev/null
+++ b/ports/esp32/modules/webrepl.py
@@ -0,0 +1 @@
+../../esp8266/modules/webrepl.py \ No newline at end of file
diff --git a/ports/esp32/modules/webrepl_setup.py b/ports/esp32/modules/webrepl_setup.py
new file mode 120000
index 000000000..999888bf1
--- /dev/null
+++ b/ports/esp32/modules/webrepl_setup.py
@@ -0,0 +1 @@
+../../esp8266/modules/webrepl_setup.py \ No newline at end of file
diff --git a/ports/esp32/modules/websocket_helper.py b/ports/esp32/modules/websocket_helper.py
new file mode 120000
index 000000000..4bcf3bcb6
--- /dev/null
+++ b/ports/esp32/modules/websocket_helper.py
@@ -0,0 +1 @@
+../../esp8266/modules/websocket_helper.py \ No newline at end of file
diff --git a/ports/esp32/moduos.c b/ports/esp32/moduos.c
new file mode 100644
index 000000000..dc85136f3
--- /dev/null
+++ b/ports/esp32/moduos.c
@@ -0,0 +1,134 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * Development of the code in this file was sponsored by Microbric Pty Ltd
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2015 Josef Gajdusek
+ * Copyright (c) 2016 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <string.h>
+
+#include "esp_system.h"
+
+#include "py/objstr.h"
+#include "py/runtime.h"
+#include "py/mperrno.h"
+#include "py/mphal.h"
+#include "extmod/misc.h"
+#include "extmod/vfs.h"
+#include "extmod/vfs_fat.h"
+#include "genhdr/mpversion.h"
+
+extern const mp_obj_type_t mp_fat_vfs_type;
+
+STATIC const qstr os_uname_info_fields[] = {
+ MP_QSTR_sysname, MP_QSTR_nodename,
+ MP_QSTR_release, MP_QSTR_version, MP_QSTR_machine
+};
+STATIC const MP_DEFINE_STR_OBJ(os_uname_info_sysname_obj, MICROPY_PY_SYS_PLATFORM);
+STATIC const MP_DEFINE_STR_OBJ(os_uname_info_nodename_obj, MICROPY_PY_SYS_PLATFORM);
+STATIC const MP_DEFINE_STR_OBJ(os_uname_info_release_obj, MICROPY_VERSION_STRING);
+STATIC const MP_DEFINE_STR_OBJ(os_uname_info_version_obj, MICROPY_GIT_TAG " on " MICROPY_BUILD_DATE);
+STATIC const MP_DEFINE_STR_OBJ(os_uname_info_machine_obj, MICROPY_HW_BOARD_NAME " with " MICROPY_HW_MCU_NAME);
+
+STATIC MP_DEFINE_ATTRTUPLE(
+ os_uname_info_obj,
+ os_uname_info_fields,
+ 5,
+ (mp_obj_t)&os_uname_info_sysname_obj,
+ (mp_obj_t)&os_uname_info_nodename_obj,
+ (mp_obj_t)&os_uname_info_release_obj,
+ (mp_obj_t)&os_uname_info_version_obj,
+ (mp_obj_t)&os_uname_info_machine_obj
+);
+
+STATIC mp_obj_t os_uname(void) {
+ return (mp_obj_t)&os_uname_info_obj;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_0(os_uname_obj, os_uname);
+
+STATIC mp_obj_t os_urandom(mp_obj_t num) {
+ mp_int_t n = mp_obj_get_int(num);
+ vstr_t vstr;
+ vstr_init_len(&vstr, n);
+ uint32_t r = 0;
+ for (int i = 0; i < n; i++) {
+ if ((i & 3) == 0) {
+ r = esp_random(); // returns 32-bit hardware random number
+ }
+ vstr.buf[i] = r;
+ r >>= 8;
+ }
+ return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(os_urandom_obj, os_urandom);
+
+#if MICROPY_PY_OS_DUPTERM
+STATIC mp_obj_t os_dupterm_notify(mp_obj_t obj_in) {
+ (void)obj_in;
+ for (;;) {
+ int c = mp_uos_dupterm_rx_chr();
+ if (c < 0) {
+ break;
+ }
+ ringbuf_put(&stdin_ringbuf, c);
+ }
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(os_dupterm_notify_obj, os_dupterm_notify);
+#endif
+
+STATIC const mp_rom_map_elem_t os_module_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_uos) },
+ { MP_ROM_QSTR(MP_QSTR_uname), MP_ROM_PTR(&os_uname_obj) },
+ { MP_ROM_QSTR(MP_QSTR_urandom), MP_ROM_PTR(&os_urandom_obj) },
+ #if MICROPY_PY_OS_DUPTERM
+ { MP_ROM_QSTR(MP_QSTR_dupterm), MP_ROM_PTR(&mp_uos_dupterm_obj) },
+ { MP_ROM_QSTR(MP_QSTR_dupterm_notify), MP_ROM_PTR(&os_dupterm_notify_obj) },
+ #endif
+ #if MICROPY_VFS
+ { MP_ROM_QSTR(MP_QSTR_ilistdir), MP_ROM_PTR(&mp_vfs_ilistdir_obj) },
+ { MP_ROM_QSTR(MP_QSTR_listdir), MP_ROM_PTR(&mp_vfs_listdir_obj) },
+ { MP_ROM_QSTR(MP_QSTR_mkdir), MP_ROM_PTR(&mp_vfs_mkdir_obj) },
+ { MP_ROM_QSTR(MP_QSTR_rmdir), MP_ROM_PTR(&mp_vfs_rmdir_obj) },
+ { MP_ROM_QSTR(MP_QSTR_chdir), MP_ROM_PTR(&mp_vfs_chdir_obj) },
+ { MP_ROM_QSTR(MP_QSTR_getcwd), MP_ROM_PTR(&mp_vfs_getcwd_obj) },
+ { MP_ROM_QSTR(MP_QSTR_remove), MP_ROM_PTR(&mp_vfs_remove_obj) },
+ { MP_ROM_QSTR(MP_QSTR_rename), MP_ROM_PTR(&mp_vfs_rename_obj) },
+ { MP_ROM_QSTR(MP_QSTR_stat), MP_ROM_PTR(&mp_vfs_stat_obj) },
+ { MP_ROM_QSTR(MP_QSTR_statvfs), MP_ROM_PTR(&mp_vfs_statvfs_obj) },
+ { MP_ROM_QSTR(MP_QSTR_mount), MP_ROM_PTR(&mp_vfs_mount_obj) },
+ { MP_ROM_QSTR(MP_QSTR_umount), MP_ROM_PTR(&mp_vfs_umount_obj) },
+ #if MICROPY_VFS_FAT
+ { MP_ROM_QSTR(MP_QSTR_VfsFat), MP_ROM_PTR(&mp_fat_vfs_type) },
+ #endif
+ #endif
+};
+
+STATIC MP_DEFINE_CONST_DICT(os_module_globals, os_module_globals_table);
+
+const mp_obj_module_t uos_module = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t*)&os_module_globals,
+};
diff --git a/ports/esp32/modutime.c b/ports/esp32/modutime.c
new file mode 100644
index 000000000..002854298
--- /dev/null
+++ b/ports/esp32/modutime.c
@@ -0,0 +1,106 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * Development of the code in this file was sponsored by Microbric Pty Ltd
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/time.h>
+
+#include "py/runtime.h"
+#include "lib/timeutils/timeutils.h"
+#include "extmod/utime_mphal.h"
+
+STATIC mp_obj_t time_localtime(size_t n_args, const mp_obj_t *args) {
+ timeutils_struct_time_t tm;
+ mp_int_t seconds;
+ if (n_args == 0 || args[0] == mp_const_none) {
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ seconds = tv.tv_sec;
+ } else {
+ seconds = mp_obj_get_int(args[0]);
+ }
+ timeutils_seconds_since_2000_to_struct_time(seconds, &tm);
+ mp_obj_t tuple[8] = {
+ tuple[0] = mp_obj_new_int(tm.tm_year),
+ tuple[1] = mp_obj_new_int(tm.tm_mon),
+ tuple[2] = mp_obj_new_int(tm.tm_mday),
+ tuple[3] = mp_obj_new_int(tm.tm_hour),
+ tuple[4] = mp_obj_new_int(tm.tm_min),
+ tuple[5] = mp_obj_new_int(tm.tm_sec),
+ tuple[6] = mp_obj_new_int(tm.tm_wday),
+ tuple[7] = mp_obj_new_int(tm.tm_yday),
+ };
+ return mp_obj_new_tuple(8, tuple);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(time_localtime_obj, 0, 1, time_localtime);
+
+STATIC mp_obj_t time_mktime(mp_obj_t tuple) {
+ size_t len;
+ mp_obj_t *elem;
+ mp_obj_get_array(tuple, &len, &elem);
+
+ // localtime generates a tuple of len 8. CPython uses 9, so we accept both.
+ if (len < 8 || len > 9) {
+ nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "mktime needs a tuple of length 8 or 9 (%d given)", len));
+ }
+
+ return mp_obj_new_int_from_uint(timeutils_mktime(mp_obj_get_int(elem[0]),
+ mp_obj_get_int(elem[1]), mp_obj_get_int(elem[2]), mp_obj_get_int(elem[3]),
+ mp_obj_get_int(elem[4]), mp_obj_get_int(elem[5])));
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(time_mktime_obj, time_mktime);
+
+STATIC mp_obj_t time_time(void) {
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ return mp_obj_new_int(tv.tv_sec);
+}
+MP_DEFINE_CONST_FUN_OBJ_0(time_time_obj, time_time);
+
+STATIC const mp_rom_map_elem_t time_module_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_utime) },
+
+ { MP_ROM_QSTR(MP_QSTR_localtime), MP_ROM_PTR(&time_localtime_obj) },
+ { MP_ROM_QSTR(MP_QSTR_mktime), MP_ROM_PTR(&time_mktime_obj) },
+ { MP_ROM_QSTR(MP_QSTR_time), MP_ROM_PTR(&time_time_obj) },
+ { MP_ROM_QSTR(MP_QSTR_sleep), MP_ROM_PTR(&mp_utime_sleep_obj) },
+ { MP_ROM_QSTR(MP_QSTR_sleep_ms), MP_ROM_PTR(&mp_utime_sleep_ms_obj) },
+ { MP_ROM_QSTR(MP_QSTR_sleep_us), MP_ROM_PTR(&mp_utime_sleep_us_obj) },
+ { MP_ROM_QSTR(MP_QSTR_ticks_ms), MP_ROM_PTR(&mp_utime_ticks_ms_obj) },
+ { MP_ROM_QSTR(MP_QSTR_ticks_us), MP_ROM_PTR(&mp_utime_ticks_us_obj) },
+ { MP_ROM_QSTR(MP_QSTR_ticks_cpu), MP_ROM_PTR(&mp_utime_ticks_cpu_obj) },
+ { MP_ROM_QSTR(MP_QSTR_ticks_add), MP_ROM_PTR(&mp_utime_ticks_add_obj) },
+ { MP_ROM_QSTR(MP_QSTR_ticks_diff), MP_ROM_PTR(&mp_utime_ticks_diff_obj) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(time_module_globals, time_module_globals_table);
+
+const mp_obj_module_t utime_module = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t*)&time_module_globals,
+};
diff --git a/ports/esp32/mpconfigport.h b/ports/esp32/mpconfigport.h
new file mode 100644
index 000000000..963aca2ef
--- /dev/null
+++ b/ports/esp32/mpconfigport.h
@@ -0,0 +1,268 @@
+// Options to control how MicroPython is built for this port,
+// overriding defaults in py/mpconfig.h.
+
+#include <stdint.h>
+#include <alloca.h>
+#include "rom/ets_sys.h"
+
+// object representation and NLR handling
+#define MICROPY_OBJ_REPR (MICROPY_OBJ_REPR_A)
+#define MICROPY_NLR_SETJMP (1)
+
+// memory allocation policies
+#define MICROPY_ALLOC_PATH_MAX (128)
+
+// emitters
+#define MICROPY_PERSISTENT_CODE_LOAD (1)
+
+// compiler configuration
+#define MICROPY_COMP_MODULE_CONST (1)
+#define MICROPY_COMP_TRIPLE_TUPLE_ASSIGN (1)
+
+// optimisations
+#define MICROPY_OPT_COMPUTED_GOTO (1)
+#define MICROPY_OPT_MPZ_BITWISE (1)
+
+// Python internal features
+#define MICROPY_READER_VFS (1)
+#define MICROPY_ENABLE_GC (1)
+#define MICROPY_ENABLE_FINALISER (1)
+#define MICROPY_STACK_CHECK (1)
+#define MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF (1)
+#define MICROPY_KBD_EXCEPTION (1)
+#define MICROPY_HELPER_REPL (1)
+#define MICROPY_REPL_EMACS_KEYS (1)
+#define MICROPY_REPL_AUTO_INDENT (1)
+#define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_MPZ)
+#define MICROPY_ENABLE_SOURCE_LINE (1)
+#define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_NORMAL)
+#define MICROPY_WARNINGS (1)
+#define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_FLOAT)
+#define MICROPY_PY_BUILTINS_COMPLEX (1)
+#define MICROPY_CPYTHON_COMPAT (1)
+#define MICROPY_STREAMS_NON_BLOCK (1)
+#define MICROPY_STREAMS_POSIX_API (1)
+#define MICROPY_MODULE_BUILTIN_INIT (1)
+#define MICROPY_MODULE_WEAK_LINKS (1)
+#define MICROPY_MODULE_FROZEN_STR (0)
+#define MICROPY_MODULE_FROZEN_MPY (1)
+#define MICROPY_QSTR_EXTRA_POOL mp_qstr_frozen_const_pool
+#define MICROPY_CAN_OVERRIDE_BUILTINS (1)
+#define MICROPY_USE_INTERNAL_ERRNO (1)
+#define MICROPY_USE_INTERNAL_PRINTF (0) // ESP32 SDK requires its own printf
+#define MICROPY_ENABLE_SCHEDULER (1)
+#define MICROPY_SCHEDULER_DEPTH (8)
+#define MICROPY_VFS (1)
+#define MICROPY_VFS_FAT (1)
+
+// control over Python builtins
+#define MICROPY_PY_FUNCTION_ATTRS (1)
+#define MICROPY_PY_DESCRIPTORS (1)
+#define MICROPY_PY_STR_BYTES_CMP_WARN (1)
+#define MICROPY_PY_BUILTINS_STR_UNICODE (1)
+#define MICROPY_PY_BUILTINS_STR_CENTER (1)
+#define MICROPY_PY_BUILTINS_STR_PARTITION (1)
+#define MICROPY_PY_BUILTINS_STR_SPLITLINES (1)
+#define MICROPY_PY_BUILTINS_BYTEARRAY (1)
+#define MICROPY_PY_BUILTINS_MEMORYVIEW (1)
+#define MICROPY_PY_BUILTINS_SET (1)
+#define MICROPY_PY_BUILTINS_SLICE (1)
+#define MICROPY_PY_BUILTINS_SLICE_ATTRS (1)
+#define MICROPY_PY_BUILTINS_FROZENSET (1)
+#define MICROPY_PY_BUILTINS_PROPERTY (1)
+#define MICROPY_PY_BUILTINS_RANGE_ATTRS (1)
+#define MICROPY_PY_BUILTINS_ROUND_INT (1)
+#define MICROPY_PY_BUILTINS_TIMEOUTERROR (1)
+#define MICROPY_PY_ALL_SPECIAL_METHODS (1)
+#define MICROPY_PY_BUILTINS_COMPILE (1)
+#define MICROPY_PY_BUILTINS_ENUMERATE (1)
+#define MICROPY_PY_BUILTINS_EXECFILE (1)
+#define MICROPY_PY_BUILTINS_FILTER (1)
+#define MICROPY_PY_BUILTINS_REVERSED (1)
+#define MICROPY_PY_BUILTINS_NOTIMPLEMENTED (1)
+#define MICROPY_PY_BUILTINS_INPUT (1)
+#define MICROPY_PY_BUILTINS_MIN_MAX (1)
+#define MICROPY_PY_BUILTINS_POW3 (1)
+#define MICROPY_PY_BUILTINS_HELP (1)
+#define MICROPY_PY_BUILTINS_HELP_TEXT esp32_help_text
+#define MICROPY_PY_BUILTINS_HELP_MODULES (1)
+#define MICROPY_PY___FILE__ (1)
+#define MICROPY_PY_MICROPYTHON_MEM_INFO (1)
+#define MICROPY_PY_ARRAY (1)
+#define MICROPY_PY_ARRAY_SLICE_ASSIGN (1)
+#define MICROPY_PY_ATTRTUPLE (1)
+#define MICROPY_PY_COLLECTIONS (1)
+#define MICROPY_PY_COLLECTIONS_DEQUE (1)
+#define MICROPY_PY_COLLECTIONS_ORDEREDDICT (1)
+#define MICROPY_PY_MATH (1)
+#define MICROPY_PY_MATH_SPECIAL_FUNCTIONS (1)
+#define MICROPY_PY_CMATH (1)
+#define MICROPY_PY_GC (1)
+#define MICROPY_PY_IO (1)
+#define MICROPY_PY_IO_IOBASE (1)
+#define MICROPY_PY_IO_FILEIO (1)
+#define MICROPY_PY_IO_BYTESIO (1)
+#define MICROPY_PY_IO_BUFFEREDWRITER (1)
+#define MICROPY_PY_STRUCT (1)
+#define MICROPY_PY_SYS (1)
+#define MICROPY_PY_SYS_MAXSIZE (1)
+#define MICROPY_PY_SYS_MODULES (1)
+#define MICROPY_PY_SYS_EXIT (1)
+#define MICROPY_PY_SYS_STDFILES (1)
+#define MICROPY_PY_SYS_STDIO_BUFFER (1)
+#define MICROPY_PY_UERRNO (1)
+#define MICROPY_PY_USELECT (1)
+#define MICROPY_PY_UTIME_MP_HAL (1)
+#define MICROPY_PY_THREAD (1)
+#define MICROPY_PY_THREAD_GIL (1)
+#define MICROPY_PY_THREAD_GIL_VM_DIVISOR (32)
+
+// extended modules
+#define MICROPY_PY_UCTYPES (1)
+#define MICROPY_PY_UZLIB (1)
+#define MICROPY_PY_UJSON (1)
+#define MICROPY_PY_URE (1)
+#define MICROPY_PY_UHEAPQ (1)
+#define MICROPY_PY_UTIMEQ (1)
+#define MICROPY_PY_UHASHLIB (1)
+#define MICROPY_PY_UHASHLIB_SHA1 (1)
+#define MICROPY_PY_UHASHLIB_SHA256 (1)
+#define MICROPY_PY_UBINASCII (1)
+#define MICROPY_PY_UBINASCII_CRC32 (1)
+#define MICROPY_PY_URANDOM (1)
+#define MICROPY_PY_URANDOM_EXTRA_FUNCS (1)
+#define MICROPY_PY_OS_DUPTERM (1)
+#define MICROPY_PY_MACHINE (1)
+#define MICROPY_PY_MACHINE_PIN_MAKE_NEW mp_pin_make_new
+#define MICROPY_PY_MACHINE_PULSE (1)
+#define MICROPY_PY_MACHINE_I2C (1)
+#define MICROPY_PY_MACHINE_SPI (1)
+#define MICROPY_PY_MACHINE_SPI_MSB (0)
+#define MICROPY_PY_MACHINE_SPI_LSB (1)
+#define MICROPY_PY_MACHINE_SPI_MAKE_NEW machine_hw_spi_make_new
+#define MICROPY_HW_SOFTSPI_MIN_DELAY (0)
+#define MICROPY_HW_SOFTSPI_MAX_BAUDRATE (ets_get_cpu_frequency() * 1000000 / 200) // roughly
+#define MICROPY_PY_USSL (1)
+#define MICROPY_SSL_MBEDTLS (1)
+#define MICROPY_PY_USSL_FINALISER (1)
+#define MICROPY_PY_WEBSOCKET (1)
+#define MICROPY_PY_WEBREPL (1)
+#define MICROPY_PY_FRAMEBUF (1)
+#define MICROPY_PY_USOCKET_EVENTS (MICROPY_PY_WEBREPL)
+
+// fatfs configuration
+#define MICROPY_FATFS_ENABLE_LFN (1)
+#define MICROPY_FATFS_RPATH (2)
+#define MICROPY_FATFS_MAX_SS (4096)
+#define MICROPY_FATFS_LFN_CODE_PAGE (437) /* 1=SFN/ANSI 437=LFN/U.S.(OEM) */
+#define mp_type_fileio mp_type_vfs_fat_fileio
+#define mp_type_textio mp_type_vfs_fat_textio
+
+// use vfs's functions for import stat and builtin open
+#define mp_import_stat mp_vfs_import_stat
+#define mp_builtin_open mp_vfs_open
+#define mp_builtin_open_obj mp_vfs_open_obj
+
+// extra built in names to add to the global namespace
+#define MICROPY_PORT_BUILTINS \
+ { MP_OBJ_NEW_QSTR(MP_QSTR_input), (mp_obj_t)&mp_builtin_input_obj }, \
+ { MP_OBJ_NEW_QSTR(MP_QSTR_open), (mp_obj_t)&mp_builtin_open_obj },
+
+// extra built in modules to add to the list of known ones
+extern const struct _mp_obj_module_t esp_module;
+extern const struct _mp_obj_module_t esp32_module;
+extern const struct _mp_obj_module_t utime_module;
+extern const struct _mp_obj_module_t uos_module;
+extern const struct _mp_obj_module_t mp_module_usocket;
+extern const struct _mp_obj_module_t mp_module_machine;
+extern const struct _mp_obj_module_t mp_module_network;
+extern const struct _mp_obj_module_t mp_module_onewire;
+
+#define MICROPY_PORT_BUILTIN_MODULES \
+ { MP_OBJ_NEW_QSTR(MP_QSTR_esp), (mp_obj_t)&esp_module }, \
+ { MP_OBJ_NEW_QSTR(MP_QSTR_esp32), (mp_obj_t)&esp32_module }, \
+ { MP_OBJ_NEW_QSTR(MP_QSTR_utime), (mp_obj_t)&utime_module }, \
+ { MP_OBJ_NEW_QSTR(MP_QSTR_uos), (mp_obj_t)&uos_module }, \
+ { MP_OBJ_NEW_QSTR(MP_QSTR_usocket), (mp_obj_t)&mp_module_usocket }, \
+ { MP_OBJ_NEW_QSTR(MP_QSTR_machine), (mp_obj_t)&mp_module_machine }, \
+ { MP_OBJ_NEW_QSTR(MP_QSTR_network), (mp_obj_t)&mp_module_network }, \
+ { MP_OBJ_NEW_QSTR(MP_QSTR__onewire), (mp_obj_t)&mp_module_onewire }, \
+ { MP_OBJ_NEW_QSTR(MP_QSTR_uhashlib), (mp_obj_t)&mp_module_uhashlib }, \
+
+#define MICROPY_PORT_BUILTIN_MODULE_WEAK_LINKS \
+ { MP_OBJ_NEW_QSTR(MP_QSTR_binascii), (mp_obj_t)&mp_module_ubinascii }, \
+ { MP_OBJ_NEW_QSTR(MP_QSTR_collections), (mp_obj_t)&mp_module_collections }, \
+ { MP_OBJ_NEW_QSTR(MP_QSTR_errno), (mp_obj_t)&mp_module_uerrno }, \
+ { MP_OBJ_NEW_QSTR(MP_QSTR_hashlib), (mp_obj_t)&mp_module_uhashlib }, \
+ { MP_OBJ_NEW_QSTR(MP_QSTR_heapq), (mp_obj_t)&mp_module_uheapq }, \
+ { MP_OBJ_NEW_QSTR(MP_QSTR_io), (mp_obj_t)&mp_module_io }, \
+ { MP_OBJ_NEW_QSTR(MP_QSTR_json), (mp_obj_t)&mp_module_ujson }, \
+ { MP_OBJ_NEW_QSTR(MP_QSTR_os), (mp_obj_t)&uos_module }, \
+ { MP_OBJ_NEW_QSTR(MP_QSTR_random), (mp_obj_t)&mp_module_urandom }, \
+ { MP_OBJ_NEW_QSTR(MP_QSTR_re), (mp_obj_t)&mp_module_ure }, \
+ { MP_OBJ_NEW_QSTR(MP_QSTR_select), (mp_obj_t)&mp_module_uselect }, \
+ { MP_OBJ_NEW_QSTR(MP_QSTR_socket), (mp_obj_t)&mp_module_usocket }, \
+ { MP_OBJ_NEW_QSTR(MP_QSTR_ssl), (mp_obj_t)&mp_module_ussl }, \
+ { MP_OBJ_NEW_QSTR(MP_QSTR_struct), (mp_obj_t)&mp_module_ustruct }, \
+ { MP_OBJ_NEW_QSTR(MP_QSTR_time), (mp_obj_t)&utime_module }, \
+ { MP_OBJ_NEW_QSTR(MP_QSTR_zlib), (mp_obj_t)&mp_module_uzlib }, \
+
+#define MP_STATE_PORT MP_STATE_VM
+
+#define MICROPY_PORT_ROOT_POINTERS \
+ const char *readline_hist[8]; \
+ mp_obj_t machine_pin_irq_handler[40]; \
+
+// type definitions for the specific machine
+
+#define BYTES_PER_WORD (4)
+#define MICROPY_MAKE_POINTER_CALLABLE(p) ((void*)((mp_uint_t)(p)))
+#define MP_PLAT_PRINT_STRN(str, len) mp_hal_stdout_tx_strn_cooked(str, len)
+#define MP_SSIZE_MAX (0x7fffffff)
+
+// Note: these "critical nested" macros do not ensure cross-CPU exclusion,
+// the only disable interrupts on the current CPU. To full manage exclusion
+// one should use portENTER_CRITICAL/portEXIT_CRITICAL instead.
+#include "freertos/FreeRTOS.h"
+#define MICROPY_BEGIN_ATOMIC_SECTION() portENTER_CRITICAL_NESTED()
+#define MICROPY_END_ATOMIC_SECTION(state) portEXIT_CRITICAL_NESTED(state)
+
+#if MICROPY_PY_USOCKET_EVENTS
+#define MICROPY_PY_USOCKET_EVENTS_HANDLER extern void usocket_events_handler(void); usocket_events_handler();
+#else
+#define MICROPY_PY_USOCKET_EVENTS_HANDLER
+#endif
+
+#if MICROPY_PY_THREAD
+#define MICROPY_EVENT_POLL_HOOK \
+ do { \
+ extern void mp_handle_pending(void); \
+ mp_handle_pending(); \
+ MICROPY_PY_USOCKET_EVENTS_HANDLER \
+ MP_THREAD_GIL_EXIT(); \
+ MP_THREAD_GIL_ENTER(); \
+ } while (0);
+#else
+#define MICROPY_EVENT_POLL_HOOK \
+ do { \
+ extern void mp_handle_pending(void); \
+ mp_handle_pending(); \
+ MICROPY_PY_USOCKET_EVENTS_HANDLER \
+ asm("waiti 0"); \
+ } while (0);
+#endif
+
+#define UINT_FMT "%u"
+#define INT_FMT "%d"
+
+typedef int32_t mp_int_t; // must be pointer size
+typedef uint32_t mp_uint_t; // must be pointer size
+typedef long mp_off_t;
+// ssize_t, off_t as required by POSIX-signatured functions in stream.h
+#include <sys/types.h>
+
+// board specifics
+
+#define MICROPY_HW_BOARD_NAME "ESP32 module"
+#define MICROPY_HW_MCU_NAME "ESP32"
+#define MICROPY_PY_SYS_PLATFORM "esp32"
diff --git a/ports/esp32/mphalport.c b/ports/esp32/mphalport.c
new file mode 100644
index 000000000..353e1343b
--- /dev/null
+++ b/ports/esp32/mphalport.c
@@ -0,0 +1,156 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * Development of the code in this file was sponsored by Microbric Pty Ltd
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2014 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include "rom/uart.h"
+
+#include "py/obj.h"
+#include "py/mpstate.h"
+#include "py/mphal.h"
+#include "extmod/misc.h"
+#include "lib/utils/pyexec.h"
+
+STATIC uint8_t stdin_ringbuf_array[256];
+ringbuf_t stdin_ringbuf = {stdin_ringbuf_array, sizeof(stdin_ringbuf_array)};
+
+int mp_hal_stdin_rx_chr(void) {
+ for (;;) {
+ int c = ringbuf_get(&stdin_ringbuf);
+ if (c != -1) {
+ return c;
+ }
+ MICROPY_EVENT_POLL_HOOK
+ vTaskDelay(1);
+ }
+}
+
+void mp_hal_stdout_tx_str(const char *str) {
+ mp_hal_stdout_tx_strn(str, strlen(str));
+}
+
+void mp_hal_stdout_tx_strn(const char *str, uint32_t len) {
+ MP_THREAD_GIL_EXIT();
+ for (uint32_t i = 0; i < len; ++i) {
+ uart_tx_one_char(str[i]);
+ }
+ MP_THREAD_GIL_ENTER();
+ mp_uos_dupterm_tx_strn(str, len);
+}
+
+// Efficiently convert "\n" to "\r\n"
+void mp_hal_stdout_tx_strn_cooked(const char *str, size_t len) {
+ const char *last = str;
+ while (len--) {
+ if (*str == '\n') {
+ if (str > last) {
+ mp_hal_stdout_tx_strn(last, str - last);
+ }
+ mp_hal_stdout_tx_strn("\r\n", 2);
+ ++str;
+ last = str;
+ } else {
+ ++str;
+ }
+ }
+ if (str > last) {
+ mp_hal_stdout_tx_strn(last, str - last);
+ }
+}
+
+uint32_t mp_hal_ticks_ms(void) {
+ return esp_timer_get_time() / 1000;
+}
+
+uint32_t mp_hal_ticks_us(void) {
+ return esp_timer_get_time();
+}
+
+void mp_hal_delay_ms(uint32_t ms) {
+ uint64_t us = ms * 1000;
+ uint64_t dt;
+ uint64_t t0 = esp_timer_get_time();
+ for (;;) {
+ uint64_t t1 = esp_timer_get_time();
+ dt = t1 - t0;
+ if (dt + portTICK_PERIOD_MS * 1000 >= us) {
+ // doing a vTaskDelay would take us beyond requested delay time
+ break;
+ }
+ MICROPY_EVENT_POLL_HOOK
+ vTaskDelay(1);
+ }
+ if (dt < us) {
+ // do the remaining delay accurately
+ mp_hal_delay_us(us - dt);
+ }
+}
+
+void mp_hal_delay_us(uint32_t us) {
+ // these constants are tested for a 240MHz clock
+ const uint32_t this_overhead = 5;
+ const uint32_t pend_overhead = 150;
+
+ // return if requested delay is less than calling overhead
+ if (us < this_overhead) {
+ return;
+ }
+ us -= this_overhead;
+
+ uint64_t t0 = esp_timer_get_time();
+ for (;;) {
+ uint64_t dt = esp_timer_get_time() - t0;
+ if (dt >= us) {
+ return;
+ }
+ if (dt + pend_overhead < us) {
+ // we have enough time to service pending events
+ // (don't use MICROPY_EVENT_POLL_HOOK because it also yields)
+ mp_handle_pending();
+ }
+ }
+}
+
+// this function could do with improvements (eg use ets_delay_us)
+void mp_hal_delay_us_fast(uint32_t us) {
+ uint32_t delay = ets_get_cpu_frequency() / 19;
+ while (--us) {
+ for (volatile uint32_t i = delay; i; --i) {
+ }
+ }
+}
+
+/*
+extern int mp_stream_errno;
+int *__errno() {
+ return &mp_stream_errno;
+}
+*/
diff --git a/ports/esp32/mphalport.h b/ports/esp32/mphalport.h
new file mode 100644
index 000000000..3215bc062
--- /dev/null
+++ b/ports/esp32/mphalport.h
@@ -0,0 +1,86 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * Development of the code in this file was sponsored by Microbric Pty Ltd
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2014 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef INCLUDED_MPHALPORT_H
+#define INCLUDED_MPHALPORT_H
+
+#include "py/ringbuf.h"
+#include "lib/utils/interrupt_char.h"
+
+extern ringbuf_t stdin_ringbuf;
+
+uint32_t mp_hal_ticks_us(void);
+__attribute__((always_inline)) static inline uint32_t mp_hal_ticks_cpu(void) {
+ uint32_t ccount;
+ __asm__ __volatile__("rsr %0,ccount":"=a" (ccount));
+ return ccount;
+}
+
+void mp_hal_delay_us(uint32_t);
+void mp_hal_delay_us_fast(uint32_t);
+void mp_hal_set_interrupt_char(int c);
+uint32_t mp_hal_get_cpu_freq(void);
+
+#define mp_hal_quiet_timing_enter() MICROPY_BEGIN_ATOMIC_SECTION()
+#define mp_hal_quiet_timing_exit(irq_state) MICROPY_END_ATOMIC_SECTION(irq_state)
+
+// C-level pin HAL
+#include "py/obj.h"
+#include "driver/gpio.h"
+#define MP_HAL_PIN_FMT "%u"
+#define mp_hal_pin_obj_t gpio_num_t
+mp_hal_pin_obj_t machine_pin_get_id(mp_obj_t pin_in);
+#define mp_hal_get_pin_obj(o) machine_pin_get_id(o)
+#define mp_obj_get_pin(o) machine_pin_get_id(o) // legacy name; only to support esp8266/modonewire
+#define mp_hal_pin_name(p) (p)
+static inline void mp_hal_pin_input(mp_hal_pin_obj_t pin) {
+ gpio_pad_select_gpio(pin);
+ gpio_set_direction(pin, GPIO_MODE_INPUT);
+}
+static inline void mp_hal_pin_output(mp_hal_pin_obj_t pin) {
+ gpio_pad_select_gpio(pin);
+ gpio_set_direction(pin, GPIO_MODE_INPUT_OUTPUT);
+}
+static inline void mp_hal_pin_open_drain(mp_hal_pin_obj_t pin) {
+ gpio_pad_select_gpio(pin);
+ gpio_set_direction(pin, GPIO_MODE_INPUT_OUTPUT_OD);
+}
+static inline void mp_hal_pin_od_low(mp_hal_pin_obj_t pin) {
+ gpio_set_level(pin, 0);
+}
+static inline void mp_hal_pin_od_high(mp_hal_pin_obj_t pin) {
+ gpio_set_level(pin, 1);
+}
+static inline int mp_hal_pin_read(mp_hal_pin_obj_t pin) {
+ return gpio_get_level(pin);
+}
+static inline void mp_hal_pin_write(mp_hal_pin_obj_t pin, int v) {
+ gpio_set_level(pin, v);
+}
+
+#endif // INCLUDED_MPHALPORT_H
diff --git a/ports/esp32/mpthreadport.c b/ports/esp32/mpthreadport.c
new file mode 100644
index 000000000..76d9431c0
--- /dev/null
+++ b/ports/esp32/mpthreadport.c
@@ -0,0 +1,226 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd
+ * Copyright (c) 2017 Pycom Limited
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "stdio.h"
+
+#include "py/mpconfig.h"
+#include "py/mpstate.h"
+#include "py/gc.h"
+#include "py/mpthread.h"
+#include "mpthreadport.h"
+
+#include "esp_task.h"
+
+#if MICROPY_PY_THREAD
+
+#define MP_THREAD_MIN_STACK_SIZE (4 * 1024)
+#define MP_THREAD_DEFAULT_STACK_SIZE (MP_THREAD_MIN_STACK_SIZE + 1024)
+#define MP_THREAD_PRIORITY (ESP_TASK_PRIO_MIN + 1)
+
+// this structure forms a linked list, one node per active thread
+typedef struct _thread_t {
+ TaskHandle_t id; // system id of thread
+ int ready; // whether the thread is ready and running
+ void *arg; // thread Python args, a GC root pointer
+ void *stack; // pointer to the stack
+ StaticTask_t *tcb; // pointer to the Task Control Block
+ size_t stack_len; // number of words in the stack
+ struct _thread_t *next;
+} thread_t;
+
+// the mutex controls access to the linked list
+STATIC mp_thread_mutex_t thread_mutex;
+STATIC thread_t thread_entry0;
+STATIC thread_t *thread; // root pointer, handled by mp_thread_gc_others
+
+void mp_thread_init(void *stack, uint32_t stack_len) {
+ mp_thread_set_state(&mp_state_ctx.thread);
+ // create the first entry in the linked list of all threads
+ thread = &thread_entry0;
+ thread->id = xTaskGetCurrentTaskHandle();
+ thread->ready = 1;
+ thread->arg = NULL;
+ thread->stack = stack;
+ thread->stack_len = stack_len;
+ thread->next = NULL;
+ mp_thread_mutex_init(&thread_mutex);
+}
+
+void mp_thread_gc_others(void) {
+ mp_thread_mutex_lock(&thread_mutex, 1);
+ for (thread_t *th = thread; th != NULL; th = th->next) {
+ gc_collect_root((void**)&th, 1);
+ gc_collect_root(&th->arg, 1); // probably not needed
+ if (th->id == xTaskGetCurrentTaskHandle()) {
+ continue;
+ }
+ if (!th->ready) {
+ continue;
+ }
+ gc_collect_root(th->stack, th->stack_len); // probably not needed
+ }
+ mp_thread_mutex_unlock(&thread_mutex);
+}
+
+mp_state_thread_t *mp_thread_get_state(void) {
+ return pvTaskGetThreadLocalStoragePointer(NULL, 1);
+}
+
+void mp_thread_set_state(void *state) {
+ vTaskSetThreadLocalStoragePointer(NULL, 1, state);
+}
+
+void mp_thread_start(void) {
+ mp_thread_mutex_lock(&thread_mutex, 1);
+ for (thread_t *th = thread; th != NULL; th = th->next) {
+ if (th->id == xTaskGetCurrentTaskHandle()) {
+ th->ready = 1;
+ break;
+ }
+ }
+ mp_thread_mutex_unlock(&thread_mutex);
+}
+
+STATIC void *(*ext_thread_entry)(void*) = NULL;
+
+STATIC void freertos_entry(void *arg) {
+ if (ext_thread_entry) {
+ ext_thread_entry(arg);
+ }
+ vTaskDelete(NULL);
+ for (;;);
+}
+
+void mp_thread_create_ex(void *(*entry)(void*), void *arg, size_t *stack_size, int priority, char *name) {
+ // store thread entry function into a global variable so we can access it
+ ext_thread_entry = entry;
+
+ if (*stack_size == 0) {
+ *stack_size = MP_THREAD_DEFAULT_STACK_SIZE; // default stack size
+ } else if (*stack_size < MP_THREAD_MIN_STACK_SIZE) {
+ *stack_size = MP_THREAD_MIN_STACK_SIZE; // minimum stack size
+ }
+
+ // allocate TCB, stack and linked-list node (must be outside thread_mutex lock)
+ StaticTask_t *tcb = m_new(StaticTask_t, 1);
+ StackType_t *stack = m_new(StackType_t, *stack_size / sizeof(StackType_t));
+ thread_t *th = m_new_obj(thread_t);
+
+ mp_thread_mutex_lock(&thread_mutex, 1);
+
+ // create thread
+ TaskHandle_t id = xTaskCreateStaticPinnedToCore(freertos_entry, name, *stack_size / sizeof(StackType_t), arg, priority, stack, tcb, 0);
+ if (id == NULL) {
+ mp_thread_mutex_unlock(&thread_mutex);
+ nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "can't create thread"));
+ }
+
+ // adjust the stack_size to provide room to recover from hitting the limit
+ *stack_size -= 1024;
+
+ // add thread to linked list of all threads
+ th->id = id;
+ th->ready = 0;
+ th->arg = arg;
+ th->stack = stack;
+ th->tcb = tcb;
+ th->stack_len = *stack_size / sizeof(StackType_t);
+ th->next = thread;
+ thread = th;
+
+ mp_thread_mutex_unlock(&thread_mutex);
+}
+
+void mp_thread_create(void *(*entry)(void*), void *arg, size_t *stack_size) {
+ mp_thread_create_ex(entry, arg, stack_size, MP_THREAD_PRIORITY, "mp_thread");
+}
+
+void mp_thread_finish(void) {
+ mp_thread_mutex_lock(&thread_mutex, 1);
+ for (thread_t *th = thread; th != NULL; th = th->next) {
+ if (th->id == xTaskGetCurrentTaskHandle()) {
+ th->ready = 0;
+ break;
+ }
+ }
+ mp_thread_mutex_unlock(&thread_mutex);
+}
+
+void vPortCleanUpTCB(void *tcb) {
+ thread_t *prev = NULL;
+ mp_thread_mutex_lock(&thread_mutex, 1);
+ for (thread_t *th = thread; th != NULL; prev = th, th = th->next) {
+ // unlink the node from the list
+ if (th->tcb == tcb) {
+ if (prev != NULL) {
+ prev->next = th->next;
+ } else {
+ // move the start pointer
+ thread = th->next;
+ }
+ // explicitly release all its memory
+ m_del(StaticTask_t, th->tcb, 1);
+ m_del(StackType_t, th->stack, th->stack_len);
+ m_del(thread_t, th, 1);
+ break;
+ }
+ }
+ mp_thread_mutex_unlock(&thread_mutex);
+}
+
+void mp_thread_mutex_init(mp_thread_mutex_t *mutex) {
+ mutex->handle = xSemaphoreCreateMutexStatic(&mutex->buffer);
+}
+
+int mp_thread_mutex_lock(mp_thread_mutex_t *mutex, int wait) {
+ return (pdTRUE == xSemaphoreTake(mutex->handle, wait ? portMAX_DELAY : 0));
+}
+
+void mp_thread_mutex_unlock(mp_thread_mutex_t *mutex) {
+ xSemaphoreGive(mutex->handle);
+}
+
+void mp_thread_deinit(void) {
+ mp_thread_mutex_lock(&thread_mutex, 1);
+ for (thread_t *th = thread; th != NULL; th = th->next) {
+ // don't delete the current task
+ if (th->id == xTaskGetCurrentTaskHandle()) {
+ continue;
+ }
+ vTaskDelete(th->id);
+ }
+ mp_thread_mutex_unlock(&thread_mutex);
+ // allow FreeRTOS to clean-up the threads
+ vTaskDelay(2);
+}
+
+#else
+
+void vPortCleanUpTCB(void *tcb) {
+}
+
+#endif // MICROPY_PY_THREAD
diff --git a/ports/esp32/mpthreadport.h b/ports/esp32/mpthreadport.h
new file mode 100644
index 000000000..54e35d61c
--- /dev/null
+++ b/ports/esp32/mpthreadport.h
@@ -0,0 +1,45 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd
+ * Copyright (c) 2017 Pycom Limited
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_ESP32_MPTHREADPORT_H
+#define MICROPY_INCLUDED_ESP32_MPTHREADPORT_H
+
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include "freertos/semphr.h"
+#include "freertos/queue.h"
+
+typedef struct _mp_thread_mutex_t {
+ SemaphoreHandle_t handle;
+ StaticSemaphore_t buffer;
+} mp_thread_mutex_t;
+
+void mp_thread_init(void *stack, uint32_t stack_len);
+void mp_thread_gc_others(void);
+void mp_thread_deinit(void);
+
+#endif // MICROPY_INCLUDED_ESP32_MPTHREADPORT_H
diff --git a/ports/esp32/network_lan.c b/ports/esp32/network_lan.c
new file mode 100644
index 000000000..fba4de73a
--- /dev/null
+++ b/ports/esp32/network_lan.c
@@ -0,0 +1,203 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 "Eric Poulsen" <eric@zyxod.com>
+ *
+ * Based on the ESP IDF example code which is Public Domain / CC0
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/runtime.h"
+#include "py/mphal.h"
+
+#include "eth_phy/phy.h"
+#include "eth_phy/phy_tlk110.h"
+#include "eth_phy/phy_lan8720.h"
+#include "tcpip_adapter.h"
+
+#include "modnetwork.h"
+
+typedef struct _lan_if_obj_t {
+ mp_obj_base_t base;
+ int if_id; // MUST BE FIRST to match wlan_if_obj_t
+ bool initialized;
+ bool active;
+ uint8_t mdc_pin;
+ uint8_t mdio_pin;
+ int8_t phy_power_pin;
+ uint8_t phy_addr;
+ uint8_t phy_type;
+ eth_phy_check_link_func link_func;
+ eth_phy_power_enable_func power_func;
+} lan_if_obj_t;
+
+const mp_obj_type_t lan_if_type;
+STATIC lan_if_obj_t lan_obj = {{&lan_if_type}, ESP_IF_ETH, false, false};
+
+STATIC void phy_power_enable(bool enable) {
+ lan_if_obj_t* self = &lan_obj;
+
+ if (self->phy_power_pin != -1) {
+
+ if (!enable) {
+ // Do the PHY-specific power_enable(false) function before powering down
+ self->power_func(false);
+ }
+
+ gpio_pad_select_gpio(self->phy_power_pin);
+ gpio_set_direction(self->phy_power_pin, GPIO_MODE_OUTPUT);
+ if (enable) {
+ gpio_set_level(self->phy_power_pin, 1);
+ } else {
+ gpio_set_level(self->phy_power_pin, 0);
+ }
+
+ // Allow the power up/down to take effect, min 300us
+ vTaskDelay(1);
+
+ if (enable) {
+ // Run the PHY-specific power on operations now the PHY has power
+ self->power_func(true);
+ }
+ }
+}
+
+STATIC void init_lan_rmii() {
+ lan_if_obj_t* self = &lan_obj;
+ phy_rmii_configure_data_interface_pins();
+ phy_rmii_smi_configure_pins(self->mdc_pin, self->mdio_pin);
+}
+
+STATIC mp_obj_t get_lan(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ lan_if_obj_t* self = &lan_obj;
+
+ if (self->initialized) {
+ return MP_OBJ_FROM_PTR(&lan_obj);
+ }
+
+ enum { ARG_id, ARG_mdc, ARG_mdio, ARG_power, ARG_phy_addr, ARG_phy_type };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_id, MP_ARG_OBJ, {.u_obj = mp_const_none} },
+ { MP_QSTR_mdc, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ },
+ { MP_QSTR_mdio, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ },
+ { MP_QSTR_power, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ },
+ { MP_QSTR_phy_addr, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_INT },
+ { MP_QSTR_phy_type, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_INT },
+ };
+
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ if (args[ARG_id].u_obj != mp_const_none) {
+ if (mp_obj_get_int(args[ARG_id].u_obj) != 0) {
+ mp_raise_ValueError("invalid LAN interface identifier");
+ }
+ }
+
+ self->mdc_pin = machine_pin_get_id(args[ARG_mdc].u_obj);
+ self->mdio_pin = machine_pin_get_id(args[ARG_mdio].u_obj);
+ self->phy_power_pin = args[ARG_power].u_obj == mp_const_none ? -1 : machine_pin_get_id(args[ARG_power].u_obj);
+
+ if (args[ARG_phy_addr].u_int < 0x00 || args[ARG_phy_addr].u_int > 0x1f) {
+ mp_raise_ValueError("invalid phy address");
+ }
+
+ if (args[ARG_phy_type].u_int != PHY_LAN8720 && args[ARG_phy_type].u_int != PHY_TLK110) {
+ mp_raise_ValueError("invalid phy type");
+ }
+
+ eth_config_t config;
+
+ switch (args[ARG_phy_type].u_int) {
+ case PHY_TLK110:
+ config = phy_tlk110_default_ethernet_config;
+ break;
+ case PHY_LAN8720:
+ config = phy_lan8720_default_ethernet_config;
+ break;
+ }
+
+ self->link_func = config.phy_check_link;
+
+ // Replace default power func with our own
+ self->power_func = config.phy_power_enable;
+ config.phy_power_enable = phy_power_enable;
+
+ config.phy_addr = args[ARG_phy_addr].u_int;
+ config.gpio_config = init_lan_rmii;
+ config.tcpip_input = tcpip_adapter_eth_input;
+
+ if (esp_eth_init(&config) == ESP_OK) {
+ self->active = false;
+ self->initialized = true;
+ } else {
+ mp_raise_msg(&mp_type_OSError, "esp_eth_init() failed");
+ }
+ return MP_OBJ_FROM_PTR(&lan_obj);
+}
+MP_DEFINE_CONST_FUN_OBJ_KW(get_lan_obj, 0, get_lan);
+
+STATIC mp_obj_t lan_active(size_t n_args, const mp_obj_t *args) {
+ lan_if_obj_t *self = MP_OBJ_TO_PTR(args[0]);
+
+ if (n_args > 1) {
+ if (mp_obj_is_true(args[1])) {
+ self->active = (esp_eth_enable() == ESP_OK);
+ if (!self->active) {
+ mp_raise_msg(&mp_type_OSError, "ethernet enable failed");
+ }
+ } else {
+ self->active = !(esp_eth_disable() == ESP_OK);
+ if (self->active) {
+ mp_raise_msg(&mp_type_OSError, "ethernet disable failed");
+ }
+ }
+ }
+ return mp_obj_new_bool(self->active);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(lan_active_obj, 1, 2, lan_active);
+
+STATIC mp_obj_t lan_status(mp_obj_t self_in) {
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(lan_status_obj, lan_status);
+
+STATIC mp_obj_t lan_isconnected(mp_obj_t self_in) {
+ lan_if_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ return self->active ? mp_obj_new_bool(self->link_func()) : mp_const_false;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(lan_isconnected_obj, lan_isconnected);
+
+STATIC const mp_rom_map_elem_t lan_if_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_active), MP_ROM_PTR(&lan_active_obj) },
+ { MP_ROM_QSTR(MP_QSTR_isconnected), MP_ROM_PTR(&lan_isconnected_obj) },
+ { MP_ROM_QSTR(MP_QSTR_status), MP_ROM_PTR(&lan_status_obj) },
+ { MP_ROM_QSTR(MP_QSTR_ifconfig), MP_ROM_PTR(&esp_ifconfig_obj) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(lan_if_locals_dict, lan_if_locals_dict_table);
+
+const mp_obj_type_t lan_if_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_LAN,
+ .locals_dict = (mp_obj_dict_t*)&lan_if_locals_dict,
+};
diff --git a/ports/esp32/partitions.csv b/ports/esp32/partitions.csv
new file mode 100644
index 000000000..98adcd20a
--- /dev/null
+++ b/ports/esp32/partitions.csv
@@ -0,0 +1,5 @@
+# Name, Type, SubType, Offset, Size, Flags
+# Note: if you change the phy_init or app partition offset, make sure to change the offset in Kconfig.projbuild
+nvs, data, nvs, 0x9000, 0x6000,
+phy_init, data, phy, 0xf000, 0x1000,
+factory, app, factory, 0x10000, 0x180000,
diff --git a/ports/esp32/qstrdefsport.h b/ports/esp32/qstrdefsport.h
new file mode 100644
index 000000000..ff6c2cc42
--- /dev/null
+++ b/ports/esp32/qstrdefsport.h
@@ -0,0 +1,30 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2014 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+// qstrs specific to this port, only needed if they aren't auto-generated
+
+// Entries for sys.path
+Q(/lib)
diff --git a/ports/esp32/sdkconfig.h b/ports/esp32/sdkconfig.h
new file mode 100644
index 000000000..f85257a19
--- /dev/null
+++ b/ports/esp32/sdkconfig.h
@@ -0,0 +1,191 @@
+/* Start bootloader config */
+#define CONFIG_FLASHMODE_DIO 1
+#define CONFIG_ESPTOOLPY_FLASHFREQ_40M 1
+/* End bootloader config */
+
+#define CONFIG_TRACEMEM_RESERVE_DRAM 0x0
+#define CONFIG_BT_RESERVE_DRAM 0x0
+#define CONFIG_ULP_COPROC_RESERVE_MEM 2040
+#define CONFIG_PHY_DATA_OFFSET 0xf000
+#define CONFIG_APP_OFFSET 0x10000
+
+#define CONFIG_SPI_FLASH_ROM_DRIVER_PATCH 1
+#define CONFIG_FOUR_UNIVERSAL_MAC_ADDRESS 1
+#define CONFIG_NUMBER_OF_UNIVERSAL_MAC_ADDRESS 4
+
+#define CONFIG_BROWNOUT_DET 1
+#define CONFIG_BROWNOUT_DET_LVL 0
+#define CONFIG_BROWNOUT_DET_LVL_SEL_0 1
+
+#define CONFIG_TCPIP_TASK_STACK_SIZE 2560
+#define CONFIG_TCPIP_RECVMBOX_SIZE 32
+
+#define CONFIG_ESP32_APPTRACE_DEST_NONE 1
+#define CONFIG_ESP32_PHY_MAX_TX_POWER 20
+#define CONFIG_ESP32_PANIC_PRINT_REBOOT 1
+#define CONFIG_ESP32_RTC_CLOCK_SOURCE_INTERNAL_RC 1
+#define CONFIG_ESP32_RTC_XTAL_BOOTSTRAP_CYCLES 100
+#define CONFIG_ESP32_TIME_SYSCALL_USE_RTC_FRC1 1
+#define CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ 240
+#define CONFIG_ESP32_DEFAULT_CPU_FREQ_240 1
+#define CONFIG_ESP32_DEBUG_OCDAWARE 1
+#define CONFIG_ESP32_DEEP_SLEEP_WAKEUP_DELAY 2000
+#define CONFIG_ESP32_ENABLE_COREDUMP_TO_NONE 1
+#define CONFIG_ESP32_PHY_CALIBRATION_AND_DATA_STORAGE 1
+#define CONFIG_ESP32_WIFI_AMPDU_ENABLED 1
+#define CONFIG_ESP32_WIFI_NVS_ENABLED 1
+#define CONFIG_ESP32_WIFI_STATIC_RX_BUFFER_NUM 10
+#define CONFIG_ESP32_WIFI_DYNAMIC_RX_BUFFER_NUM 0
+#define CONFIG_ESP32_WIFI_TX_BUFFER_TYPE 1
+#define CONFIG_ESP32_WIFI_DYNAMIC_TX_BUFFER 1
+#define CONFIG_ESP32_WIFI_DYNAMIC_TX_BUFFER_NUM 32
+#define CONFIG_ESP32_WIFI_RX_BA_WIN 6
+#define CONFIG_ESP32_WIFI_TX_BA_WIN 6
+#define CONFIG_ESP32_XTAL_FREQ_AUTO 1
+#define CONFIG_ESP32_XTAL_FREQ 0
+#define CONFIG_ESP32_RTC_CLK_CAL_CYCLES 1024
+#define CONFIG_ESP32_PTHREAD_TASK_PRIO_DEFAULT 5
+#define CONFIG_ESP32_PTHREAD_TASK_STACK_SIZE_DEFAULT 2048
+
+#if CONFIG_SPIRAM_SUPPORT
+#define CONFIG_SPIRAM_TYPE_ESPPSRAM32 1
+#define CONFIG_SPIRAM_SIZE 4194304
+#define CONFIG_SPIRAM_SPEED_40M 1
+#define CONFIG_SPIRAM_CACHE_WORKAROUND 1
+#define CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL 16384
+#define CONFIG_SPIRAM_BOOT_INIT 1
+#define CONFIG_SPIRAM_MEMTEST 1
+#define CONFIG_SPIRAM_USE_MALLOC 1
+#define CONFIG_SPIRAM_MALLOC_RESERVE_INTERNAL 32768
+#define CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY 1
+#endif
+
+#define CONFIG_FOUR_MAC_ADDRESS_FROM_EFUSE 1
+#define CONFIG_DMA_RX_BUF_NUM 10
+#define CONFIG_DMA_TX_BUF_NUM 10
+#define CONFIG_EMAC_TASK_PRIORITY 20
+
+#define CONFIG_INT_WDT 1
+#define CONFIG_INT_WDT_TIMEOUT_MS 300
+#define CONFIG_INT_WDT_CHECK_CPU1 0
+#define CONFIG_TASK_WDT 1
+#define CONFIG_TASK_WDT_PANIC 1
+#define CONFIG_TASK_WDT_TIMEOUT_S 5
+#define CONFIG_TASK_WDT_CHECK_IDLE_TASK 0
+#define CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU1 0
+
+#define CONFIG_FREERTOS_UNICORE 1
+#define CONFIG_FREERTOS_CORETIMER_0 1
+#define CONFIG_FREERTOS_HZ 100
+#define CONFIG_FREERTOS_ASSERT_FAIL_ABORT 1
+#define CONFIG_FREERTOS_ASSERT_ON_UNTESTED_FUNCTION 1
+#define CONFIG_FREERTOS_CHECK_STACKOVERFLOW_NONE 1
+#define CONFIG_FREERTOS_THREAD_LOCAL_STORAGE_POINTERS 2
+#define CONFIG_FREERTOS_IDLE_TASK_STACKSIZE 1024
+#define CONFIG_FREERTOS_ISR_STACKSIZE 1536
+#define CONFIG_FREERTOS_BREAK_ON_SCHEDULER_START_JTAG 1
+#define CONFIG_FREERTOS_MAX_TASK_NAME_LEN 16
+#define CONFIG_SUPPORT_STATIC_ALLOCATION 1
+#define CONFIG_ENABLE_STATIC_TASK_CLEAN_UP_HOOK 1
+
+#define CONFIG_MAIN_TASK_STACK_SIZE 4096
+#define CONFIG_IPC_TASK_STACK_SIZE 1024
+#define CONFIG_BTC_TASK_STACK_SIZE 3072
+#define CONFIG_SYSTEM_EVENT_TASK_STACK_SIZE 4096
+#define CONFIG_SYSTEM_EVENT_QUEUE_SIZE 32
+#define CONFIG_TIMER_TASK_STACK_SIZE 4096
+#define CONFIG_TIMER_TASK_PRIORITY 1
+#define CONFIG_TIMER_TASK_STACK_DEPTH 2048
+#define CONFIG_TIMER_QUEUE_LENGTH 10
+
+#define CONFIG_NEWLIB_STDIN_LINE_ENDING_CR 1
+#define CONFIG_NEWLIB_STDOUT_LINE_ENDING_CRLF 1
+#define CONFIG_PHY_ENABLED 1
+#define CONFIG_WIFI_ENABLED 1
+#define CONFIG_OPTIMIZATION_LEVEL_DEBUG 1
+#define CONFIG_MEMMAP_SMP 1
+
+#define CONFIG_PARTITION_TABLE_SINGLE_APP 1
+#define CONFIG_PARTITION_TABLE_FILENAME "partitions_singleapp.csv"
+#define CONFIG_PARTITION_TABLE_CUSTOM_APP_BIN_OFFSET 0x10000
+#define CONFIG_PARTITION_TABLE_CUSTOM_FILENAME "partitions.csv"
+
+#define CONFIG_CONSOLE_UART_BAUDRATE 115200
+#define CONFIG_CONSOLE_UART_NUM 0
+#define CONFIG_CONSOLE_UART_DEFAULT 1
+
+#define CONFIG_LOG_DEFAULT_LEVEL_INFO 1
+#define CONFIG_LOG_BOOTLOADER_LEVEL_WARN 1
+#define CONFIG_LOG_DEFAULT_LEVEL 3
+#define CONFIG_LOG_COLORS 1
+#define CONFIG_LOG_BOOTLOADER_LEVEL 2
+
+#define CONFIG_LWIP_THREAD_LOCAL_STORAGE_INDEX 0
+#define CONFIG_LWIP_DHCP_DOES_ARP_CHECK 1
+#define CONFIG_LWIP_DHCP_MAX_NTP_SERVERS 1
+#define CONFIG_LWIP_DHCPS_LEASE_UNIT 60
+#define CONFIG_LWIP_DHCPS_MAX_STATION_NUM 8
+#define CONFIG_LWIP_MAX_ACTIVE_TCP 16
+#define CONFIG_LWIP_MAX_SOCKETS 8
+#define CONFIG_LWIP_SO_REUSE 1
+#define CONFIG_LWIP_ETHARP_TRUST_IP_MAC 1
+#define CONFIG_IP_LOST_TIMER_INTERVAL 120
+#define CONFIG_UDP_RECVMBOX_SIZE 6
+#define CONFIG_TCP_MAXRTX 12
+#define CONFIG_TCP_SYNMAXRTX 6
+#define CONFIG_TCP_MSL 60000
+#define CONFIG_TCP_MSS 1436
+#define CONFIG_TCP_SND_BUF_DEFAULT 5744
+#define CONFIG_TCP_WND_DEFAULT 5744
+#define CONFIG_TCP_QUEUE_OOSEQ 1
+#define CONFIG_TCP_OVERSIZE_MSS 1
+#define CONFIG_TCP_RECVMBOX_SIZE 6
+
+#define CONFIG_MBEDTLS_AES_C 1
+#define CONFIG_MBEDTLS_CCM_C 1
+#define CONFIG_MBEDTLS_ECDH_C 1
+#define CONFIG_MBEDTLS_ECDSA_C 1
+#define CONFIG_MBEDTLS_ECP_C 1
+#define CONFIG_MBEDTLS_ECP_DP_BP256R1_ENABLED 1
+#define CONFIG_MBEDTLS_ECP_DP_BP384R1_ENABLED 1
+#define CONFIG_MBEDTLS_ECP_DP_BP512R1_ENABLED 1
+#define CONFIG_MBEDTLS_ECP_DP_CURVE25519_ENABLED 1
+#define CONFIG_MBEDTLS_ECP_DP_SECP192K1_ENABLED 1
+#define CONFIG_MBEDTLS_ECP_DP_SECP192R1_ENABLED 1
+#define CONFIG_MBEDTLS_ECP_DP_SECP224K1_ENABLED 1
+#define CONFIG_MBEDTLS_ECP_DP_SECP224R1_ENABLED 1
+#define CONFIG_MBEDTLS_ECP_DP_SECP256K1_ENABLED 1
+#define CONFIG_MBEDTLS_ECP_DP_SECP256R1_ENABLED 1
+#define CONFIG_MBEDTLS_ECP_DP_SECP384R1_ENABLED 1
+#define CONFIG_MBEDTLS_ECP_DP_SECP521R1_ENABLED 1
+#define CONFIG_MBEDTLS_ECP_NIST_OPTIM 1
+#define CONFIG_MBEDTLS_GCM_C 1
+#define CONFIG_MBEDTLS_HARDWARE_AES 1
+#define CONFIG_MBEDTLS_HAVE_TIME 1
+#define CONFIG_MBEDTLS_KEY_EXCHANGE_DHE_RSA 1
+#define CONFIG_MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA 1
+#define CONFIG_MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA 1
+#define CONFIG_MBEDTLS_KEY_EXCHANGE_ECDHE_RSA 1
+#define CONFIG_MBEDTLS_KEY_EXCHANGE_ECDH_RSA 1
+#define CONFIG_MBEDTLS_KEY_EXCHANGE_ELLIPTIC_CURVE 1
+#define CONFIG_MBEDTLS_KEY_EXCHANGE_RSA 1
+#define CONFIG_MBEDTLS_PEM_PARSE_C 1
+#define CONFIG_MBEDTLS_PEM_WRITE_C 1
+#define CONFIG_MBEDTLS_RC4_DISABLED 1
+#define CONFIG_MBEDTLS_SSL_ALPN 1
+#define CONFIG_MBEDTLS_SSL_MAX_CONTENT_LEN 16384
+#define CONFIG_MBEDTLS_SSL_PROTO_TLS1 1
+#define CONFIG_MBEDTLS_SSL_PROTO_TLS1_1 1
+#define CONFIG_MBEDTLS_SSL_PROTO_TLS1_2 1
+#define CONFIG_MBEDTLS_SSL_RENEGOTIATION 1
+#define CONFIG_MBEDTLS_SSL_SESSION_TICKETS 1
+#define CONFIG_MBEDTLS_TLS_CLIENT 1
+#define CONFIG_MBEDTLS_TLS_ENABLED 1
+#define CONFIG_MBEDTLS_TLS_SERVER 1
+#define CONFIG_MBEDTLS_TLS_SERVER_AND_CLIENT 1
+#define CONFIG_MBEDTLS_X509_CRL_PARSE_C 1
+#define CONFIG_MBEDTLS_X509_CSR_PARSE_C 1
+
+#define CONFIG_MAKE_WARN_UNDEFINED_VARIABLES 1
+#define CONFIG_TOOLPREFIX "xtensa-esp32-elf-"
+#define CONFIG_PYTHON "python2"
diff --git a/ports/esp32/uart.c b/ports/esp32/uart.c
new file mode 100644
index 000000000..10a4ba462
--- /dev/null
+++ b/ports/esp32/uart.c
@@ -0,0 +1,65 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * Development of the code in this file was sponsored by Microbric Pty Ltd
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdio.h>
+
+#include "driver/uart.h"
+
+#include "py/mpstate.h"
+#include "py/mphal.h"
+
+STATIC void uart_irq_handler(void *arg);
+
+void uart_init(void) {
+ uart_isr_handle_t handle;
+ uart_isr_register(UART_NUM_0, uart_irq_handler, NULL, ESP_INTR_FLAG_LOWMED | ESP_INTR_FLAG_IRAM, &handle);
+ uart_enable_rx_intr(UART_NUM_0);
+}
+
+// all code executed in ISR must be in IRAM, and any const data must be in DRAM
+STATIC void IRAM_ATTR uart_irq_handler(void *arg) {
+ volatile uart_dev_t *uart = &UART0;
+ uart->int_clr.rxfifo_full = 1;
+ uart->int_clr.frm_err = 1;
+ uart->int_clr.rxfifo_tout = 1;
+ while (uart->status.rxfifo_cnt) {
+ uint8_t c = uart->fifo.rw_byte;
+ if (c == mp_interrupt_char) {
+ // inline version of mp_keyboard_interrupt();
+ MP_STATE_VM(mp_pending_exception) = MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_kbd_exception));
+ #if MICROPY_ENABLE_SCHEDULER
+ if (MP_STATE_VM(sched_state) == MP_SCHED_IDLE) {
+ MP_STATE_VM(sched_state) = MP_SCHED_PENDING;
+ }
+ #endif
+ } else {
+ // this is an inline function so will be in IRAM
+ ringbuf_put(&stdin_ringbuf, c);
+ }
+ }
+}
diff --git a/ports/esp32/uart.h b/ports/esp32/uart.h
new file mode 100644
index 000000000..264c8b894
--- /dev/null
+++ b/ports/esp32/uart.h
@@ -0,0 +1,33 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * Development of the code in this file was sponsored by Microbric Pty Ltd
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#ifndef MICROPY_INCLUDED_ESP32_UART_H
+#define MICROPY_INCLUDED_ESP32_UART_H
+
+void uart_init(void);
+
+#endif // MICROPY_INCLUDED_ESP32_UART_H
diff --git a/ports/esp8266/Makefile b/ports/esp8266/Makefile
index 8fabd3412..5c0983fe7 100644
--- a/ports/esp8266/Makefile
+++ b/ports/esp8266/Makefile
@@ -193,6 +193,7 @@ LIB_SRC_C += \
lib/oofatfs/option/unicode.c
endif
+ bus/softspi.c \
SRC_S = \
gchelper.s \
@@ -205,7 +206,6 @@ OBJ += $(addprefix $(BUILD)/, $(SRC_SHARED_MODULE_EXPANDED:.c=.o))
OBJ += $(addprefix $(BUILD)/, $(STM_SRC_C:.c=.o))
OBJ += $(addprefix $(BUILD)/, $(EXTMOD_SRC_C:.c=.o))
OBJ += $(addprefix $(BUILD)/, $(LIB_SRC_C:.c=.o))
-#OBJ += $(BUILD)/pins_$(BOARD).o
# List of sources for qstr extraction
SRC_QSTR += $(SRC_C) $(SRC_COMMON_HAL_EXPANDED) $(SRC_SHARED_MODULE_EXPANDED) $(STM_SRC_C) $(EXTMOD_SRC_C) $(DRIVERS_SRC_C)
@@ -258,32 +258,6 @@ ota:
rm -f $(BUILD)/firmware.elf $(BUILD)/firmware.elf*.bin
$(MAKE) LDSCRIPT=esp8266_ota.ld FWBIN=$(BUILD)/firmware-ota.bin
-#MAKE_PINS = boards/make-pins.py
-#BOARD_PINS = boards/$(BOARD)/pins.csv
-#AF_FILE = boards/stm32f4xx_af.csv
-#PREFIX_FILE = boards/stm32f4xx_prefix.c
-#GEN_PINS_SRC = $(BUILD)/pins_$(BOARD).c
-#GEN_PINS_HDR = $(HEADER_BUILD)/pins.h
-#GEN_PINS_QSTR = $(BUILD)/pins_qstr.h
-#GEN_PINS_AF_CONST = $(HEADER_BUILD)/pins_af_const.h
-#GEN_PINS_AF_PY = $(BUILD)/pins_af.py
-
-# Making OBJ use an order-only depenedency on the generated pins.h file
-# has the side effect of making the pins.h file before we actually compile
-# any of the objects. The normal dependency generation will deal with the
-# case when pins.h is modified. But when it doesn't exist, we don't know
-# which source files might need it.
-#$(OBJ): | $(HEADER_BUILD)/pins.h
-
-# Use a pattern rule here so that make will only call make-pins.py once to make
-# both pins_$(BOARD).c and pins.h
-#$(BUILD)/%_$(BOARD).c $(HEADER_BUILD)/%.h $(HEADER_BUILD)/%_af_const.h $(BUILD)/%_qstr.h: boards/$(BOARD)/%.csv $(MAKE_PINS) $(AF_FILE) $(PREFIX_FILE) | $(HEADER_BUILD)
-# $(ECHO) "Create $@"
-# $(Q)$(PYTHON) $(MAKE_PINS) --board $(BOARD_PINS) --af $(AF_FILE) --prefix $(PREFIX_FILE) --hdr $(GEN_PINS_HDR) --qstr $(GEN_PINS_QSTR) --af-const $(GEN_PINS_AF_CONST) --af-py $(GEN_PINS_AF_PY) > $(GEN_PINS_SRC)
-#
-#$(BUILD)/pins_$(BOARD).o: $(BUILD)/pins_$(BOARD).c
-# $(call compile_c)
-
include $(TOP)/py/mkrules.mk
axtls: $(BUILD)/libaxtls.a
diff --git a/ports/esp8266/README.md b/ports/esp8266/README.md
index 252e195d8..f4dddd1ca 100644
--- a/ports/esp8266/README.md
+++ b/ports/esp8266/README.md
@@ -49,7 +49,7 @@ $ make -C mpy-cross
Then, to build MicroPython for the ESP8266, just run:
```bash
-$ cd esp8266
+$ cd ports/esp8266
$ make axtls
$ make
```
@@ -92,12 +92,16 @@ of FlashROM.
First start
-----------
+Be sure to change ESP8266's WiFi access point password ASAP, see below.
+
__Serial prompt__
You can access the REPL (Python prompt) over UART (the same as used for
programming).
- Baudrate: 115200
+Run `help()` for some basic information.
+
__WiFi__
Initially, the device configures itself as a WiFi access point (AP).
@@ -105,14 +109,32 @@ Initially, the device configures itself as a WiFi access point (AP).
- Password: micropythoN (note the upper-case N).
- IP address of the board: 192.168.4.1.
- DHCP-server is activated.
+- Please be sure to change the password to something non-guessable
+ immediately. `help()` gives information how.
__WebREPL__
Python prompt over WiFi, connecting through a browser.
- Hosted at http://micropython.org/webrepl.
- GitHub repository https://github.com/micropython/webrepl.
+ Please follow the instructions there.
+
+__upip__
+
+The ESP8266 port comes with builtin `upip` package manager, which can
+be used to install additional modules (see the main README for more
+information):
+
+```
+>>> import upip
+>>> upip.install("micropython-pystone_lowmem")
+[...]
+>>> import pystone_lowmem
+>>> pystone_lowmem.main()
+```
-Please follow the instructions there.
+Downloading and installing packages may requite a lot of free memory,
+if you get an error, retry immediately after the hard reset.
Documentation
-------------
diff --git a/ports/esp8266/common-hal/os/__init__.c b/ports/esp8266/common-hal/os/__init__.c
index d9d1da266..b9773d186 100644
--- a/ports/esp8266/common-hal/os/__init__.c
+++ b/ports/esp8266/common-hal/os/__init__.c
@@ -58,7 +58,7 @@ STATIC mp_obj_tuple_t os_uname_info_obj = {
mp_obj_t common_hal_os_uname(void) {
// We must populate the "release" field each time in case it was GC'd since the last call.
const char *ver = system_get_sdk_version();
- os_uname_info_obj.items[2] = mp_obj_new_str(ver, strlen(ver), false);
+ os_uname_info_obj.items[2] = mp_obj_new_str(ver, strlen(ver));
return (mp_obj_t)&os_uname_info_obj;
}
@@ -75,6 +75,19 @@ bool common_hal_os_urandom(uint8_t* buffer, uint32_t length) {
i++;
new_random >>= 8;
}
+// We wrap the mp_uos_dupterm function to detect if a UART is attached or not
+mp_obj_t os_dupterm(size_t n_args, const mp_obj_t *args) {
+ mp_obj_t prev_obj = mp_uos_dupterm_obj.fun.var(n_args, args);
+ if (mp_obj_get_type(args[0]) == &pyb_uart_type) {
+ ++uart_attached_to_dupterm;
+ }
+ if (mp_obj_get_type(prev_obj) == &pyb_uart_type) {
+ --uart_attached_to_dupterm;
+ }
+ return prev_obj;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(os_dupterm_obj, 1, 2, os_dupterm);
+
}
return true;
}
diff --git a/ports/esp8266/esp8266_common.ld b/ports/esp8266/esp8266_common.ld
index aeeecb927..b247e3ffd 100644
--- a/ports/esp8266/esp8266_common.ld
+++ b/ports/esp8266/esp8266_common.ld
@@ -139,6 +139,7 @@ SECTIONS
*lib/netutils/*.o*(.literal*, .text*)
*lib/timeutils/*.o*(.literal*, .text*)
*lib/utils/*.o*(.literal*, .text*)
+ *drivers/bus/*.o(.literal* .text*)
build/main.o(.literal* .text*)
*gccollect.o(.literal* .text*)
diff --git a/ports/esp8266/esp_mphal.c b/ports/esp8266/esp_mphal.c
index 93ebc450a..5dcdd6fba 100644
--- a/ports/esp8266/esp_mphal.c
+++ b/ports/esp8266/esp_mphal.c
@@ -35,15 +35,18 @@
#include "extmod/misc.h"
#include "lib/utils/pyexec.h"
-STATIC byte input_buf_array[256];
-ringbuf_t input_buf = {input_buf_array, sizeof(input_buf_array)};
+STATIC byte stdin_ringbuf_array[256];
+ringbuf_t stdin_ringbuf = {stdin_ringbuf_array, sizeof(stdin_ringbuf_array), 0, 0};
void mp_hal_debug_tx_strn_cooked(void *env, const char *str, uint32_t len);
const mp_print_t mp_debug_print = {NULL, mp_hal_debug_tx_strn_cooked};
+int uart_attached_to_dupterm;
+
void mp_hal_init(void) {
//ets_wdt_disable(); // it's a pain while developing
mp_hal_rtc_init();
uart_init(UART_BIT_RATE_115200, UART_BIT_RATE_115200);
+ uart_attached_to_dupterm = 0;
}
void mp_hal_delay_us(uint32_t us) {
@@ -59,7 +62,7 @@ uint32_t mp_hal_get_cpu_freq(void) {
int mp_hal_stdin_rx_chr(void) {
for (;;) {
- int c = ringbuf_get(&input_buf);
+ int c = ringbuf_get(&stdin_ringbuf);
if (c != -1) {
return c;
}
@@ -84,19 +87,11 @@ void mp_hal_debug_str(const char *str) {
#endif
void mp_hal_stdout_tx_str(const char *str) {
- const char *last = str;
- while (*str) {
- uart_tx_one_char(UART0, *str++);
- }
- mp_uos_dupterm_tx_strn(last, str - last);
+ mp_uos_dupterm_tx_strn(str, strlen(str));
}
void mp_hal_stdout_tx_strn(const char *str, uint32_t len) {
- const char *last = str;
- while (len--) {
- uart_tx_one_char(UART0, *str++);
- }
- mp_uos_dupterm_tx_strn(last, str - last);
+ mp_uos_dupterm_tx_strn(str, len);
}
void mp_hal_stdout_tx_strn_cooked(const char *str, uint32_t len) {
@@ -106,13 +101,11 @@ void mp_hal_stdout_tx_strn_cooked(const char *str, uint32_t len) {
if (str > last) {
mp_uos_dupterm_tx_strn(last, str - last);
}
- uart_tx_one_char(UART0, '\r');
- uart_tx_one_char(UART0, '\n');
mp_uos_dupterm_tx_strn("\r\n", 2);
++str;
last = str;
} else {
- uart_tx_one_char(UART0, *str++);
+ ++str;
}
}
if (str > last) {
@@ -170,7 +163,7 @@ STATIC void dupterm_task_handler(os_event_t *evt) {
if (c < 0) {
break;
}
- ringbuf_put(&input_buf, c);
+ ringbuf_put(&stdin_ringbuf, c);
}
mp_hal_signal_input();
lock = 0;
diff --git a/ports/esp8266/esp_mphal.h b/ports/esp8266/esp_mphal.h
index 194e56f64..56d9fa35f 100644
--- a/ports/esp8266/esp_mphal.h
+++ b/ports/esp8266/esp_mphal.h
@@ -34,12 +34,15 @@ struct _mp_print_t;
// Structure for UART-only output via mp_printf()
extern const struct _mp_print_t mp_debug_print;
-extern ringbuf_t input_buf;
-// Call this after putting data to input_buf
+extern ringbuf_t stdin_ringbuf;
+// Call this after putting data to stdin_ringbuf
void mp_hal_signal_input(void);
// Call this when data is available in dupterm object
void mp_hal_signal_dupterm_input(void);
+// This variable counts how many times the UART is attached to dupterm
+extern int uart_attached_to_dupterm;
+
void mp_hal_init(void);
void mp_hal_rtc_init(void);
@@ -86,7 +89,7 @@ void mp_hal_pin_open_drain(mp_hal_pin_obj_t pin);
} while (0)
#define mp_hal_pin_od_high(p) do { \
if ((p) == 16) { WRITE_PERI_REG(RTC_GPIO_ENABLE, (READ_PERI_REG(RTC_GPIO_ENABLE) & ~1)); } \
- else { gpio_output_set(1 << (p), 0, 1 << (p), 0); } \
+ else { gpio_output_set(0, 0, 0, 1 << (p)); /* set as input to avoid glitches */ } \
} while (0)
#define mp_hal_pin_read(p) pin_get(p)
#define mp_hal_pin_write(p, v) pin_set((p), (v))
diff --git a/ports/esp8266/esppwm.c b/ports/esp8266/esppwm.c
index f1d7060df..33eaf3b9a 100644
--- a/ports/esp8266/esppwm.c
+++ b/ports/esp8266/esppwm.c
@@ -190,11 +190,8 @@ pwm_start(void)
// start
gpio_output_set(local_single[0].gpio_set, local_single[0].gpio_clear, pwm_gpio, 0);
- // yeah, if all channels' duty is 0 or 255, don't need to start timer, otherwise start...
- if (*local_channel != 1) {
- pwm_timer_down = 0;
- RTC_REG_WRITE(FRC1_LOAD_ADDRESS, local_single[0].h_time);
- }
+ pwm_timer_down = 0;
+ RTC_REG_WRITE(FRC1_LOAD_ADDRESS, local_single[0].h_time);
}
if (pwm_toggle == 1) {
@@ -210,12 +207,12 @@ pwm_start(void)
/******************************************************************************
* FunctionName : pwm_set_duty
* Description : set each channel's duty params
- * Parameters : uint8 duty : 0 ~ PWM_DEPTH
+ * Parameters : int16_t duty : 0 ~ PWM_DEPTH
* uint8 channel : channel index
* Returns : NONE
*******************************************************************************/
void ICACHE_FLASH_ATTR
-pwm_set_duty(uint16 duty, uint8 channel)
+pwm_set_duty(int16_t duty, uint8 channel)
{
uint8 i;
for(i=0;i<pwm_channel_num;i++){
@@ -319,11 +316,7 @@ pwm_tim1_intr_handler(void *dummy)
pwm_current_channel = 0;
- if (*pwm_channel != 1) {
- RTC_REG_WRITE(FRC1_LOAD_ADDRESS, pwm_single[pwm_current_channel].h_time);
- } else {
- pwm_timer_down = 1;
- }
+ RTC_REG_WRITE(FRC1_LOAD_ADDRESS, pwm_single[pwm_current_channel].h_time);
} else {
gpio_output_set(pwm_single[pwm_current_channel].gpio_set,
pwm_single[pwm_current_channel].gpio_clear,
diff --git a/ports/esp8266/esppwm.h b/ports/esp8266/esppwm.h
index 1ee4a2f55..288ef6d53 100644
--- a/ports/esp8266/esppwm.h
+++ b/ports/esp8266/esppwm.h
@@ -7,7 +7,7 @@
void pwm_init(void);
void pwm_start(void);
-void pwm_set_duty(uint16_t duty, uint8_t channel);
+void pwm_set_duty(int16_t duty, uint8_t channel);
uint16_t pwm_get_duty(uint8_t channel);
void pwm_set_freq(uint16_t freq, uint8_t channel);
uint16_t pwm_get_freq(uint8_t channel);
diff --git a/ports/esp8266/espuart.c b/ports/esp8266/espuart.c
index dc4d1e611..557b771a3 100644
--- a/ports/esp8266/espuart.c
+++ b/ports/esp8266/espuart.c
@@ -34,6 +34,11 @@ static int uart_os = UART_OS;
static os_event_t uart_evt_queue[16];
#endif
+// A small, static ring buffer for incoming chars
+// This will only be populated if the UART is not attached to dupterm
+static byte uart_ringbuf_array[16];
+static ringbuf_t uart_ringbuf = {uart_ringbuf_array, sizeof(uart_ringbuf_array), 0, 0};
+
static void uart0_rx_intr_handler(void *para);
void soft_reset(void);
@@ -170,18 +175,26 @@ static void uart0_rx_intr_handler(void *para) {
while (READ_PERI_REG(UART_STATUS(uart_no)) & (UART_RXFIFO_CNT << UART_RXFIFO_CNT_S)) {
uint8 RcvChar = READ_PERI_REG(UART_FIFO(uart_no)) & 0xff;
- if (RcvChar == mp_interrupt_char) {
- mp_keyboard_interrupt();
+ // For efficiency, when connected to dupterm we put incoming chars
+ // directly on stdin_ringbuf, rather than going via uart_ringbuf
+ if (uart_attached_to_dupterm) {
+ if (RcvChar == mp_interrupt_char) {
+ mp_keyboard_interrupt();
+ } else {
+ ringbuf_put(&stdin_ringbuf, RcvChar);
+ }
} else {
- ringbuf_put(&input_buf, RcvChar);
+ ringbuf_put(&uart_ringbuf, RcvChar);
}
}
- mp_hal_signal_input();
-
// Clear pending FIFO interrupts
WRITE_PERI_REG(UART_INT_CLR(UART_REPL), UART_RXFIFO_TOUT_INT_CLR | UART_RXFIFO_FULL_INT_ST);
ETS_UART_INTR_ENABLE();
+
+ if (uart_attached_to_dupterm) {
+ mp_hal_signal_input();
+ }
}
}
@@ -190,7 +203,7 @@ static void uart0_rx_intr_handler(void *para) {
bool uart_rx_wait(uint32_t timeout_us) {
uint32_t start = system_get_time();
for (;;) {
- if (input_buf.iget != input_buf.iput) {
+ if (uart_ringbuf.iget != uart_ringbuf.iput) {
return true; // have at least 1 char ready for reading
}
if (system_get_time() - start >= timeout_us) {
@@ -201,7 +214,7 @@ bool uart_rx_wait(uint32_t timeout_us) {
}
int uart_rx_any(uint8 uart) {
- if (input_buf.iget != input_buf.iput) {
+ if (uart_ringbuf.iget != uart_ringbuf.iput) {
return true; // have at least 1 char ready for reading
}
return false;
@@ -217,7 +230,7 @@ int uart_tx_any_room(uint8 uart) {
// Returns char from the input buffer, else -1 if buffer is empty.
int uart_rx_char(void) {
- return ringbuf_get(&input_buf);
+ return ringbuf_get(&uart_ringbuf);
}
int uart_rx_one_char(uint8 uart_no) {
@@ -276,7 +289,7 @@ void uart_task_handler(os_event_t *evt) {
int c, ret = 0;
while ((c = ringbuf_get(&input_buf)) >= 0) {
- if (c == interrupt_char) {
+ if (c == mp_interrupt_char) {
mp_keyboard_interrupt();
}
ret = pyexec_event_repl_process_char(c);
diff --git a/ports/esp8266/machine_hspi.c b/ports/esp8266/machine_hspi.c
index 9fd0f4868..07770c8c8 100644
--- a/ports/esp8266/machine_hspi.c
+++ b/ports/esp8266/machine_hspi.c
@@ -39,6 +39,8 @@
#include "modmachine.h"
#include "hspi.h"
+#if MICROPY_PY_MACHINE_SPI
+
typedef struct _machine_hspi_obj_t {
mp_obj_base_t base;
uint32_t baudrate;
@@ -65,6 +67,9 @@ STATIC void machine_hspi_transfer(mp_obj_base_t *self_in, size_t len, const uint
spi_tx8fast(HSPI, src[i]);
++i;
}
+ // wait for SPI transaction to complete
+ while (spi_busy(HSPI)) {
+ }
} else {
// we need to read and write data
@@ -177,3 +182,5 @@ const mp_obj_type_t machine_hspi_type = {
.protocol = &machine_hspi_p,
.locals_dict = (mp_obj_dict_t*)&mp_machine_spi_locals_dict,
};
+
+#endif // MICROPY_PY_MACHINE_SPI
diff --git a/ports/esp8266/main.c b/ports/esp8266/main.c
index c590ab59e..da41b00c9 100644
--- a/ports/esp8266/main.c
+++ b/ports/esp8266/main.c
@@ -111,9 +111,29 @@ STATIC void mp_reset(void) {
readline_init0();
dupterm_task_init();
pwmout_reset();
+
+ // Check if there are any dupterm objects registered and if not then
+ // activate UART(0), or else there will never be any chance to get a REPL
+ size_t idx;
+ for (idx = 0; idx < MICROPY_PY_OS_DUPTERM; ++idx) {
+ if (MP_STATE_VM(dupterm_objs[idx]) != MP_OBJ_NULL) {
+ break;
+ }
+ }
+ if (idx == MICROPY_PY_OS_DUPTERM) {
+ mp_obj_t args[2];
+ args[0] = MP_OBJ_NEW_SMALL_INT(0);
+ args[1] = MP_OBJ_NEW_SMALL_INT(115200);
+ args[0] = pyb_uart_type.make_new(&pyb_uart_type, 2, 0, args);
+ args[1] = MP_OBJ_NEW_SMALL_INT(1);
+ extern mp_obj_t os_dupterm(size_t n_args, const mp_obj_t *args);
+ os_dupterm(2, args);
+ mp_hal_stdout_tx_str("Activated UART(0) for REPL\r\n");
+ }
}
bool soft_reset(void) {
+ gc_sweep_all();
mp_hal_stdout_tx_str("PYB: soft reboot\r\n");
mp_hal_delay_us(10000); // allow UART to flush output
mp_reset();
@@ -177,3 +197,17 @@ void __assert(const char *file, int line, const char *expr) {
for (;;) {
}
}
+
+#if !MICROPY_DEBUG_PRINTERS
+// With MICROPY_DEBUG_PRINTERS disabled DEBUG_printf is not defined but it
+// is still needed by esp-open-lwip for debugging output, so define it here.
+#include <stdarg.h>
+int mp_vprintf(const mp_print_t *print, const char *fmt, va_list args);
+int DEBUG_printf(const char *fmt, ...) {
+ va_list ap;
+ va_start(ap, fmt);
+ int ret = mp_vprintf(&MICROPY_DEBUG_PRINTER_DEST, fmt, ap);
+ va_end(ap);
+ return ret;
+}
+#endif
diff --git a/ports/esp8266/modmachine.c b/ports/esp8266/modmachine.c
index 99286848e..7e5f6714b 100644
--- a/ports/esp8266/modmachine.c
+++ b/ports/esp8266/modmachine.c
@@ -255,8 +255,12 @@ STATIC const mp_rom_map_elem_t machine_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR_PWM), MP_ROM_PTR(&pyb_pwm_type) },
{ MP_ROM_QSTR(MP_QSTR_ADC), MP_ROM_PTR(&pyb_adc_type) },
{ MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&pyb_uart_type) },
+ #if MICROPY_PY_MACHINE_I2C
{ MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&machine_i2c_type) },
+ #endif
+ #if MICROPY_PY_MACHINE_SPI
{ MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&machine_hspi_type) },
+ #endif
// wake abilities
{ MP_ROM_QSTR(MP_QSTR_DEEPSLEEP), MP_ROM_INT(MACHINE_WAKE_DEEPSLEEP) },
diff --git a/ports/esp8266/modnetwork.c b/ports/esp8266/modnetwork.c
index ff2172d42..e220808b1 100644
--- a/ports/esp8266/modnetwork.c
+++ b/ports/esp8266/modnetwork.c
@@ -65,6 +65,9 @@ STATIC mp_obj_t get_wlan(size_t n_args, const mp_obj_t *args) {
int idx = 0;
if (n_args > 0) {
idx = mp_obj_get_int(args[0]);
+ if (idx < 0 || idx >= sizeof(wlan_objs)) {
+ mp_raise_ValueError(NULL);
+ }
}
return MP_OBJ_FROM_PTR(&wlan_objs[idx]);
}
@@ -150,14 +153,26 @@ STATIC mp_obj_t esp_disconnect(mp_obj_t self_in) {
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp_disconnect_obj, esp_disconnect);
-STATIC mp_obj_t esp_status(mp_obj_t self_in) {
- wlan_if_obj_t *self = MP_OBJ_TO_PTR(self_in);
- if (self->if_id == STATION_IF) {
- return MP_OBJ_NEW_SMALL_INT(wifi_station_get_connect_status());
+STATIC mp_obj_t esp_status(size_t n_args, const mp_obj_t *args) {
+ wlan_if_obj_t *self = MP_OBJ_TO_PTR(args[0]);
+ if (n_args == 1) {
+ // Get link status
+ if (self->if_id == STATION_IF) {
+ return MP_OBJ_NEW_SMALL_INT(wifi_station_get_connect_status());
+ }
+ return MP_OBJ_NEW_SMALL_INT(-1);
+ } else {
+ // Get specific status parameter
+ switch (mp_obj_str_get_qstr(args[1])) {
+ case MP_QSTR_rssi:
+ if (self->if_id == STATION_IF) {
+ return MP_OBJ_NEW_SMALL_INT(wifi_station_get_rssi());
+ }
+ }
+ mp_raise_ValueError("unknown status param");
}
- return MP_OBJ_NEW_SMALL_INT(-1);
}
-STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp_status_obj, esp_status);
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp_status_obj, 1, 2, esp_status);
STATIC mp_obj_t *esp_scan_list = NULL;
@@ -402,42 +417,45 @@ STATIC mp_obj_t esp_config(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs
mp_obj_t val;
- #define QS(x) (uintptr_t)MP_OBJ_NEW_QSTR(x)
- switch ((uintptr_t)args[1]) {
- case QS(MP_QSTR_mac): {
+ qstr key = mp_obj_str_get_qstr(args[1]);
+ switch (key) {
+ case MP_QSTR_mac: {
uint8_t mac[6];
wifi_get_macaddr(self->if_id, mac);
return mp_obj_new_bytes(mac, sizeof(mac));
}
- case QS(MP_QSTR_essid):
+ case MP_QSTR_essid:
if (self->if_id == STATION_IF) {
val = mp_obj_new_str((char*)cfg.sta.ssid, strlen((char*)cfg.sta.ssid), false);
} else {
val = mp_obj_new_str((char*)cfg.ap.ssid, cfg.ap.ssid_len, false);
}
break;
- case QS(MP_QSTR_hidden):
+ case MP_QSTR_hidden:
req_if = SOFTAP_IF;
val = mp_obj_new_bool(cfg.ap.ssid_hidden);
break;
- case QS(MP_QSTR_authmode):
+ case MP_QSTR_authmode:
req_if = SOFTAP_IF;
val = MP_OBJ_NEW_SMALL_INT(cfg.ap.authmode);
break;
- case QS(MP_QSTR_channel):
+ case MP_QSTR_channel:
req_if = SOFTAP_IF;
val = MP_OBJ_NEW_SMALL_INT(cfg.ap.channel);
break;
- case QS(MP_QSTR_dhcp_hostname): {
+ case MP_QSTR_dhcp_hostname: {
req_if = STATION_IF;
char* s = wifi_station_get_hostname();
- val = mp_obj_new_str(s, strlen(s), false);
+ if (s == NULL) {
+ val = MP_OBJ_NEW_QSTR(MP_QSTR_);
+ } else {
+ val = mp_obj_new_str(s, strlen(s));
+ }
break;
}
default:
goto unknown;
}
- #undef QS
// We post-check interface requirements to save on code size
if (req_if >= 0) {
diff --git a/ports/esp8266/modules/inisetup.py b/ports/esp8266/modules/inisetup.py
index 46f089248..7aa8bd435 100644
--- a/ports/esp8266/modules/inisetup.py
+++ b/ports/esp8266/modules/inisetup.py
@@ -48,6 +48,8 @@ def setup():
# This file is executed on every boot (including wake-boot from deepsleep)
#import esp
#esp.osdebug(None)
+import uos, machine
+uos.dupterm(machine.UART(0, 115200), 1)
import gc
#import webrepl
#webrepl.start()
diff --git a/ports/esp8266/modules/ntptime.py b/ports/esp8266/modules/ntptime.py
index a97e08e60..85c754af6 100644
--- a/ports/esp8266/modules/ntptime.py
+++ b/ports/esp8266/modules/ntptime.py
@@ -33,4 +33,3 @@ def settime():
tm = utime.localtime(t)
tm = tm[0:3] + (0,) + tm[3:6] + (0,)
machine.RTC().datetime(tm)
- print(utime.localtime())
diff --git a/ports/esp8266/modules/webrepl_setup.py b/ports/esp8266/modules/webrepl_setup.py
index 50d866b55..00b7c89e6 100644
--- a/ports/esp8266/modules/webrepl_setup.py
+++ b/ports/esp8266/modules/webrepl_setup.py
@@ -34,12 +34,6 @@ def exists(fname):
except OSError:
return False
-def copy_stream(s_in, s_out):
- buf = bytearray(64)
- while 1:
- sz = s_in.readinto(buf)
- s_out.write(buf, sz)
-
def get_daemon_status():
with open(RC) as f:
@@ -50,22 +44,22 @@ def get_daemon_status():
return True
return None
-def add_daemon():
- with open(RC) as old_f, open(RC + ".tmp", "w") as new_f:
- new_f.write("import webrepl\nwebrepl.start()\n")
- copy_stream(old_f, new_f)
def change_daemon(action):
LINES = ("import webrepl", "webrepl.start()")
with open(RC) as old_f, open(RC + ".tmp", "w") as new_f:
+ found = False
for l in old_f:
for patt in LINES:
if patt in l:
+ found = True
if action and l.startswith("#"):
l = l[1:]
elif not action and not l.startswith("#"):
l = "#" + l
new_f.write(l)
+ if not found:
+ new_f.write("import webrepl\nwebrepl.start()\n")
# FatFs rename() is not POSIX compliant, will raise OSError if
# dest file exists.
os.remove(RC)
diff --git a/ports/esp8266/mpconfigport.h b/ports/esp8266/mpconfigport.h
index 907a4cbdf..84c18f996 100644
--- a/ports/esp8266/mpconfigport.h
+++ b/ports/esp8266/mpconfigport.h
@@ -30,6 +30,7 @@
#define MICROPY_CAN_OVERRIDE_BUILTINS (1)
#define MICROPY_USE_INTERNAL_ERRNO (0)
#define MICROPY_ENABLE_SCHEDULER (1)
+#define MICROPY_PY_DESCRIPTORS (1)
#define MICROPY_PY_ALL_SPECIAL_METHODS (1)
#define MICROPY_PY_BUILTINS_COMPLEX (0)
#define MICROPY_PY_BUILTINS_STR_UNICODE (1)
@@ -40,7 +41,7 @@
#define MICROPY_PY_BUILTINS_SLICE (1)
#define MICROPY_PY_BUILTINS_SLICE_ATTRS (1)
#define MICROPY_PY_BUILTINS_PROPERTY (1)
-#define MICROPY_PY_DESCRIPTORS (1)
+#define MICROPY_PY_BUILTINS_ROUND_INT (1)
#define MICROPY_PY_BUILTINS_INPUT (1)
#define MICROPY_PY_BUILTINS_HELP (1)
#define MICROPY_PY_BUILTINS_HELP_TEXT esp_help_text
@@ -51,10 +52,12 @@
#define MICROPY_PY_ARRAY_SLICE_ASSIGN (1)
#define MICROPY_NONSTANDARD_TYPECODES (0)
#define MICROPY_PY_COLLECTIONS (1)
+#define MICROPY_PY_COLLECTIONS_DEQUE (1)
#define MICROPY_PY_COLLECTIONS_ORDEREDDICT (1)
#define MICROPY_PY_MATH (0)
#define MICROPY_PY_CMATH (0)
#define MICROPY_PY_IO (1)
+#define MICROPY_PY_IO_IOBASE (1)
#define MICROPY_PY_IO_FILEIO (1)
#define MICROPY_PY_STRUCT (0)
#define MICROPY_PY_SYS (1)
@@ -87,7 +90,7 @@
#define MICROPY_PY_WEBREPL_DELAY (20)
#define MICROPY_PY_FRAMEBUF (1)
#define MICROPY_PY_MICROPYTHON_MEM_INFO (1)
-#define MICROPY_PY_OS_DUPTERM (1)
+#define MICROPY_PY_OS_DUPTERM (2)
#define MICROPY_CPYTHON_COMPAT (0)
#define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_MPZ)
#define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_FLOAT)
@@ -142,8 +145,8 @@ typedef uint32_t sys_prot_t; // for modlwip
void *esp_native_code_commit(void*, size_t);
#define MP_PLAT_COMMIT_EXEC(buf, len) esp_native_code_commit(buf, len)
-#define mp_type_fileio fatfs_type_fileio
-#define mp_type_textio fatfs_type_textio
+#define mp_type_fileio mp_type_vfs_fat_fileio
+#define mp_type_textio mp_type_vfs_fat_textio
// use vfs's functions for import stat and builtin open
#define mp_import_stat mp_vfs_import_stat
diff --git a/ports/esp8266/mpconfigport_512k.h b/ports/esp8266/mpconfigport_512k.h
index b84c13479..dc97efd35 100644
--- a/ports/esp8266/mpconfigport_512k.h
+++ b/ports/esp8266/mpconfigport_512k.h
@@ -5,6 +5,9 @@
#undef MICROPY_EMIT_INLINE_XTENSA
#define MICROPY_EMIT_INLINE_XTENSA (0)
+#undef MICROPY_DEBUG_PRINTERS
+#define MICROPY_DEBUG_PRINTERS (0)
+
#undef MICROPY_ERROR_REPORTING
#define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_TERSE)
diff --git a/ports/esp8266/posix_helpers.c b/ports/esp8266/posix_helpers.c
index 1c20c8b0b..adb0145e7 100644
--- a/ports/esp8266/posix_helpers.c
+++ b/ports/esp8266/posix_helpers.c
@@ -55,14 +55,13 @@ void *realloc(void *ptr, size_t size) {
return p;
}
-#define PLATFORM_HTONL(_n) ((uint32_t)( (((_n) & 0xff) << 24) | (((_n) & 0xff00) << 8) | (((_n) >> 8) & 0xff00) | (((_n) >> 24) & 0xff) ))
#undef htonl
#undef ntohl
uint32_t ntohl(uint32_t netlong) {
- return PLATFORM_HTONL(netlong);
+ return MP_BE32TOH(netlong);
}
uint32_t htonl(uint32_t netlong) {
- return PLATFORM_HTONL(netlong);
+ return MP_HTOBE32(netlong);
}
time_t time(time_t *t) {
diff --git a/ports/minimal/Makefile b/ports/minimal/Makefile
index ae295d655..64ad3cc0b 100644
--- a/ports/minimal/Makefile
+++ b/ports/minimal/Makefile
@@ -41,13 +41,14 @@ LIBS =
SRC_C = \
main.c \
uart_core.c \
+ lib/utils/printf.c \
lib/utils/stdout_helpers.c \
lib/utils/pyexec.c \
lib/libc/string0.c \
lib/mp-readline/readline.c \
$(BUILD)/_frozen_mpy.c \
-OBJ = $(PY_O) $(addprefix $(BUILD)/, $(SRC_C:.c=.o))
+OBJ = $(PY_CORE_O) $(addprefix $(BUILD)/, $(SRC_C:.c=.o))
ifeq ($(CROSS), 1)
all: $(BUILD)/firmware.dfu
diff --git a/ports/minimal/README.md b/ports/minimal/README.md
index 14b8c00a3..356fc4b3e 100644
--- a/ports/minimal/README.md
+++ b/ports/minimal/README.md
@@ -9,7 +9,7 @@ By default the port will be built for the host machine:
$ make
-To run a small test script do:
+To run the executable and get a basic working REPL do:
$ make run
diff --git a/ports/minimal/main.c b/ports/minimal/main.c
index 9d43a9cf9..5e145dc82 100644
--- a/ports/minimal/main.c
+++ b/ports/minimal/main.c
@@ -27,7 +27,9 @@ void do_str(const char *src, mp_parse_input_kind_t input_kind) {
#endif
static char *stack_top;
+#if MICROPY_ENABLE_GC
static char heap[2048];
+#endif
int main(int argc, char **argv) {
int stack_dummy;
diff --git a/ports/qemu-arm/Makefile b/ports/qemu-arm/Makefile
index 39e13853f..95f349beb 100644
--- a/ports/qemu-arm/Makefile
+++ b/ports/qemu-arm/Makefile
@@ -9,10 +9,12 @@ include $(TOP)/py/py.mk
CROSS_COMPILE = arm-none-eabi-
+TINYTEST = $(TOP)/lib/tinytest
+
INC += -I.
INC += -I$(TOP)
INC += -I$(BUILD)
-INC += -I$(TOP)/tools/tinytest/
+INC += -I$(TINYTEST)
CFLAGS_CORTEX_M3 = -mthumb -mcpu=cortex-m3 -mfloat-abi=soft
CFLAGS = $(INC) -Wall -Wpointer-arith -Werror -std=gnu99 $(CFLAGS_CORTEX_M3) $(COPT) \
@@ -44,7 +46,7 @@ SRC_RUN_C = \
SRC_TEST_C = \
test_main.c \
-LIB_SRC_C = $(addprefix lib/,\
+LIB_SRC_C += $(addprefix lib/,\
libm/math.c \
libm/fmodf.c \
libm/nearbyintf.c \
@@ -89,27 +91,9 @@ all: run
run: $(BUILD)/firmware.elf
qemu-system-arm -machine integratorcp -cpu cortex-m3 -nographic -monitor null -serial null -semihosting -kernel $(BUILD)/firmware.elf
-test: $(BUILD)/firmware-test.elf
- qemu-system-arm -machine integratorcp -cpu cortex-m3 -nographic -monitor null -serial null -semihosting -kernel $(BUILD)/firmware-test.elf > $(BUILD)/console.out
- $(Q)tail -n2 $(BUILD)/console.out
- $(Q)tail -n1 $(BUILD)/console.out | grep -q "status: 0"
-
-.PHONY: $(BUILD)/genhdr/tests.h
-
-$(BUILD)/test_main.o: $(BUILD)/genhdr/tests.h
-$(BUILD)/genhdr/tests.h:
- $(Q)echo "Generating $@";(cd $(TOP)/tests; ../tools/tinytest-codegen.py) > $@
-
-$(BUILD)/tinytest.o:
- $(Q)$(CC) $(CFLAGS) -DNO_FORKING -o $@ -c $(TOP)/tools/tinytest/tinytest.c
-
## `$(LD)` doesn't seem to like `--specs` for some reason, but we can just use `$(CC)` here.
$(BUILD)/firmware.elf: $(OBJ_COMMON) $(OBJ_RUN)
$(Q)$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LIBS)
$(Q)$(SIZE) $@
-$(BUILD)/firmware-test.elf: $(OBJ_COMMON) $(OBJ_TEST)
- $(Q)$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LIBS)
- $(Q)$(SIZE) $@
-
include $(TOP)/py/mkrules.mk
diff --git a/ports/qemu-arm/Makefile.test b/ports/qemu-arm/Makefile.test
new file mode 100644
index 000000000..a9aace6d0
--- /dev/null
+++ b/ports/qemu-arm/Makefile.test
@@ -0,0 +1,24 @@
+LIB_SRC_C = lib/upytesthelper/upytesthelper.c
+
+include Makefile
+
+CFLAGS += -DTEST
+
+.PHONY: $(BUILD)/genhdr/tests.h
+
+$(BUILD)/test_main.o: $(BUILD)/genhdr/tests.h
+$(BUILD)/genhdr/tests.h:
+ (cd $(TOP)/tests; ./run-tests --write-exp)
+ $(Q)echo "Generating $@";(cd $(TOP)/tests; ../tools/tinytest-codegen.py) > $@
+
+$(BUILD)/tinytest.o:
+ $(Q)$(CC) $(CFLAGS) -DNO_FORKING -o $@ -c $(TINYTEST)/tinytest.c
+
+$(BUILD)/firmware-test.elf: $(OBJ_COMMON) $(OBJ_TEST)
+ $(Q)$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LIBS)
+ $(Q)$(SIZE) $@
+
+test: $(BUILD)/firmware-test.elf
+ qemu-system-arm -machine integratorcp -cpu cortex-m3 -nographic -monitor null -serial null -semihosting -kernel $(BUILD)/firmware-test.elf > $(BUILD)/console.out
+ $(Q)tail -n2 $(BUILD)/console.out
+ $(Q)tail -n1 $(BUILD)/console.out | grep -q "status: 0"
diff --git a/ports/qemu-arm/README.md b/ports/qemu-arm/README.md
index 0cf93c7d5..4f1e79b10 100644
--- a/ports/qemu-arm/README.md
+++ b/ports/qemu-arm/README.md
@@ -21,3 +21,7 @@ toolchain and not with CodeSourcery toolchain. You will need to modify
The difference is that CodeSourcery needs `-T generic-m-hosted.ld` while
ARM's version requires `--specs=nano.specs --specs=rdimon.specs` to be
passed to the linker.
+
+To build and run image with builtin testsuite:
+
+ make -f Makefile.test test
diff --git a/ports/qemu-arm/mpconfigport.h b/ports/qemu-arm/mpconfigport.h
index 199883784..dbfc395af 100644
--- a/ports/qemu-arm/mpconfigport.h
+++ b/ports/qemu-arm/mpconfigport.h
@@ -17,6 +17,7 @@
#define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_MPZ)
#define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_FLOAT)
#define MICROPY_CAN_OVERRIDE_BUILTINS (1)
+#define MICROPY_WARNINGS (1)
#define MICROPY_PY_ALL_SPECIAL_METHODS (1)
#define MICROPY_PY_REVERSE_SPECIAL_METHODS (1)
#define MICROPY_PY_ARRAY_SLICE_ASSIGN (1)
@@ -70,3 +71,9 @@ extern const struct _mp_obj_module_t mp_module_uos;
// We need to provide a declaration/definition of alloca()
#include <alloca.h>
+
+#ifdef TEST
+#include "lib/upytesthelper/upytesthelper.h"
+#undef MP_PLAT_PRINT_STRN
+#define MP_PLAT_PRINT_STRN(str, len) upytest_output(str, len)
+#endif
diff --git a/ports/qemu-arm/test_main.c b/ports/qemu-arm/test_main.c
index c018ae428..adbdf04e1 100644
--- a/ports/qemu-arm/test_main.c
+++ b/ports/qemu-arm/test_main.c
@@ -3,6 +3,7 @@
#include <stdio.h>
#include <string.h>
#include <malloc.h>
+#include <setjmp.h>
#include "py/obj.h"
#include "py/compile.h"
@@ -17,44 +18,15 @@
#define HEAP_SIZE (128 * 1024)
STATIC void *heap;
-void do_str(const char *src);
-inline void do_str(const char *src) {
- gc_init(heap, (char*)heap + HEAP_SIZE);
- mp_init();
-
- nlr_buf_t nlr;
- if (nlr_push(&nlr) == 0) {
- mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, src, strlen(src), 0);
- qstr source_name = lex->source_name;
- mp_parse_tree_t parse_tree = mp_parse(lex, MP_PARSE_FILE_INPUT);
- mp_obj_t module_fun = mp_compile(&parse_tree, source_name, MP_EMIT_OPT_NONE, false);
- mp_call_function_0(module_fun);
- nlr_pop();
- } else {
- mp_obj_t exc = (mp_obj_t)nlr.ret_val;
- if (mp_obj_is_subclass_fast(mp_obj_get_type(exc), &mp_type_SystemExit)) {
- // Assume that sys.exit() is called to skip the test.
- // TODO: That can be always true, we should set up convention to
- // use specific exit code as skip indicator.
- tinytest_set_test_skipped_();
- goto end;
- }
- mp_obj_print_exception(&mp_plat_print, exc);
- tt_abort_msg("Uncaught exception");
- }
-end:
- mp_deinit();
-}
-
#include "genhdr/tests.h"
int main() {
- const char a[] = {"sim"};
mp_stack_ctrl_init();
mp_stack_set_limit(10240);
heap = malloc(HEAP_SIZE);
- int r = tinytest_main(1, (const char **) a, groups);
- printf( "status: %i\n", r);
+ upytest_set_heap(heap, (char*)heap + HEAP_SIZE);
+ int r = tinytest_main(0, NULL, groups);
+ printf("status: %d\n", r);
return r;
}
diff --git a/ports/stm32/Makefile b/ports/stm32/Makefile
index a6e82b24d..bedfa7009 100644
--- a/ports/stm32/Makefile
+++ b/ports/stm32/Makefile
@@ -14,6 +14,7 @@ include boards/$(BOARD)/mpconfigboard.mk
# qstr definitions (must come before including py.mk)
QSTR_DEFS = qstrdefsport.h $(BUILD)/pins_qstr.h $(BUILD)/modstm_qstr.h
+QSTR_GLOBAL_DEPENDENCIES = mpconfigboard_common.h boards/$(BOARD)/mpconfigboard.h
# directory containing scripts to be frozen as bytecode
FROZEN_MPY_DIR ?= modules
@@ -37,6 +38,7 @@ DEVICE=0483:df11
STFLASH ?= st-flash
OPENOCD ?= openocd
OPENOCD_CONFIG ?= boards/openocd_stm32f4.cfg
+STARTUP_FILE ?= boards/startup_stm32$(MCU_SERIES).o
CROSS_COMPILE = arm-none-eabi-
@@ -53,16 +55,22 @@ INC += -I$(USBDEV_DIR)/core/inc -I$(USBDEV_DIR)/class/inc
CFLAGS_CORTEX_M = -mthumb
# Select hardware floating-point support
-ifeq ($(CMSIS_MCU),$(filter $(CMSIS_MCU),STM32F767xx STM32F769xx))
+ifeq ($(CMSIS_MCU),$(filter $(CMSIS_MCU),STM32F767xx STM32F769xx STM32H743xx))
CFLAGS_CORTEX_M += -mfpu=fpv5-d16 -mfloat-abi=hard
else
+ifeq ($(MCU_SERIES),f0)
+CFLAGS_CORTEX_M += -msoft-float
+else
CFLAGS_CORTEX_M += -mfpu=fpv4-sp-d16 -mfloat-abi=hard
endif
+endif
# Options for particular MCU series
-CFLAGS_MCU_f4 = $(CFLAGS_CORTEX_M) -mtune=cortex-m4 -mcpu=cortex-m4 -DMCU_SERIES_F4
-CFLAGS_MCU_f7 = $(CFLAGS_CORTEX_M) -mtune=cortex-m7 -mcpu=cortex-m7 -DMCU_SERIES_F7
-CFLAGS_MCU_l4 = $(CFLAGS_CORTEX_M) -mtune=cortex-m4 -mcpu=cortex-m4 -DMCU_SERIES_L4
+CFLAGS_MCU_f0 = $(CFLAGS_CORTEX_M) -mtune=cortex-m0 -mcpu=cortex-m0
+CFLAGS_MCU_f4 = $(CFLAGS_CORTEX_M) -mtune=cortex-m4 -mcpu=cortex-m4
+CFLAGS_MCU_f7 = $(CFLAGS_CORTEX_M) -mtune=cortex-m7 -mcpu=cortex-m7
+CFLAGS_MCU_l4 = $(CFLAGS_CORTEX_M) -mtune=cortex-m4 -mcpu=cortex-m4
+CFLAGS_MCU_h7 = $(CFLAGS_CORTEX_M) -mtune=cortex-m7 -mcpu=cortex-m7
CFLAGS = $(INC) -Wall -Wpointer-arith -Werror -std=gnu99 -nostdlib $(CFLAGS_MOD) $(CFLAGS_EXTRA)
CFLAGS += -D$(CMSIS_MCU)
@@ -70,6 +78,7 @@ CFLAGS += $(CFLAGS_MCU_$(MCU_SERIES))
CFLAGS += $(COPT)
CFLAGS += -Iboards/$(BOARD)
CFLAGS += -DSTM32_HAL_H='<stm32$(MCU_SERIES)xx_hal.h>'
+CFLAGS += -DMICROPY_HW_VTOR=$(TEXT0_ADDR)
ifeq ($(MICROPY_FLOAT_IMPL),double)
CFLAGS += -DMICROPY_FLOAT_IMPL=MICROPY_FLOAT_IMPL_DOUBLE
@@ -78,7 +87,7 @@ CFLAGS += -DMICROPY_FLOAT_IMPL=MICROPY_FLOAT_IMPL_FLOAT
CFLAGS += -fsingle-precision-constant -Wdouble-promotion
endif
-LDFLAGS = -nostdlib -L $(LD_DIR) -T $(LD_FILE) -Map=$(@:.elf=.map) --cref
+LDFLAGS = -nostdlib -L $(LD_DIR) $(addprefix -T,$(LD_FILES)) -Map=$(@:.elf=.map) --cref
LIBS = $(shell $(CC) $(CFLAGS) -print-libgcc-file-name)
# Remove uncalled code from the final image.
@@ -153,7 +162,6 @@ SRC_LIBM = $(addprefix lib/libm_dbl/,\
else
SRC_LIBM = $(addprefix lib/libm/,\
math.c \
- thumb_vfp_sqrtf.c \
acoshf.c \
asinfacosf.c \
asinhf.c \
@@ -179,19 +187,27 @@ SRC_LIBM = $(addprefix lib/libm/,\
wf_lgamma.c \
wf_tgamma.c \
)
+ifeq ($(MCU_SERIES),f0)
+SRC_LIBM += lib/libm/ef_sqrt.c
+else
+SRC_LIBM += lib/libm/thumb_vfp_sqrtf.c
+endif
endif
EXTMOD_SRC_C = $(addprefix extmod/,\
+ modlwip.c \
modonewire.c \
)
DRIVERS_SRC_C = $(addprefix drivers/,\
+ bus/softspi.c \
+ bus/softqspi.c \
memory/spiflash.c \
+ dht/dht.c \
)
SRC_C = \
main.c \
- system_stm32.c \
stm32_it.c \
usbd_conf.c \
usbd_desc.c \
@@ -212,7 +228,9 @@ SRC_C = \
bufhelper.c \
dma.c \
i2c.c \
+ pyb_i2c.c \
spi.c \
+ qspi.c \
uart.c \
can.c \
usb.c \
@@ -232,6 +250,8 @@ SRC_C = \
rng.c \
rtc.c \
flash.c \
+ flashbdev.c \
+ spibdev.c \
storage.c \
sdcard.c \
fatfs_port.c \
@@ -242,15 +262,24 @@ SRC_C = \
adc.c \
$(wildcard boards/$(BOARD)/*.c)
+ifeq ($(MCU_SERIES),f0)
SRC_O = \
- startup_stm32.o \
- gchelper.o \
+ $(STARTUP_FILE) \
+ system_stm32f0.o \
+ resethandler_m0.o \
+ gchelper_m0.o
+else
+SRC_O = \
+ $(STARTUP_FILE) \
+ system_stm32.o \
+ resethandler.o \
+ gchelper.o
+endif
SRC_HAL = $(addprefix $(HAL_DIR)/Src/stm32$(MCU_SERIES)xx_,\
hal.c \
hal_adc.c \
hal_adc_ex.c \
- hal_can.c \
hal_cortex.c \
hal_dac.c \
hal_dac_ex.c \
@@ -265,17 +294,27 @@ SRC_HAL = $(addprefix $(HAL_DIR)/Src/stm32$(MCU_SERIES)xx_,\
hal_pwr_ex.c \
hal_rcc.c \
hal_rcc_ex.c \
- hal_rng.c \
hal_rtc.c \
hal_rtc_ex.c \
- hal_sd.c \
hal_spi.c \
hal_tim.c \
hal_tim_ex.c \
hal_uart.c \
+ )
+
+ifeq ($(MCU_SERIES),$(filter $(MCU_SERIES),f4 f7 h7 l4))
+SRC_HAL += $(addprefix $(HAL_DIR)/Src/stm32$(MCU_SERIES)xx_,\
+ hal_sd.c \
ll_sdmmc.c \
ll_usb.c \
)
+endif
+
+ifeq ($(CMSIS_MCU),$(filter $(CMSIS_MCU),STM32H743xx))
+ SRC_HAL += $(addprefix $(HAL_DIR)/Src/stm32$(MCU_SERIES)xx_, hal_fdcan.c)
+else
+ SRC_HAL += $(addprefix $(HAL_DIR)/Src/stm32$(MCU_SERIES)xx_, hal_can.c)
+endif
SRC_USBDEV = $(addprefix $(USBDEV_DIR)/,\
core/src/usbd_core.c \
@@ -291,7 +330,7 @@ ifneq ($(MICROPY_PY_WIZNET5K),0)
WIZNET5K_DIR=drivers/wiznet5k
INC += -I$(TOP)/$(WIZNET5K_DIR)
CFLAGS_MOD += -DMICROPY_PY_WIZNET5K=$(MICROPY_PY_WIZNET5K) -D_WIZCHIP_=$(MICROPY_PY_WIZNET5K)
-SRC_MOD += modnwwiznet5k.c
+SRC_MOD += network_wiznet5k.c modnwwiznet5k.c
SRC_MOD += $(addprefix $(WIZNET5K_DIR)/,\
ethernet/w$(MICROPY_PY_WIZNET5K)/w$(MICROPY_PY_WIZNET5K).c \
ethernet/wizchip_conf.c \
@@ -323,6 +362,47 @@ SRC_MOD += $(addprefix $(CC3000_DIR)/src/,\
)
endif
+LWIP_DIR = lib/lwip/src
+INC += -I$(TOP)/$(LWIP_DIR)/include -Ilwip_inc
+$(BUILD)/$(LWIP_DIR)/core/ipv4/dhcp.o: CFLAGS += -Wno-address
+SRC_MOD += $(addprefix $(LWIP_DIR)/,\
+ core/def.c \
+ core/dns.c \
+ core/inet_chksum.c \
+ core/init.c \
+ core/ip.c \
+ core/mem.c \
+ core/memp.c \
+ core/netif.c \
+ core/pbuf.c \
+ core/raw.c \
+ core/stats.c \
+ core/sys.c \
+ core/tcp.c \
+ core/tcp_in.c \
+ core/tcp_out.c \
+ core/timeouts.c \
+ core/udp.c \
+ core/ipv4/autoip.c \
+ core/ipv4/dhcp.c \
+ core/ipv4/etharp.c \
+ core/ipv4/icmp.c \
+ core/ipv4/igmp.c \
+ core/ipv4/ip4_addr.c \
+ core/ipv4/ip4.c \
+ core/ipv4/ip4_frag.c \
+ core/ipv6/dhcp6.c \
+ core/ipv6/ethip6.c \
+ core/ipv6/icmp6.c \
+ core/ipv6/inet6.c \
+ core/ipv6/ip6_addr.c \
+ core/ipv6/ip6.c \
+ core/ipv6/ip6_frag.c \
+ core/ipv6/mld6.c \
+ core/ipv6/nd6.c \
+ netif/ethernet.c \
+ )
+
OBJ =
OBJ += $(PY_O)
OBJ += $(addprefix $(BUILD)/, $(SRC_LIB:.c=.o))
@@ -336,6 +416,11 @@ OBJ += $(addprefix $(BUILD)/, $(SRC_USBDEV:.c=.o))
OBJ += $(addprefix $(BUILD)/, $(SRC_MOD:.c=.o))
OBJ += $(BUILD)/pins_$(BOARD).o
+# This file contains performance critical functions so turn up the optimisation
+# level. It doesn't add much to the code size and improves performance a bit.
+# Don't use -O3 with this file because gcc tries to optimise memset in terms of itself.
+$(BUILD)/lib/libc/string0.o: COPT += -O2
+
# We put several files into the first 16K section with the ISRs.
# If we compile these using -O0 then it won't fit. So if you really want these
# to be compiled with -O0, then edit boards/common.ld (in the .isr_vector section)
@@ -376,27 +461,50 @@ else
$(Q)$(DFU_UTIL) -a 0 -d $(DEVICE) -D $<
endif
-FLASH_ADDR ?= 0x08000000
-TEXT_ADDR ?= 0x08020000
+# A board should specify TEXT0_ADDR if to use a different location than the
+# default for the firmware memory location. A board can also optionally define
+# TEXT1_ADDR to split the firmware into two sections; see below for details.
+TEXT0_ADDR ?= 0x08000000
+
+ifeq ($(TEXT1_ADDR),)
+# No TEXT1_ADDR given so put all firmware at TEXT0_ADDR location
+
+deploy-stlink: $(BUILD)/firmware.dfu
+ $(ECHO) "Writing $(BUILD)/firmware.bin to the board via ST-LINK"
+ $(Q)$(STFLASH) write $(BUILD)/firmware.bin $(TEXT0_ADDR)
+
+deploy-openocd: $(BUILD)/firmware.dfu
+ $(ECHO) "Writing $(BUILD)/firmware.bin to the board via ST-LINK using OpenOCD"
+ $(Q)$(OPENOCD) -f $(OPENOCD_CONFIG) -c "stm_flash $(BUILD)/firmware.bin $(TEXT0_ADDR)"
+
+$(BUILD)/firmware.dfu: $(BUILD)/firmware.elf
+ $(ECHO) "Create $@"
+ $(Q)$(OBJCOPY) -O binary -j .isr_vector -j .text -j .data $^ $(BUILD)/firmware.bin
+ $(Q)$(PYTHON) $(DFU) -b $(TEXT0_ADDR):$(BUILD)/firmware.bin $@
+
+else
+# TEXT0_ADDR and TEXT1_ADDR are specified so split firmware between these locations
deploy-stlink: $(BUILD)/firmware.dfu
$(ECHO) "Writing $(BUILD)/firmware0.bin to the board via ST-LINK"
- $(Q)$(STFLASH) write $(BUILD)/firmware0.bin $(FLASH_ADDR)
+ $(Q)$(STFLASH) write $(BUILD)/firmware0.bin $(TEXT0_ADDR)
$(ECHO) "Writing $(BUILD)/firmware1.bin to the board via ST-LINK"
- $(Q)$(STFLASH) --reset write $(BUILD)/firmware1.bin $(TEXT_ADDR)
+ $(Q)$(STFLASH) --reset write $(BUILD)/firmware1.bin $(TEXT1_ADDR)
deploy-openocd: $(BUILD)/firmware.dfu
$(ECHO) "Writing $(BUILD)/firmware{0,1}.bin to the board via ST-LINK using OpenOCD"
- $(Q)$(OPENOCD) -f $(OPENOCD_CONFIG) -c "stm_flash $(BUILD)/firmware0.bin $(FLASH_ADDR) $(BUILD)/firmware1.bin $(TEXT_ADDR)"
+ $(Q)$(OPENOCD) -f $(OPENOCD_CONFIG) -c "stm_flash $(BUILD)/firmware0.bin $(TEXT0_ADDR) $(BUILD)/firmware1.bin $(TEXT1_ADDR)"
$(BUILD)/firmware.dfu: $(BUILD)/firmware.elf
- $(ECHO) "Create $@"
+ $(ECHO) "GEN $@"
$(Q)$(OBJCOPY) -O binary -j .isr_vector $^ $(BUILD)/firmware0.bin
$(Q)$(OBJCOPY) -O binary -j .text -j .data $^ $(BUILD)/firmware1.bin
- $(Q)$(PYTHON) $(DFU) -b $(FLASH_ADDR):$(BUILD)/firmware0.bin -b $(TEXT_ADDR):$(BUILD)/firmware1.bin $@
+ $(Q)$(PYTHON) $(DFU) -b $(TEXT0_ADDR):$(BUILD)/firmware0.bin -b $(TEXT1_ADDR):$(BUILD)/firmware1.bin $@
+
+endif
$(BUILD)/firmware.hex: $(BUILD)/firmware.elf
- $(ECHO) "Create $@"
+ $(ECHO) "GEN $@"
$(Q)$(OBJCOPY) -O ihex $< $@
$(BUILD)/firmware.elf: $(OBJ)
@@ -445,7 +553,7 @@ main.c: $(GEN_CDCINF_HEADER)
# Use a pattern rule here so that make will only call make-pins.py once to make
# both pins_$(BOARD).c and pins.h
$(BUILD)/%_$(BOARD).c $(HEADER_BUILD)/%.h $(HEADER_BUILD)/%_af_const.h $(BUILD)/%_qstr.h: boards/$(BOARD)/%.csv $(MAKE_PINS) $(AF_FILE) $(PREFIX_FILE) | $(HEADER_BUILD)
- $(ECHO) "Create $@"
+ $(ECHO) "GEN $@"
$(Q)$(PYTHON) $(MAKE_PINS) --board $(BOARD_PINS) --af $(AF_FILE) --prefix $(PREFIX_FILE) --hdr $(GEN_PINS_HDR) --qstr $(GEN_PINS_QSTR) --af-const $(GEN_PINS_AF_CONST) --af-py $(GEN_PINS_AF_PY) > $(GEN_PINS_SRC)
$(BUILD)/pins_$(BOARD).o: $(BUILD)/pins_$(BOARD).c
@@ -460,22 +568,22 @@ CMSIS_MCU_HDR = $(CMSIS_DIR)/$(CMSIS_MCU_LOWER).h
modmachine.c: $(GEN_PLLFREQTABLE_HDR)
$(GEN_PLLFREQTABLE_HDR): $(PLLVALUES) | $(HEADER_BUILD)
- $(ECHO) "Create $@"
+ $(ECHO) "GEN $@"
$(Q)$(PYTHON) $(PLLVALUES) -c file:boards/$(BOARD)/stm32$(MCU_SERIES)xx_hal_conf.h > $@
$(BUILD)/modstm.o: $(GEN_STMCONST_HDR)
# Use a pattern rule here so that make will only call make-stmconst.py once to
# make both modstm_const.h and modstm_qstr.h
$(HEADER_BUILD)/%_const.h $(BUILD)/%_qstr.h: $(CMSIS_MCU_HDR) make-stmconst.py | $(HEADER_BUILD)
- $(ECHO) "Create stmconst $@"
+ $(ECHO) "GEN stmconst $@"
$(Q)$(PYTHON) make-stmconst.py --qstr $(GEN_STMCONST_QSTR) --mpz $(GEN_STMCONST_MPZ) $(CMSIS_MCU_HDR) > $(GEN_STMCONST_HDR)
$(GEN_CDCINF_HEADER): $(GEN_CDCINF_FILE) $(FILE2H) | $(HEADER_BUILD)
- $(ECHO) "Create $@"
+ $(ECHO) "GEN $@"
$(Q)$(PYTHON) $(FILE2H) $< > $@
$(GEN_CDCINF_FILE): $(CDCINF_TEMPLATE) $(INSERT_USB_IDS) $(USB_IDS_FILE) | $(HEADER_BUILD)
- $(ECHO) "Create $@"
+ $(ECHO) "GEN $@"
$(Q)$(PYTHON) $(INSERT_USB_IDS) $(USB_IDS_FILE) $< > $@
include $(TOP)/py/mkrules.mk
diff --git a/ports/stm32/README.md b/ports/stm32/README.md
index bb184e8db..a0c3b7ff3 100644
--- a/ports/stm32/README.md
+++ b/ports/stm32/README.md
@@ -1,9 +1,9 @@
MicroPython port to STM32 MCUs
==============================
-This directory contains the port of MicroPython to ST's line of STM32Fxxx
-microcontrollers. It is based on the STM32Cube HAL library and currently
-supports: STM32F401, STM32F405, STM32F411, STM32F429, STM32F746.
+This directory contains the port of MicroPython to ST's line of STM32
+microcontrollers. Supported MCU series are: STM32F0, STM32F4, STM32F7 and
+STM32L4. Parts of the code here utilise the STM32Cube HAL library.
The officially supported boards are the line of pyboards: PYBv1.0 and PYBv1.1
(both with STM32F405), and PYBLITEv1.0 (with STM32F411). See
@@ -14,6 +14,12 @@ Other boards that are supported include ST Discovery and Nucleo boards.
See the boards/ subdirectory, which contains the configuration files used
to build each individual board.
+The STM32H7 series has preliminary support: there is a working REPL via
+USB and UART, as well as very basic peripheral support, but some things do
+not work and none of the advanced features of the STM32H7 are yet supported,
+such as the clock tree. At this point the STM32H7 should be considered as a
+fast version of the STM32F7.
+
Build instructions
------------------
diff --git a/ports/stm32/accel.c b/ports/stm32/accel.c
index 7b36e2082..49674eb2d 100644
--- a/ports/stm32/accel.c
+++ b/ports/stm32/accel.c
@@ -30,7 +30,6 @@
#include "py/mphal.h"
#include "py/runtime.h"
#include "pin.h"
-#include "genhdr/pins.h"
#include "i2c.h"
#include "accel.h"
@@ -47,7 +46,7 @@
///
/// Raw values are between -32 and 31.
-#define MMA_ADDR (0x98)
+#define MMA_ADDR (76)
#define MMA_REG_X (0)
#define MMA_REG_Y (1)
#define MMA_REG_Z (2)
@@ -57,44 +56,35 @@
void accel_init(void) {
// PB5 is connected to AVDD; pull high to enable MMA accel device
- mp_hal_pin_low(&MICROPY_HW_MMA_AVDD_PIN); // turn off AVDD
- mp_hal_pin_output(&MICROPY_HW_MMA_AVDD_PIN);
+ mp_hal_pin_low(MICROPY_HW_MMA_AVDD_PIN); // turn off AVDD
+ mp_hal_pin_output(MICROPY_HW_MMA_AVDD_PIN);
}
STATIC void accel_start(void) {
// start the I2C bus in master mode
- I2CHandle1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
- I2CHandle1.Init.ClockSpeed = 400000;
- I2CHandle1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLED;
- I2CHandle1.Init.DutyCycle = I2C_DUTYCYCLE_16_9;
- I2CHandle1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLED;
- I2CHandle1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
- I2CHandle1.Init.OwnAddress1 = PYB_I2C_MASTER_ADDRESS;
- I2CHandle1.Init.OwnAddress2 = 0xfe; // unused
- i2c_init(&I2CHandle1);
+ i2c_init(I2C1, MICROPY_HW_I2C1_SCL, MICROPY_HW_I2C1_SDA, 400000);
// turn off AVDD, wait 30ms, turn on AVDD, wait 30ms again
- mp_hal_pin_low(&MICROPY_HW_MMA_AVDD_PIN); // turn off
+ mp_hal_pin_low(MICROPY_HW_MMA_AVDD_PIN); // turn off
mp_hal_delay_ms(30);
- mp_hal_pin_high(&MICROPY_HW_MMA_AVDD_PIN); // turn on
+ mp_hal_pin_high(MICROPY_HW_MMA_AVDD_PIN); // turn on
mp_hal_delay_ms(30);
- HAL_StatusTypeDef status;
-
- for (int i = 0; i < 10; i++) {
- status = HAL_I2C_IsDeviceReady(&I2CHandle1, MMA_ADDR, 10, 200);
- if (status == HAL_OK) {
+ int ret;
+ for (int i = 0; i < 4; i++) {
+ ret = i2c_writeto(I2C1, MMA_ADDR, NULL, 0, true);
+ if (ret == 0) {
break;
}
}
- if (status != HAL_OK) {
+ if (ret != 0) {
mp_raise_msg(&mp_type_OSError, "accelerometer not found");
}
// set MMA to active mode
- uint8_t data[1] = {1}; // active mode
- status = HAL_I2C_Mem_Write(&I2CHandle1, MMA_ADDR, MMA_REG_MODE, I2C_MEMADD_SIZE_8BIT, data, 1, 200);
+ uint8_t data[2] = {MMA_REG_MODE, 1}; // active mode
+ i2c_writeto(I2C1, MMA_ADDR, data, 2, true);
// wait for MMA to become active
mp_hal_delay_ms(30);
@@ -136,8 +126,9 @@ STATIC mp_obj_t pyb_accel_make_new(const mp_obj_type_t *type, size_t n_args, siz
}
STATIC mp_obj_t read_axis(int axis) {
- uint8_t data[1];
- HAL_I2C_Mem_Read(&I2CHandle1, MMA_ADDR, axis, I2C_MEMADD_SIZE_8BIT, data, 1, 200);
+ uint8_t data[1] = { axis };
+ i2c_writeto(I2C1, MMA_ADDR, data, 1, false);
+ i2c_readfrom(I2C1, MMA_ADDR, data, 1, true);
return mp_obj_new_int(MMA_AXIS_SIGNED_VALUE(data[0]));
}
@@ -165,8 +156,9 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_accel_z_obj, pyb_accel_z);
/// \method tilt()
/// Get the tilt register.
STATIC mp_obj_t pyb_accel_tilt(mp_obj_t self_in) {
- uint8_t data[1];
- HAL_I2C_Mem_Read(&I2CHandle1, MMA_ADDR, MMA_REG_TILT, I2C_MEMADD_SIZE_8BIT, data, 1, 200);
+ uint8_t data[1] = { MMA_REG_TILT };
+ i2c_writeto(I2C1, MMA_ADDR, data, 1, false);
+ i2c_readfrom(I2C1, MMA_ADDR, data, 1, true);
return mp_obj_new_int(data[0]);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_accel_tilt_obj, pyb_accel_tilt);
@@ -178,8 +170,9 @@ STATIC mp_obj_t pyb_accel_filtered_xyz(mp_obj_t self_in) {
memmove(self->buf, self->buf + NUM_AXIS, NUM_AXIS * (FILT_DEPTH - 1) * sizeof(int16_t));
- uint8_t data[NUM_AXIS];
- HAL_I2C_Mem_Read(&I2CHandle1, MMA_ADDR, MMA_REG_X, I2C_MEMADD_SIZE_8BIT, data, NUM_AXIS, 200);
+ uint8_t data[NUM_AXIS] = { MMA_REG_X };
+ i2c_writeto(I2C1, MMA_ADDR, data, 1, false);
+ i2c_readfrom(I2C1, MMA_ADDR, data, 3, true);
mp_obj_t tuple[NUM_AXIS];
for (int i = 0; i < NUM_AXIS; i++) {
@@ -196,16 +189,16 @@ STATIC mp_obj_t pyb_accel_filtered_xyz(mp_obj_t self_in) {
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_accel_filtered_xyz_obj, pyb_accel_filtered_xyz);
STATIC mp_obj_t pyb_accel_read(mp_obj_t self_in, mp_obj_t reg) {
- uint8_t data[1];
- HAL_I2C_Mem_Read(&I2CHandle1, MMA_ADDR, mp_obj_get_int(reg), I2C_MEMADD_SIZE_8BIT, data, 1, 200);
+ uint8_t data[1] = { mp_obj_get_int(reg) };
+ i2c_writeto(I2C1, MMA_ADDR, data, 1, false);
+ i2c_writeto(I2C1, MMA_ADDR, data, 1, true);
return mp_obj_new_int(data[0]);
}
MP_DEFINE_CONST_FUN_OBJ_2(pyb_accel_read_obj, pyb_accel_read);
STATIC mp_obj_t pyb_accel_write(mp_obj_t self_in, mp_obj_t reg, mp_obj_t val) {
- uint8_t data[1];
- data[0] = mp_obj_get_int(val);
- HAL_I2C_Mem_Write(&I2CHandle1, MMA_ADDR, mp_obj_get_int(reg), I2C_MEMADD_SIZE_8BIT, data, 1, 200);
+ uint8_t data[2] = { mp_obj_get_int(reg), mp_obj_get_int(val) };
+ i2c_writeto(I2C1, MMA_ADDR, data, 2, true);
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_3(pyb_accel_write_obj, pyb_accel_write);
diff --git a/ports/stm32/accel.h b/ports/stm32/accel.h
index fc35f7775..1fea1249c 100644
--- a/ports/stm32/accel.h
+++ b/ports/stm32/accel.h
@@ -23,11 +23,11 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
-#ifndef MICROPY_INCLUDED_STMHAL_ACCEL_H
-#define MICROPY_INCLUDED_STMHAL_ACCEL_H
+#ifndef MICROPY_INCLUDED_STM32_ACCEL_H
+#define MICROPY_INCLUDED_STM32_ACCEL_H
extern const mp_obj_type_t pyb_accel_type;
void accel_init(void);
-#endif // MICROPY_INCLUDED_STMHAL_ACCEL_H
+#endif // MICROPY_INCLUDED_STM32_ACCEL_H
diff --git a/ports/stm32/adc.c b/ports/stm32/adc.c
index 9a0dc56a3..f439503e6 100644
--- a/ports/stm32/adc.c
+++ b/ports/stm32/adc.c
@@ -32,9 +32,10 @@
#include "py/mphal.h"
#include "adc.h"
#include "pin.h"
-#include "genhdr/pins.h"
#include "timer.h"
+#if MICROPY_HW_ENABLE_ADC
+
/// \moduleref pyb
/// \class ADC - analog to digital conversion: read analog values on a pin
///
@@ -50,11 +51,23 @@
/// val = adc.read_core_vref() # read MCU VREF
/* ADC defintions */
+#if defined(STM32H7)
+#define ADCx (ADC3)
+#else
#define ADCx (ADC1)
-#define ADCx_CLK_ENABLE __ADC1_CLK_ENABLE
+#endif
+#define ADCx_CLK_ENABLE __HAL_RCC_ADC1_CLK_ENABLE
#define ADC_NUM_CHANNELS (19)
-#if defined(MCU_SERIES_F4)
+#if defined(STM32F0)
+
+#define ADC_FIRST_GPIO_CHANNEL (0)
+#define ADC_LAST_GPIO_CHANNEL (15)
+#define ADC_CAL_ADDRESS (0x1ffff7ba)
+#define ADC_CAL1 ((uint16_t*)0x1ffff7b8)
+#define ADC_CAL2 ((uint16_t*)0x1ffff7c2)
+
+#elif defined(STM32F4)
#define ADC_FIRST_GPIO_CHANNEL (0)
#define ADC_LAST_GPIO_CHANNEL (15)
@@ -62,15 +75,30 @@
#define ADC_CAL1 ((uint16_t*)(ADC_CAL_ADDRESS + 2))
#define ADC_CAL2 ((uint16_t*)(ADC_CAL_ADDRESS + 4))
-#elif defined(MCU_SERIES_F7)
+#elif defined(STM32F7)
#define ADC_FIRST_GPIO_CHANNEL (0)
#define ADC_LAST_GPIO_CHANNEL (15)
+#if defined(STM32F722xx) || defined(STM32F723xx) || \
+ defined(STM32F732xx) || defined(STM32F733xx)
+#define ADC_CAL_ADDRESS (0x1ff07a2a)
+#else
#define ADC_CAL_ADDRESS (0x1ff0f44a)
+#endif
+
#define ADC_CAL1 ((uint16_t*)(ADC_CAL_ADDRESS + 2))
#define ADC_CAL2 ((uint16_t*)(ADC_CAL_ADDRESS + 4))
-#elif defined(MCU_SERIES_L4)
+#elif defined(STM32H7)
+
+#define ADC_FIRST_GPIO_CHANNEL (0)
+#define ADC_LAST_GPIO_CHANNEL (16)
+#define ADC_CAL_ADDRESS (0x1FF1E860)
+#define ADC_CAL1 ((uint16_t*)(0x1FF1E820))
+#define ADC_CAL2 ((uint16_t*)(0x1FF1E840))
+#define ADC_CHANNEL_VBAT ADC_CHANNEL_VBAT_DIV4
+
+#elif defined(STM32L4)
#define ADC_FIRST_GPIO_CHANNEL (1)
#define ADC_LAST_GPIO_CHANNEL (16)
@@ -84,22 +112,32 @@
#endif
-#if defined(STM32F405xx) || defined(STM32F415xx) || \
+#if defined(STM32F091xC)
+#define VBAT_DIV (2)
+#elif defined(STM32F405xx) || defined(STM32F415xx) || \
defined(STM32F407xx) || defined(STM32F417xx) || \
defined(STM32F401xC) || defined(STM32F401xE) || \
defined(STM32F411xE)
#define VBAT_DIV (2)
#elif defined(STM32F427xx) || defined(STM32F429xx) || \
defined(STM32F437xx) || defined(STM32F439xx) || \
+ defined(STM32F722xx) || defined(STM32F723xx) || \
+ defined(STM32F732xx) || defined(STM32F733xx) || \
defined(STM32F746xx) || defined(STM32F767xx) || \
defined(STM32F769xx) || defined(STM32F446xx)
#define VBAT_DIV (4)
-#elif defined(STM32L475xx) || defined(STM32L476xx)
+#elif defined(STM32H743xx)
+#define VBAT_DIV (4)
+#elif defined(STM32L475xx) || defined(STM32L476xx) || \
+ defined(STM32L496xx)
#define VBAT_DIV (3)
#else
#error Unsupported processor
#endif
+// Timeout for waiting for end-of-conversion, in ms
+#define EOC_TIMEOUT (10)
+
/* Core temperature sensor definitions */
#define CORE_TEMP_V25 (943) /* (0.76v/3.3v)*(2^ADC resoultion) */
#define CORE_TEMP_AVG_SLOPE (3) /* (2.5mv/3.3v)*(2^ADC resoultion) */
@@ -117,7 +155,7 @@ typedef struct _pyb_obj_adc_t {
// convert user-facing channel number into internal channel number
static inline uint32_t adc_get_internal_channel(uint32_t channel) {
- #if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7)
+ #if defined(STM32F4) || defined(STM32F7)
// on F4 and F7 MCUs we want channel 16 to always be the TEMPSENSOR
// (on some MCUs ADC_CHANNEL_TEMPSENSOR=16, on others it doesn't)
if (channel == 16) {
@@ -128,9 +166,12 @@ static inline uint32_t adc_get_internal_channel(uint32_t channel) {
}
STATIC bool is_adcx_channel(int channel) {
-#if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7)
+#if defined(STM32F411xE)
+ // The HAL has an incorrect IS_ADC_CHANNEL macro for the F411 so we check for temp
+ return IS_ADC_CHANNEL(channel) || channel == ADC_CHANNEL_TEMPSENSOR;
+#elif defined(STM32F0) || defined(STM32F4) || defined(STM32F7) || defined(STM32H7)
return IS_ADC_CHANNEL(channel);
-#elif defined(MCU_SERIES_L4)
+#elif defined(STM32L4)
ADC_HandleTypeDef handle;
handle.Instance = ADCx;
return IS_ADC_CHANNEL(&handle, channel);
@@ -141,9 +182,9 @@ STATIC bool is_adcx_channel(int channel) {
STATIC void adc_wait_for_eoc_or_timeout(int32_t timeout) {
uint32_t tickstart = HAL_GetTick();
-#if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7)
+#if defined(STM32F4) || defined(STM32F7)
while ((ADCx->SR & ADC_FLAG_EOC) != ADC_FLAG_EOC) {
-#elif defined(MCU_SERIES_L4)
+#elif defined(STM32F0) || defined(STM32H7) || defined(STM32L4)
while (READ_BIT(ADCx->ISR, ADC_FLAG_EOC) != ADC_FLAG_EOC) {
#else
#error Unsupported processor
@@ -155,74 +196,82 @@ STATIC void adc_wait_for_eoc_or_timeout(int32_t timeout) {
}
STATIC void adcx_clock_enable(void) {
-#if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7)
+#if defined(STM32F0) || defined(STM32F4) || defined(STM32F7)
ADCx_CLK_ENABLE();
-#elif defined(MCU_SERIES_L4)
+#elif defined(STM32H7)
+ __HAL_RCC_ADC3_CLK_ENABLE();
+ __HAL_RCC_ADC_CONFIG(RCC_ADCCLKSOURCE_CLKP);
+#elif defined(STM32L4)
__HAL_RCC_ADC_CLK_ENABLE();
#else
#error Unsupported processor
#endif
}
+STATIC void adcx_init_periph(ADC_HandleTypeDef *adch, uint32_t resolution) {
+ adcx_clock_enable();
+
+ adch->Instance = ADCx;
+ adch->Init.Resolution = resolution;
+ adch->Init.ContinuousConvMode = DISABLE;
+ adch->Init.DiscontinuousConvMode = DISABLE;
+ #if !defined(STM32F0)
+ adch->Init.NbrOfDiscConversion = 0;
+ adch->Init.NbrOfConversion = 1;
+ #endif
+ adch->Init.EOCSelection = ADC_EOC_SINGLE_CONV;
+ adch->Init.ExternalTrigConv = ADC_SOFTWARE_START;
+ adch->Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
+ #if defined(STM32F0) || defined(STM32F4) || defined(STM32F7)
+ adch->Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV2;
+ adch->Init.ScanConvMode = DISABLE;
+ adch->Init.DataAlign = ADC_DATAALIGN_RIGHT;
+ adch->Init.DMAContinuousRequests = DISABLE;
+ #elif defined(STM32H7)
+ adch->Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;
+ adch->Init.BoostMode = ENABLE;
+ adch->Init.ScanConvMode = DISABLE;
+ adch->Init.LowPowerAutoWait = DISABLE;
+ adch->Init.Overrun = ADC_OVR_DATA_OVERWRITTEN;
+ adch->Init.OversamplingMode = DISABLE;
+ adch->Init.LeftBitShift = ADC_LEFTBITSHIFT_NONE;
+ adch->Init.ConversionDataManagement = ADC_CONVERSIONDATA_DR;
+ #elif defined(STM32L4)
+ adch->Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV1;
+ adch->Init.ScanConvMode = ADC_SCAN_DISABLE;
+ adch->Init.LowPowerAutoWait = DISABLE;
+ adch->Init.Overrun = ADC_OVR_DATA_PRESERVED;
+ adch->Init.OversamplingMode = DISABLE;
+ adch->Init.DataAlign = ADC_DATAALIGN_RIGHT;
+ adch->Init.DMAContinuousRequests = DISABLE;
+ #else
+ #error Unsupported processor
+ #endif
+
+ HAL_ADC_Init(adch);
+
+ #if defined(STM32H7)
+ HAL_ADCEx_Calibration_Start(adch, ADC_CALIB_OFFSET, ADC_SINGLE_ENDED);
+ #endif
+}
+
STATIC void adc_init_single(pyb_obj_adc_t *adc_obj) {
if (!is_adcx_channel(adc_obj->channel)) {
return;
}
if (ADC_FIRST_GPIO_CHANNEL <= adc_obj->channel && adc_obj->channel <= ADC_LAST_GPIO_CHANNEL) {
- // Channels 0-16 correspond to real pins. Configure the GPIO pin in
- // ADC mode.
- const pin_obj_t *pin = pin_adc1[adc_obj->channel];
- mp_hal_gpio_clock_enable(pin->gpio);
- GPIO_InitTypeDef GPIO_InitStructure;
- GPIO_InitStructure.Pin = pin->pin_mask;
-#if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7)
- GPIO_InitStructure.Mode = GPIO_MODE_ANALOG;
-#elif defined(MCU_SERIES_L4)
- GPIO_InitStructure.Mode = GPIO_MODE_ANALOG_ADC_CONTROL;
-#else
- #error Unsupported processor
-#endif
- GPIO_InitStructure.Pull = GPIO_NOPULL;
- HAL_GPIO_Init(pin->gpio, &GPIO_InitStructure);
+ // Channels 0-16 correspond to real pins. Configure the GPIO pin in ADC mode.
+ const pin_obj_t *pin = pin_adc1[adc_obj->channel];
+ mp_hal_pin_config(pin, MP_HAL_PIN_MODE_ADC, MP_HAL_PIN_PULL_NONE, 0);
}
- adcx_clock_enable();
-
- ADC_HandleTypeDef *adcHandle = &adc_obj->handle;
- adcHandle->Instance = ADCx;
- adcHandle->Init.ContinuousConvMode = DISABLE;
- adcHandle->Init.DiscontinuousConvMode = DISABLE;
- adcHandle->Init.NbrOfDiscConversion = 0;
- adcHandle->Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
- adcHandle->Init.DataAlign = ADC_DATAALIGN_RIGHT;
- adcHandle->Init.NbrOfConversion = 1;
- adcHandle->Init.DMAContinuousRequests = DISABLE;
- adcHandle->Init.Resolution = ADC_RESOLUTION_12B;
-#if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7)
- adcHandle->Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV2;
- adcHandle->Init.ScanConvMode = DISABLE;
- adcHandle->Init.ExternalTrigConv = ADC_EXTERNALTRIGCONV_T1_CC1;
- adcHandle->Init.EOCSelection = DISABLE;
-#elif defined(MCU_SERIES_L4)
- adcHandle->Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV1;
- adcHandle->Init.ScanConvMode = ADC_SCAN_DISABLE;
- adcHandle->Init.EOCSelection = ADC_EOC_SINGLE_CONV;
- adcHandle->Init.ExternalTrigConv = ADC_SOFTWARE_START;
- adcHandle->Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
- adcHandle->Init.LowPowerAutoWait = DISABLE;
- adcHandle->Init.Overrun = ADC_OVR_DATA_PRESERVED;
- adcHandle->Init.OversamplingMode = DISABLE;
-#else
- #error Unsupported processor
-#endif
+ adcx_init_periph(&adc_obj->handle, ADC_RESOLUTION_12B);
- HAL_ADC_Init(adcHandle);
-
-#if defined(MCU_SERIES_L4)
+#if defined(STM32L4)
ADC_MultiModeTypeDef multimode;
multimode.Mode = ADC_MODE_INDEPENDENT;
- if (HAL_ADCEx_MultiModeConfigChannel(adcHandle, &multimode) != HAL_OK)
+ if (HAL_ADCEx_MultiModeConfigChannel(&adc_obj->handle, &multimode) != HAL_OK)
{
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "Can not set multimode on ADC1 channel: %d", adc_obj->channel));
}
@@ -234,31 +283,39 @@ STATIC void adc_config_channel(ADC_HandleTypeDef *adc_handle, uint32_t channel)
sConfig.Channel = channel;
sConfig.Rank = 1;
-#if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7)
+#if defined(STM32F0)
+ sConfig.SamplingTime = ADC_SAMPLETIME_28CYCLES_5;
+#elif defined(STM32F4) || defined(STM32F7)
sConfig.SamplingTime = ADC_SAMPLETIME_15CYCLES;
-#elif defined(MCU_SERIES_L4)
+#elif defined(STM32H7)
+ sConfig.SamplingTime = ADC_SAMPLETIME_8CYCLES_5;
+ sConfig.SingleDiff = ADC_SINGLE_ENDED;
+ sConfig.OffsetNumber = ADC_OFFSET_NONE;
+ sConfig.OffsetRightShift = DISABLE;
+ sConfig.OffsetSignedSaturation = DISABLE;
+#elif defined(STM32L4)
sConfig.SamplingTime = ADC_SAMPLETIME_12CYCLES_5;
sConfig.SingleDiff = ADC_SINGLE_ENDED;
sConfig.OffsetNumber = ADC_OFFSET_NONE;
+ sConfig.Offset = 0;
#else
#error Unsupported processor
#endif
- sConfig.Offset = 0;
HAL_ADC_ConfigChannel(adc_handle, &sConfig);
}
STATIC uint32_t adc_read_channel(ADC_HandleTypeDef *adcHandle) {
- uint32_t rawValue = 0;
-
HAL_ADC_Start(adcHandle);
- if (HAL_ADC_PollForConversion(adcHandle, 10) == HAL_OK
- && (HAL_ADC_GetState(adcHandle) & HAL_ADC_STATE_EOC_REG) == HAL_ADC_STATE_EOC_REG) {
- rawValue = HAL_ADC_GetValue(adcHandle);
- }
+ adc_wait_for_eoc_or_timeout(EOC_TIMEOUT);
+ uint32_t value = ADCx->DR;
HAL_ADC_Stop(adcHandle);
+ return value;
+}
- return rawValue;
+STATIC uint32_t adc_config_and_read_channel(ADC_HandleTypeDef *adcHandle, uint32_t channel) {
+ adc_config_channel(adcHandle, channel);
+ return adc_read_channel(adcHandle);
}
/******************************************************************************/
@@ -268,7 +325,7 @@ STATIC void adc_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t
pyb_obj_adc_t *self = self_in;
mp_print_str(print, "<ADC on ");
mp_obj_print_helper(print, self->pin_name, PRINT_STR);
- mp_printf(print, " channel=%lu>", self->channel);
+ mp_printf(print, " channel=%u>", self->channel);
}
/// \classmethod \constructor(pin)
@@ -322,10 +379,7 @@ STATIC mp_obj_t adc_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_
/// will be between 0 and 4095.
STATIC mp_obj_t adc_read(mp_obj_t self_in) {
pyb_obj_adc_t *self = self_in;
-
- adc_config_channel(&self->handle, self->channel);
- uint32_t data = adc_read_channel(&self->handle);
- return mp_obj_new_int(data);
+ return mp_obj_new_int(adc_config_and_read_channel(&self->handle, self->channel));
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(adc_read_obj, adc_read);
@@ -401,9 +455,9 @@ STATIC mp_obj_t adc_read_timed(mp_obj_t self_in, mp_obj_t buf_in, mp_obj_t freq_
HAL_ADC_Start(&self->handle);
} else {
// for subsequent samples we can just set the "start sample" bit
-#if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7)
+#if defined(STM32F4) || defined(STM32F7)
ADCx->CR2 |= (uint32_t)ADC_CR2_SWSTART;
-#elif defined(MCU_SERIES_L4)
+#elif defined(STM32F0) || defined(STM32H7) || defined(STM32L4)
SET_BIT(ADCx->CR, ADC_CR_ADSTART);
#else
#error Unsupported processor
@@ -411,8 +465,7 @@ STATIC mp_obj_t adc_read_timed(mp_obj_t self_in, mp_obj_t buf_in, mp_obj_t freq_
}
// wait for sample to complete
- #define READ_TIMED_TIMEOUT (10) // in ms
- adc_wait_for_eoc_or_timeout(READ_TIMED_TIMEOUT);
+ adc_wait_for_eoc_or_timeout(EOC_TIMEOUT);
// read value
uint value = ADCx->DR;
@@ -438,9 +491,114 @@ STATIC mp_obj_t adc_read_timed(mp_obj_t self_in, mp_obj_t buf_in, mp_obj_t freq_
}
STATIC MP_DEFINE_CONST_FUN_OBJ_3(adc_read_timed_obj, adc_read_timed);
+// read_timed_multi((adcx, adcy, ...), (bufx, bufy, ...), timer)
+//
+// Read analog values from multiple ADC's into buffers at a rate set by the
+// timer. The ADC values have 12-bit resolution and are stored directly into
+// the corresponding buffer if its element size is 16 bits or greater, otherwise
+// the sample resolution will be reduced to 8 bits.
+//
+// This function should not allocate any heap memory.
+STATIC mp_obj_t adc_read_timed_multi(mp_obj_t adc_array_in, mp_obj_t buf_array_in, mp_obj_t tim_in) {
+ size_t nadcs, nbufs;
+ mp_obj_t *adc_array, *buf_array;
+ mp_obj_get_array(adc_array_in, &nadcs, &adc_array);
+ mp_obj_get_array(buf_array_in, &nbufs, &buf_array);
+
+ if (nadcs < 1) {
+ mp_raise_ValueError("need at least 1 ADC");
+ }
+ if (nadcs != nbufs) {
+ mp_raise_ValueError("length of ADC and buffer lists differ");
+ }
+
+ // Get buf for first ADC, get word size, check other buffers match in type
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(buf_array[0], &bufinfo, MP_BUFFER_WRITE);
+ size_t typesize = mp_binary_get_size('@', bufinfo.typecode, NULL);
+ void *bufptrs[nbufs];
+ for (uint array_index = 0; array_index < nbufs; array_index++) {
+ mp_buffer_info_t bufinfo_curr;
+ mp_get_buffer_raise(buf_array[array_index], &bufinfo_curr, MP_BUFFER_WRITE);
+ if ((bufinfo.len != bufinfo_curr.len) || (bufinfo.typecode != bufinfo_curr.typecode)) {
+ mp_raise_ValueError("size and type of buffers must match");
+ }
+ bufptrs[array_index] = bufinfo_curr.buf;
+ }
+
+ // Use the supplied timer object as the sampling time base
+ TIM_HandleTypeDef *tim;
+ tim = pyb_timer_get_handle(tim_in);
+
+ // Start adc; this is slow so wait for it to start
+ pyb_obj_adc_t *adc0 = adc_array[0];
+ adc_config_channel(&adc0->handle, adc0->channel);
+ HAL_ADC_Start(&adc0->handle);
+ // Wait for sample to complete and discard
+ adc_wait_for_eoc_or_timeout(EOC_TIMEOUT);
+ // Read (and discard) value
+ uint value = ADCx->DR;
+
+ // Ensure first sample is on a timer tick
+ __HAL_TIM_CLEAR_FLAG(tim, TIM_FLAG_UPDATE);
+ while (__HAL_TIM_GET_FLAG(tim, TIM_FLAG_UPDATE) == RESET) {
+ }
+ __HAL_TIM_CLEAR_FLAG(tim, TIM_FLAG_UPDATE);
+
+ // Overrun check: assume success
+ bool success = true;
+ size_t nelems = bufinfo.len / typesize;
+ for (size_t elem_index = 0; elem_index < nelems; elem_index++) {
+ if (__HAL_TIM_GET_FLAG(tim, TIM_FLAG_UPDATE) != RESET) {
+ // Timer has already triggered
+ success = false;
+ } else {
+ // Wait for the timer to trigger so we sample at the correct frequency
+ while (__HAL_TIM_GET_FLAG(tim, TIM_FLAG_UPDATE) == RESET) {
+ }
+ }
+ __HAL_TIM_CLEAR_FLAG(tim, TIM_FLAG_UPDATE);
+
+ for (size_t array_index = 0; array_index < nadcs; array_index++) {
+ pyb_obj_adc_t *adc = adc_array[array_index];
+ // configure the ADC channel
+ adc_config_channel(&adc->handle, adc->channel);
+ // for the first sample we need to turn the ADC on
+ // ADC is started: set the "start sample" bit
+ #if defined(STM32F4) || defined(STM32F7)
+ ADCx->CR2 |= (uint32_t)ADC_CR2_SWSTART;
+ #elif defined(STM32F0) || defined(STM32H7) || defined(STM32L4)
+ SET_BIT(ADCx->CR, ADC_CR_ADSTART);
+ #else
+ #error Unsupported processor
+ #endif
+ // wait for sample to complete
+ adc_wait_for_eoc_or_timeout(EOC_TIMEOUT);
+
+ // read value
+ value = ADCx->DR;
+
+ // store values in buffer
+ if (typesize == 1) {
+ value >>= 4;
+ }
+ mp_binary_set_val_array_from_int(bufinfo.typecode, bufptrs[array_index], elem_index, value);
+ }
+ }
+
+ // Turn the ADC off
+ adc0 = adc_array[0];
+ HAL_ADC_Stop(&adc0->handle);
+
+ return mp_obj_new_bool(success);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_3(adc_read_timed_multi_fun_obj, adc_read_timed_multi);
+STATIC MP_DEFINE_CONST_STATICMETHOD_OBJ(adc_read_timed_multi_obj, MP_ROM_PTR(&adc_read_timed_multi_fun_obj));
+
STATIC const mp_rom_map_elem_t adc_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&adc_read_obj) },
{ MP_ROM_QSTR(MP_QSTR_read_timed), MP_ROM_PTR(&adc_read_timed_obj) },
+ { MP_ROM_QSTR(MP_QSTR_read_timed_multi), MP_ROM_PTR(&adc_read_timed_multi_obj) },
};
STATIC MP_DEFINE_CONST_DICT(adc_locals_dict, adc_locals_dict_table);
@@ -464,7 +622,9 @@ typedef struct _pyb_adc_all_obj_t {
void adc_init_all(pyb_adc_all_obj_t *adc_all, uint32_t resolution, uint32_t en_mask) {
switch (resolution) {
+ #if !defined(STM32H7)
case 6: resolution = ADC_RESOLUTION_6B; break;
+ #endif
case 8: resolution = ADC_RESOLUTION_8B; break;
case 10: resolution = ADC_RESOLUTION_10B; break;
case 12: resolution = ADC_RESOLUTION_12B; break;
@@ -480,57 +640,21 @@ void adc_init_all(pyb_adc_all_obj_t *adc_all, uint32_t resolution, uint32_t en_m
// ADC mode.
const pin_obj_t *pin = pin_adc1[channel];
if (pin) {
- mp_hal_gpio_clock_enable(pin->gpio);
- GPIO_InitTypeDef GPIO_InitStructure;
- GPIO_InitStructure.Pin = pin->pin_mask;
- GPIO_InitStructure.Mode = GPIO_MODE_ANALOG;
- GPIO_InitStructure.Pull = GPIO_NOPULL;
- HAL_GPIO_Init(pin->gpio, &GPIO_InitStructure);
+ mp_hal_pin_config(pin, MP_HAL_PIN_MODE_ADC, MP_HAL_PIN_PULL_NONE, 0);
}
}
}
- adcx_clock_enable();
-
- ADC_HandleTypeDef *adcHandle = &adc_all->handle;
- adcHandle->Instance = ADCx;
- adcHandle->Init.Resolution = resolution;
- adcHandle->Init.ContinuousConvMode = DISABLE;
- adcHandle->Init.DiscontinuousConvMode = DISABLE;
- adcHandle->Init.NbrOfDiscConversion = 0;
- adcHandle->Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
- adcHandle->Init.DataAlign = ADC_DATAALIGN_RIGHT;
- adcHandle->Init.NbrOfConversion = 1;
- adcHandle->Init.DMAContinuousRequests = DISABLE;
- adcHandle->Init.EOCSelection = DISABLE;
-#if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7)
- adcHandle->Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV2;
- adcHandle->Init.ScanConvMode = DISABLE;
- adcHandle->Init.ExternalTrigConv = ADC_EXTERNALTRIGCONV_T1_CC1;
-#elif defined(MCU_SERIES_L4)
- adcHandle->Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV2;
- adcHandle->Init.ScanConvMode = ADC_SCAN_DISABLE;
- adcHandle->Init.ExternalTrigConv = ADC_EXTERNALTRIG_T1_CC1;
- adcHandle->Init.LowPowerAutoWait = DISABLE;
- adcHandle->Init.Overrun = ADC_OVR_DATA_PRESERVED;
- adcHandle->Init.OversamplingMode = DISABLE;
-#else
- #error Unsupported processor
-#endif
-
- HAL_ADC_Init(adcHandle);
-}
-
-uint32_t adc_config_and_read_channel(ADC_HandleTypeDef *adcHandle, uint32_t channel) {
- adc_config_channel(adcHandle, channel);
- return adc_read_channel(adcHandle);
+ adcx_init_periph(&adc_all->handle, resolution);
}
int adc_get_resolution(ADC_HandleTypeDef *adcHandle) {
- uint32_t res_reg = __HAL_ADC_GET_RESOLUTION(adcHandle);
+ uint32_t res_reg = ADC_GET_RESOLUTION(adcHandle);
switch (res_reg) {
+ #if !defined(STM32H7)
case ADC_RESOLUTION_6B: return 6;
+ #endif
case ADC_RESOLUTION_8B: return 8;
case ADC_RESOLUTION_10B: return 10;
}
@@ -568,7 +692,7 @@ float adc_read_core_vbat(ADC_HandleTypeDef *adcHandle) {
// be 12-bits.
raw_value <<= (12 - adc_get_resolution(adcHandle));
- #if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7)
+ #if defined(STM32F4) || defined(STM32F7)
// ST docs say that (at least on STM32F42x and STM32F43x), VBATE must
// be disabled when TSVREFE is enabled for TEMPSENSOR and VREFINT
// conversions to work. VBATE is enabled by the above call to read
@@ -675,3 +799,5 @@ const mp_obj_type_t pyb_adc_all_type = {
.make_new = adc_all_make_new,
.locals_dict = (mp_obj_dict_t*)&adc_all_locals_dict,
};
+
+#endif // MICROPY_HW_ENABLE_ADC
diff --git a/ports/stm32/adc.h b/ports/stm32/adc.h
index c90e6b343..4ae6022bc 100644
--- a/ports/stm32/adc.h
+++ b/ports/stm32/adc.h
@@ -23,10 +23,10 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
-#ifndef MICROPY_INCLUDED_STMHAL_ADC_H
-#define MICROPY_INCLUDED_STMHAL_ADC_H
+#ifndef MICROPY_INCLUDED_STM32_ADC_H
+#define MICROPY_INCLUDED_STM32_ADC_H
extern const mp_obj_type_t pyb_adc_type;
extern const mp_obj_type_t pyb_adc_all_type;
-#endif // MICROPY_INCLUDED_STMHAL_ADC_H
+#endif // MICROPY_INCLUDED_STM32_ADC_H
diff --git a/ports/stm32/boards/B_L475E_IOT01A/mpconfigboard.h b/ports/stm32/boards/B_L475E_IOT01A/mpconfigboard.h
index 77f029c00..3ab3d5fa1 100644
--- a/ports/stm32/boards/B_L475E_IOT01A/mpconfigboard.h
+++ b/ports/stm32/boards/B_L475E_IOT01A/mpconfigboard.h
@@ -2,17 +2,9 @@
#define MICROPY_HW_MCU_NAME "STM32L475"
#define MICROPY_HW_HAS_SWITCH (1)
-#define MICROPY_HW_HAS_FLASH (0)
-#define MICROPY_HW_HAS_SDCARD (0)
-#define MICROPY_HW_HAS_MMA7660 (0)
-#define MICROPY_HW_HAS_LIS3DSH (0)
-#define MICROPY_HW_HAS_LCD (0)
#define MICROPY_HW_ENABLE_RNG (1)
#define MICROPY_HW_ENABLE_RTC (1)
-#define MICROPY_HW_ENABLE_TIMER (1)
-#define MICROPY_HW_ENABLE_SERVO (0)
-#define MICROPY_HW_ENABLE_DAC (0)
-#define MICROPY_HW_ENABLE_CAN (0)
+#define MICROPY_HW_ENABLE_USB (1)
// MSI is used and is 4MHz
#define MICROPY_HW_CLK_PLLM (1)
@@ -74,3 +66,6 @@
#define MICROPY_HW_LED2 (pin_B14) // green
#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_high(pin))
#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin))
+
+// USB config
+#define MICROPY_HW_USB_FS (1)
diff --git a/ports/stm32/boards/B_L475E_IOT01A/mpconfigboard.mk b/ports/stm32/boards/B_L475E_IOT01A/mpconfigboard.mk
index 1ba61a327..55e443e91 100644
--- a/ports/stm32/boards/B_L475E_IOT01A/mpconfigboard.mk
+++ b/ports/stm32/boards/B_L475E_IOT01A/mpconfigboard.mk
@@ -3,6 +3,7 @@ CMSIS_MCU = STM32L475xx
# The stm32l475 does not have a LDC controller which is
# the only diffrence to the stm32l476 - so reuse some files.
AF_FILE = boards/stm32l476_af.csv
-LD_FILE = boards/stm32l476xg.ld
-TEXT_ADDR = 0x08004000
+LD_FILES = boards/stm32l476xg.ld boards/common_ifs.ld
+TEXT0_ADDR = 0x08000000
+TEXT1_ADDR = 0x08004000
OPENOCD_CONFIG = boards/openocd_stm32l4.cfg
diff --git a/ports/stm32/boards/B_L475E_IOT01A/stm32l4xx_hal_conf.h b/ports/stm32/boards/B_L475E_IOT01A/stm32l4xx_hal_conf.h
index 9348e0679..6bfb28118 100644
--- a/ports/stm32/boards/B_L475E_IOT01A/stm32l4xx_hal_conf.h
+++ b/ports/stm32/boards/B_L475E_IOT01A/stm32l4xx_hal_conf.h
@@ -45,7 +45,6 @@
extern "C" {
#endif
-#define USE_USB_FS
/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
diff --git a/ports/stm32/boards/CERB40/mpconfigboard.h b/ports/stm32/boards/CERB40/mpconfigboard.h
index 284de7a40..7c166922b 100644
--- a/ports/stm32/boards/CERB40/mpconfigboard.h
+++ b/ports/stm32/boards/CERB40/mpconfigboard.h
@@ -1,20 +1,11 @@
-#define CERB40
-
#define MICROPY_HW_BOARD_NAME "Cerb40"
#define MICROPY_HW_MCU_NAME "STM32F405RG"
-#define MICROPY_HW_HAS_SWITCH (0)
#define MICROPY_HW_HAS_FLASH (1)
-#define MICROPY_HW_HAS_SDCARD (0)
-#define MICROPY_HW_HAS_MMA7660 (0)
-#define MICROPY_HW_HAS_LIS3DSH (0)
-#define MICROPY_HW_HAS_LCD (0)
#define MICROPY_HW_ENABLE_RNG (1)
#define MICROPY_HW_ENABLE_RTC (1)
-#define MICROPY_HW_ENABLE_TIMER (1)
-#define MICROPY_HW_ENABLE_SERVO (0)
#define MICROPY_HW_ENABLE_DAC (1)
-#define MICROPY_HW_ENABLE_CAN (1)
+#define MICROPY_HW_ENABLE_USB (1)
// HSE is 12MHz
#define MICROPY_HW_CLK_PLLM (12)
@@ -58,10 +49,17 @@
#define MICROPY_HW_SPI3_MISO (pin_B4)
#define MICROPY_HW_SPI3_MOSI (pin_B5)
+// CAN busses
+#define MICROPY_HW_CAN1_TX (pin_B9)
+#define MICROPY_HW_CAN1_RX (pin_B8)
+#define MICROPY_HW_CAN2_TX (pin_B13)
+#define MICROPY_HW_CAN2_RX (pin_B12)
+
// The Cerb40 has No LEDs
// The Cerb40 has No SDCard
// USB config
+#define MICROPY_HW_USB_FS (1)
//#define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_A9)
//#define MICROPY_HW_USB_OTG_ID_PIN (pin_A10)
diff --git a/ports/stm32/boards/CERB40/mpconfigboard.mk b/ports/stm32/boards/CERB40/mpconfigboard.mk
index 5734c6690..40972b385 100644
--- a/ports/stm32/boards/CERB40/mpconfigboard.mk
+++ b/ports/stm32/boards/CERB40/mpconfigboard.mk
@@ -1,4 +1,6 @@
MCU_SERIES = f4
CMSIS_MCU = STM32F405xx
AF_FILE = boards/stm32f405_af.csv
-LD_FILE = boards/stm32f405.ld
+LD_FILES = boards/stm32f405.ld boards/common_ifs.ld
+TEXT0_ADDR = 0x08000000
+TEXT1_ADDR = 0x08020000
diff --git a/ports/stm32/boards/CERB40/pins.csv b/ports/stm32/boards/CERB40/pins.csv
index 411031e8f..cca0bc053 100644
--- a/ports/stm32/boards/CERB40/pins.csv
+++ b/ports/stm32/boards/CERB40/pins.csv
@@ -44,3 +44,7 @@ UART3_TX,PD8
UART3_RX,PD9
UART3_RTS,PD12
UART3_CTS,PD11
+CAN2_TX,PB13
+CAN2_RX,PB12
+USB_DM,PA11
+USB_DP,PA12
diff --git a/ports/stm32/boards/CERB40/stm32f4xx_hal_conf.h b/ports/stm32/boards/CERB40/stm32f4xx_hal_conf.h
index d6aca705c..e71ba3369 100644
--- a/ports/stm32/boards/CERB40/stm32f4xx_hal_conf.h
+++ b/ports/stm32/boards/CERB40/stm32f4xx_hal_conf.h
@@ -46,8 +46,6 @@
/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
-#define USE_USB_FS
-
/* ########################## Module Selection ############################## */
/**
* @brief This is the list of modules to be used in the HAL driver
diff --git a/ports/stm32/boards/ESPRUINO_PICO/mpconfigboard.h b/ports/stm32/boards/ESPRUINO_PICO/mpconfigboard.h
index d065180d8..53c7f3cd5 100644
--- a/ports/stm32/boards/ESPRUINO_PICO/mpconfigboard.h
+++ b/ports/stm32/boards/ESPRUINO_PICO/mpconfigboard.h
@@ -9,16 +9,9 @@
#define MICROPY_HW_HAS_SWITCH (1)
#define MICROPY_HW_HAS_FLASH (1)
-#define MICROPY_HW_HAS_SDCARD (0)
-#define MICROPY_HW_HAS_MMA7660 (0)
-#define MICROPY_HW_HAS_LIS3DSH (0)
-#define MICROPY_HW_HAS_LCD (0)
-#define MICROPY_HW_ENABLE_RNG (0)
#define MICROPY_HW_ENABLE_RTC (1)
-#define MICROPY_HW_ENABLE_TIMER (1)
+#define MICROPY_HW_ENABLE_USB (1)
#define MICROPY_HW_ENABLE_SERVO (1)
-#define MICROPY_HW_ENABLE_DAC (0)
-#define MICROPY_HW_ENABLE_CAN (0)
// Pico has an 8 MHz HSE and the F401 does 84 MHz max
#define MICROPY_HW_CLK_PLLM (5)
@@ -70,3 +63,6 @@
#define MICROPY_HW_LED4 (pin_B12) // green
#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_high(pin))
#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin))
+
+// USB config
+#define MICROPY_HW_USB_FS (1)
diff --git a/ports/stm32/boards/ESPRUINO_PICO/mpconfigboard.mk b/ports/stm32/boards/ESPRUINO_PICO/mpconfigboard.mk
index d531a594a..16cacc089 100644
--- a/ports/stm32/boards/ESPRUINO_PICO/mpconfigboard.mk
+++ b/ports/stm32/boards/ESPRUINO_PICO/mpconfigboard.mk
@@ -1,7 +1,9 @@
MCU_SERIES = f4
CMSIS_MCU = STM32F401xE
AF_FILE = boards/stm32f401_af.csv
-LD_FILE = boards/stm32f401xd.ld
+LD_FILES = boards/stm32f401xd.ld boards/common_ifs.ld
+TEXT0_ADDR = 0x08000000
+TEXT1_ADDR = 0x08020000
# Don't include default frozen modules because MCU is tight on flash space
FROZEN_MPY_DIR ?=
diff --git a/ports/stm32/boards/ESPRUINO_PICO/stm32f4xx_hal_conf.h b/ports/stm32/boards/ESPRUINO_PICO/stm32f4xx_hal_conf.h
index 11a396b73..d27e2e9ef 100644
--- a/ports/stm32/boards/ESPRUINO_PICO/stm32f4xx_hal_conf.h
+++ b/ports/stm32/boards/ESPRUINO_PICO/stm32f4xx_hal_conf.h
@@ -46,8 +46,6 @@
/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
-#define USE_USB_FS
-
/* ########################## Module Selection ############################## */
/**
* @brief This is the list of modules to be used in the HAL driver
diff --git a/ports/stm32/boards/HYDRABUS/mpconfigboard.h b/ports/stm32/boards/HYDRABUS/mpconfigboard.h
index 38fba9787..2e73d3ec8 100644
--- a/ports/stm32/boards/HYDRABUS/mpconfigboard.h
+++ b/ports/stm32/boards/HYDRABUS/mpconfigboard.h
@@ -1,20 +1,12 @@
-#define HYDRABUSV10
-
#define MICROPY_HW_BOARD_NAME "HydraBus1.0"
#define MICROPY_HW_MCU_NAME "STM32F4"
#define MICROPY_HW_HAS_SWITCH (1)
#define MICROPY_HW_HAS_FLASH (1)
#define MICROPY_HW_HAS_SDCARD (1)
-#define MICROPY_HW_HAS_MMA7660 (0)
-#define MICROPY_HW_HAS_LIS3DSH (0)
-#define MICROPY_HW_HAS_LCD (0)
#define MICROPY_HW_ENABLE_RNG (1)
-#define MICROPY_HW_ENABLE_RTC (0)
-#define MICROPY_HW_ENABLE_TIMER (1)
-#define MICROPY_HW_ENABLE_SERVO (0)
#define MICROPY_HW_ENABLE_DAC (1)
-#define MICROPY_HW_ENABLE_CAN (0)
+#define MICROPY_HW_ENABLE_USB (1)
// HSE is 8MHz
#define MICROPY_HW_CLK_PLLM (8)
@@ -78,4 +70,5 @@
#define MICROPY_HW_SDCARD_DETECT_PRESENT (1)
// USB config
+#define MICROPY_HW_USB_FS (1)
#define MICROPY_HW_USB_OTG_ID_PIN (pin_A10)
diff --git a/ports/stm32/boards/HYDRABUS/mpconfigboard.mk b/ports/stm32/boards/HYDRABUS/mpconfigboard.mk
index 5734c6690..40972b385 100644
--- a/ports/stm32/boards/HYDRABUS/mpconfigboard.mk
+++ b/ports/stm32/boards/HYDRABUS/mpconfigboard.mk
@@ -1,4 +1,6 @@
MCU_SERIES = f4
CMSIS_MCU = STM32F405xx
AF_FILE = boards/stm32f405_af.csv
-LD_FILE = boards/stm32f405.ld
+LD_FILES = boards/stm32f405.ld boards/common_ifs.ld
+TEXT0_ADDR = 0x08000000
+TEXT1_ADDR = 0x08020000
diff --git a/ports/stm32/boards/HYDRABUS/stm32f4xx_hal_conf.h b/ports/stm32/boards/HYDRABUS/stm32f4xx_hal_conf.h
index d3df51c10..daf9b63ce 100644
--- a/ports/stm32/boards/HYDRABUS/stm32f4xx_hal_conf.h
+++ b/ports/stm32/boards/HYDRABUS/stm32f4xx_hal_conf.h
@@ -46,8 +46,6 @@
/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
-#define USE_USB_FS
-
/* ########################## Module Selection ############################## */
/**
* @brief This is the list of modules to be used in the HAL driver
diff --git a/ports/stm32/boards/LIMIFROG/board_init.c b/ports/stm32/boards/LIMIFROG/board_init.c
index 72f920842..67ccf23cc 100644
--- a/ports/stm32/boards/LIMIFROG/board_init.c
+++ b/ports/stm32/boards/LIMIFROG/board_init.c
@@ -104,10 +104,10 @@ static void LBF_DFU_If_Needed(void)
// Initialize and assert pin BTLE_RST
// (hw reset to BLE module, so it won't drive UART3)
- __GPIOC_CLK_ENABLE();
+ __HAL_RCC_GPIOC_CLK_ENABLE();
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
- GPIO_InitStruct.Speed = GPIO_SPEED_LOW;
+ GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Pin = BT_RST_PIN;
HAL_GPIO_Init(BT_RST_PORT, &GPIO_InitStruct);
@@ -124,7 +124,7 @@ static void LBF_DFU_If_Needed(void)
// Initialize Extension Port Position 10 = PB8 (bears I2C1_SCL)
// Use weak pull-up to detect if pin is externally pulled low
- __GPIOB_CLK_ENABLE();
+ __HAL_RCC_GPIOB_CLK_ENABLE();
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Pin = CONN_POS10_PIN;
diff --git a/ports/stm32/boards/LIMIFROG/mpconfigboard.h b/ports/stm32/boards/LIMIFROG/mpconfigboard.h
index 42b862fcf..d27c2e66e 100644
--- a/ports/stm32/boards/LIMIFROG/mpconfigboard.h
+++ b/ports/stm32/boards/LIMIFROG/mpconfigboard.h
@@ -3,16 +3,9 @@
#define MICROPY_HW_HAS_SWITCH (1)
#define MICROPY_HW_HAS_FLASH (1)
-#define MICROPY_HW_HAS_SDCARD (0)
-#define MICROPY_HW_HAS_MMA7660 (0)
-#define MICROPY_HW_HAS_LIS3DSH (0)
-#define MICROPY_HW_HAS_LCD (0)
#define MICROPY_HW_ENABLE_RNG (1)
#define MICROPY_HW_ENABLE_RTC (1)
-#define MICROPY_HW_ENABLE_TIMER (1)
-#define MICROPY_HW_ENABLE_SERVO (0)
-#define MICROPY_HW_ENABLE_DAC (0)
-#define MICROPY_HW_ENABLE_CAN (0)
+#define MICROPY_HW_ENABLE_USB (1)
#define MICROPY_BOARD_EARLY_INIT LIMIFROG_board_early_init
void LIMIFROG_board_early_init(void);
@@ -58,4 +51,5 @@ void LIMIFROG_board_early_init(void);
#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin))
// USB config
+#define MICROPY_HW_USB_FS (1)
// #define MICROPY_HW_USB_OTG_ID_PIN (pin_C12) // This is not the official ID Pin which should be PA10
diff --git a/ports/stm32/boards/LIMIFROG/mpconfigboard.mk b/ports/stm32/boards/LIMIFROG/mpconfigboard.mk
index a1304b655..2adc98f0b 100644
--- a/ports/stm32/boards/LIMIFROG/mpconfigboard.mk
+++ b/ports/stm32/boards/LIMIFROG/mpconfigboard.mk
@@ -1,5 +1,6 @@
MCU_SERIES = l4
CMSIS_MCU = STM32L476xx
AF_FILE = boards/stm32l476_af.csv
-LD_FILE = boards/stm32l476xe.ld
-TEXT_ADDR = 0x08004000
+LD_FILES = boards/stm32l476xe.ld boards/common_ifs.ld
+TEXT0_ADDR = 0x08000000
+TEXT1_ADDR = 0x08004000
diff --git a/ports/stm32/boards/LIMIFROG/stm32l4xx_hal_conf.h b/ports/stm32/boards/LIMIFROG/stm32l4xx_hal_conf.h
index 9348e0679..6bfb28118 100644
--- a/ports/stm32/boards/LIMIFROG/stm32l4xx_hal_conf.h
+++ b/ports/stm32/boards/LIMIFROG/stm32l4xx_hal_conf.h
@@ -45,7 +45,6 @@
extern "C" {
#endif
-#define USE_USB_FS
/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
diff --git a/ports/stm32/boards/NETDUINO_PLUS_2/board_init.c b/ports/stm32/boards/NETDUINO_PLUS_2/board_init.c
index 085034b2d..53df72503 100644
--- a/ports/stm32/boards/NETDUINO_PLUS_2/board_init.c
+++ b/ports/stm32/boards/NETDUINO_PLUS_2/board_init.c
@@ -2,11 +2,11 @@
void NETDUINO_PLUS_2_board_early_init(void) {
- __GPIOB_CLK_ENABLE();
+ __HAL_RCC_GPIOB_CLK_ENABLE();
// Turn off the backlight. LCD_BL_CTRL = PK3
GPIO_InitTypeDef GPIO_InitStructure;
- GPIO_InitStructure.Speed = GPIO_SPEED_HIGH;
+ GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStructure.Pull = GPIO_PULLUP;
diff --git a/ports/stm32/boards/NETDUINO_PLUS_2/mpconfigboard.h b/ports/stm32/boards/NETDUINO_PLUS_2/mpconfigboard.h
index 9586ae4e5..312576756 100644
--- a/ports/stm32/boards/NETDUINO_PLUS_2/mpconfigboard.h
+++ b/ports/stm32/boards/NETDUINO_PLUS_2/mpconfigboard.h
@@ -8,15 +8,9 @@
// SPI, so the driver needs to be converted to support that before
// we can turn this on.
#define MICROPY_HW_HAS_SDCARD (0)
-#define MICROPY_HW_HAS_MMA7660 (0)
-#define MICROPY_HW_HAS_LIS3DSH (0)
-#define MICROPY_HW_HAS_LCD (0)
#define MICROPY_HW_ENABLE_RNG (1)
-#define MICROPY_HW_ENABLE_RTC (0)
-#define MICROPY_HW_ENABLE_TIMER (1)
+#define MICROPY_HW_ENABLE_USB (1)
#define MICROPY_HW_ENABLE_SERVO (1)
-#define MICROPY_HW_ENABLE_DAC (0)
-#define MICROPY_HW_ENABLE_CAN (0)
void NETDUINO_PLUS_2_board_early_init(void);
#define MICROPY_BOARD_EARLY_INIT NETDUINO_PLUS_2_board_early_init
@@ -69,5 +63,6 @@ void NETDUINO_PLUS_2_board_early_init(void);
#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_high(pin))
#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin))
-// USB VBUS detect pin
+// USB config
+#define MICROPY_HW_USB_FS (1)
#define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_A9)
diff --git a/ports/stm32/boards/NETDUINO_PLUS_2/mpconfigboard.mk b/ports/stm32/boards/NETDUINO_PLUS_2/mpconfigboard.mk
index 5734c6690..40972b385 100644
--- a/ports/stm32/boards/NETDUINO_PLUS_2/mpconfigboard.mk
+++ b/ports/stm32/boards/NETDUINO_PLUS_2/mpconfigboard.mk
@@ -1,4 +1,6 @@
MCU_SERIES = f4
CMSIS_MCU = STM32F405xx
AF_FILE = boards/stm32f405_af.csv
-LD_FILE = boards/stm32f405.ld
+LD_FILES = boards/stm32f405.ld boards/common_ifs.ld
+TEXT0_ADDR = 0x08000000
+TEXT1_ADDR = 0x08020000
diff --git a/ports/stm32/boards/NETDUINO_PLUS_2/pins.csv b/ports/stm32/boards/NETDUINO_PLUS_2/pins.csv
index 3e71fade6..53ffa9d1f 100644
--- a/ports/stm32/boards/NETDUINO_PLUS_2/pins.csv
+++ b/ports/stm32/boards/NETDUINO_PLUS_2/pins.csv
@@ -33,3 +33,5 @@ UART3_RX,PD9
UART3_RTS,PD12
UART3_CTS,PD11
UART5_TX,PC12
+USB_DM,PA11
+USB_DP,PA12
diff --git a/ports/stm32/boards/NETDUINO_PLUS_2/stm32f4xx_hal_conf.h b/ports/stm32/boards/NETDUINO_PLUS_2/stm32f4xx_hal_conf.h
index 42c2c4e9b..4cb5a83e4 100644
--- a/ports/stm32/boards/NETDUINO_PLUS_2/stm32f4xx_hal_conf.h
+++ b/ports/stm32/boards/NETDUINO_PLUS_2/stm32f4xx_hal_conf.h
@@ -46,8 +46,6 @@
/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
-#define USE_USB_FS
-
/* ########################## Module Selection ############################## */
/**
* @brief This is the list of modules to be used in the HAL driver
diff --git a/ports/stm32/boards/NUCLEO_F091RC/mpconfigboard.h b/ports/stm32/boards/NUCLEO_F091RC/mpconfigboard.h
new file mode 100644
index 000000000..3546d521b
--- /dev/null
+++ b/ports/stm32/boards/NUCLEO_F091RC/mpconfigboard.h
@@ -0,0 +1,59 @@
+#define MICROPY_HW_BOARD_NAME "NUCLEO-F091RC"
+#define MICROPY_HW_MCU_NAME "STM32F091RCT6"
+
+#define MICROPY_EMIT_THUMB (0)
+#define MICROPY_EMIT_INLINE_THUMB (0)
+#define MICROPY_PY_USOCKET (0)
+#define MICROPY_PY_NETWORK (0)
+#define MICROPY_PY_STM (0)
+#define MICROPY_PY_PYB_LEGACY (0)
+#define MICROPY_VFS_FAT (0)
+
+#define MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE (0)
+#define MICROPY_HW_ENABLE_RTC (1)
+#define MICROPY_HW_ENABLE_ADC (1)
+#define MICROPY_HW_ENABLE_DAC (1)
+#define MICROPY_HW_ENABLE_TIMER (1)
+#define MICROPY_HW_HAS_SWITCH (1)
+
+// For system clock, board uses internal 48MHz, HSI48
+
+// The board has an external 32kHz crystal
+#define MICROPY_HW_RTC_USE_LSE (1)
+
+// UART config
+#define MICROPY_HW_UART1_TX (pin_B6)
+#define MICROPY_HW_UART1_RX (pin_B7)
+#define MICROPY_HW_UART2_TX (pin_A2)
+#define MICROPY_HW_UART2_RX (pin_A3)
+
+// USART2 is connected to the ST-LINK USB VCP
+#define MICROPY_HW_UART_REPL PYB_UART_2
+#define MICROPY_HW_UART_REPL_BAUD 115200
+
+// I2C busses
+#define MICROPY_HW_I2C1_SCL (pin_B8) // Arduino D15, pin 3 on CN10
+#define MICROPY_HW_I2C1_SDA (pin_B9) // Arduino D14, pin 5 on CN10
+#define MICROPY_HW_I2C2_SCL (pin_B10) // Arduino D6, pin 25 on CN10
+#define MICROPY_HW_I2C2_SDA (pin_B11) // pin 18 on CN10
+
+// SPI busses
+#define MICROPY_HW_SPI1_NSS (pin_A15) // pin 17 on CN7
+#define MICROPY_HW_SPI1_SCK (pin_A5) // Arduino D13, pin 11 on CN10
+#define MICROPY_HW_SPI1_MISO (pin_A6) // Arduino D12, pin 13 on CN10
+#define MICROPY_HW_SPI1_MOSI (pin_A7) // Arduino D11, pin 15 on CN10
+#define MICROPY_HW_SPI2_NSS (pin_B12) // pin 16 on CN10
+#define MICROPY_HW_SPI2_SCK (pin_B13) // pin 30 on CN10
+#define MICROPY_HW_SPI2_MISO (pin_B14) // pin 28 on CN10
+#define MICROPY_HW_SPI2_MOSI (pin_B15) // pin 26 on CN10
+
+// USER B1 has a pull-up and is active low
+#define MICROPY_HW_USRSW_PIN (pin_C13)
+#define MICROPY_HW_USRSW_PULL (0)
+#define MICROPY_HW_USRSW_EXTI_MODE (GPIO_MODE_IT_FALLING)
+#define MICROPY_HW_USRSW_PRESSED (0)
+
+// NUCLEO-64 has one user LED
+#define MICROPY_HW_LED1 (pin_A5) // green
+#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_high(pin))
+#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin))
diff --git a/ports/stm32/boards/NUCLEO_F091RC/mpconfigboard.mk b/ports/stm32/boards/NUCLEO_F091RC/mpconfigboard.mk
new file mode 100644
index 000000000..1d66f7e6b
--- /dev/null
+++ b/ports/stm32/boards/NUCLEO_F091RC/mpconfigboard.mk
@@ -0,0 +1,7 @@
+MCU_SERIES = f0
+CMSIS_MCU = STM32F091xC
+AF_FILE = boards/stm32f091_af.csv
+LD_FILES = boards/stm32f091xc.ld boards/common_basic.ld
+
+# Don't include default frozen modules because MCU is tight on flash space
+FROZEN_MPY_DIR ?=
diff --git a/ports/stm32/boards/NUCLEO_F091RC/pins.csv b/ports/stm32/boards/NUCLEO_F091RC/pins.csv
new file mode 100644
index 000000000..36d314108
--- /dev/null
+++ b/ports/stm32/boards/NUCLEO_F091RC/pins.csv
@@ -0,0 +1,87 @@
+D0,PA3
+D1,PA2
+D2,PA10
+D3,PB3
+D4,PB5
+D5,PB4
+D6,PB10
+D7,PA8
+D8,PA9
+D9,PC7
+D10,PB6
+D11,PA7
+D12,PA6
+D13,PA5
+D14,PB9
+D15,PB8
+A0,PA0
+A1,PA1
+A2,PA4
+A3,PB0
+A4,PC1
+A5,PC0
+RX,PA3
+TX,PA2
+SCL,PB8
+SDA,PB9
+SCK,PA5
+MISO,PA6
+MOSI,PA7
+CS,PB6
+BOOT0,PF11
+SWDIO,PA13
+SWCLK,PA14
+USER_B1,PC13
+LED_GREEN,PA5
+PA0,PA0
+PA1,PA1
+PA2,PA2
+PA3,PA3
+PA4,PA4
+PA5,PA5
+PA6,PA6
+PA7,PA7
+PA8,PA8
+PA9,PA9
+PA10,PA10
+PA11,PA11
+PA12,PA12
+PA13,PA13
+PA14,PA14
+PA15,PA15
+PB0,PB0
+PB1,PB1
+PB2,PB2
+PB3,PB3
+PB4,PB4
+PB5,PB5
+PB6,PB6
+PB7,PB7
+PB8,PB8
+PB9,PB9
+PB10,PB10
+PB11,PB11
+PB12,PB12
+PB13,PB13
+PB14,PB14
+PB15,PB15
+PC0,PC0
+PC1,PC1
+PC2,PC2
+PC3,PC3
+PC4,PC4
+PC5,PC5
+PC6,PC6
+PC7,PC7
+PC8,PC8
+PC9,PC9
+PC10,PC10
+PC11,PC11
+PC12,PC12
+PC13,PC13
+PC14,PC14
+PC15,PC15
+PD2,PD2
+PF0,PF0
+PF1,PF1
+PF11,PF11
diff --git a/ports/stm32/boards/NUCLEO_F091RC/stm32f0xx_hal_conf.h b/ports/stm32/boards/NUCLEO_F091RC/stm32f0xx_hal_conf.h
new file mode 100644
index 000000000..53ea047cb
--- /dev/null
+++ b/ports/stm32/boards/NUCLEO_F091RC/stm32f0xx_hal_conf.h
@@ -0,0 +1,312 @@
+/**
+ ******************************************************************************
+ * @file stm32f0xx_hal_conf_template.h
+ * @author MCD Application Team
+ * @brief HAL configuration template file.
+ * This file should be copied to the application folder and renamed
+ * to stm32f0xx_hal_conf.h.
+ ******************************************************************************
+ * @attention
+ *
+ * <h2><center>&copy; COPYRIGHT(c) 2016 STMicroelectronics</center></h2>
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of STMicroelectronics nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ******************************************************************************
+ */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __STM32F0xx_HAL_CONF_H
+#define __STM32F0xx_HAL_CONF_H
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/* Exported types ------------------------------------------------------------*/
+/* Exported constants --------------------------------------------------------*/
+
+/* ########################## Module Selection ############################## */
+/**
+ * @brief This is the list of modules to be used in the HAL driver
+ */
+#define HAL_MODULE_ENABLED
+#define HAL_ADC_MODULE_ENABLED
+#define HAL_CAN_MODULE_ENABLED
+#define HAL_CEC_MODULE_ENABLED
+#define HAL_COMP_MODULE_ENABLED
+#define HAL_CORTEX_MODULE_ENABLED
+#define HAL_CRC_MODULE_ENABLED
+#define HAL_DAC_MODULE_ENABLED
+#define HAL_DMA_MODULE_ENABLED
+#define HAL_FLASH_MODULE_ENABLED
+#define HAL_GPIO_MODULE_ENABLED
+#define HAL_I2C_MODULE_ENABLED
+#define HAL_I2S_MODULE_ENABLED
+#define HAL_IRDA_MODULE_ENABLED
+#define HAL_IWDG_MODULE_ENABLED
+#define HAL_PCD_MODULE_ENABLED
+#define HAL_PWR_MODULE_ENABLED
+#define HAL_RCC_MODULE_ENABLED
+#define HAL_RTC_MODULE_ENABLED
+#define HAL_SMARTCARD_MODULE_ENABLED
+#define HAL_SMBUS_MODULE_ENABLED
+#define HAL_SPI_MODULE_ENABLED
+#define HAL_TIM_MODULE_ENABLED
+#define HAL_TSC_MODULE_ENABLED
+#define HAL_UART_MODULE_ENABLED
+#define HAL_USART_MODULE_ENABLED
+#define HAL_WWDG_MODULE_ENABLED
+
+/* ######################### Oscillator Values adaptation ################### */
+/**
+ * @brief Adjust the value of External High Speed oscillator (HSE) used in your application.
+ * This value is used by the RCC HAL module to compute the system frequency
+ * (when HSE is used as system clock source, directly or through the PLL).
+ */
+#if !defined (HSE_VALUE)
+ #define HSE_VALUE ((uint32_t)8000000) /*!< Value of the External oscillator in Hz */
+#endif /* HSE_VALUE */
+
+/**
+ * @brief In the following line adjust the External High Speed oscillator (HSE) Startup
+ * Timeout value
+ */
+#if !defined (HSE_STARTUP_TIMEOUT)
+ #define HSE_STARTUP_TIMEOUT 100U /*!< Time out for HSE start up, in ms */
+#endif /* HSE_STARTUP_TIMEOUT */
+
+/**
+ * @brief Internal High Speed oscillator (HSI) value.
+ * This value is used by the RCC HAL module to compute the system frequency
+ * (when HSI is used as system clock source, directly or through the PLL).
+ */
+#if !defined (HSI_VALUE)
+ #define HSI_VALUE 8000000U /*!< Value of the Internal oscillator in Hz*/
+#endif /* HSI_VALUE */
+
+/**
+ * @brief In the following line adjust the Internal High Speed oscillator (HSI) Startup
+ * Timeout value
+ */
+#if !defined (HSI_STARTUP_TIMEOUT)
+ #define HSI_STARTUP_TIMEOUT 5000U /*!< Time out for HSI start up */
+#endif /* HSI_STARTUP_TIMEOUT */
+
+/**
+ * @brief Internal High Speed oscillator for ADC (HSI14) value.
+ */
+#if !defined (HSI14_VALUE)
+ #define HSI14_VALUE 14000000U /*!< Value of the Internal High Speed oscillator for ADC in Hz.
+ The real value may vary depending on the variations
+ in voltage and temperature. */
+#endif /* HSI14_VALUE */
+
+/**
+ * @brief Internal High Speed oscillator for USB (HSI48) value.
+ */
+#if !defined (HSI48_VALUE)
+ #define HSI48_VALUE 48000000U /*!< Value of the Internal High Speed oscillator for USB in Hz.
+ The real value may vary depending on the variations
+ in voltage and temperature. */
+#endif /* HSI48_VALUE */
+
+/**
+ * @brief Internal Low Speed oscillator (LSI) value.
+ */
+#if !defined (LSI_VALUE)
+ #define LSI_VALUE 40000U
+#endif /* LSI_VALUE */ /*!< Value of the Internal Low Speed oscillator in Hz
+ The real value may vary depending on the variations
+ in voltage and temperature. */
+/**
+ * @brief External Low Speed oscillator (LSE) value.
+ */
+#if !defined (LSE_VALUE)
+ #define LSE_VALUE 32768U /*!< Value of the External Low Speed oscillator in Hz */
+#endif /* LSE_VALUE */
+
+/**
+ * @brief Time out for LSE start up value in ms.
+ */
+#if !defined (LSE_STARTUP_TIMEOUT)
+ #define LSE_STARTUP_TIMEOUT 5000U /*!< Time out for LSE start up, in ms */
+#endif /* LSE_STARTUP_TIMEOUT */
+
+
+/* Tip: To avoid modifying this file each time you need to use different HSE,
+ === you can define the HSE value in your toolchain compiler preprocessor. */
+
+/* ########################### System Configuration ######################### */
+/**
+ * @brief This is the HAL system configuration section
+ */
+#define VDD_VALUE 3300U /*!< Value of VDD in mv */
+#define TICK_INT_PRIORITY ((uint32_t)0x00) /*!< tick interrupt priority */
+#define USE_RTOS 0U
+#define PREFETCH_ENABLE 1U
+#define INSTRUCTION_CACHE_ENABLE 0U
+#define DATA_CACHE_ENABLE 0U
+#define USE_SPI_CRC 1U
+
+/* ########################## Assert Selection ############################## */
+/**
+ * @brief Uncomment the line below to expanse the "assert_param" macro in the
+ * HAL drivers code
+ */
+/*#define USE_FULL_ASSERT 1*/
+
+/* Includes ------------------------------------------------------------------*/
+/**
+ * @brief Include module's header file
+ */
+
+#ifdef HAL_RCC_MODULE_ENABLED
+ #include "stm32f0xx_hal_rcc.h"
+#endif /* HAL_RCC_MODULE_ENABLED */
+
+#ifdef HAL_GPIO_MODULE_ENABLED
+ #include "stm32f0xx_hal_gpio.h"
+#endif /* HAL_GPIO_MODULE_ENABLED */
+
+#ifdef HAL_DMA_MODULE_ENABLED
+ #include "stm32f0xx_hal_dma.h"
+#endif /* HAL_DMA_MODULE_ENABLED */
+
+#ifdef HAL_CORTEX_MODULE_ENABLED
+ #include "stm32f0xx_hal_cortex.h"
+#endif /* HAL_CORTEX_MODULE_ENABLED */
+
+#ifdef HAL_ADC_MODULE_ENABLED
+ #include "stm32f0xx_hal_adc.h"
+#endif /* HAL_ADC_MODULE_ENABLED */
+
+#ifdef HAL_CAN_MODULE_ENABLED
+ #include "stm32f0xx_hal_can.h"
+#endif /* HAL_CAN_MODULE_ENABLED */
+
+#ifdef HAL_CEC_MODULE_ENABLED
+ #include "stm32f0xx_hal_cec.h"
+#endif /* HAL_CEC_MODULE_ENABLED */
+
+#ifdef HAL_COMP_MODULE_ENABLED
+ #include "stm32f0xx_hal_comp.h"
+#endif /* HAL_COMP_MODULE_ENABLED */
+
+#ifdef HAL_CRC_MODULE_ENABLED
+ #include "stm32f0xx_hal_crc.h"
+#endif /* HAL_CRC_MODULE_ENABLED */
+
+#ifdef HAL_DAC_MODULE_ENABLED
+ #include "stm32f0xx_hal_dac.h"
+#endif /* HAL_DAC_MODULE_ENABLED */
+
+#ifdef HAL_FLASH_MODULE_ENABLED
+ #include "stm32f0xx_hal_flash.h"
+#endif /* HAL_FLASH_MODULE_ENABLED */
+
+#ifdef HAL_I2C_MODULE_ENABLED
+ #include "stm32f0xx_hal_i2c.h"
+#endif /* HAL_I2C_MODULE_ENABLED */
+
+#ifdef HAL_I2S_MODULE_ENABLED
+ #include "stm32f0xx_hal_i2s.h"
+#endif /* HAL_I2S_MODULE_ENABLED */
+
+#ifdef HAL_IRDA_MODULE_ENABLED
+ #include "stm32f0xx_hal_irda.h"
+#endif /* HAL_IRDA_MODULE_ENABLED */
+
+#ifdef HAL_IWDG_MODULE_ENABLED
+ #include "stm32f0xx_hal_iwdg.h"
+#endif /* HAL_IWDG_MODULE_ENABLED */
+
+#ifdef HAL_PCD_MODULE_ENABLED
+ #include "stm32f0xx_hal_pcd.h"
+#endif /* HAL_PCD_MODULE_ENABLED */
+
+#ifdef HAL_PWR_MODULE_ENABLED
+ #include "stm32f0xx_hal_pwr.h"
+#endif /* HAL_PWR_MODULE_ENABLED */
+
+#ifdef HAL_RTC_MODULE_ENABLED
+ #include "stm32f0xx_hal_rtc.h"
+#endif /* HAL_RTC_MODULE_ENABLED */
+
+#ifdef HAL_SMARTCARD_MODULE_ENABLED
+ #include "stm32f0xx_hal_smartcard.h"
+#endif /* HAL_SMARTCARD_MODULE_ENABLED */
+
+#ifdef HAL_SMBUS_MODULE_ENABLED
+ #include "stm32f0xx_hal_smbus.h"
+#endif /* HAL_SMBUS_MODULE_ENABLED */
+
+#ifdef HAL_SPI_MODULE_ENABLED
+ #include "stm32f0xx_hal_spi.h"
+#endif /* HAL_SPI_MODULE_ENABLED */
+
+#ifdef HAL_TIM_MODULE_ENABLED
+ #include "stm32f0xx_hal_tim.h"
+#endif /* HAL_TIM_MODULE_ENABLED */
+
+#ifdef HAL_TSC_MODULE_ENABLED
+ #include "stm32f0xx_hal_tsc.h"
+#endif /* HAL_TSC_MODULE_ENABLED */
+
+#ifdef HAL_UART_MODULE_ENABLED
+ #include "stm32f0xx_hal_uart.h"
+#endif /* HAL_UART_MODULE_ENABLED */
+
+#ifdef HAL_USART_MODULE_ENABLED
+ #include "stm32f0xx_hal_usart.h"
+#endif /* HAL_USART_MODULE_ENABLED */
+
+#ifdef HAL_WWDG_MODULE_ENABLED
+ #include "stm32f0xx_hal_wwdg.h"
+#endif /* HAL_WWDG_MODULE_ENABLED */
+
+/* Exported macro ------------------------------------------------------------*/
+#ifdef USE_FULL_ASSERT
+/**
+ * @brief The assert_param macro is used for function's parameters check.
+ * @param expr: If expr is false, it calls assert_failed function
+ * which reports the name of the source file and the source
+ * line number of the call that failed.
+ * If expr is true, it returns no value.
+ * @retval None
+ */
+ #define assert_param(expr) ((expr) ? (void)0U : assert_failed((char *)__FILE__, __LINE__))
+/* Exported functions ------------------------------------------------------- */
+ void assert_failed(char* file, uint32_t line);
+#else
+ #define assert_param(expr) ((void)0U)
+#endif /* USE_FULL_ASSERT */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __STM32F0xx_HAL_CONF_H */
+
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/ports/stm32/boards/NUCLEO_F401RE/mpconfigboard.mk b/ports/stm32/boards/NUCLEO_F401RE/mpconfigboard.mk
index eb391bed7..4c3022f54 100644
--- a/ports/stm32/boards/NUCLEO_F401RE/mpconfigboard.mk
+++ b/ports/stm32/boards/NUCLEO_F401RE/mpconfigboard.mk
@@ -1,4 +1,6 @@
MCU_SERIES = f4
CMSIS_MCU = STM32F401xE
AF_FILE = boards/stm32f401_af.csv
-LD_FILE = boards/stm32f401xe.ld
+LD_FILES = boards/stm32f401xe.ld boards/common_ifs.ld
+TEXT0_ADDR = 0x08000000
+TEXT1_ADDR = 0x08020000
diff --git a/ports/stm32/boards/NUCLEO_F401RE/stm32f4xx_hal_conf.h b/ports/stm32/boards/NUCLEO_F401RE/stm32f4xx_hal_conf.h
index f4db4cb63..daf9b63ce 100644
--- a/ports/stm32/boards/NUCLEO_F401RE/stm32f4xx_hal_conf.h
+++ b/ports/stm32/boards/NUCLEO_F401RE/stm32f4xx_hal_conf.h
@@ -46,10 +46,6 @@
/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
-// This board doesn't really have USB, but the stm32 codebase doesn't build
-// without some USB defined, so we leave this on for now.
-#define USE_USB_FS
-
/* ########################## Module Selection ############################## */
/**
* @brief This is the list of modules to be used in the HAL driver
diff --git a/ports/stm32/boards/NUCLEO_F411RE/mpconfigboard.mk b/ports/stm32/boards/NUCLEO_F411RE/mpconfigboard.mk
index 71b3b19d6..df9506522 100644
--- a/ports/stm32/boards/NUCLEO_F411RE/mpconfigboard.mk
+++ b/ports/stm32/boards/NUCLEO_F411RE/mpconfigboard.mk
@@ -1,4 +1,6 @@
MCU_SERIES = f4
CMSIS_MCU = STM32F411xE
AF_FILE = boards/stm32f411_af.csv
-LD_FILE = boards/stm32f411.ld
+LD_FILES = boards/stm32f411.ld boards/common_ifs.ld
+TEXT0_ADDR = 0x08000000
+TEXT1_ADDR = 0x08020000
diff --git a/ports/stm32/boards/NUCLEO_F411RE/stm32f4xx_hal_conf.h b/ports/stm32/boards/NUCLEO_F411RE/stm32f4xx_hal_conf.h
index 0c424888f..8f0b66381 100644
--- a/ports/stm32/boards/NUCLEO_F411RE/stm32f4xx_hal_conf.h
+++ b/ports/stm32/boards/NUCLEO_F411RE/stm32f4xx_hal_conf.h
@@ -46,10 +46,6 @@
/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
-// This board doesn't really have USB, but the stm32 codebase doesn't build
-// without some USB defined, so we leave this on for now.
-#define USE_USB_FS
-
/* ########################## Module Selection ############################## */
/**
* @brief This is the list of modules to be used in the HAL driver
diff --git a/ports/stm32/boards/NUCLEO_F429ZI/mpconfigboard.h b/ports/stm32/boards/NUCLEO_F429ZI/mpconfigboard.h
index 42cc9d68c..17883a192 100644
--- a/ports/stm32/boards/NUCLEO_F429ZI/mpconfigboard.h
+++ b/ports/stm32/boards/NUCLEO_F429ZI/mpconfigboard.h
@@ -3,22 +3,15 @@
#define MICROPY_HW_HAS_SWITCH (1)
#define MICROPY_HW_HAS_FLASH (1)
-#define MICROPY_HW_HAS_SDCARD (0)
-#define MICROPY_HW_HAS_MMA7660 (0)
-#define MICROPY_HW_HAS_LIS3DSH (0)
-#define MICROPY_HW_HAS_LCD (0)
#define MICROPY_HW_ENABLE_RNG (1)
#define MICROPY_HW_ENABLE_RTC (1)
-#define MICROPY_HW_ENABLE_TIMER (1)
-#define MICROPY_HW_ENABLE_SERVO (0)
-#define MICROPY_HW_ENABLE_DAC (0)
-#define MICROPY_HW_ENABLE_CAN (1)
+#define MICROPY_HW_ENABLE_USB (1)
// HSE is 8MHz
#define MICROPY_HW_CLK_PLLM (8)
-#define MICROPY_HW_CLK_PLLN (180)
+#define MICROPY_HW_CLK_PLLN (336)
#define MICROPY_HW_CLK_PLLP (RCC_PLLP_DIV2)
-#define MICROPY_HW_CLK_PLLQ (4)
+#define MICROPY_HW_CLK_PLLQ (7)
// From the reference manual, for 2.7V to 3.6V
// 151-180 MHz => 5 wait states
@@ -65,6 +58,12 @@
#define MICROPY_HW_SPI5_MISO (pin_F8)
#define MICROPY_HW_SPI5_MOSI (pin_F9)
+// CAN busses
+#define MICROPY_HW_CAN1_TX (pin_B9)
+#define MICROPY_HW_CAN1_RX (pin_B8)
+#define MICROPY_HW_CAN2_TX (pin_B13)
+#define MICROPY_HW_CAN2_RX (pin_B12)
+
// USRSW is pulled low. Pressing the button makes the input go high.
#define MICROPY_HW_USRSW_PIN (pin_C13)
#define MICROPY_HW_USRSW_PULL (GPIO_NOPULL)
@@ -79,5 +78,6 @@
#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin))
// USB config (CN13 - USB OTG FS)
+#define MICROPY_HW_USB_FS (1)
#define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_A9)
#define MICROPY_HW_USB_OTG_ID_PIN (pin_A10)
diff --git a/ports/stm32/boards/NUCLEO_F429ZI/mpconfigboard.mk b/ports/stm32/boards/NUCLEO_F429ZI/mpconfigboard.mk
index 1bbf808b6..d19a35c31 100644
--- a/ports/stm32/boards/NUCLEO_F429ZI/mpconfigboard.mk
+++ b/ports/stm32/boards/NUCLEO_F429ZI/mpconfigboard.mk
@@ -1,4 +1,6 @@
MCU_SERIES = f4
CMSIS_MCU = STM32F429xx
AF_FILE = boards/stm32f429_af.csv
-LD_FILE = boards/stm32f429.ld
+LD_FILES = boards/stm32f429.ld boards/common_ifs.ld
+TEXT0_ADDR = 0x08000000
+TEXT1_ADDR = 0x08020000
diff --git a/ports/stm32/boards/NUCLEO_F429ZI/stm32f4xx_hal_conf.h b/ports/stm32/boards/NUCLEO_F429ZI/stm32f4xx_hal_conf.h
index d121b18c5..5b5a8a3e4 100644
--- a/ports/stm32/boards/NUCLEO_F429ZI/stm32f4xx_hal_conf.h
+++ b/ports/stm32/boards/NUCLEO_F429ZI/stm32f4xx_hal_conf.h
@@ -46,8 +46,6 @@
/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
-#define USE_USB_FS
-
/* ########################## Module Selection ############################## */
/**
* @brief This is the list of modules to be used in the HAL driver
diff --git a/ports/stm32/boards/NUCLEO_F446RE/mpconfigboard.mk b/ports/stm32/boards/NUCLEO_F446RE/mpconfigboard.mk
index e1ec6d57c..64a80e992 100644
--- a/ports/stm32/boards/NUCLEO_F446RE/mpconfigboard.mk
+++ b/ports/stm32/boards/NUCLEO_F446RE/mpconfigboard.mk
@@ -1,4 +1,6 @@
MCU_SERIES = f4
CMSIS_MCU = STM32F446xx
AF_FILE = boards/stm32f429_af.csv
-LD_FILE = boards/stm32f411.ld
+LD_FILES = boards/stm32f411.ld boards/common_ifs.ld
+TEXT0_ADDR = 0x08000000
+TEXT1_ADDR = 0x08020000
diff --git a/ports/stm32/boards/NUCLEO_F446RE/stm32f4xx_hal_conf.h b/ports/stm32/boards/NUCLEO_F446RE/stm32f4xx_hal_conf.h
index 487ca009f..245fb9a06 100644
--- a/ports/stm32/boards/NUCLEO_F446RE/stm32f4xx_hal_conf.h
+++ b/ports/stm32/boards/NUCLEO_F446RE/stm32f4xx_hal_conf.h
@@ -46,10 +46,6 @@
/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
-// This board doesn't really have USB, but the stm32 codebase doesn't build
-// without some USB defined, so we leave this on for now.
-#define USE_USB_FS
-
/* ########################## Module Selection ############################## */
/**
* @brief This is the list of modules to be used in the HAL driver
diff --git a/ports/stm32/boards/NUCLEO_F746ZG/mpconfigboard.h b/ports/stm32/boards/NUCLEO_F746ZG/mpconfigboard.h
new file mode 100644
index 000000000..a9fbea576
--- /dev/null
+++ b/ports/stm32/boards/NUCLEO_F746ZG/mpconfigboard.h
@@ -0,0 +1,77 @@
+// This board is only confirmed to operate using DFU mode and openocd.
+// DFU mode can be accessed by setting BOOT0 (see schematics)
+// To use openocd run "OPENOCD_CONFIG=boards/openocd_stm32f7.cfg" in
+// the make command.
+
+#define MICROPY_HW_BOARD_NAME "NUCLEO-F746ZG"
+#define MICROPY_HW_MCU_NAME "STM32F746"
+
+#define MICROPY_HW_HAS_SWITCH (1)
+#define MICROPY_HW_HAS_FLASH (1)
+#define MICROPY_HW_ENABLE_RNG (1)
+#define MICROPY_HW_ENABLE_RTC (1)
+#define MICROPY_HW_ENABLE_DAC (1)
+#define MICROPY_HW_ENABLE_USB (1)
+
+// HSE is 8MHz
+// VCOClock = HSE * PLLN / PLLM = 8 MHz * 216 / 4 = 432 MHz
+// SYSCLK = VCOClock / PLLP = 432 MHz / 2 = 216 MHz
+// USB/SDMMC/RNG Clock = VCOClock / PLLQ = 432 MHz / 9 = 48 MHz
+#define MICROPY_HW_CLK_PLLM (4)
+#define MICROPY_HW_CLK_PLLN (216)
+#define MICROPY_HW_CLK_PLLP (RCC_PLLP_DIV2)
+#define MICROPY_HW_CLK_PLLQ (9)
+
+// From the reference manual, for 2.7V to 3.6V
+// 151-180 MHz => 5 wait states
+// 181-210 MHz => 6 wait states
+// 211-216 MHz => 7 wait states
+#define MICROPY_HW_FLASH_LATENCY FLASH_LATENCY_7 // 210-216 MHz needs 7 wait states
+
+// UART config
+#define MICROPY_HW_UART2_TX (pin_D5)
+#define MICROPY_HW_UART2_RX (pin_D6)
+#define MICROPY_HW_UART2_RTS (pin_D4)
+#define MICROPY_HW_UART2_CTS (pin_D3)
+#define MICROPY_HW_UART3_TX (pin_D8)
+#define MICROPY_HW_UART3_RX (pin_D9)
+#define MICROPY_HW_UART6_TX (pin_G14)
+#define MICROPY_HW_UART6_RX (pin_G9)
+#define MICROPY_HW_UART_REPL PYB_UART_3
+#define MICROPY_HW_UART_REPL_BAUD 115200
+
+// I2C busses
+#define MICROPY_HW_I2C1_SCL (pin_B8)
+#define MICROPY_HW_I2C1_SDA (pin_B9)
+#define MICROPY_HW_I2C3_SCL (pin_H7)
+#define MICROPY_HW_I2C3_SDA (pin_H8)
+
+// SPI
+#define MICROPY_HW_SPI3_NSS (pin_A4)
+#define MICROPY_HW_SPI3_SCK (pin_B3)
+#define MICROPY_HW_SPI3_MISO (pin_B4)
+#define MICROPY_HW_SPI3_MOSI (pin_B5)
+
+// CAN busses
+#define MICROPY_HW_CAN1_TX (pin_B9)
+#define MICROPY_HW_CAN1_RX (pin_B8)
+#define MICROPY_HW_CAN2_TX (pin_B13)
+#define MICROPY_HW_CAN2_RX (pin_B12)
+
+// USRSW is pulled low. Pressing the button makes the input go high.
+#define MICROPY_HW_USRSW_PIN (pin_C13)
+#define MICROPY_HW_USRSW_PULL (GPIO_NOPULL)
+#define MICROPY_HW_USRSW_EXTI_MODE (GPIO_MODE_IT_RISING)
+#define MICROPY_HW_USRSW_PRESSED (1)
+
+// LEDs
+#define MICROPY_HW_LED1 (pin_B0) // green
+#define MICROPY_HW_LED2 (pin_B7) // blue
+#define MICROPY_HW_LED3 (pin_B14) // red
+#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_high(pin))
+#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin))
+
+// USB config (CN13 - USB OTG FS)
+#define MICROPY_HW_USB_FS (1)
+#define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_A9)
+#define MICROPY_HW_USB_OTG_ID_PIN (pin_A10)
diff --git a/ports/stm32/boards/NUCLEO_F746ZG/mpconfigboard.mk b/ports/stm32/boards/NUCLEO_F746ZG/mpconfigboard.mk
new file mode 100644
index 000000000..160218fd3
--- /dev/null
+++ b/ports/stm32/boards/NUCLEO_F746ZG/mpconfigboard.mk
@@ -0,0 +1,6 @@
+MCU_SERIES = f7
+CMSIS_MCU = STM32F746xx
+AF_FILE = boards/stm32f746_af.csv
+LD_FILES = boards/stm32f746.ld boards/common_ifs.ld
+TEXT0_ADDR = 0x08000000
+TEXT1_ADDR = 0x08020000
diff --git a/ports/stm32/boards/NUCLEO_F746ZG/pins.csv b/ports/stm32/boards/NUCLEO_F746ZG/pins.csv
new file mode 100644
index 000000000..aa5143e8c
--- /dev/null
+++ b/ports/stm32/boards/NUCLEO_F746ZG/pins.csv
@@ -0,0 +1,68 @@
+A0,PA3
+A1,PC0
+A2,PC3
+A3,PF3
+A4,PF5
+A5,PF10
+D0,PG9
+D1,PG14
+D2,PF15
+D3,PE13
+D4,PF14
+D5,PE11
+D6,PE9
+D7,PF13
+D8,PF12
+D9,PD15
+D10,PD14
+D11,PA7
+D12,PA6
+D13,PA5
+D14,PB9
+D15,PB8
+D16,PC6
+D17,PB15
+D18,PB13
+D19,PB12
+D20,PA15
+D21,PC7
+D22,PB5
+D23,PB3
+D24,PA4
+D25,PB4
+LED1,PB0
+LED2,PB7
+LED3,PB14
+SW,PC13
+TP1,PH2
+TP2,PI8
+TP3,PH15
+AUDIO_INT,PD6
+AUDIO_SDA,PH8
+AUDIO_SCL,PH7
+EXT_SDA,PB9
+EXT_SCL,PB8
+EXT_RST,PG3
+SD_SW,PC13
+LCD_BL_CTRL,PK3
+LCD_INT,PI13
+LCD_SDA,PH8
+LCD_SCL,PH7
+OTG_FS_POWER,PD5
+OTG_FS_OVER_CURRENT,PD4
+OTG_HS_OVER_CURRENT,PE3
+USB_VBUS,PA9
+USB_ID,PA10
+USB_DM,PA11
+USB_DP,PA12
+VCP_TX,PD8
+VCP_RX,PD9
+UART2_TX,PD5
+UART2_RX,PD6
+UART2_RTS,PD4
+UART2_CTS,PD3
+UART6_TX,PG14
+UART6_RX,PG9
+SPI_B_NSS,PA4
+SPI_B_SCK,PB3
+SPI_B_MOSI,PB5
diff --git a/ports/stm32/boards/NUCLEO_F746ZG/stm32f7xx_hal_conf.h b/ports/stm32/boards/NUCLEO_F746ZG/stm32f7xx_hal_conf.h
new file mode 100644
index 000000000..a019ee4ce
--- /dev/null
+++ b/ports/stm32/boards/NUCLEO_F746ZG/stm32f7xx_hal_conf.h
@@ -0,0 +1,427 @@
+/**
+ ******************************************************************************
+ * @file stm32f7xx_hal_conf.h
+ * @author MCD Application Team
+ * @version V1.0.1
+ * @date 25-June-2015
+ * @brief HAL configuration file.
+ ******************************************************************************
+ * @attention
+ *
+ * <h2><center>&copy; COPYRIGHT(c) 2015 STMicroelectronics</center></h2>
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of STMicroelectronics nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ******************************************************************************
+ */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __STM32F7xx_HAL_CONF_H
+#define __STM32F7xx_HAL_CONF_H
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/* Exported types ------------------------------------------------------------*/
+/* Exported constants --------------------------------------------------------*/
+
+/* ########################## Module Selection ############################## */
+/**
+ * @brief This is the list of modules to be used in the HAL driver
+ */
+#define HAL_MODULE_ENABLED
+#define HAL_ADC_MODULE_ENABLED
+#define HAL_CAN_MODULE_ENABLED
+/* #define HAL_CEC_MODULE_ENABLED */
+/* #define HAL_CRC_MODULE_ENABLED */
+/* #define HAL_CRYP_MODULE_ENABLED */
+#define HAL_DAC_MODULE_ENABLED
+/* #define HAL_DCMI_MODULE_ENABLED */
+#define HAL_DMA_MODULE_ENABLED
+/* #define HAL_DMA2D_MODULE_ENABLED */
+/* #define HAL_ETH_MODULE_ENABLED */
+#define HAL_FLASH_MODULE_ENABLED
+/* #define HAL_NAND_MODULE_ENABLED */
+/* #define HAL_NOR_MODULE_ENABLED */
+/* #define HAL_SRAM_MODULE_ENABLED */
+/* #define HAL_SDRAM_MODULE_ENABLED */
+/* #define HAL_HASH_MODULE_ENABLED */
+#define HAL_GPIO_MODULE_ENABLED
+#define HAL_I2C_MODULE_ENABLED
+#define HAL_I2S_MODULE_ENABLED
+/* #define HAL_IWDG_MODULE_ENABLED */
+/* #define HAL_LPTIM_MODULE_ENABLED */
+/* #define HAL_LTDC_MODULE_ENABLED */
+#define HAL_PWR_MODULE_ENABLED
+/* #define HAL_QSPI_MODULE_ENABLED */
+#define HAL_RCC_MODULE_ENABLED
+#define HAL_RNG_MODULE_ENABLED
+#define HAL_RTC_MODULE_ENABLED
+/* #define HAL_SAI_MODULE_ENABLED */
+#define HAL_SD_MODULE_ENABLED
+/* #define HAL_SPDIFRX_MODULE_ENABLED */
+#define HAL_SPI_MODULE_ENABLED
+#define HAL_TIM_MODULE_ENABLED
+#define HAL_UART_MODULE_ENABLED
+/* #define HAL_USART_MODULE_ENABLED */
+/* #define HAL_IRDA_MODULE_ENABLED */
+/* #define HAL_SMARTCARD_MODULE_ENABLED */
+/* #define HAL_WWDG_MODULE_ENABLED */
+#define HAL_CORTEX_MODULE_ENABLED
+#define HAL_PCD_MODULE_ENABLED
+/* #define HAL_HCD_MODULE_ENABLED */
+
+
+/* ########################## Timeout Configuration ######################### */
+/**
+ * @brief This is the HAL configuration section
+ */
+#define HAL_ACCURATE_TIMEOUT_ENABLED 0
+#define HAL_TIMEOUT_VALUE 0x1FFFFFF
+
+/* ########################## HSE/HSI Values adaptation ##################### */
+/**
+ * @brief Adjust the value of External High Speed oscillator (HSE) used in your application.
+ * This value is used by the RCC HAL module to compute the system frequency
+ * (when HSE is used as system clock source, directly or through the PLL).
+ */
+#if !defined (HSE_VALUE)
+ #define HSE_VALUE ((uint32_t)8000000) /*!< Value of the External oscillator in Hz */
+#endif /* HSE_VALUE */
+
+#if !defined (HSE_STARTUP_TIMEOUT)
+ #define HSE_STARTUP_TIMEOUT ((uint32_t)5000) /*!< Time out for HSE start up, in ms */
+#endif /* HSE_STARTUP_TIMEOUT */
+
+/**
+ * @brief Internal High Speed oscillator (HSI) value.
+ * This value is used by the RCC HAL module to compute the system frequency
+ * (when HSI is used as system clock source, directly or through the PLL).
+ */
+#if !defined (HSI_VALUE)
+ #define HSI_VALUE ((uint32_t)16000000) /*!< Value of the Internal oscillator in Hz*/
+#endif /* HSI_VALUE */
+
+/**
+ * @brief Internal Low Speed oscillator (LSI) value.
+ */
+#if !defined (LSI_VALUE)
+ #define LSI_VALUE ((uint32_t)32000)
+#endif /* LSI_VALUE */ /*!< Value of the Internal Low Speed oscillator in Hz
+ The real value may vary depending on the variations
+ in voltage and temperature. */
+/**
+ * @brief External Low Speed oscillator (LSE) value.
+ */
+#if !defined (LSE_VALUE)
+ #define LSE_VALUE ((uint32_t)32768) /*!< Value of the External Low Speed oscillator in Hz */
+#endif /* LSE_VALUE */
+
+#if !defined (LSE_STARTUP_TIMEOUT)
+ #define LSE_STARTUP_TIMEOUT ((uint32_t)5000U) /*!< Time out for LSE start up, in ms */
+#endif /* LSE_STARTUP_TIMEOUT */
+
+/**
+ * @brief External clock source for I2S peripheral
+ * This value is used by the I2S HAL module to compute the I2S clock source
+ * frequency, this source is inserted directly through I2S_CKIN pad.
+ */
+#if !defined (EXTERNAL_CLOCK_VALUE)
+ #define EXTERNAL_CLOCK_VALUE ((uint32_t)12288000) /*!< Value of the Internal oscillator in Hz*/
+#endif /* EXTERNAL_CLOCK_VALUE */
+
+/* Tip: To avoid modifying this file each time you need to use different HSE,
+ === you can define the HSE value in your toolchain compiler preprocessor. */
+
+/* ########################### System Configuration ######################### */
+/**
+ * @brief This is the HAL system configuration section
+ */
+#define VDD_VALUE ((uint32_t)3300) /*!< Value of VDD in mv */
+#define TICK_INT_PRIORITY ((uint32_t)0x00) /*!< tick interrupt priority */
+#define USE_RTOS 0
+#define ART_ACCLERATOR_ENABLE 1 /* To enable instruction cache and prefetch */
+
+/* ########################## Assert Selection ############################## */
+/**
+ * @brief Uncomment the line below to expanse the "assert_param" macro in the
+ * HAL drivers code
+ */
+/* #define USE_FULL_ASSERT 1 */
+
+/* ################## Ethernet peripheral configuration ##################### */
+
+/* Section 1 : Ethernet peripheral configuration */
+
+/* MAC ADDRESS: MAC_ADDR0:MAC_ADDR1:MAC_ADDR2:MAC_ADDR3:MAC_ADDR4:MAC_ADDR5 */
+#define MAC_ADDR0 2
+#define MAC_ADDR1 1
+#define MAC_ADDR2 0
+#define MAC_ADDR3 0
+#define MAC_ADDR4 0
+#define MAC_ADDR5 0
+
+/* Definition of the Ethernet driver buffers size and count */
+#define ETH_RX_BUF_SIZE ETH_MAX_PACKET_SIZE /* buffer size for receive */
+#define ETH_TX_BUF_SIZE ETH_MAX_PACKET_SIZE /* buffer size for transmit */
+#define ETH_RXBUFNB ((uint32_t)5) /* 5 Rx buffers of size ETH_RX_BUF_SIZE */
+#define ETH_TXBUFNB ((uint32_t)5) /* 5 Tx buffers of size ETH_TX_BUF_SIZE */
+
+/* Section 2: PHY configuration section */
+/* LAN8742A PHY Address*/
+#define LAN8742A_PHY_ADDRESS 0x00
+/* PHY Reset delay these values are based on a 1 ms Systick interrupt*/
+#define PHY_RESET_DELAY ((uint32_t)0x00000FFF)
+/* PHY Configuration delay */
+#define PHY_CONFIG_DELAY ((uint32_t)0x00000FFFF)
+
+#define PHY_READ_TO ((uint32_t)0x0000FFFF)
+#define PHY_WRITE_TO ((uint32_t)0x0000FFFF)
+
+/* Section 3: Common PHY Registers */
+
+#define PHY_BCR ((uint16_t)0x00) /*!< Transceiver Basic Control Register */
+#define PHY_BSR ((uint16_t)0x01) /*!< Transceiver Basic Status Register */
+
+#define PHY_RESET ((uint16_t)0x8000) /*!< PHY Reset */
+#define PHY_LOOPBACK ((uint16_t)0x4000) /*!< Select loop-back mode */
+#define PHY_FULLDUPLEX_100M ((uint16_t)0x2100) /*!< Set the full-duplex mode at 100 Mb/s */
+#define PHY_HALFDUPLEX_100M ((uint16_t)0x2000) /*!< Set the half-duplex mode at 100 Mb/s */
+#define PHY_FULLDUPLEX_10M ((uint16_t)0x0100) /*!< Set the full-duplex mode at 10 Mb/s */
+#define PHY_HALFDUPLEX_10M ((uint16_t)0x0000) /*!< Set the half-duplex mode at 10 Mb/s */
+#define PHY_AUTONEGOTIATION ((uint16_t)0x1000) /*!< Enable auto-negotiation function */
+#define PHY_RESTART_AUTONEGOTIATION ((uint16_t)0x0200) /*!< Restart auto-negotiation function */
+#define PHY_POWERDOWN ((uint16_t)0x0800) /*!< Select the power down mode */
+#define PHY_ISOLATE ((uint16_t)0x0400) /*!< Isolate PHY from MII */
+
+#define PHY_AUTONEGO_COMPLETE ((uint16_t)0x0020) /*!< Auto-Negotiation process completed */
+#define PHY_LINKED_STATUS ((uint16_t)0x0004) /*!< Valid link established */
+#define PHY_JABBER_DETECTION ((uint16_t)0x0002) /*!< Jabber condition detected */
+
+/* Section 4: Extended PHY Registers */
+
+#define PHY_SR ((uint16_t)0x10) /*!< PHY status register Offset */
+#define PHY_MICR ((uint16_t)0x11) /*!< MII Interrupt Control Register */
+#define PHY_MISR ((uint16_t)0x12) /*!< MII Interrupt Status and Misc. Control Register */
+
+#define PHY_LINK_STATUS ((uint16_t)0x0001) /*!< PHY Link mask */
+#define PHY_SPEED_STATUS ((uint16_t)0x0002) /*!< PHY Speed mask */
+#define PHY_DUPLEX_STATUS ((uint16_t)0x0004) /*!< PHY Duplex mask */
+
+#define PHY_MICR_INT_EN ((uint16_t)0x0002) /*!< PHY Enable interrupts */
+#define PHY_MICR_INT_OE ((uint16_t)0x0001) /*!< PHY Enable output interrupt events */
+
+#define PHY_MISR_LINK_INT_EN ((uint16_t)0x0020) /*!< Enable Interrupt on change of link status */
+#define PHY_LINK_INTERRUPT ((uint16_t)0x2000) /*!< PHY link status interrupt mask */
+
+/* Includes ------------------------------------------------------------------*/
+/**
+ * @brief Include module's header file
+ */
+
+#ifdef HAL_RCC_MODULE_ENABLED
+ #include "stm32f7xx_hal_rcc.h"
+#endif /* HAL_RCC_MODULE_ENABLED */
+
+#ifdef HAL_GPIO_MODULE_ENABLED
+ #include "stm32f7xx_hal_gpio.h"
+#endif /* HAL_GPIO_MODULE_ENABLED */
+
+#ifdef HAL_DMA_MODULE_ENABLED
+ #include "stm32f7xx_hal_dma.h"
+#endif /* HAL_DMA_MODULE_ENABLED */
+
+#ifdef HAL_CORTEX_MODULE_ENABLED
+ #include "stm32f7xx_hal_cortex.h"
+#endif /* HAL_CORTEX_MODULE_ENABLED */
+
+#ifdef HAL_ADC_MODULE_ENABLED
+ #include "stm32f7xx_hal_adc.h"
+#endif /* HAL_ADC_MODULE_ENABLED */
+
+#ifdef HAL_CAN_MODULE_ENABLED
+ #include "stm32f7xx_hal_can.h"
+#endif /* HAL_CAN_MODULE_ENABLED */
+
+#ifdef HAL_CEC_MODULE_ENABLED
+ #include "stm32f7xx_hal_cec.h"
+#endif /* HAL_CEC_MODULE_ENABLED */
+
+#ifdef HAL_CRC_MODULE_ENABLED
+ #include "stm32f7xx_hal_crc.h"
+#endif /* HAL_CRC_MODULE_ENABLED */
+
+#ifdef HAL_CRYP_MODULE_ENABLED
+ #include "stm32f7xx_hal_cryp.h"
+#endif /* HAL_CRYP_MODULE_ENABLED */
+
+#ifdef HAL_DMA2D_MODULE_ENABLED
+ #include "stm32f7xx_hal_dma2d.h"
+#endif /* HAL_DMA2D_MODULE_ENABLED */
+
+#ifdef HAL_DAC_MODULE_ENABLED
+ #include "stm32f7xx_hal_dac.h"
+#endif /* HAL_DAC_MODULE_ENABLED */
+
+#ifdef HAL_DCMI_MODULE_ENABLED
+ #include "stm32f7xx_hal_dcmi.h"
+#endif /* HAL_DCMI_MODULE_ENABLED */
+
+#ifdef HAL_ETH_MODULE_ENABLED
+ #include "stm32f7xx_hal_eth.h"
+#endif /* HAL_ETH_MODULE_ENABLED */
+
+#ifdef HAL_FLASH_MODULE_ENABLED
+ #include "stm32f7xx_hal_flash.h"
+#endif /* HAL_FLASH_MODULE_ENABLED */
+
+#ifdef HAL_SRAM_MODULE_ENABLED
+ #include "stm32f7xx_hal_sram.h"
+#endif /* HAL_SRAM_MODULE_ENABLED */
+
+#ifdef HAL_NOR_MODULE_ENABLED
+ #include "stm32f7xx_hal_nor.h"
+#endif /* HAL_NOR_MODULE_ENABLED */
+
+#ifdef HAL_NAND_MODULE_ENABLED
+ #include "stm32f7xx_hal_nand.h"
+#endif /* HAL_NAND_MODULE_ENABLED */
+
+#ifdef HAL_SDRAM_MODULE_ENABLED
+ #include "stm32f7xx_hal_sdram.h"
+#endif /* HAL_SDRAM_MODULE_ENABLED */
+
+#ifdef HAL_HASH_MODULE_ENABLED
+ #include "stm32f7xx_hal_hash.h"
+#endif /* HAL_HASH_MODULE_ENABLED */
+
+#ifdef HAL_I2C_MODULE_ENABLED
+ #include "stm32f7xx_hal_i2c.h"
+#endif /* HAL_I2C_MODULE_ENABLED */
+
+#ifdef HAL_I2S_MODULE_ENABLED
+ #include "stm32f7xx_hal_i2s.h"
+#endif /* HAL_I2S_MODULE_ENABLED */
+
+#ifdef HAL_IWDG_MODULE_ENABLED
+ #include "stm32f7xx_hal_iwdg.h"
+#endif /* HAL_IWDG_MODULE_ENABLED */
+
+#ifdef HAL_LPTIM_MODULE_ENABLED
+ #include "stm32f7xx_hal_lptim.h"
+#endif /* HAL_LPTIM_MODULE_ENABLED */
+
+#ifdef HAL_LTDC_MODULE_ENABLED
+ #include "stm32f7xx_hal_ltdc.h"
+#endif /* HAL_LTDC_MODULE_ENABLED */
+
+#ifdef HAL_PWR_MODULE_ENABLED
+ #include "stm32f7xx_hal_pwr.h"
+#endif /* HAL_PWR_MODULE_ENABLED */
+
+#ifdef HAL_QSPI_MODULE_ENABLED
+ #include "stm32f7xx_hal_qspi.h"
+#endif /* HAL_QSPI_MODULE_ENABLED */
+
+#ifdef HAL_RNG_MODULE_ENABLED
+ #include "stm32f7xx_hal_rng.h"
+#endif /* HAL_RNG_MODULE_ENABLED */
+
+#ifdef HAL_RTC_MODULE_ENABLED
+ #include "stm32f7xx_hal_rtc.h"
+#endif /* HAL_RTC_MODULE_ENABLED */
+
+#ifdef HAL_SAI_MODULE_ENABLED
+ #include "stm32f7xx_hal_sai.h"
+#endif /* HAL_SAI_MODULE_ENABLED */
+
+#ifdef HAL_SD_MODULE_ENABLED
+ #include "stm32f7xx_hal_sd.h"
+#endif /* HAL_SD_MODULE_ENABLED */
+
+#ifdef HAL_SPDIFRX_MODULE_ENABLED
+ #include "stm32f7xx_hal_spdifrx.h"
+#endif /* HAL_SPDIFRX_MODULE_ENABLED */
+
+#ifdef HAL_SPI_MODULE_ENABLED
+ #include "stm32f7xx_hal_spi.h"
+#endif /* HAL_SPI_MODULE_ENABLED */
+
+#ifdef HAL_TIM_MODULE_ENABLED
+ #include "stm32f7xx_hal_tim.h"
+#endif /* HAL_TIM_MODULE_ENABLED */
+
+#ifdef HAL_UART_MODULE_ENABLED
+ #include "stm32f7xx_hal_uart.h"
+#endif /* HAL_UART_MODULE_ENABLED */
+
+#ifdef HAL_USART_MODULE_ENABLED
+ #include "stm32f7xx_hal_usart.h"
+#endif /* HAL_USART_MODULE_ENABLED */
+
+#ifdef HAL_IRDA_MODULE_ENABLED
+ #include "stm32f7xx_hal_irda.h"
+#endif /* HAL_IRDA_MODULE_ENABLED */
+
+#ifdef HAL_SMARTCARD_MODULE_ENABLED
+ #include "stm32f7xx_hal_smartcard.h"
+#endif /* HAL_SMARTCARD_MODULE_ENABLED */
+
+#ifdef HAL_WWDG_MODULE_ENABLED
+ #include "stm32f7xx_hal_wwdg.h"
+#endif /* HAL_WWDG_MODULE_ENABLED */
+
+#ifdef HAL_PCD_MODULE_ENABLED
+ #include "stm32f7xx_hal_pcd.h"
+#endif /* HAL_PCD_MODULE_ENABLED */
+
+#ifdef HAL_HCD_MODULE_ENABLED
+ #include "stm32f7xx_hal_hcd.h"
+#endif /* HAL_HCD_MODULE_ENABLED */
+
+/* Exported macro ------------------------------------------------------------*/
+#ifdef USE_FULL_ASSERT
+/**
+ * @brief The assert_param macro is used for function's parameters check.
+ * @param expr: If expr is false, it calls assert_failed function
+ * which reports the name of the source file and the source
+ * line number of the call that failed.
+ * If expr is true, it returns no value.
+ * @retval None
+ */
+ #define assert_param(expr) ((expr) ? (void)0 : assert_failed((uint8_t *)__FILE__, __LINE__))
+/* Exported functions ------------------------------------------------------- */
+ void assert_failed(uint8_t* file, uint32_t line);
+#else
+ #define assert_param(expr) ((void)0)
+#endif /* USE_FULL_ASSERT */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __STM32F7xx_HAL_CONF_H */
+
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/ports/stm32/boards/NUCLEO_F767ZI/board_init.c b/ports/stm32/boards/NUCLEO_F767ZI/board_init.c
new file mode 100644
index 000000000..7d25a445d
--- /dev/null
+++ b/ports/stm32/boards/NUCLEO_F767ZI/board_init.c
@@ -0,0 +1,8 @@
+#include "py/mphal.h"
+
+void NUCLEO_F767ZI_board_early_init(void) {
+ // Turn off the USB switch
+ #define USB_PowerSwitchOn pin_G6
+ mp_hal_pin_output(USB_PowerSwitchOn);
+ mp_hal_pin_low(USB_PowerSwitchOn);
+}
diff --git a/ports/stm32/boards/NUCLEO_F767ZI/mpconfigboard.h b/ports/stm32/boards/NUCLEO_F767ZI/mpconfigboard.h
index 8952bce82..3f23d77d4 100644
--- a/ports/stm32/boards/NUCLEO_F767ZI/mpconfigboard.h
+++ b/ports/stm32/boards/NUCLEO_F767ZI/mpconfigboard.h
@@ -8,16 +8,13 @@
#define MICROPY_HW_HAS_SWITCH (1)
#define MICROPY_HW_HAS_FLASH (1)
-#define MICROPY_HW_HAS_SDCARD (0)
-#define MICROPY_HW_HAS_MMA7660 (0)
-#define MICROPY_HW_HAS_LIS3DSH (0)
-#define MICROPY_HW_HAS_LCD (0)
#define MICROPY_HW_ENABLE_RNG (1)
#define MICROPY_HW_ENABLE_RTC (1)
-#define MICROPY_HW_ENABLE_TIMER (1)
-#define MICROPY_HW_ENABLE_SERVO (0)
#define MICROPY_HW_ENABLE_DAC (1)
-#define MICROPY_HW_ENABLE_CAN (1)
+#define MICROPY_HW_ENABLE_USB (1)
+
+#define MICROPY_BOARD_EARLY_INIT NUCLEO_F767ZI_board_early_init
+void NUCLEO_F767ZI_board_early_init(void);
// HSE is 25MHz
// VCOClock = HSE * PLLN / PLLM = 25 MHz * 432 / 25 = 432 MHz
@@ -58,6 +55,12 @@
#define MICROPY_HW_SPI3_MISO (pin_B4)
#define MICROPY_HW_SPI3_MOSI (pin_B5)
+// CAN busses
+#define MICROPY_HW_CAN1_TX (pin_B9)
+#define MICROPY_HW_CAN1_RX (pin_B8)
+#define MICROPY_HW_CAN2_TX (pin_B13)
+#define MICROPY_HW_CAN2_RX (pin_B12)
+
// USRSW is pulled low. Pressing the button makes the input go high.
#define MICROPY_HW_USRSW_PIN (pin_C13)
#define MICROPY_HW_USRSW_PULL (GPIO_NOPULL)
@@ -72,5 +75,6 @@
#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin))
// USB config (CN13 - USB OTG FS)
+#define MICROPY_HW_USB_FS (1)
#define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_A9)
#define MICROPY_HW_USB_OTG_ID_PIN (pin_A10)
diff --git a/ports/stm32/boards/NUCLEO_F767ZI/mpconfigboard.mk b/ports/stm32/boards/NUCLEO_F767ZI/mpconfigboard.mk
index ba28a16e1..b79ee7da2 100644
--- a/ports/stm32/boards/NUCLEO_F767ZI/mpconfigboard.mk
+++ b/ports/stm32/boards/NUCLEO_F767ZI/mpconfigboard.mk
@@ -2,4 +2,6 @@ MCU_SERIES = f7
CMSIS_MCU = STM32F767xx
MICROPY_FLOAT_IMPL = double
AF_FILE = boards/stm32f767_af.csv
-LD_FILE = boards/stm32f767.ld
+LD_FILES = boards/stm32f767.ld boards/common_ifs.ld
+TEXT0_ADDR = 0x08000000
+TEXT1_ADDR = 0x08020000
diff --git a/ports/stm32/boards/NUCLEO_F767ZI/pins.csv b/ports/stm32/boards/NUCLEO_F767ZI/pins.csv
index 897b1473e..3cae615da 100644
--- a/ports/stm32/boards/NUCLEO_F767ZI/pins.csv
+++ b/ports/stm32/boards/NUCLEO_F767ZI/pins.csv
@@ -4,6 +4,9 @@ A2,PC3
A3,PF3
A4,PF5
A5,PF10
+A6,PB1
+A7,PC2
+A8,PF4
D0,PG9
D1,PG14
D2,PF15
@@ -51,10 +54,11 @@ LCD_SCL,PH7
OTG_FS_POWER,PD5
OTG_FS_OVER_CURRENT,PD4
OTG_HS_OVER_CURRENT,PE3
-USB_VBUS,PJ12
+USB_VBUS,PA9
USB_ID,PA10
USB_DM,PA11
USB_DP,PA12
+USB_POWER,PG6
VCP_TX,PD8
VCP_RX,PD9
UART2_TX,PD5
diff --git a/ports/stm32/boards/NUCLEO_F767ZI/stm32f7xx_hal_conf.h b/ports/stm32/boards/NUCLEO_F767ZI/stm32f7xx_hal_conf.h
index e1aa4578d..a019ee4ce 100644
--- a/ports/stm32/boards/NUCLEO_F767ZI/stm32f7xx_hal_conf.h
+++ b/ports/stm32/boards/NUCLEO_F767ZI/stm32f7xx_hal_conf.h
@@ -46,8 +46,6 @@
/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
-#define USE_USB_FS
-
/* ########################## Module Selection ############################## */
/**
* @brief This is the list of modules to be used in the HAL driver
diff --git a/ports/stm32/boards/NUCLEO_H743ZI/board_init.c b/ports/stm32/boards/NUCLEO_H743ZI/board_init.c
new file mode 100644
index 000000000..04149c37b
--- /dev/null
+++ b/ports/stm32/boards/NUCLEO_H743ZI/board_init.c
@@ -0,0 +1,8 @@
+#include "py/mphal.h"
+
+void NUCLEO_H743ZI_board_early_init(void) {
+ // Turn off the USB switch
+ #define USB_PowerSwitchOn pin_G6
+ mp_hal_pin_output(USB_PowerSwitchOn);
+ mp_hal_pin_low(USB_PowerSwitchOn);
+}
diff --git a/ports/stm32/boards/NUCLEO_H743ZI/mpconfigboard.h b/ports/stm32/boards/NUCLEO_H743ZI/mpconfigboard.h
new file mode 100644
index 000000000..117e7f3f6
--- /dev/null
+++ b/ports/stm32/boards/NUCLEO_H743ZI/mpconfigboard.h
@@ -0,0 +1,65 @@
+#define MICROPY_HW_BOARD_NAME "NUCLEO_H743ZI"
+#define MICROPY_HW_MCU_NAME "STM32H743"
+
+#define MICROPY_HW_ENABLE_RTC (1)
+#define MICROPY_HW_ENABLE_RNG (1)
+#define MICROPY_HW_ENABLE_ADC (1)
+#define MICROPY_HW_ENABLE_DAC (1)
+#define MICROPY_HW_ENABLE_USB (1)
+#define MICROPY_HW_HAS_SWITCH (1)
+#define MICROPY_HW_HAS_FLASH (1)
+#define MICROPY_HW_HAS_SDCARD (1)
+
+#define MICROPY_BOARD_EARLY_INIT NUCLEO_H743ZI_board_early_init
+void NUCLEO_H743ZI_board_early_init(void);
+
+// The board has an 8MHz HSE, the following gives 400MHz CPU speed
+#define MICROPY_HW_CLK_PLLM (4)
+#define MICROPY_HW_CLK_PLLN (400)
+#define MICROPY_HW_CLK_PLLP (2)
+#define MICROPY_HW_CLK_PLLQ (4)
+#define MICROPY_HW_CLK_PLLR (2)
+
+// 4 wait states
+#define MICROPY_HW_FLASH_LATENCY FLASH_LATENCY_4
+
+// UART config
+#define MICROPY_HW_UART3_TX (pin_D8)
+#define MICROPY_HW_UART3_RX (pin_D9)
+#define MICROPY_HW_UART_REPL PYB_UART_3
+#define MICROPY_HW_UART_REPL_BAUD 115200
+
+// I2C busses
+#define MICROPY_HW_I2C1_SCL (pin_B8)
+#define MICROPY_HW_I2C1_SDA (pin_B9)
+#define MICROPY_HW_I2C2_SCL (pin_F1)
+#define MICROPY_HW_I2C2_SDA (pin_F0)
+
+// SPI
+//#define MICROPY_HW_SPI2_NSS (pin_I0)
+//#define MICROPY_HW_SPI2_SCK (pin_I1)
+//#define MICROPY_HW_SPI2_MISO (pin_B14)
+//#define MICROPY_HW_SPI2_MOSI (pin_B15)
+
+// USRSW is pulled low. Pressing the button makes the input go high.
+#define MICROPY_HW_USRSW_PIN (pin_C13)
+#define MICROPY_HW_USRSW_PULL (GPIO_NOPULL)
+#define MICROPY_HW_USRSW_EXTI_MODE (GPIO_MODE_IT_RISING)
+#define MICROPY_HW_USRSW_PRESSED (1)
+
+// LEDs
+#define MICROPY_HW_LED1 (pin_B0) // green
+#define MICROPY_HW_LED2 (pin_B7) // blue
+#define MICROPY_HW_LED3 (pin_B14) // red
+#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_high(pin))
+#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin))
+
+// USB config
+#define MICROPY_HW_USB_FS (1)
+#define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_A9)
+#define MICROPY_HW_USB_OTG_ID_PIN (pin_A10)
+
+// SD card detect switch
+#define MICROPY_HW_SDCARD_DETECT_PIN (pin_G2)
+#define MICROPY_HW_SDCARD_DETECT_PULL (GPIO_PULLUP)
+#define MICROPY_HW_SDCARD_DETECT_PRESENT (GPIO_PIN_RESET)
diff --git a/ports/stm32/boards/NUCLEO_H743ZI/mpconfigboard.mk b/ports/stm32/boards/NUCLEO_H743ZI/mpconfigboard.mk
new file mode 100644
index 000000000..4d3455441
--- /dev/null
+++ b/ports/stm32/boards/NUCLEO_H743ZI/mpconfigboard.mk
@@ -0,0 +1,7 @@
+MCU_SERIES = h7
+CMSIS_MCU = STM32H743xx
+MICROPY_FLOAT_IMPL = double
+AF_FILE = boards/stm32h743_af.csv
+LD_FILES = boards/stm32h743.ld boards/common_ifs.ld
+TEXT0_ADDR = 0x08000000
+TEXT1_ADDR = 0x08040000
diff --git a/ports/stm32/boards/NUCLEO_H743ZI/pins.csv b/ports/stm32/boards/NUCLEO_H743ZI/pins.csv
new file mode 100644
index 000000000..30910c4dd
--- /dev/null
+++ b/ports/stm32/boards/NUCLEO_H743ZI/pins.csv
@@ -0,0 +1,63 @@
+A0,PA0
+A1,PF10
+A2,PF9
+A3,PF8
+A4,PF7
+A5,PF6
+D0,PC7
+D1,PC6
+D2,PG6
+D3,PB4
+D4,PG7
+D5,PA8
+D6,PH6
+D7,PI3
+D8,PI2
+D9,PA15
+D10,PI0
+D11,PB15
+D12,PB14
+D13,PI1
+D14,PB9
+D15,PB8
+DAC1,PA4
+DAC2,PA5
+LED1,PB0
+LED2,PB7
+LED3,PB14
+SW,PC13
+TP1,PH2
+TP2,PI8
+TP3,PH15
+AUDIO_INT,PD6
+AUDIO_SDA,PH8
+AUDIO_SCL,PH7
+I2C1_SDA,PB9
+I2C1_SCL,PB8
+I2C2_SDA,PF0
+I2C2_SCL,PF1
+EXT_RST,PG3
+SD_D0,PC8
+SD_D1,PC9
+SD_D2,PC10
+SD_D3,PC11
+SD_CMD,PD2
+SD_CK,PC12
+SD_SW,PG2
+LCD_BL_CTRL,PK3
+LCD_INT,PI13
+LCD_SDA,PH8
+LCD_SCL,PH7
+OTG_FS_POWER,PD5
+OTG_FS_OVER_CURRENT,PD4
+OTG_HS_OVER_CURRENT,PE3
+USB_VBUS,PJ12
+USB_ID,PA8
+USB_DM,PA11
+USB_DP,PA12
+UART1_TX,PA9
+UART1_RX,PA10
+UART5_TX,PC12
+UART5_RX,PD2
+UART3_TX,PD8
+UART3_RX,PD9
diff --git a/ports/stm32/boards/NUCLEO_H743ZI/stm32h7xx_hal_conf.h b/ports/stm32/boards/NUCLEO_H743ZI/stm32h7xx_hal_conf.h
new file mode 100644
index 000000000..97b141d49
--- /dev/null
+++ b/ports/stm32/boards/NUCLEO_H743ZI/stm32h7xx_hal_conf.h
@@ -0,0 +1,434 @@
+/**
+ ******************************************************************************
+ * @file stm32h7xx_hal_conf_template.h
+ * @author MCD Application Team
+ * @version V1.2.0
+ * @date 29-December-2017
+ * @brief HAL configuration template file.
+ * This file should be copied to the application folder and renamed
+ * to stm32h7xx_hal_conf.h.
+ ******************************************************************************
+ * @attention
+ *
+ * <h2><center>&copy; COPYRIGHT(c) 2017 STMicroelectronics</center></h2>
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of STMicroelectronics nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ******************************************************************************
+ */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __STM32H7xx_HAL_CONF_H
+#define __STM32H7xx_HAL_CONF_H
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/* Exported types ------------------------------------------------------------*/
+/* Exported constants --------------------------------------------------------*/
+
+/* ########################## Module Selection ############################## */
+/**
+ * @brief This is the list of modules to be used in the HAL driver
+ */
+#define HAL_MODULE_ENABLED
+#define HAL_ADC_MODULE_ENABLED
+#define HAL_CEC_MODULE_ENABLED
+#define HAL_COMP_MODULE_ENABLED
+#define HAL_CORTEX_MODULE_ENABLED
+#define HAL_CRC_MODULE_ENABLED
+#define HAL_CRYP_MODULE_ENABLED
+#define HAL_DAC_MODULE_ENABLED
+#define HAL_DCMI_MODULE_ENABLED
+#define HAL_DFSDM_MODULE_ENABLED
+#define HAL_DMA_MODULE_ENABLED
+#define HAL_DMA2D_MODULE_ENABLED
+#define HAL_ETH_MODULE_ENABLED
+#define HAL_FDCAN_MODULE_ENABLED
+#define HAL_FLASH_MODULE_ENABLED
+#define HAL_GPIO_MODULE_ENABLED
+#define HAL_HASH_MODULE_ENABLED
+#define HAL_HCD_MODULE_ENABLED
+#define HAL_HRTIM_MODULE_ENABLED
+#define HAL_HSEM_MODULE_ENABLED
+#define HAL_I2C_MODULE_ENABLED
+#define HAL_I2S_MODULE_ENABLED
+#define HAL_IRDA_MODULE_ENABLED
+#define HAL_IWDG_MODULE_ENABLED
+#define HAL_JPEG_MODULE_ENABLED
+#define HAL_LPTIM_MODULE_ENABLED
+#define HAL_LTDC_MODULE_ENABLED
+#define HAL_MDIOS_MODULE_ENABLED
+#define HAL_MDMA_MODULE_ENABLED
+#define HAL_MMC_MODULE_ENABLED
+#define HAL_NAND_MODULE_ENABLED
+#define HAL_NOR_MODULE_ENABLED
+#define HAL_OPAMP_MODULE_ENABLED
+#define HAL_PCD_MODULE_ENABLED
+#define HAL_PWR_MODULE_ENABLED
+#define HAL_QSPI_MODULE_ENABLED
+#define HAL_RCC_MODULE_ENABLED
+#define HAL_RNG_MODULE_ENABLED
+#define HAL_RTC_MODULE_ENABLED
+#define HAL_SAI_MODULE_ENABLED
+#define HAL_SD_MODULE_ENABLED
+#define HAL_SDRAM_MODULE_ENABLED
+#define HAL_SMARTCARD_MODULE_ENABLED
+#define HAL_SMBUS_MODULE_ENABLED
+#define HAL_SPDIFRX_MODULE_ENABLED
+#define HAL_SPI_MODULE_ENABLED
+#define HAL_SRAM_MODULE_ENABLED
+#define HAL_SWPMI_MODULE_ENABLED
+#define HAL_TIM_MODULE_ENABLED
+#define HAL_UART_MODULE_ENABLED
+#define HAL_USART_MODULE_ENABLED
+#define HAL_WWDG_MODULE_ENABLED
+
+/* ########################## Oscillator Values adaptation ####################*/
+/**
+ * @brief Adjust the value of External High Speed oscillator (HSE) used in your application.
+ * This value is used by the RCC HAL module to compute the system frequency
+ * (when HSE is used as system clock source, directly or through the PLL).
+ */
+#if !defined (HSE_VALUE)
+#define HSE_VALUE ((uint32_t)8000000) /*!< Value of the External oscillator in Hz */
+#endif /* HSE_VALUE */
+
+#if !defined (HSE_STARTUP_TIMEOUT)
+ #define HSE_STARTUP_TIMEOUT ((uint32_t)5000) /*!< Time out for HSE start up, in ms */
+#endif /* HSE_STARTUP_TIMEOUT */
+
+/**
+ * @brief Internal oscillator (CSI) default value.
+ * This value is the default CSI value after Reset.
+ */
+#if !defined (CSI_VALUE)
+ #define CSI_VALUE ((uint32_t)4000000) /*!< Value of the Internal oscillator in Hz*/
+#endif /* CSI_VALUE */
+
+/**
+ * @brief Internal High Speed oscillator (HSI) value.
+ * This value is used by the RCC HAL module to compute the system frequency
+ * (when HSI is used as system clock source, directly or through the PLL).
+ */
+#if !defined (HSI_VALUE)
+ #define HSI_VALUE ((uint32_t)64000000) /*!< Value of the Internal oscillator in Hz*/
+#endif /* HSI_VALUE */
+
+/**
+ * @brief External Low Speed oscillator (LSE) value.
+ * This value is used by the UART, RTC HAL module to compute the system frequency
+ */
+#if !defined (LSE_VALUE)
+ #define LSE_VALUE ((uint32_t)32768) /*!< Value of the External oscillator in Hz*/
+#endif /* LSE_VALUE */
+
+
+#if !defined (LSE_STARTUP_TIMEOUT)
+ #define LSE_STARTUP_TIMEOUT ((uint32_t)5000) /*!< Time out for LSE start up, in ms */
+#endif /* LSE_STARTUP_TIMEOUT */
+
+/**
+ * @brief External clock source for I2S peripheral
+ * This value is used by the I2S HAL module to compute the I2S clock source
+ * frequency, this source is inserted directly through I2S_CKIN pad.
+ */
+#if !defined (EXTERNAL_CLOCK_VALUE)
+ #define EXTERNAL_CLOCK_VALUE 12288000U /*!< Value of the External clock in Hz*/
+#endif /* EXTERNAL_CLOCK_VALUE */
+
+/* Tip: To avoid modifying this file each time you need to use different HSE,
+ === you can define the HSE value in your toolchain compiler preprocessor. */
+
+/* ########################### System Configuration ######################### */
+/**
+ * @brief This is the HAL system configuration section
+ */
+#define VDD_VALUE ((uint32_t)3300) /*!< Value of VDD in mv */
+#define TICK_INT_PRIORITY ((uint32_t)0x00) /*!< tick interrupt priority */
+#define USE_RTOS 0
+#define USE_SD_TRANSCEIVER 0U /*!< use uSD Transceiver */
+
+/* ########################### Ethernet Configuration ######################### */
+#define ETH_TX_DESC_CNT 4 /* number of Ethernet Tx DMA descriptors */
+#define ETH_RX_DESC_CNT 4 /* number of Ethernet Rx DMA descriptors */
+
+#define ETH_MAC_ADDR0 ((uint8_t)0x02)
+#define ETH_MAC_ADDR1 ((uint8_t)0x00)
+#define ETH_MAC_ADDR2 ((uint8_t)0x00)
+#define ETH_MAC_ADDR3 ((uint8_t)0x00)
+#define ETH_MAC_ADDR4 ((uint8_t)0x00)
+#define ETH_MAC_ADDR5 ((uint8_t)0x00)
+
+/* ########################## Assert Selection ############################## */
+/**
+ * @brief Uncomment the line below to expanse the "assert_param" macro in the
+ * HAL drivers code
+ */
+/* #define USE_FULL_ASSERT 1 */
+
+/* ################## SPI peripheral configuration ########################## */
+/**
+ * @brief Used to activate CRC feature inside HAL SPI Driver
+ * Activated (1U): CRC code is compiled within HAL SPI driver
+ * Deactivated (0U): CRC code excluded from HAL SPI driver
+ */
+
+#define USE_SPI_CRC 1U
+
+
+/* Includes ------------------------------------------------------------------*/
+/**
+ * @brief Include module's header file
+ */
+
+#ifdef HAL_RCC_MODULE_ENABLED
+ #include "stm32h7xx_hal_rcc.h"
+#endif /* HAL_RCC_MODULE_ENABLED */
+
+#ifdef HAL_GPIO_MODULE_ENABLED
+ #include "stm32h7xx_hal_gpio.h"
+#endif /* HAL_GPIO_MODULE_ENABLED */
+
+#ifdef HAL_DMA_MODULE_ENABLED
+ #include "stm32h7xx_hal_dma.h"
+#endif /* HAL_DMA_MODULE_ENABLED */
+
+#ifdef HAL_HASH_MODULE_ENABLED
+ #include "stm32h7xx_hal_hash.h"
+#endif /* HAL_HASH_MODULE_ENABLED */
+
+#ifdef HAL_DCMI_MODULE_ENABLED
+ #include "stm32h7xx_hal_dcmi.h"
+#endif /* HAL_DCMI_MODULE_ENABLED */
+
+#ifdef HAL_DMA2D_MODULE_ENABLED
+ #include "stm32h7xx_hal_dma2d.h"
+#endif /* HAL_DMA2D_MODULE_ENABLED */
+
+#ifdef HAL_DFSDM_MODULE_ENABLED
+ #include "stm32h7xx_hal_dfsdm.h"
+#endif /* HAL_DFSDM_MODULE_ENABLED */
+
+#ifdef HAL_ETH_MODULE_ENABLED
+ #include "stm32h7xx_hal_eth.h"
+#endif /* HAL_ETH_MODULE_ENABLED */
+
+#ifdef HAL_CORTEX_MODULE_ENABLED
+ #include "stm32h7xx_hal_cortex.h"
+#endif /* HAL_CORTEX_MODULE_ENABLED */
+
+#ifdef HAL_ADC_MODULE_ENABLED
+ #include "stm32h7xx_hal_adc.h"
+#endif /* HAL_ADC_MODULE_ENABLED */
+
+#ifdef HAL_FDCAN_MODULE_ENABLED
+ #include "stm32h7xx_hal_fdcan.h"
+#endif /* HAL_FDCAN_MODULE_ENABLED */
+
+#ifdef HAL_CEC_MODULE_ENABLED
+ #include "stm32h7xx_hal_cec.h"
+#endif /* HAL_CEC_MODULE_ENABLED */
+
+#ifdef HAL_COMP_MODULE_ENABLED
+ #include "stm32h7xx_hal_comp.h"
+#endif /* HAL_COMP_MODULE_ENABLED */
+
+#ifdef HAL_CRC_MODULE_ENABLED
+ #include "stm32h7xx_hal_crc.h"
+#endif /* HAL_CRC_MODULE_ENABLED */
+
+#ifdef HAL_CRYP_MODULE_ENABLED
+ #include "stm32h7xx_hal_cryp.h"
+#endif /* HAL_CRYP_MODULE_ENABLED */
+
+#ifdef HAL_DAC_MODULE_ENABLED
+ #include "stm32h7xx_hal_dac.h"
+#endif /* HAL_DAC_MODULE_ENABLED */
+
+#ifdef HAL_FLASH_MODULE_ENABLED
+ #include "stm32h7xx_hal_flash.h"
+#endif /* HAL_FLASH_MODULE_ENABLED */
+
+#ifdef HAL_HRTIM_MODULE_ENABLED
+ #include "stm32h7xx_hal_hrtim.h"
+#endif /* HAL_HRTIM_MODULE_ENABLED */
+
+#ifdef HAL_HSEM_MODULE_ENABLED
+ #include "stm32h7xx_hal_hsem.h"
+#endif /* HAL_HSEM_MODULE_ENABLED */
+
+#ifdef HAL_SRAM_MODULE_ENABLED
+ #include "stm32h7xx_hal_sram.h"
+#endif /* HAL_SRAM_MODULE_ENABLED */
+
+#ifdef HAL_NOR_MODULE_ENABLED
+ #include "stm32h7xx_hal_nor.h"
+#endif /* HAL_NOR_MODULE_ENABLED */
+
+#ifdef HAL_NAND_MODULE_ENABLED
+ #include "stm32h7xx_hal_nand.h"
+#endif /* HAL_NAND_MODULE_ENABLED */
+
+#ifdef HAL_I2C_MODULE_ENABLED
+ #include "stm32h7xx_hal_i2c.h"
+#endif /* HAL_I2C_MODULE_ENABLED */
+
+#ifdef HAL_I2S_MODULE_ENABLED
+ #include "stm32h7xx_hal_i2s.h"
+#endif /* HAL_I2S_MODULE_ENABLED */
+
+#ifdef HAL_IWDG_MODULE_ENABLED
+ #include "stm32h7xx_hal_iwdg.h"
+#endif /* HAL_IWDG_MODULE_ENABLED */
+
+#ifdef HAL_JPEG_MODULE_ENABLED
+ #include "stm32h7xx_hal_jpeg.h"
+#endif /* HAL_JPEG_MODULE_ENABLED */
+
+#ifdef HAL_MDIOS_MODULE_ENABLED
+ #include "stm32h7xx_hal_mdios.h"
+#endif /* HAL_MDIOS_MODULE_ENABLED */
+
+#ifdef HAL_MDMA_MODULE_ENABLED
+ #include "stm32h7xx_hal_mdma.h"
+#endif /* HAL_MDMA_MODULE_ENABLED */
+
+#ifdef HAL_MMC_MODULE_ENABLED
+ #include "stm32h7xx_hal_mmc.h"
+#endif /* HAL_MMC_MODULE_ENABLED */
+
+#ifdef HAL_LPTIM_MODULE_ENABLED
+#include "stm32h7xx_hal_lptim.h"
+#endif /* HAL_LPTIM_MODULE_ENABLED */
+
+#ifdef HAL_LTDC_MODULE_ENABLED
+#include "stm32h7xx_hal_ltdc.h"
+#endif /* HAL_LTDC_MODULE_ENABLED */
+
+#ifdef HAL_OPAMP_MODULE_ENABLED
+#include "stm32h7xx_hal_opamp.h"
+#endif /* HAL_OPAMP_MODULE_ENABLED */
+
+#ifdef HAL_PWR_MODULE_ENABLED
+ #include "stm32h7xx_hal_pwr.h"
+#endif /* HAL_PWR_MODULE_ENABLED */
+
+#ifdef HAL_QSPI_MODULE_ENABLED
+ #include "stm32h7xx_hal_qspi.h"
+#endif /* HAL_QSPI_MODULE_ENABLED */
+
+#ifdef HAL_RNG_MODULE_ENABLED
+ #include "stm32h7xx_hal_rng.h"
+#endif /* HAL_RNG_MODULE_ENABLED */
+
+#ifdef HAL_RTC_MODULE_ENABLED
+ #include "stm32h7xx_hal_rtc.h"
+#endif /* HAL_RTC_MODULE_ENABLED */
+
+#ifdef HAL_SAI_MODULE_ENABLED
+ #include "stm32h7xx_hal_sai.h"
+#endif /* HAL_SAI_MODULE_ENABLED */
+
+#ifdef HAL_SD_MODULE_ENABLED
+ #include "stm32h7xx_hal_sd.h"
+#endif /* HAL_SD_MODULE_ENABLED */
+
+#ifdef HAL_SDRAM_MODULE_ENABLED
+ #include "stm32h7xx_hal_sdram.h"
+#endif /* HAL_SDRAM_MODULE_ENABLED */
+
+#ifdef HAL_SPI_MODULE_ENABLED
+ #include "stm32h7xx_hal_spi.h"
+#endif /* HAL_SPI_MODULE_ENABLED */
+
+#ifdef HAL_SPDIFRX_MODULE_ENABLED
+ #include "stm32h7xx_hal_spdifrx.h"
+#endif /* HAL_SPDIFRX_MODULE_ENABLED */
+
+#ifdef HAL_SWPMI_MODULE_ENABLED
+ #include "stm32h7xx_hal_swpmi.h"
+#endif /* HAL_SWPMI_MODULE_ENABLED */
+
+#ifdef HAL_TIM_MODULE_ENABLED
+ #include "stm32h7xx_hal_tim.h"
+#endif /* HAL_TIM_MODULE_ENABLED */
+
+#ifdef HAL_UART_MODULE_ENABLED
+ #include "stm32h7xx_hal_uart.h"
+#endif /* HAL_UART_MODULE_ENABLED */
+
+#ifdef HAL_USART_MODULE_ENABLED
+ #include "stm32h7xx_hal_usart.h"
+#endif /* HAL_USART_MODULE_ENABLED */
+
+#ifdef HAL_IRDA_MODULE_ENABLED
+ #include "stm32h7xx_hal_irda.h"
+#endif /* HAL_IRDA_MODULE_ENABLED */
+
+#ifdef HAL_SMARTCARD_MODULE_ENABLED
+ #include "stm32h7xx_hal_smartcard.h"
+#endif /* HAL_SMARTCARD_MODULE_ENABLED */
+
+#ifdef HAL_SMBUS_MODULE_ENABLED
+ #include "stm32h7xx_hal_smbus.h"
+#endif /* HAL_SMBUS_MODULE_ENABLED */
+
+#ifdef HAL_WWDG_MODULE_ENABLED
+ #include "stm32h7xx_hal_wwdg.h"
+#endif /* HAL_WWDG_MODULE_ENABLED */
+
+#ifdef HAL_PCD_MODULE_ENABLED
+ #include "stm32h7xx_hal_pcd.h"
+#endif /* HAL_PCD_MODULE_ENABLED */
+
+#ifdef HAL_HCD_MODULE_ENABLED
+ #include "stm32h7xx_hal_hcd.h"
+#endif /* HAL_HCD_MODULE_ENABLED */
+
+/* Exported macro ------------------------------------------------------------*/
+#ifdef USE_FULL_ASSERT
+/**
+ * @brief The assert_param macro is used for function's parameters check.
+ * @param expr: If expr is false, it calls assert_failed function
+ * which reports the name of the source file and the source
+ * line number of the call that failed.
+ * If expr is true, it returns no value.
+ * @retval None
+ */
+ #define assert_param(expr) ((expr) ? (void)0 : assert_failed((uint8_t *)__FILE__, __LINE__))
+/* Exported functions ------------------------------------------------------- */
+ void assert_failed(uint8_t* file, uint32_t line);
+#else
+ #define assert_param(expr) ((void)0)
+#endif /* USE_FULL_ASSERT */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __STM32H7xx_HAL_CONF_H */
+
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/ports/stm32/boards/NUCLEO_L476RG/mpconfigboard.h b/ports/stm32/boards/NUCLEO_L476RG/mpconfigboard.h
index f2474619f..0d5dab394 100644
--- a/ports/stm32/boards/NUCLEO_L476RG/mpconfigboard.h
+++ b/ports/stm32/boards/NUCLEO_L476RG/mpconfigboard.h
@@ -3,9 +3,8 @@
#define MICROPY_HW_HAS_SWITCH (1)
#define MICROPY_HW_HAS_FLASH (1)
-#define MICROPY_HW_HAS_SDCARD (0)
-#define MICROPY_HW_HAS_LCD (0)
#define MICROPY_HW_ENABLE_RTC (1)
+#define MICROPY_HW_ENABLE_USB (1)
// MSI is used and is 4MHz
#define MICROPY_HW_CLK_PLLM (1)
@@ -51,3 +50,6 @@
#define MICROPY_HW_LED1 (pin_A5) // Green LD2 LED on Nucleo
#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_high(pin))
#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin))
+
+// USB config
+#define MICROPY_HW_USB_FS (1)
diff --git a/ports/stm32/boards/NUCLEO_L476RG/mpconfigboard.mk b/ports/stm32/boards/NUCLEO_L476RG/mpconfigboard.mk
index abb4a3570..38ae5af21 100644
--- a/ports/stm32/boards/NUCLEO_L476RG/mpconfigboard.mk
+++ b/ports/stm32/boards/NUCLEO_L476RG/mpconfigboard.mk
@@ -1,5 +1,6 @@
MCU_SERIES = l4
CMSIS_MCU = STM32L476xx
AF_FILE = boards/stm32l476_af.csv
-LD_FILE = boards/stm32l476xg.ld
-TEXT_ADDR = 0x08004000
+LD_FILES = boards/stm32l476xg.ld boards/common_ifs.ld
+TEXT0_ADDR = 0x08000000
+TEXT1_ADDR = 0x08004000
diff --git a/ports/stm32/boards/NUCLEO_L476RG/stm32l4xx_hal_conf.h b/ports/stm32/boards/NUCLEO_L476RG/stm32l4xx_hal_conf.h
index 9348e0679..6bfb28118 100755
--- a/ports/stm32/boards/NUCLEO_L476RG/stm32l4xx_hal_conf.h
+++ b/ports/stm32/boards/NUCLEO_L476RG/stm32l4xx_hal_conf.h
@@ -45,7 +45,6 @@
extern "C" {
#endif
-#define USE_USB_FS
/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
diff --git a/ports/stm32/boards/OLIMEX_E407/mpconfigboard.h b/ports/stm32/boards/OLIMEX_E407/mpconfigboard.h
index 5ede68264..a56f6f79d 100644
--- a/ports/stm32/boards/OLIMEX_E407/mpconfigboard.h
+++ b/ports/stm32/boards/OLIMEX_E407/mpconfigboard.h
@@ -1,20 +1,13 @@
-#define STM32E407
-
#define MICROPY_HW_BOARD_NAME "OLIMEX STM32-E407"
#define MICROPY_HW_MCU_NAME "STM32F407"
#define MICROPY_HW_HAS_SWITCH (1)
#define MICROPY_HW_HAS_FLASH (1)
#define MICROPY_HW_HAS_SDCARD (1)
-#define MICROPY_HW_HAS_MMA7660 (0)
-#define MICROPY_HW_HAS_LIS3DSH (0)
-#define MICROPY_HW_HAS_LCD (0)
#define MICROPY_HW_ENABLE_RNG (1)
#define MICROPY_HW_ENABLE_RTC (1)
-#define MICROPY_HW_ENABLE_TIMER (1)
-#define MICROPY_HW_ENABLE_SERVO (0)
#define MICROPY_HW_ENABLE_DAC (1)
-#define MICROPY_HW_ENABLE_CAN (1)
+#define MICROPY_HW_ENABLE_USB (1)
// HSE is 12MHz
#define MICROPY_HW_CLK_PLLM (12)
@@ -59,6 +52,12 @@
#define MICROPY_HW_SPI2_MISO (pin_B14)
#define MICROPY_HW_SPI2_MOSI (pin_B15)
+// CAN busses
+#define MICROPY_HW_CAN1_TX (pin_B9)
+#define MICROPY_HW_CAN1_RX (pin_B8)
+#define MICROPY_HW_CAN2_TX (pin_B13)
+#define MICROPY_HW_CAN2_RX (pin_B12)
+
// USRSW is pulled low. Pressing the button makes the input go high.
#define MICROPY_HW_USRSW_PIN (pin_A0)
#define MICROPY_HW_USRSW_PULL (GPIO_NOPULL)
@@ -76,5 +75,6 @@
#define MICROPY_HW_SDCARD_DETECT_PRESENT (GPIO_PIN_RESET)
// USB config
+#define MICROPY_HW_USB_FS (1)
#define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_A9)
#define MICROPY_HW_USB_OTG_ID_PIN (pin_A10)
diff --git a/ports/stm32/boards/OLIMEX_E407/mpconfigboard.mk b/ports/stm32/boards/OLIMEX_E407/mpconfigboard.mk
index ece09caa1..b154dcfba 100644
--- a/ports/stm32/boards/OLIMEX_E407/mpconfigboard.mk
+++ b/ports/stm32/boards/OLIMEX_E407/mpconfigboard.mk
@@ -1,4 +1,6 @@
MCU_SERIES = f4
CMSIS_MCU = STM32F407xx
AF_FILE = boards/stm32f405_af.csv
-LD_FILE = boards/stm32f405.ld
+LD_FILES = boards/stm32f405.ld boards/common_ifs.ld
+TEXT0_ADDR = 0x08000000
+TEXT1_ADDR = 0x08020000
diff --git a/ports/stm32/boards/OLIMEX_E407/pins.csv b/ports/stm32/boards/OLIMEX_E407/pins.csv
index 6b91f74ae..81a9bcb85 100644
--- a/ports/stm32/boards/OLIMEX_E407/pins.csv
+++ b/ports/stm32/boards/OLIMEX_E407/pins.csv
@@ -82,4 +82,5 @@ PD13,PD13
PD14,PD14
PD15,PD15
PA0,PA0
-
+USB_DM,PA11
+USB_DP,PA12
diff --git a/ports/stm32/boards/OLIMEX_E407/stm32f4xx_hal_conf.h b/ports/stm32/boards/OLIMEX_E407/stm32f4xx_hal_conf.h
index b84b0a892..24cc9228b 100644
--- a/ports/stm32/boards/OLIMEX_E407/stm32f4xx_hal_conf.h
+++ b/ports/stm32/boards/OLIMEX_E407/stm32f4xx_hal_conf.h
@@ -46,8 +46,6 @@
/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
-#define USE_USB_FS
-
/* ########################## Module Selection ############################## */
/**
* @brief This is the list of modules to be used in the HAL driver
diff --git a/ports/stm32/boards/PYBLITEV10/mpconfigboard.h b/ports/stm32/boards/PYBLITEV10/mpconfigboard.h
index 090ba4cf1..60a6980aa 100644
--- a/ports/stm32/boards/PYBLITEV10/mpconfigboard.h
+++ b/ports/stm32/boards/PYBLITEV10/mpconfigboard.h
@@ -5,14 +5,10 @@
#define MICROPY_HW_HAS_FLASH (1)
#define MICROPY_HW_HAS_SDCARD (1)
#define MICROPY_HW_HAS_MMA7660 (1)
-#define MICROPY_HW_HAS_LIS3DSH (0)
#define MICROPY_HW_HAS_LCD (1)
-#define MICROPY_HW_ENABLE_RNG (0)
#define MICROPY_HW_ENABLE_RTC (1)
-#define MICROPY_HW_ENABLE_TIMER (1)
+#define MICROPY_HW_ENABLE_USB (1)
#define MICROPY_HW_ENABLE_SERVO (1)
-#define MICROPY_HW_ENABLE_DAC (0)
-#define MICROPY_HW_ENABLE_CAN (0)
// HSE is 12MHz
#define MICROPY_HW_CLK_PLLM (12)
@@ -81,6 +77,7 @@
#define MICROPY_HW_SDCARD_DETECT_PRESENT (GPIO_PIN_RESET)
// USB config
+#define MICROPY_HW_USB_FS (1)
#define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_A9)
// MMA accelerometer config
diff --git a/ports/stm32/boards/PYBLITEV10/mpconfigboard.mk b/ports/stm32/boards/PYBLITEV10/mpconfigboard.mk
index 71b3b19d6..df9506522 100644
--- a/ports/stm32/boards/PYBLITEV10/mpconfigboard.mk
+++ b/ports/stm32/boards/PYBLITEV10/mpconfigboard.mk
@@ -1,4 +1,6 @@
MCU_SERIES = f4
CMSIS_MCU = STM32F411xE
AF_FILE = boards/stm32f411_af.csv
-LD_FILE = boards/stm32f411.ld
+LD_FILES = boards/stm32f411.ld boards/common_ifs.ld
+TEXT0_ADDR = 0x08000000
+TEXT1_ADDR = 0x08020000
diff --git a/ports/stm32/boards/PYBLITEV10/stm32f4xx_hal_conf.h b/ports/stm32/boards/PYBLITEV10/stm32f4xx_hal_conf.h
index 4ee8e7276..4e96f785a 100644
--- a/ports/stm32/boards/PYBLITEV10/stm32f4xx_hal_conf.h
+++ b/ports/stm32/boards/PYBLITEV10/stm32f4xx_hal_conf.h
@@ -46,8 +46,6 @@
/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
-#define USE_USB_FS
-
/* ########################## Module Selection ############################## */
/**
* @brief This is the list of modules to be used in the HAL driver
diff --git a/ports/stm32/boards/PYBV10/mpconfigboard.h b/ports/stm32/boards/PYBV10/mpconfigboard.h
index c06022a34..3439f5a0f 100644
--- a/ports/stm32/boards/PYBV10/mpconfigboard.h
+++ b/ports/stm32/boards/PYBV10/mpconfigboard.h
@@ -5,14 +5,12 @@
#define MICROPY_HW_HAS_FLASH (1)
#define MICROPY_HW_HAS_SDCARD (1)
#define MICROPY_HW_HAS_MMA7660 (1)
-#define MICROPY_HW_HAS_LIS3DSH (0)
#define MICROPY_HW_HAS_LCD (1)
#define MICROPY_HW_ENABLE_RNG (1)
#define MICROPY_HW_ENABLE_RTC (1)
-#define MICROPY_HW_ENABLE_TIMER (1)
#define MICROPY_HW_ENABLE_SERVO (1)
#define MICROPY_HW_ENABLE_DAC (1)
-#define MICROPY_HW_ENABLE_CAN (1)
+#define MICROPY_HW_ENABLE_USB (1)
// HSE is 8MHz
#define MICROPY_HW_CLK_PLLM (8)
@@ -67,8 +65,12 @@
#define MICROPY_HW_SPI2_MOSI (pin_B15) // Y8
// CAN busses
-#define MICROPY_HW_CAN1_NAME "YA" // CAN1 on RX,TX = Y3,Y4 = PB8,PB9
-#define MICROPY_HW_CAN2_NAME "YB" // CAN2 on RX,TX = Y5,Y6 = PB12,PB13
+#define MICROPY_HW_CAN1_NAME "YA"
+#define MICROPY_HW_CAN1_TX (pin_B9) // Y4
+#define MICROPY_HW_CAN1_RX (pin_B8) // Y3
+#define MICROPY_HW_CAN2_NAME "YB"
+#define MICROPY_HW_CAN2_TX (pin_B13) // Y6
+#define MICROPY_HW_CAN2_RX (pin_B12) // Y5
// USRSW has no pullup or pulldown, and pressing the switch makes the input go low
#define MICROPY_HW_USRSW_PIN (pin_B3)
@@ -92,6 +94,7 @@
#define MICROPY_HW_SDCARD_DETECT_PRESENT (GPIO_PIN_RESET)
// USB config
+#define MICROPY_HW_USB_FS (1)
#define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_A9)
#define MICROPY_HW_USB_OTG_ID_PIN (pin_A10)
diff --git a/ports/stm32/boards/PYBV10/mpconfigboard.mk b/ports/stm32/boards/PYBV10/mpconfigboard.mk
index 5734c6690..40972b385 100644
--- a/ports/stm32/boards/PYBV10/mpconfigboard.mk
+++ b/ports/stm32/boards/PYBV10/mpconfigboard.mk
@@ -1,4 +1,6 @@
MCU_SERIES = f4
CMSIS_MCU = STM32F405xx
AF_FILE = boards/stm32f405_af.csv
-LD_FILE = boards/stm32f405.ld
+LD_FILES = boards/stm32f405.ld boards/common_ifs.ld
+TEXT0_ADDR = 0x08000000
+TEXT1_ADDR = 0x08020000
diff --git a/ports/stm32/boards/PYBV10/stm32f4xx_hal_conf.h b/ports/stm32/boards/PYBV10/stm32f4xx_hal_conf.h
index 3d9252264..4f18ac81e 100644
--- a/ports/stm32/boards/PYBV10/stm32f4xx_hal_conf.h
+++ b/ports/stm32/boards/PYBV10/stm32f4xx_hal_conf.h
@@ -46,8 +46,6 @@
/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
-#define USE_USB_FS
-
/* ########################## Module Selection ############################## */
/**
* @brief This is the list of modules to be used in the HAL driver
diff --git a/ports/stm32/boards/PYBV11/mpconfigboard.h b/ports/stm32/boards/PYBV11/mpconfigboard.h
index c69e52cc5..2c75d0e64 100644
--- a/ports/stm32/boards/PYBV11/mpconfigboard.h
+++ b/ports/stm32/boards/PYBV11/mpconfigboard.h
@@ -5,14 +5,12 @@
#define MICROPY_HW_HAS_FLASH (1)
#define MICROPY_HW_HAS_SDCARD (1)
#define MICROPY_HW_HAS_MMA7660 (1)
-#define MICROPY_HW_HAS_LIS3DSH (0)
#define MICROPY_HW_HAS_LCD (1)
#define MICROPY_HW_ENABLE_RNG (1)
#define MICROPY_HW_ENABLE_RTC (1)
-#define MICROPY_HW_ENABLE_TIMER (1)
#define MICROPY_HW_ENABLE_SERVO (1)
#define MICROPY_HW_ENABLE_DAC (1)
-#define MICROPY_HW_ENABLE_CAN (1)
+#define MICROPY_HW_ENABLE_USB (1)
// HSE is 12MHz
#define MICROPY_HW_CLK_PLLM (12)
@@ -67,8 +65,12 @@
#define MICROPY_HW_SPI2_MOSI (pin_B15) // Y8
// CAN busses
-#define MICROPY_HW_CAN1_NAME "YA" // CAN1 on RX,TX = Y3,Y4 = PB8,PB9
-#define MICROPY_HW_CAN2_NAME "YB" // CAN2 on RX,TX = Y5,Y6 = PB12,PB13
+#define MICROPY_HW_CAN1_NAME "YA"
+#define MICROPY_HW_CAN1_TX (pin_B9) // Y4
+#define MICROPY_HW_CAN1_RX (pin_B8) // Y3
+#define MICROPY_HW_CAN2_NAME "YB"
+#define MICROPY_HW_CAN2_TX (pin_B13) // Y6
+#define MICROPY_HW_CAN2_RX (pin_B12) // Y5
// USRSW has no pullup or pulldown, and pressing the switch makes the input go low
#define MICROPY_HW_USRSW_PIN (pin_B3)
@@ -92,6 +94,7 @@
#define MICROPY_HW_SDCARD_DETECT_PRESENT (GPIO_PIN_RESET)
// USB config
+#define MICROPY_HW_USB_FS (1)
#define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_A9)
#define MICROPY_HW_USB_OTG_ID_PIN (pin_A10)
diff --git a/ports/stm32/boards/PYBV11/mpconfigboard.mk b/ports/stm32/boards/PYBV11/mpconfigboard.mk
index 5734c6690..40972b385 100644
--- a/ports/stm32/boards/PYBV11/mpconfigboard.mk
+++ b/ports/stm32/boards/PYBV11/mpconfigboard.mk
@@ -1,4 +1,6 @@
MCU_SERIES = f4
CMSIS_MCU = STM32F405xx
AF_FILE = boards/stm32f405_af.csv
-LD_FILE = boards/stm32f405.ld
+LD_FILES = boards/stm32f405.ld boards/common_ifs.ld
+TEXT0_ADDR = 0x08000000
+TEXT1_ADDR = 0x08020000
diff --git a/ports/stm32/boards/PYBV11/stm32f4xx_hal_conf.h b/ports/stm32/boards/PYBV11/stm32f4xx_hal_conf.h
index b84b0a892..24cc9228b 100644
--- a/ports/stm32/boards/PYBV11/stm32f4xx_hal_conf.h
+++ b/ports/stm32/boards/PYBV11/stm32f4xx_hal_conf.h
@@ -46,8 +46,6 @@
/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
-#define USE_USB_FS
-
/* ########################## Module Selection ############################## */
/**
* @brief This is the list of modules to be used in the HAL driver
diff --git a/ports/stm32/boards/PYBV3/mpconfigboard.h b/ports/stm32/boards/PYBV3/mpconfigboard.h
index 1f49af4da..3e457c5e2 100644
--- a/ports/stm32/boards/PYBV3/mpconfigboard.h
+++ b/ports/stm32/boards/PYBV3/mpconfigboard.h
@@ -5,14 +5,11 @@
#define MICROPY_HW_HAS_FLASH (1)
#define MICROPY_HW_HAS_SDCARD (1)
#define MICROPY_HW_HAS_MMA7660 (1)
-#define MICROPY_HW_HAS_LIS3DSH (0)
-#define MICROPY_HW_HAS_LCD (0)
#define MICROPY_HW_ENABLE_RNG (1)
#define MICROPY_HW_ENABLE_RTC (1)
-#define MICROPY_HW_ENABLE_TIMER (1)
#define MICROPY_HW_ENABLE_SERVO (1)
#define MICROPY_HW_ENABLE_DAC (1)
-#define MICROPY_HW_ENABLE_CAN (1)
+#define MICROPY_HW_ENABLE_USB (1)
// HSE is 8MHz
#define MICROPY_HW_CLK_PLLM (8)
@@ -59,6 +56,12 @@
#define MICROPY_HW_SPI2_MISO (pin_B14) // Y7
#define MICROPY_HW_SPI2_MOSI (pin_B15) // Y8
+// CAN busses
+#define MICROPY_HW_CAN1_TX (pin_B9) // Y4
+#define MICROPY_HW_CAN1_RX (pin_B8) // Y3
+#define MICROPY_HW_CAN2_TX (pin_B13) // Y6
+#define MICROPY_HW_CAN2_RX (pin_B12) // Y5
+
// USRSW has no pullup or pulldown, and pressing the switch makes the input go low
#define MICROPY_HW_USRSW_PIN (pin_A13)
#define MICROPY_HW_USRSW_PULL (GPIO_PULLUP)
@@ -82,6 +85,7 @@
#define MICROPY_HW_SDCARD_DETECT_PRESENT (GPIO_PIN_SET)
// USB VBUS detect pin
+#define MICROPY_HW_USB_FS (1)
#define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_A9)
// MMA accelerometer config
diff --git a/ports/stm32/boards/PYBV3/mpconfigboard.mk b/ports/stm32/boards/PYBV3/mpconfigboard.mk
index 5734c6690..40972b385 100644
--- a/ports/stm32/boards/PYBV3/mpconfigboard.mk
+++ b/ports/stm32/boards/PYBV3/mpconfigboard.mk
@@ -1,4 +1,6 @@
MCU_SERIES = f4
CMSIS_MCU = STM32F405xx
AF_FILE = boards/stm32f405_af.csv
-LD_FILE = boards/stm32f405.ld
+LD_FILES = boards/stm32f405.ld boards/common_ifs.ld
+TEXT0_ADDR = 0x08000000
+TEXT1_ADDR = 0x08020000
diff --git a/ports/stm32/boards/PYBV3/pins.csv b/ports/stm32/boards/PYBV3/pins.csv
index b20bd4ffb..1ddc3f52d 100644
--- a/ports/stm32/boards/PYBV3/pins.csv
+++ b/ports/stm32/boards/PYBV3/pins.csv
@@ -44,3 +44,5 @@ SD_D3,PC11
SD_CK,PC12
SD_CMD,PD2
UART1_TX,PA9
+USB_DM,PA11
+USB_DP,PA12
diff --git a/ports/stm32/boards/PYBV3/stm32f4xx_hal_conf.h b/ports/stm32/boards/PYBV3/stm32f4xx_hal_conf.h
index d3df51c10..daf9b63ce 100644
--- a/ports/stm32/boards/PYBV3/stm32f4xx_hal_conf.h
+++ b/ports/stm32/boards/PYBV3/stm32f4xx_hal_conf.h
@@ -46,8 +46,6 @@
/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
-#define USE_USB_FS
-
/* ########################## Module Selection ############################## */
/**
* @brief This is the list of modules to be used in the HAL driver
diff --git a/ports/stm32/boards/PYBV4/mpconfigboard.h b/ports/stm32/boards/PYBV4/mpconfigboard.h
index 2a4829c3e..8c05644f6 100644
--- a/ports/stm32/boards/PYBV4/mpconfigboard.h
+++ b/ports/stm32/boards/PYBV4/mpconfigboard.h
@@ -5,14 +5,12 @@
#define MICROPY_HW_HAS_FLASH (1)
#define MICROPY_HW_HAS_SDCARD (1)
#define MICROPY_HW_HAS_MMA7660 (1)
-#define MICROPY_HW_HAS_LIS3DSH (0)
#define MICROPY_HW_HAS_LCD (1)
#define MICROPY_HW_ENABLE_RNG (1)
#define MICROPY_HW_ENABLE_RTC (1)
-#define MICROPY_HW_ENABLE_TIMER (1)
#define MICROPY_HW_ENABLE_SERVO (1)
#define MICROPY_HW_ENABLE_DAC (1)
-#define MICROPY_HW_ENABLE_CAN (1)
+#define MICROPY_HW_ENABLE_USB (1)
// HSE is 8MHz
#define MICROPY_HW_CLK_PLLM (8)
@@ -64,8 +62,12 @@
#define MICROPY_HW_SPI2_MOSI (pin_B15) // Y8
// CAN busses
-#define MICROPY_HW_CAN1_NAME "YA" // CAN1 on RX,TX = Y3,Y4 = PB8,PB9
-#define MICROPY_HW_CAN2_NAME "YB" // CAN2 on RX,TX = Y5,Y6 = PB12,PB13
+#define MICROPY_HW_CAN1_NAME "YA"
+#define MICROPY_HW_CAN1_TX (pin_B9) // Y4
+#define MICROPY_HW_CAN1_RX (pin_B8) // Y3
+#define MICROPY_HW_CAN2_NAME "YB"
+#define MICROPY_HW_CAN2_TX (pin_B13) // Y6
+#define MICROPY_HW_CAN2_RX (pin_B12) // Y5
// USRSW has no pullup or pulldown, and pressing the switch makes the input go low
#define MICROPY_HW_USRSW_PIN (pin_B3)
@@ -89,6 +91,7 @@
#define MICROPY_HW_SDCARD_DETECT_PRESENT (GPIO_PIN_RESET)
// USB config
+#define MICROPY_HW_USB_FS (1)
#define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_A9)
#define MICROPY_HW_USB_OTG_ID_PIN (pin_A10)
diff --git a/ports/stm32/boards/PYBV4/mpconfigboard.mk b/ports/stm32/boards/PYBV4/mpconfigboard.mk
index 5734c6690..40972b385 100644
--- a/ports/stm32/boards/PYBV4/mpconfigboard.mk
+++ b/ports/stm32/boards/PYBV4/mpconfigboard.mk
@@ -1,4 +1,6 @@
MCU_SERIES = f4
CMSIS_MCU = STM32F405xx
AF_FILE = boards/stm32f405_af.csv
-LD_FILE = boards/stm32f405.ld
+LD_FILES = boards/stm32f405.ld boards/common_ifs.ld
+TEXT0_ADDR = 0x08000000
+TEXT1_ADDR = 0x08020000
diff --git a/ports/stm32/boards/PYBV4/stm32f4xx_hal_conf.h b/ports/stm32/boards/PYBV4/stm32f4xx_hal_conf.h
index d3df51c10..daf9b63ce 100644
--- a/ports/stm32/boards/PYBV4/stm32f4xx_hal_conf.h
+++ b/ports/stm32/boards/PYBV4/stm32f4xx_hal_conf.h
@@ -46,8 +46,6 @@
/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
-#define USE_USB_FS
-
/* ########################## Module Selection ############################## */
/**
* @brief This is the list of modules to be used in the HAL driver
diff --git a/ports/stm32/boards/STM32F411DISC/mpconfigboard.h b/ports/stm32/boards/STM32F411DISC/mpconfigboard.h
index 1488cd764..13172333b 100644
--- a/ports/stm32/boards/STM32F411DISC/mpconfigboard.h
+++ b/ports/stm32/boards/STM32F411DISC/mpconfigboard.h
@@ -3,16 +3,9 @@
#define MICROPY_HW_HAS_SWITCH (1)
#define MICROPY_HW_HAS_FLASH (1)
-#define MICROPY_HW_HAS_SDCARD (0)
-#define MICROPY_HW_HAS_MMA7660 (0)
-#define MICROPY_HW_HAS_LIS3DSH (0)
-#define MICROPY_HW_HAS_LCD (0)
-#define MICROPY_HW_ENABLE_RNG (0)
#define MICROPY_HW_ENABLE_RTC (1)
-#define MICROPY_HW_ENABLE_TIMER (1)
+#define MICROPY_HW_ENABLE_USB (1)
#define MICROPY_HW_ENABLE_SERVO (1)
-#define MICROPY_HW_ENABLE_DAC (0)
-#define MICROPY_HW_ENABLE_CAN (0)
// HSE is 8MHz
#define MICROPY_HW_CLK_PLLM (5)
@@ -66,5 +59,6 @@
#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin))
// USB config
+#define MICROPY_HW_USB_FS (1)
#define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_A9)
#define MICROPY_HW_USB_OTG_ID_PIN (pin_A10)
diff --git a/ports/stm32/boards/STM32F411DISC/mpconfigboard.mk b/ports/stm32/boards/STM32F411DISC/mpconfigboard.mk
index 71b3b19d6..df9506522 100644
--- a/ports/stm32/boards/STM32F411DISC/mpconfigboard.mk
+++ b/ports/stm32/boards/STM32F411DISC/mpconfigboard.mk
@@ -1,4 +1,6 @@
MCU_SERIES = f4
CMSIS_MCU = STM32F411xE
AF_FILE = boards/stm32f411_af.csv
-LD_FILE = boards/stm32f411.ld
+LD_FILES = boards/stm32f411.ld boards/common_ifs.ld
+TEXT0_ADDR = 0x08000000
+TEXT1_ADDR = 0x08020000
diff --git a/ports/stm32/boards/STM32F411DISC/pins.csv b/ports/stm32/boards/STM32F411DISC/pins.csv
index 96077d54d..a747aef3e 100644
--- a/ports/stm32/boards/STM32F411DISC/pins.csv
+++ b/ports/stm32/boards/STM32F411DISC/pins.csv
@@ -82,3 +82,5 @@ LED_ORANGE,PD13
LED_RED,PD14
LED_BLUE,PD15
SW,PA0
+USB_DM,PA11
+USB_DP,PA12
diff --git a/ports/stm32/boards/STM32F411DISC/stm32f4xx_hal_conf.h b/ports/stm32/boards/STM32F411DISC/stm32f4xx_hal_conf.h
index 921cbe5fe..8f0b66381 100644
--- a/ports/stm32/boards/STM32F411DISC/stm32f4xx_hal_conf.h
+++ b/ports/stm32/boards/STM32F411DISC/stm32f4xx_hal_conf.h
@@ -46,8 +46,6 @@
/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
-#define USE_USB_FS
-
/* ########################## Module Selection ############################## */
/**
* @brief This is the list of modules to be used in the HAL driver
diff --git a/ports/stm32/boards/STM32F429DISC/mpconfigboard.h b/ports/stm32/boards/STM32F429DISC/mpconfigboard.h
index fc0702025..be25d2e77 100644
--- a/ports/stm32/boards/STM32F429DISC/mpconfigboard.h
+++ b/ports/stm32/boards/STM32F429DISC/mpconfigboard.h
@@ -3,16 +3,9 @@
#define MICROPY_HW_HAS_SWITCH (1)
#define MICROPY_HW_HAS_FLASH (1)
-#define MICROPY_HW_HAS_SDCARD (0)
-#define MICROPY_HW_HAS_MMA7660 (0)
-#define MICROPY_HW_HAS_LIS3DSH (0)
-#define MICROPY_HW_HAS_LCD (0)
#define MICROPY_HW_ENABLE_RNG (1)
#define MICROPY_HW_ENABLE_RTC (1)
-#define MICROPY_HW_ENABLE_TIMER (1)
-#define MICROPY_HW_ENABLE_SERVO (0)
-#define MICROPY_HW_ENABLE_DAC (0)
-#define MICROPY_HW_ENABLE_CAN (1)
+#define MICROPY_HW_ENABLE_USB (1)
// HSE is 8MHz
#define MICROPY_HW_CLK_PLLM (8)
@@ -56,6 +49,12 @@
//#define MICROPY_HW_SPI6_MISO (pin_G12)
//#define MICROPY_HW_SPI6_MOSI (pin_G14)
+// CAN busses
+#define MICROPY_HW_CAN1_TX (pin_B9)
+#define MICROPY_HW_CAN1_RX (pin_B8)
+#define MICROPY_HW_CAN2_TX (pin_B13)
+#define MICROPY_HW_CAN2_RX (pin_B12)
+
// USRSW is pulled low. Pressing the button makes the input go high.
#define MICROPY_HW_USRSW_PIN (pin_A0)
#define MICROPY_HW_USRSW_PULL (GPIO_NOPULL)
@@ -69,5 +68,7 @@
#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin))
// USB config
+#define MICROPY_HW_USB_HS (1)
+#define MICROPY_HW_USB_HS_IN_FS (1)
#define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_B13)
#define MICROPY_HW_USB_OTG_ID_PIN (pin_B12)
diff --git a/ports/stm32/boards/STM32F429DISC/mpconfigboard.mk b/ports/stm32/boards/STM32F429DISC/mpconfigboard.mk
index 1bbf808b6..d19a35c31 100644
--- a/ports/stm32/boards/STM32F429DISC/mpconfigboard.mk
+++ b/ports/stm32/boards/STM32F429DISC/mpconfigboard.mk
@@ -1,4 +1,6 @@
MCU_SERIES = f4
CMSIS_MCU = STM32F429xx
AF_FILE = boards/stm32f429_af.csv
-LD_FILE = boards/stm32f429.ld
+LD_FILES = boards/stm32f429.ld boards/common_ifs.ld
+TEXT0_ADDR = 0x08000000
+TEXT1_ADDR = 0x08020000
diff --git a/ports/stm32/boards/STM32F429DISC/stm32f4xx_hal_conf.h b/ports/stm32/boards/STM32F429DISC/stm32f4xx_hal_conf.h
index 4f5962dcb..5b5a8a3e4 100644
--- a/ports/stm32/boards/STM32F429DISC/stm32f4xx_hal_conf.h
+++ b/ports/stm32/boards/STM32F429DISC/stm32f4xx_hal_conf.h
@@ -46,9 +46,6 @@
/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
-#define USE_USB_HS
-#define USE_USB_HS_IN_FS
-
/* ########################## Module Selection ############################## */
/**
* @brief This is the list of modules to be used in the HAL driver
diff --git a/ports/stm32/boards/STM32F439/mpconfigboard.h b/ports/stm32/boards/STM32F439/mpconfigboard.h
index eca79bf58..4ac5b3213 100644
--- a/ports/stm32/boards/STM32F439/mpconfigboard.h
+++ b/ports/stm32/boards/STM32F439/mpconfigboard.h
@@ -1,18 +1,12 @@
#define MICROPY_HW_BOARD_NAME "CustomPCB"
#define MICROPY_HW_MCU_NAME "STM32F439"
-#define MICROPY_HW_HAS_SWITCH (0)
#define MICROPY_HW_HAS_FLASH (1)
#define MICROPY_HW_HAS_SDCARD (1) //works with no SD card too
-#define MICROPY_HW_HAS_MMA7660 (0)
-#define MICROPY_HW_HAS_LIS3DSH (0)
-#define MICROPY_HW_HAS_LCD (0)
#define MICROPY_HW_ENABLE_RNG (1)
#define MICROPY_HW_ENABLE_RTC (1)
-#define MICROPY_HW_ENABLE_TIMER (1)
-#define MICROPY_HW_ENABLE_SERVO (0)
#define MICROPY_HW_ENABLE_DAC (1)
-#define MICROPY_HW_ENABLE_CAN (1)
+#define MICROPY_HW_ENABLE_USB (1)
// SD card detect switch
#if MICROPY_HW_HAS_SDCARD
@@ -27,6 +21,9 @@
#define MICROPY_HW_CLK_PLLP (RCC_PLLP_DIV2) //divide PLL clock by this to get core clock
#define MICROPY_HW_CLK_PLLQ (8) //divide core clock by this to get 48MHz
+// USB config
+#define MICROPY_HW_USB_FS (1)
+
// UART config
#define MICROPY_HW_UART1_TX (pin_A9)
#define MICROPY_HW_UART1_RX (pin_A10)
@@ -52,7 +49,7 @@
#define MICROPY_HW_SPI1_SCK (pin_A5)
#define MICROPY_HW_SPI1_MISO (pin_A6)
#define MICROPY_HW_SPI1_MOSI (pin_A7)
-#if defined(USE_USB_HS_IN_FS)
+#if MICROPY_HW_USB_HS_IN_FS
// The HS USB uses B14 & B15 for D- and D+
#else
#define MICROPY_HW_SPI2_NSS (pin_B12)
@@ -77,6 +74,12 @@
//#define MICROPY_HW_SPI6_MISO (pin_G12)
//#define MICROPY_HW_SPI6_MOSI (pin_G14)
+// CAN busses
+#define MICROPY_HW_CAN1_TX (pin_B9)
+#define MICROPY_HW_CAN1_RX (pin_B8)
+#define MICROPY_HW_CAN2_TX (pin_B13)
+#define MICROPY_HW_CAN2_RX (pin_B12)
+
// USRSW is pulled low. Pressing the button makes the input go high.
#define MICROPY_HW_USRSW_PIN (pin_A0)
#define MICROPY_HW_USRSW_PULL (GPIO_NOPULL)
diff --git a/ports/stm32/boards/STM32F439/mpconfigboard.mk b/ports/stm32/boards/STM32F439/mpconfigboard.mk
index 0c30c06a3..ca97acbf6 100644
--- a/ports/stm32/boards/STM32F439/mpconfigboard.mk
+++ b/ports/stm32/boards/STM32F439/mpconfigboard.mk
@@ -1,4 +1,6 @@
MCU_SERIES = f4
CMSIS_MCU = STM32F439xx
AF_FILE = boards/stm32f439_af.csv
-LD_FILE = boards/stm32f439.ld
+LD_FILES = boards/stm32f439.ld boards/common_ifs.ld
+TEXT0_ADDR = 0x08000000
+TEXT1_ADDR = 0x08020000
diff --git a/ports/stm32/boards/STM32F439/stm32f4xx_hal_conf.h b/ports/stm32/boards/STM32F439/stm32f4xx_hal_conf.h
index d121b18c5..5b5a8a3e4 100644
--- a/ports/stm32/boards/STM32F439/stm32f4xx_hal_conf.h
+++ b/ports/stm32/boards/STM32F439/stm32f4xx_hal_conf.h
@@ -46,8 +46,6 @@
/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
-#define USE_USB_FS
-
/* ########################## Module Selection ############################## */
/**
* @brief This is the list of modules to be used in the HAL driver
diff --git a/ports/stm32/boards/STM32F4DISC/mpconfigboard.h b/ports/stm32/boards/STM32F4DISC/mpconfigboard.h
index 105875515..3e4c8261c 100644
--- a/ports/stm32/boards/STM32F4DISC/mpconfigboard.h
+++ b/ports/stm32/boards/STM32F4DISC/mpconfigboard.h
@@ -1,20 +1,12 @@
-#define STM32F4DISC
-
#define MICROPY_HW_BOARD_NAME "F4DISC"
#define MICROPY_HW_MCU_NAME "STM32F407"
#define MICROPY_HW_HAS_SWITCH (1)
#define MICROPY_HW_HAS_FLASH (1)
-#define MICROPY_HW_HAS_SDCARD (0)
-#define MICROPY_HW_HAS_MMA7660 (0)
-#define MICROPY_HW_HAS_LIS3DSH (1)
-#define MICROPY_HW_HAS_LCD (0)
#define MICROPY_HW_ENABLE_RNG (1)
#define MICROPY_HW_ENABLE_RTC (1)
-#define MICROPY_HW_ENABLE_TIMER (1)
-#define MICROPY_HW_ENABLE_SERVO (0)
#define MICROPY_HW_ENABLE_DAC (1)
-#define MICROPY_HW_ENABLE_CAN (1)
+#define MICROPY_HW_ENABLE_USB (1)
// HSE is 8MHz
#define MICROPY_HW_CLK_PLLM (8)
@@ -67,6 +59,12 @@
#define MICROPY_HW_SPI2_MISO (pin_B14)
#define MICROPY_HW_SPI2_MOSI (pin_B15)
+// CAN busses
+#define MICROPY_HW_CAN1_TX (pin_B9)
+#define MICROPY_HW_CAN1_RX (pin_B8)
+#define MICROPY_HW_CAN2_TX (pin_B13)
+#define MICROPY_HW_CAN2_RX (pin_B12)
+
// USRSW is pulled low. Pressing the button makes the input go high.
#define MICROPY_HW_USRSW_PIN (pin_A0)
#define MICROPY_HW_USRSW_PULL (GPIO_NOPULL)
@@ -82,5 +80,6 @@
#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin))
// USB config
+#define MICROPY_HW_USB_FS (1)
#define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_A9)
#define MICROPY_HW_USB_OTG_ID_PIN (pin_A10)
diff --git a/ports/stm32/boards/STM32F4DISC/mpconfigboard.mk b/ports/stm32/boards/STM32F4DISC/mpconfigboard.mk
index ece09caa1..b154dcfba 100644
--- a/ports/stm32/boards/STM32F4DISC/mpconfigboard.mk
+++ b/ports/stm32/boards/STM32F4DISC/mpconfigboard.mk
@@ -1,4 +1,6 @@
MCU_SERIES = f4
CMSIS_MCU = STM32F407xx
AF_FILE = boards/stm32f405_af.csv
-LD_FILE = boards/stm32f405.ld
+LD_FILES = boards/stm32f405.ld boards/common_ifs.ld
+TEXT0_ADDR = 0x08000000
+TEXT1_ADDR = 0x08020000
diff --git a/ports/stm32/boards/STM32F4DISC/pins.csv b/ports/stm32/boards/STM32F4DISC/pins.csv
index 4049fef7d..a747aef3e 100644
--- a/ports/stm32/boards/STM32F4DISC/pins.csv
+++ b/ports/stm32/boards/STM32F4DISC/pins.csv
@@ -82,4 +82,5 @@ LED_ORANGE,PD13
LED_RED,PD14
LED_BLUE,PD15
SW,PA0
-
+USB_DM,PA11
+USB_DP,PA12
diff --git a/ports/stm32/boards/STM32F4DISC/stm32f4xx_hal_conf.h b/ports/stm32/boards/STM32F4DISC/stm32f4xx_hal_conf.h
index d3df51c10..daf9b63ce 100644
--- a/ports/stm32/boards/STM32F4DISC/stm32f4xx_hal_conf.h
+++ b/ports/stm32/boards/STM32F4DISC/stm32f4xx_hal_conf.h
@@ -46,8 +46,6 @@
/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
-#define USE_USB_FS
-
/* ########################## Module Selection ############################## */
/**
* @brief This is the list of modules to be used in the HAL driver
diff --git a/ports/stm32/boards/STM32F769DISC/mpconfigboard.h b/ports/stm32/boards/STM32F769DISC/mpconfigboard.h
index 50b9c1618..8b29e5773 100644
--- a/ports/stm32/boards/STM32F769DISC/mpconfigboard.h
+++ b/ports/stm32/boards/STM32F769DISC/mpconfigboard.h
@@ -8,15 +8,9 @@
#define MICROPY_HW_HAS_SWITCH (1)
#define MICROPY_HW_HAS_FLASH (1)
#define MICROPY_HW_HAS_SDCARD (1)
-#define MICROPY_HW_HAS_MMA7660 (0)
-#define MICROPY_HW_HAS_LIS3DSH (0)
-#define MICROPY_HW_HAS_LCD (0)
#define MICROPY_HW_ENABLE_RNG (1)
#define MICROPY_HW_ENABLE_RTC (1)
-#define MICROPY_HW_ENABLE_TIMER (1)
-#define MICROPY_HW_ENABLE_SERVO (0)
-#define MICROPY_HW_ENABLE_DAC (0)
-#define MICROPY_HW_ENABLE_CAN (1)
+#define MICROPY_HW_ENABLE_USB (1)
// HSE is 25MHz
// VCOClock = HSE * PLLN / PLLM = 25 MHz * 432 / 25 = 432 MHz
@@ -49,6 +43,12 @@
#define MICROPY_HW_SPI2_MISO (pin_B14)
#define MICROPY_HW_SPI2_MOSI (pin_B15)
+// CAN busses
+#define MICROPY_HW_CAN1_TX (pin_B9)
+#define MICROPY_HW_CAN1_RX (pin_B8)
+#define MICROPY_HW_CAN2_TX (pin_B13)
+#define MICROPY_HW_CAN2_RX (pin_B12)
+
// USRSW is pulled low. Pressing the button makes the input go high.
#define MICROPY_HW_USRSW_PIN (pin_A0)
#define MICROPY_HW_USRSW_PULL (GPIO_NOPULL)
@@ -74,5 +74,7 @@
#define MICROPY_HW_SDCARD_DETECT_PRESENT (GPIO_PIN_RESET)
// USB config (CN13 - USB OTG FS)
+#define MICROPY_HW_USB_HS (1)
+#define MICROPY_HW_USB_HS_IN_FS (1)
/*#define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_J12)*/
#define MICROPY_HW_USB_OTG_ID_PIN (pin_J12)
diff --git a/ports/stm32/boards/STM32F769DISC/mpconfigboard.mk b/ports/stm32/boards/STM32F769DISC/mpconfigboard.mk
index 99234e4cf..873368ce5 100644
--- a/ports/stm32/boards/STM32F769DISC/mpconfigboard.mk
+++ b/ports/stm32/boards/STM32F769DISC/mpconfigboard.mk
@@ -2,4 +2,6 @@ MCU_SERIES = f7
CMSIS_MCU = STM32F769xx
MICROPY_FLOAT_IMPL = double
AF_FILE = boards/stm32f767_af.csv
-LD_FILE = boards/stm32f769.ld
+LD_FILES = boards/stm32f769.ld boards/common_ifs.ld
+TEXT0_ADDR = 0x08000000
+TEXT1_ADDR = 0x08020000
diff --git a/ports/stm32/boards/STM32F769DISC/pins.csv b/ports/stm32/boards/STM32F769DISC/pins.csv
index dcc2df208..e68ed9536 100644
--- a/ports/stm32/boards/STM32F769DISC/pins.csv
+++ b/ports/stm32/boards/STM32F769DISC/pins.csv
@@ -55,3 +55,5 @@ UART1_TX,PA9
UART1_RX,PA10
UART5_TX,PC12
UART5_RX,PD2
+CAN2_TX,PB13
+CAN2_RX,PB12
diff --git a/ports/stm32/boards/STM32F769DISC/stm32f7xx_hal_conf.h b/ports/stm32/boards/STM32F769DISC/stm32f7xx_hal_conf.h
index ce8254902..ff968bca9 100644
--- a/ports/stm32/boards/STM32F769DISC/stm32f7xx_hal_conf.h
+++ b/ports/stm32/boards/STM32F769DISC/stm32f7xx_hal_conf.h
@@ -46,9 +46,6 @@
/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
-#define USE_USB_HS
-#define USE_USB_HS_IN_FS
-
/* ########################## Module Selection ############################## */
/**
* @brief This is the list of modules to be used in the HAL driver
diff --git a/ports/stm32/boards/STM32F7DISC/board_init.c b/ports/stm32/boards/STM32F7DISC/board_init.c
index 4530a4706..dd268fb9c 100644
--- a/ports/stm32/boards/STM32F7DISC/board_init.c
+++ b/ports/stm32/boards/STM32F7DISC/board_init.c
@@ -3,13 +3,13 @@
void STM32F7DISC_board_early_init(void) {
GPIO_InitTypeDef GPIO_InitStructure;
- __GPIOK_CLK_ENABLE();
+ __HAL_RCC_GPIOK_CLK_ENABLE();
// Turn off the backlight. LCD_BL_CTRL = PK3
GPIO_InitStructure.Pin = GPIO_PIN_3;
GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStructure.Pull = GPIO_PULLUP;
- GPIO_InitStructure.Speed = GPIO_SPEED_HIGH;
+ GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
HAL_GPIO_Init(GPIOK, &GPIO_InitStructure);
HAL_GPIO_WritePin(GPIOK, GPIO_PIN_3, GPIO_PIN_RESET);
}
diff --git a/ports/stm32/boards/STM32F7DISC/mpconfigboard.h b/ports/stm32/boards/STM32F7DISC/mpconfigboard.h
index 44a39c0a1..7b506a305 100644
--- a/ports/stm32/boards/STM32F7DISC/mpconfigboard.h
+++ b/ports/stm32/boards/STM32F7DISC/mpconfigboard.h
@@ -1,20 +1,12 @@
-#define STM32F7DISC
-
#define MICROPY_HW_BOARD_NAME "F7DISC"
#define MICROPY_HW_MCU_NAME "STM32F746"
#define MICROPY_HW_HAS_SWITCH (1)
#define MICROPY_HW_HAS_FLASH (1)
#define MICROPY_HW_HAS_SDCARD (1)
-#define MICROPY_HW_HAS_MMA7660 (0)
-#define MICROPY_HW_HAS_LIS3DSH (0)
-#define MICROPY_HW_HAS_LCD (0)
#define MICROPY_HW_ENABLE_RNG (1)
#define MICROPY_HW_ENABLE_RTC (1)
-#define MICROPY_HW_ENABLE_TIMER (1)
-#define MICROPY_HW_ENABLE_SERVO (0)
-#define MICROPY_HW_ENABLE_DAC (0)
-#define MICROPY_HW_ENABLE_CAN (1)
+#define MICROPY_HW_ENABLE_USB (1)
#define MICROPY_BOARD_EARLY_INIT STM32F7DISC_board_early_init
void STM32F7DISC_board_early_init(void);
@@ -57,6 +49,12 @@ void STM32F7DISC_board_early_init(void);
#define MICROPY_HW_SPI2_MISO (pin_B14)
#define MICROPY_HW_SPI2_MOSI (pin_B15)
+// CAN busses
+#define MICROPY_HW_CAN1_TX (pin_B9)
+#define MICROPY_HW_CAN1_RX (pin_B8)
+#define MICROPY_HW_CAN2_TX (pin_B13)
+#define MICROPY_HW_CAN2_RX (pin_B12)
+
// USRSW is pulled low. Pressing the button makes the input go high.
#define MICROPY_HW_USRSW_PIN (pin_I11)
#define MICROPY_HW_USRSW_PULL (GPIO_NOPULL)
@@ -77,6 +75,6 @@ void STM32F7DISC_board_early_init(void);
// The Hardware VBUS detect only works on pin PA9. The STM32F7 Discovery uses
// PA9 for VCP_TX functionality and connects the VBUS to pin J12 (so software
// only detect). So we don't define the VBUS detect pin since that requires PA9.
-
+#define MICROPY_HW_USB_FS (1)
/*#define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_J12)*/
#define MICROPY_HW_USB_OTG_ID_PIN (pin_A10)
diff --git a/ports/stm32/boards/STM32F7DISC/mpconfigboard.mk b/ports/stm32/boards/STM32F7DISC/mpconfigboard.mk
index 7c6bc4584..160218fd3 100644
--- a/ports/stm32/boards/STM32F7DISC/mpconfigboard.mk
+++ b/ports/stm32/boards/STM32F7DISC/mpconfigboard.mk
@@ -1,4 +1,6 @@
MCU_SERIES = f7
CMSIS_MCU = STM32F746xx
AF_FILE = boards/stm32f746_af.csv
-LD_FILE = boards/stm32f746.ld
+LD_FILES = boards/stm32f746.ld boards/common_ifs.ld
+TEXT0_ADDR = 0x08000000
+TEXT1_ADDR = 0x08020000
diff --git a/ports/stm32/boards/STM32F7DISC/pins.csv b/ports/stm32/boards/STM32F7DISC/pins.csv
index 1aa8a9b3a..8b49003f7 100644
--- a/ports/stm32/boards/STM32F7DISC/pins.csv
+++ b/ports/stm32/boards/STM32F7DISC/pins.csv
@@ -51,3 +51,5 @@ USB_DM,PA11
USB_DP,PA12
VCP_TX,PA9
VCP_RX,PB7
+CAN_TX,PB13
+CAN_RX,PB12
diff --git a/ports/stm32/boards/STM32F7DISC/stm32f7xx_hal_conf.h b/ports/stm32/boards/STM32F7DISC/stm32f7xx_hal_conf.h
index 3fbfb4310..ff968bca9 100644
--- a/ports/stm32/boards/STM32F7DISC/stm32f7xx_hal_conf.h
+++ b/ports/stm32/boards/STM32F7DISC/stm32f7xx_hal_conf.h
@@ -46,8 +46,6 @@
/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
-#define USE_USB_FS
-
/* ########################## Module Selection ############################## */
/**
* @brief This is the list of modules to be used in the HAL driver
diff --git a/ports/stm32/boards/STM32L476DISC/bdev.c b/ports/stm32/boards/STM32L476DISC/bdev.c
new file mode 100644
index 000000000..01f06b8b1
--- /dev/null
+++ b/ports/stm32/boards/STM32L476DISC/bdev.c
@@ -0,0 +1,24 @@
+#include "storage.h"
+
+// External SPI flash uses standard SPI interface
+
+STATIC const mp_soft_spi_obj_t soft_spi_bus = {
+ .delay_half = MICROPY_HW_SOFTSPI_MIN_DELAY,
+ .polarity = 0,
+ .phase = 0,
+ .sck = MICROPY_HW_SPIFLASH_SCK,
+ .mosi = MICROPY_HW_SPIFLASH_MOSI,
+ .miso = MICROPY_HW_SPIFLASH_MISO,
+};
+
+STATIC mp_spiflash_cache_t spi_bdev_cache;
+
+const mp_spiflash_config_t spiflash_config = {
+ .bus_kind = MP_SPIFLASH_BUS_SPI,
+ .bus.u_spi.cs = MICROPY_HW_SPIFLASH_CS,
+ .bus.u_spi.data = (void*)&soft_spi_bus,
+ .bus.u_spi.proto = &mp_soft_spi_proto,
+ .cache = &spi_bdev_cache,
+};
+
+spi_bdev_t spi_bdev;
diff --git a/ports/stm32/boards/STM32L476DISC/board_init.c b/ports/stm32/boards/STM32L476DISC/board_init.c
index fdc41c401..eb44f320f 100644
--- a/ports/stm32/boards/STM32L476DISC/board_init.c
+++ b/ports/stm32/boards/STM32L476DISC/board_init.c
@@ -1,10 +1,9 @@
#include "py/mphal.h"
-#include "genhdr/pins.h"
void STM32L476DISC_board_early_init(void) {
// set SPI flash WP and HOLD pins high
- mp_hal_pin_output(&pin_E14);
- mp_hal_pin_output(&pin_E15);
- mp_hal_pin_write(&pin_E14, 1);
- mp_hal_pin_write(&pin_E15, 1);
+ mp_hal_pin_output(pin_E14);
+ mp_hal_pin_output(pin_E15);
+ mp_hal_pin_write(pin_E14, 1);
+ mp_hal_pin_write(pin_E15, 1);
}
diff --git a/ports/stm32/boards/STM32L476DISC/mpconfigboard.h b/ports/stm32/boards/STM32L476DISC/mpconfigboard.h
index 9dbadd530..a35dee118 100644
--- a/ports/stm32/boards/STM32L476DISC/mpconfigboard.h
+++ b/ports/stm32/boards/STM32L476DISC/mpconfigboard.h
@@ -4,18 +4,12 @@ void STM32L476DISC_board_early_init(void);
#define MICROPY_HW_BOARD_NAME "L476-DISCO"
#define MICROPY_HW_MCU_NAME "STM32L476"
+#define MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE (0)
#define MICROPY_HW_HAS_SWITCH (1)
#define MICROPY_HW_HAS_FLASH (1)
-#define MICROPY_HW_HAS_SDCARD (0)
-#define MICROPY_HW_HAS_MMA7660 (0)
-#define MICROPY_HW_HAS_LIS3DSH (0)
-#define MICROPY_HW_HAS_LCD (0)
#define MICROPY_HW_ENABLE_RNG (1)
#define MICROPY_HW_ENABLE_RTC (1)
-#define MICROPY_HW_ENABLE_TIMER (1)
-#define MICROPY_HW_ENABLE_SERVO (0)
-#define MICROPY_HW_ENABLE_DAC (0)
-#define MICROPY_HW_ENABLE_CAN (0)
+#define MICROPY_HW_ENABLE_USB (1)
// use external SPI flash for storage
#define MICROPY_HW_SPIFLASH_SIZE_BITS (128 * 1024 * 1024)
@@ -24,6 +18,17 @@ void STM32L476DISC_board_early_init(void);
#define MICROPY_HW_SPIFLASH_MOSI (pin_E12)
#define MICROPY_HW_SPIFLASH_MISO (pin_E13)
+// block device config for SPI flash
+extern const struct _mp_spiflash_config_t spiflash_config;
+extern struct _spi_bdev_t spi_bdev;
+#define MICROPY_HW_BDEV_IOCTL(op, arg) ( \
+ (op) == BDEV_IOCTL_NUM_BLOCKS ? (MICROPY_HW_SPIFLASH_SIZE_BITS / 8 / FLASH_BLOCK_SIZE) : \
+ (op) == BDEV_IOCTL_INIT ? spi_bdev_ioctl(&spi_bdev, (op), (uint32_t)&spiflash_config) : \
+ spi_bdev_ioctl(&spi_bdev, (op), (arg)) \
+)
+#define MICROPY_HW_BDEV_READBLOCKS(dest, bl, n) spi_bdev_readblocks(&spi_bdev, (dest), (bl), (n))
+#define MICROPY_HW_BDEV_WRITEBLOCKS(src, bl, n) spi_bdev_writeblocks(&spi_bdev, (src), (bl), (n))
+
// MSI is used and is 4MHz
#define MICROPY_HW_CLK_PLLM (1)
#define MICROPY_HW_CLK_PLLN (40)
@@ -52,6 +57,10 @@ void STM32L476DISC_board_early_init(void);
#define MICROPY_HW_SPI2_MISO (pin_D3)
#define MICROPY_HW_SPI2_MOSI (pin_D4)
+// CAN busses
+#define MICROPY_HW_CAN1_TX (pin_B9)
+#define MICROPY_HW_CAN1_RX (pin_B8)
+
// Joystick is pulled low. Pressing the button makes the input go high.
#define MICROPY_HW_USRSW_PIN (pin_A0)
#define MICROPY_HW_USRSW_PULL (GPIO_NOPULL)
@@ -65,4 +74,5 @@ void STM32L476DISC_board_early_init(void);
#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin))
// USB config
+#define MICROPY_HW_USB_FS (1)
// #define MICROPY_HW_USB_OTG_ID_PIN (pin_C12) // This is not the official ID Pin which should be PA10
diff --git a/ports/stm32/boards/STM32L476DISC/mpconfigboard.mk b/ports/stm32/boards/STM32L476DISC/mpconfigboard.mk
index 72468d89c..2cad9e2e5 100644
--- a/ports/stm32/boards/STM32L476DISC/mpconfigboard.mk
+++ b/ports/stm32/boards/STM32L476DISC/mpconfigboard.mk
@@ -1,6 +1,7 @@
MCU_SERIES = l4
CMSIS_MCU = STM32L476xx
AF_FILE = boards/stm32l476_af.csv
-LD_FILE = boards/stm32l476xg.ld
-TEXT_ADDR = 0x08004000
+LD_FILES = boards/stm32l476xg.ld boards/common_ifs.ld
+TEXT0_ADDR = 0x08000000
+TEXT1_ADDR = 0x08004000
OPENOCD_CONFIG = boards/openocd_stm32l4.cfg
diff --git a/ports/stm32/boards/STM32L476DISC/stm32l4xx_hal_conf.h b/ports/stm32/boards/STM32L476DISC/stm32l4xx_hal_conf.h
index 9348e0679..6bfb28118 100644
--- a/ports/stm32/boards/STM32L476DISC/stm32l4xx_hal_conf.h
+++ b/ports/stm32/boards/STM32L476DISC/stm32l4xx_hal_conf.h
@@ -45,7 +45,6 @@
extern "C" {
#endif
-#define USE_USB_FS
/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
diff --git a/ports/stm32/boards/STM32L496GDISC/mpconfigboard.h b/ports/stm32/boards/STM32L496GDISC/mpconfigboard.h
new file mode 100644
index 000000000..6a17d74d3
--- /dev/null
+++ b/ports/stm32/boards/STM32L496GDISC/mpconfigboard.h
@@ -0,0 +1,52 @@
+#define MICROPY_HW_BOARD_NAME "L496G-DISCO"
+#define MICROPY_HW_MCU_NAME "STM32L496"
+
+#define MICROPY_HW_HAS_SWITCH (1)
+#define MICROPY_HW_ENABLE_RNG (1)
+#define MICROPY_HW_ENABLE_RTC (1)
+#define MICROPY_HW_ENABLE_TIMER (1)
+#define MICROPY_HW_ENABLE_USB (1)
+
+// MSI is used and is 4MHz,
+// Resulting core frequency is 80MHz:
+#define MICROPY_HW_CLK_PLLM (1)
+#define MICROPY_HW_CLK_PLLN (40)
+#define MICROPY_HW_CLK_PLLP (RCC_PLLP_DIV7)
+#define MICROPY_HW_CLK_PLLR (RCC_PLLR_DIV2)
+#define MICROPY_HW_CLK_PLLQ (RCC_PLLQ_DIV2)
+
+#define MICROPY_HW_FLASH_LATENCY FLASH_LATENCY_4
+
+// USART config
+#define MICROPY_HW_UART2_TX (pin_A2)
+#define MICROPY_HW_UART2_RX (pin_D6)
+// USART 2 is connected to the virtual com port on the ST-LINK
+#define MICROPY_HW_UART_REPL PYB_UART_2
+#define MICROPY_HW_UART_REPL_BAUD 115200
+
+// I2C busses
+#define MICROPY_HW_I2C1_SCL (pin_G14)
+#define MICROPY_HW_I2C1_SDA (pin_G13)
+#define MICROPY_HW_I2C2_SCL (pin_H4)
+#define MICROPY_HW_I2C2_SDA (pin_B14)
+
+// SPI busses
+// -> To the arduino connector
+#define MICROPY_HW_SPI1_NSS (pin_A15)
+#define MICROPY_HW_SPI1_SCK (pin_A5)
+#define MICROPY_HW_SPI1_MISO (pin_B4)
+#define MICROPY_HW_SPI1_MOSI (pin_B5)
+
+// Use Sel from joystick. Joystick is pulled low. Pressing the button makes the input go high.
+#define MICROPY_HW_USRSW_PIN (pin_C13)
+#define MICROPY_HW_USRSW_PULL (GPIO_PULLDOWN)
+#define MICROPY_HW_USRSW_EXTI_MODE (GPIO_MODE_IT_RISING)
+#define MICROPY_HW_USRSW_PRESSED (1)
+
+// LED (The orange LED is controlled over MFX)
+#define MICROPY_HW_LED1 (pin_B13) // Green
+#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_low(pin))
+#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_high(pin))
+// USB config
+#define MICROPY_HW_USB_FS (1)
+#define MICROPY_HW_USB_OTG_ID_PIN (pin_A10)
diff --git a/ports/stm32/boards/STM32L496GDISC/mpconfigboard.mk b/ports/stm32/boards/STM32L496GDISC/mpconfigboard.mk
new file mode 100644
index 000000000..3a6174655
--- /dev/null
+++ b/ports/stm32/boards/STM32L496GDISC/mpconfigboard.mk
@@ -0,0 +1,7 @@
+MCU_SERIES = l4
+CMSIS_MCU = STM32L496xx
+AF_FILE = boards/stm32l496_af.csv
+LD_FILES = boards/stm32l496xg.ld boards/common_ifs.ld
+TEXT0_ADDR = 0x08000000
+TEXT1_ADDR = 0x08004000
+OPENOCD_CONFIG = boards/openocd_stm32l4.cfg
diff --git a/ports/stm32/boards/STM32L496GDISC/pins.csv b/ports/stm32/boards/STM32L496GDISC/pins.csv
new file mode 100644
index 000000000..2ee054032
--- /dev/null
+++ b/ports/stm32/boards/STM32L496GDISC/pins.csv
@@ -0,0 +1,140 @@
+PA0,PA0
+PA1,PA1
+PA2,PA2
+PA3,PA3
+PA4,PA4
+PA5,PA5
+PA6,PA6
+PA7,PA7
+PA8,PA8
+PA9,PA9
+PA10,PA10
+PA11,PA11
+PA12,PA12
+PA13,PA13
+PA14,PA14
+PA15,PA15
+PB0,PB0
+PB1,PB1
+PB2,PB2
+PB3,PB3
+PB4,PB4
+PB5,PB5
+PB6,PB6
+PB7,PB7
+PB8,PB8
+PB9,PB9
+PB10,PB10
+PB11,PB11
+PB12,PB12
+PB13,PB13
+PB14,PB14
+PB15,PB15
+PC0,PC0
+PC1,PC1
+PC2,PC2
+PC3,PC3
+PC4,PC4
+PC5,PC5
+PC6,PC6
+PC7,PC7
+PC8,PC8
+PC9,PC9
+PC10,PC10
+PC11,PC11
+PC12,PC12
+PC13,PC13
+PC14,PC14
+PC15,PC15
+PD0,PD0
+PD1,PD1
+PD2,PD2
+PD3,PD3
+PD4,PD4
+PD5,PD5
+PD6,PD6
+PD7,PD7
+PD8,PD8
+PD9,PD9
+PD10,PD10
+PD11,PD11
+PD12,PD12
+PD13,PD13
+PD14,PD14
+PD15,PD15
+PE0,PE0
+PE1,PE1
+PE2,PE2
+PE3,PE3
+PE4,PE4
+PE5,PE5
+PE6,PE6
+PE7,PE7
+PE8,PE8
+PE9,PE9
+PE10,PE10
+PE11,PE11
+PE12,PE12
+PE13,PE13
+PE14,PE14
+PE15,PE15
+PF0,PF0
+PF1,PF1
+PF2,PF2
+PF3,PF3
+PF4,PF4
+PF5,PF5
+PF6,PF6
+PF7,PF7
+PF8,PF8
+PF9,PF9
+PF10,PF10
+PF11,PF11
+PF12,PF12
+PF13,PF13
+PF14,PF14
+PF15,PF15
+PG0,PG0
+PG1,PG1
+PG2,PG2
+PG3,PG3
+PG4,PG4
+PG5,PG5
+PG6,PG6
+PG7,PG7
+PG8,PG8
+PG9,PG9
+PG10,PG10
+PG11,PG11
+PG12,PG12
+PG13,PG13
+PG14,PG14
+PG15,PG15
+PH0,PH0
+PH1,PH1
+PH2,PH2
+PH3,PH3
+PH4,PH4
+PH5,PH5
+PH6,PH6
+PH7,PH7
+PH8,PH8
+PH9,PH9
+PH10,PH10
+PH11,PH11
+PH12,PH12
+PH13,PH13
+PH14,PH14
+PH15,PH15
+PI0,PI0
+PI1,PI1
+PI2,PI2
+PI3,PI3
+PI4,PI4
+PI5,PI5
+PI6,PI6
+PI7,PI7
+PI8,PI8
+PI9,PI9
+PI10,PI10
+PI11,PI11
diff --git a/ports/stm32/boards/STM32L496GDISC/stm32l4xx_hal_conf.h b/ports/stm32/boards/STM32L496GDISC/stm32l4xx_hal_conf.h
new file mode 100644
index 000000000..884db5ef1
--- /dev/null
+++ b/ports/stm32/boards/STM32L496GDISC/stm32l4xx_hal_conf.h
@@ -0,0 +1,421 @@
+/**
+ ******************************************************************************
+ * @file stm32l4xx_hal_conf.h
+ * @brief HAL configuration file.
+ ******************************************************************************
+ * @attention
+ *
+ * <h2><center>&copy; COPYRIGHT(c) 2018 STMicroelectronics</center></h2>
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of STMicroelectronics nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ******************************************************************************
+ */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __STM32L4xx_HAL_CONF_H
+#define __STM32L4xx_HAL_CONF_H
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/* Exported types ------------------------------------------------------------*/
+/* Exported constants --------------------------------------------------------*/
+
+/* ########################## Module Selection ############################## */
+/**
+ * @brief This is the list of modules to be used in the HAL driver
+ */
+
+#define HAL_MODULE_ENABLED
+#define HAL_ADC_MODULE_ENABLED
+/*#define HAL_CRYP_MODULE_ENABLED */
+#define HAL_CAN_MODULE_ENABLED
+/* #define HAL_COMP_MODULE_ENABLED */
+/* #define HAL_CRC_MODULE_ENABLED */
+/* #define HAL_CRYP_MODULE_ENABLED */
+#define HAL_DAC_MODULE_ENABLED
+/* #define HAL_DCMI_MODULE_ENABLED */
+/*#define HAL_DMA2D_MODULE_ENABLED */
+/* #define HAL_DFSDM_MODULE_ENABLED */
+/*#define HAL_DSI_MODULE_ENABLED */
+/*#define HAL_FIREWALL_MODULE_ENABLED */
+/*#define HAL_GFXMMU_MODULE_ENABLED */
+/*#define HAL_HCD_MODULE_ENABLED */
+/*#define HAL_HASH_MODULE_ENABLED */
+/*#define HAL_I2S_MODULE_ENABLED */
+/*#define HAL_IRDA_MODULE_ENABLED */
+/*#define HAL_IWDG_MODULE_ENABLED */
+/*#define HAL_LTDC_MODULE_ENABLED */
+/*#define HAL_LCD_MODULE_ENABLED */
+/*#define HAL_LPTIM_MODULE_ENABLED */
+/*#define HAL_NAND_MODULE_ENABLED */
+/*#define HAL_NOR_MODULE_ENABLED */
+/*#define HAL_OPAMP_MODULE_ENABLED */
+/*#define HAL_OSPI_MODULE_ENABLED */
+#define HAL_PCD_MODULE_ENABLED
+#define HAL_RNG_MODULE_ENABLED
+#define HAL_RTC_MODULE_ENABLED
+/* #define HAL_SAI_MODULE_ENABLED */
+#define HAL_SD_MODULE_ENABLED
+/* #define HAL_SMBUS_MODULE_ENABLED */
+/* #define HAL_SMARTCARD_MODULE_ENABLED */
+#define HAL_SPI_MODULE_ENABLED
+/*#define HAL_SRAM_MODULE_ENABLED */
+/*#define HAL_SWPMI_MODULE_ENABLED */
+#define HAL_TIM_MODULE_ENABLED
+/*#define HAL_TSC_MODULE_ENABLED */
+#define HAL_UART_MODULE_ENABLED
+/*#define HAL_USART_MODULE_ENABLED */
+/*#define HAL_WWDG_MODULE_ENABLED */
+#define HAL_GPIO_MODULE_ENABLED
+#define HAL_I2C_MODULE_ENABLED
+#define HAL_DMA_MODULE_ENABLED
+#define HAL_RCC_MODULE_ENABLED
+#define HAL_FLASH_MODULE_ENABLED
+#define HAL_PWR_MODULE_ENABLED
+#define HAL_CORTEX_MODULE_ENABLED
+
+/* ########################## Oscillator Values adaptation ####################*/
+/**
+ * @brief Adjust the value of External High Speed oscillator (HSE) used in your application.
+ * This value is used by the RCC HAL module to compute the system frequency
+ * (when HSE is used as system clock source, directly or through the PLL).
+ */
+#if !defined (HSE_VALUE)
+ #define HSE_VALUE ((uint32_t)8000000) /*!< Value of the External oscillator in Hz */
+#endif /* HSE_VALUE */
+
+#if !defined (HSE_STARTUP_TIMEOUT)
+ #define HSE_STARTUP_TIMEOUT ((uint32_t)100) /*!< Time out for HSE start up, in ms */
+#endif /* HSE_STARTUP_TIMEOUT */
+
+/**
+ * @brief Internal Multiple Speed oscillator (MSI) default value.
+ * This value is the default MSI range value after Reset.
+ */
+#if !defined (MSI_VALUE)
+ #define MSI_VALUE ((uint32_t)4000000) /*!< Value of the Internal oscillator in Hz*/
+#endif /* MSI_VALUE */
+/**
+ * @brief Internal High Speed oscillator (HSI) value.
+ * This value is used by the RCC HAL module to compute the system frequency
+ * (when HSI is used as system clock source, directly or through the PLL).
+ */
+#if !defined (HSI_VALUE)
+ #define HSI_VALUE ((uint32_t)16000000) /*!< Value of the Internal oscillator in Hz*/
+#endif /* HSI_VALUE */
+
+ /**
+ * @brief Internal High Speed oscillator (HSI48) value for USB FS, SDMMC and RNG.
+ * This internal oscillator is mainly dedicated to provide a high precision clock to
+ * the USB peripheral by means of a special Clock Recovery System (CRS) circuitry.
+ * When the CRS is not used, the HSI48 RC oscillator runs on it default frequency
+ * which is subject to manufacturing process variations.
+ */
+ #if !defined (HSI48_VALUE)
+ #define HSI48_VALUE ((uint32_t)48000000U) /*!< Value of the Internal High Speed oscillator for USB FS/SDMMC/RNG in Hz.
+ The real value my vary depending on manufacturing process variations.*/
+ #endif /* HSI48_VALUE */
+
+/**
+ * @brief Internal Low Speed oscillator (LSI) value.
+ */
+#if !defined (LSI_VALUE)
+ #define LSI_VALUE ((uint32_t)32000) /*!< LSI Typical Value in Hz*/
+#endif /* LSI_VALUE */ /*!< Value of the Internal Low Speed oscillator in Hz
+ The real value may vary depending on the variations
+ in voltage and temperature. */
+/**
+ * @brief External Low Speed oscillator (LSE) value.
+ * This value is used by the UART, RTC HAL module to compute the system frequency
+ */
+#if !defined (LSE_VALUE)
+ #define LSE_VALUE ((uint32_t)32768) /*!< Value of the External oscillator in Hz*/
+#endif /* LSE_VALUE */
+
+#if !defined (LSE_STARTUP_TIMEOUT)
+ #define LSE_STARTUP_TIMEOUT ((uint32_t)5000) /*!< Time out for LSE start up, in ms */
+#endif /* HSE_STARTUP_TIMEOUT */
+
+/**
+ * @brief External clock source for SAI1 peripheral
+ * This value is used by the RCC HAL module to compute the SAI1 & SAI2 clock source
+ * frequency.
+ */
+#if !defined (EXTERNAL_SAI1_CLOCK_VALUE)
+ #define EXTERNAL_SAI1_CLOCK_VALUE ((uint32_t)48000) /*!< Value of the SAI1 External clock source in Hz*/
+#endif /* EXTERNAL_SAI1_CLOCK_VALUE */
+
+/**
+ * @brief External clock source for SAI2 peripheral
+ * This value is used by the RCC HAL module to compute the SAI1 & SAI2 clock source
+ * frequency.
+ */
+#if !defined (EXTERNAL_SAI2_CLOCK_VALUE)
+ #define EXTERNAL_SAI2_CLOCK_VALUE ((uint32_t)48000) /*!< Value of the SAI2 External clock source in Hz*/
+#endif /* EXTERNAL_SAI2_CLOCK_VALUE */
+
+/* Tip: To avoid modifying this file each time you need to use different HSE,
+ === you can define the HSE value in your toolchain compiler preprocessor. */
+
+/* ########################### System Configuration ######################### */
+/**
+ * @brief This is the HAL system configuration section
+ */
+#define VDD_VALUE ((uint32_t)3300) /*!< Value of VDD in mv */
+#define TICK_INT_PRIORITY ((uint32_t)0x00) /*!< tick interrupt priority */
+#define USE_RTOS 0
+#define PREFETCH_ENABLE 1
+#define INSTRUCTION_CACHE_ENABLE 1
+#define DATA_CACHE_ENABLE 1
+
+/* ########################## Assert Selection ############################## */
+/**
+ * @brief Uncomment the line below to expanse the "assert_param" macro in the
+ * HAL drivers code
+ */
+/* #define USE_FULL_ASSERT 1 */
+
+/* CRC FEATURE: Use to activate CRC feature inside HAL SPI Driver
+ * Activated: CRC code is present inside driver
+ * Deactivated: CRC code cleaned from driver
+ */
+
+#define USE_SPI_CRC 0
+
+/* Includes ------------------------------------------------------------------*/
+/**
+ * @brief Include module's header file
+ */
+
+#ifdef HAL_RCC_MODULE_ENABLED
+ #include "stm32l4xx_hal_rcc.h"
+ #include "stm32l4xx_hal_rcc_ex.h"
+#endif /* HAL_RCC_MODULE_ENABLED */
+
+#ifdef HAL_GPIO_MODULE_ENABLED
+ #include "stm32l4xx_hal_gpio.h"
+#endif /* HAL_GPIO_MODULE_ENABLED */
+
+#ifdef HAL_DMA_MODULE_ENABLED
+ #include "stm32l4xx_hal_dma.h"
+#endif /* HAL_DMA_MODULE_ENABLED */
+
+#ifdef HAL_DFSDM_MODULE_ENABLED
+ #include "stm32l4xx_hal_dfsdm.h"
+#endif /* HAL_DFSDM_MODULE_ENABLED */
+
+#ifdef HAL_CORTEX_MODULE_ENABLED
+ #include "stm32l4xx_hal_cortex.h"
+#endif /* HAL_CORTEX_MODULE_ENABLED */
+
+#ifdef HAL_ADC_MODULE_ENABLED
+ #include "stm32l4xx_hal_adc.h"
+#endif /* HAL_ADC_MODULE_ENABLED */
+
+#ifdef HAL_CAN_MODULE_ENABLED
+ #include "stm32l4xx_hal_can.h"
+#endif /* HAL_CAN_MODULE_ENABLED */
+
+#ifdef HAL_COMP_MODULE_ENABLED
+ #include "stm32l4xx_hal_comp.h"
+#endif /* HAL_COMP_MODULE_ENABLED */
+
+#ifdef HAL_CRC_MODULE_ENABLED
+ #include "stm32l4xx_hal_crc.h"
+#endif /* HAL_CRC_MODULE_ENABLED */
+
+#ifdef HAL_CRYP_MODULE_ENABLED
+ #include "stm32l4xx_hal_cryp.h"
+#endif /* HAL_CRYP_MODULE_ENABLED */
+
+#ifdef HAL_DAC_MODULE_ENABLED
+ #include "stm32l4xx_hal_dac.h"
+#endif /* HAL_DAC_MODULE_ENABLED */
+
+#ifdef HAL_DCMI_MODULE_ENABLED
+ #include "stm32l4xx_hal_dcmi.h"
+#endif /* HAL_DCMI_MODULE_ENABLED */
+
+#ifdef HAL_DMA2D_MODULE_ENABLED
+ #include "stm32l4xx_hal_dma2d.h"
+#endif /* HAL_DMA2D_MODULE_ENABLED */
+
+#ifdef HAL_DSI_MODULE_ENABLED
+ #include "stm32l4xx_hal_dsi.h"
+#endif /* HAL_DSI_MODULE_ENABLED */
+
+#ifdef HAL_FIREWALL_MODULE_ENABLED
+ #include "stm32l4xx_hal_firewall.h"
+#endif /* HAL_FIREWALL_MODULE_ENABLED */
+
+#ifdef HAL_FLASH_MODULE_ENABLED
+ #include "stm32l4xx_hal_flash.h"
+#endif /* HAL_FLASH_MODULE_ENABLED */
+
+#ifdef HAL_HASH_MODULE_ENABLED
+ #include "stm32l4xx_hal_hash.h"
+#endif /* HAL_HASH_MODULE_ENABLED */
+
+#ifdef HAL_SRAM_MODULE_ENABLED
+ #include "stm32l4xx_hal_sram.h"
+#endif /* HAL_SRAM_MODULE_ENABLED */
+
+#ifdef HAL_NOR_MODULE_ENABLED
+ #include "stm32l4xx_hal_nor.h"
+#endif /* HAL_NOR_MODULE_ENABLED */
+
+#ifdef HAL_NAND_MODULE_ENABLED
+ #include "stm32l4xx_hal_nand.h"
+#endif /* HAL_NAND_MODULE_ENABLED */
+
+#ifdef HAL_I2C_MODULE_ENABLED
+ #include "stm32l4xx_hal_i2c.h"
+#endif /* HAL_I2C_MODULE_ENABLED */
+
+#ifdef HAL_IWDG_MODULE_ENABLED
+ #include "stm32l4xx_hal_iwdg.h"
+#endif /* HAL_IWDG_MODULE_ENABLED */
+
+#ifdef HAL_LCD_MODULE_ENABLED
+ #include "stm32l4xx_hal_lcd.h"
+#endif /* HAL_LCD_MODULE_ENABLED */
+
+#ifdef HAL_LPTIM_MODULE_ENABLED
+ #include "stm32l4xx_hal_lptim.h"
+#endif /* HAL_LPTIM_MODULE_ENABLED */
+
+#ifdef HAL_LTDC_MODULE_ENABLED
+ #include "stm32l4xx_hal_ltdc.h"
+#endif /* HAL_LTDC_MODULE_ENABLED */
+
+#ifdef HAL_OPAMP_MODULE_ENABLED
+ #include "stm32l4xx_hal_opamp.h"
+#endif /* HAL_OPAMP_MODULE_ENABLED */
+
+#ifdef HAL_OSPI_MODULE_ENABLED
+ #include "stm32l4xx_hal_ospi.h"
+#endif /* HAL_OSPI_MODULE_ENABLED */
+
+#ifdef HAL_PWR_MODULE_ENABLED
+ #include "stm32l4xx_hal_pwr.h"
+#endif /* HAL_PWR_MODULE_ENABLED */
+
+#ifdef HAL_QSPI_MODULE_ENABLED
+ #include "stm32l4xx_hal_qspi.h"
+#endif /* HAL_QSPI_MODULE_ENABLED */
+
+#ifdef HAL_RNG_MODULE_ENABLED
+ #include "stm32l4xx_hal_rng.h"
+#endif /* HAL_RNG_MODULE_ENABLED */
+
+#ifdef HAL_RTC_MODULE_ENABLED
+ #include "stm32l4xx_hal_rtc.h"
+#endif /* HAL_RTC_MODULE_ENABLED */
+
+#ifdef HAL_SAI_MODULE_ENABLED
+ #include "stm32l4xx_hal_sai.h"
+#endif /* HAL_SAI_MODULE_ENABLED */
+
+#ifdef HAL_SD_MODULE_ENABLED
+ #include "stm32l4xx_hal_sd.h"
+#endif /* HAL_SD_MODULE_ENABLED */
+
+#ifdef HAL_SMBUS_MODULE_ENABLED
+ #include "stm32l4xx_hal_smbus.h"
+#endif /* HAL_SMBUS_MODULE_ENABLED */
+
+#ifdef HAL_SPI_MODULE_ENABLED
+ #include "stm32l4xx_hal_spi.h"
+#endif /* HAL_SPI_MODULE_ENABLED */
+
+#ifdef HAL_SWPMI_MODULE_ENABLED
+ #include "stm32l4xx_hal_swpmi.h"
+#endif /* HAL_SWPMI_MODULE_ENABLED */
+
+#ifdef HAL_TIM_MODULE_ENABLED
+ #include "stm32l4xx_hal_tim.h"
+#endif /* HAL_TIM_MODULE_ENABLED */
+
+#ifdef HAL_TSC_MODULE_ENABLED
+ #include "stm32l4xx_hal_tsc.h"
+#endif /* HAL_TSC_MODULE_ENABLED */
+
+#ifdef HAL_UART_MODULE_ENABLED
+ #include "stm32l4xx_hal_uart.h"
+#endif /* HAL_UART_MODULE_ENABLED */
+
+#ifdef HAL_USART_MODULE_ENABLED
+ #include "stm32l4xx_hal_usart.h"
+#endif /* HAL_USART_MODULE_ENABLED */
+
+#ifdef HAL_IRDA_MODULE_ENABLED
+ #include "stm32l4xx_hal_irda.h"
+#endif /* HAL_IRDA_MODULE_ENABLED */
+
+#ifdef HAL_SMARTCARD_MODULE_ENABLED
+ #include "stm32l4xx_hal_smartcard.h"
+#endif /* HAL_SMARTCARD_MODULE_ENABLED */
+
+#ifdef HAL_WWDG_MODULE_ENABLED
+ #include "stm32l4xx_hal_wwdg.h"
+#endif /* HAL_WWDG_MODULE_ENABLED */
+
+#ifdef HAL_PCD_MODULE_ENABLED
+ #include "stm32l4xx_hal_pcd.h"
+#endif /* HAL_PCD_MODULE_ENABLED */
+
+#ifdef HAL_HCD_MODULE_ENABLED
+ #include "stm32l4xx_hal_hcd.h"
+#endif /* HAL_HCD_MODULE_ENABLED */
+
+#ifdef HAL_GFXMMU_MODULE_ENABLED
+ #include "stm32l4xx_hal_gfxmmu.h"
+#endif /* HAL_GFXMMU_MODULE_ENABLED */
+
+/* Exported macro ------------------------------------------------------------*/
+#ifdef USE_FULL_ASSERT
+/**
+ * @brief The assert_param macro is used for function's parameters check.
+ * @param expr: If expr is false, it calls assert_failed function
+ * which reports the name of the source file and the source
+ * line number of the call that failed.
+ * If expr is true, it returns no value.
+ * @retval None
+ */
+ #define assert_param(expr) ((expr) ? (void)0U : assert_failed((uint8_t *)__FILE__, __LINE__))
+/* Exported functions ------------------------------------------------------- */
+ void assert_failed(uint8_t* file, uint32_t line);
+#else
+ #define assert_param(expr) ((void)0U)
+#endif /* USE_FULL_ASSERT */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __STM32L4xx_HAL_CONF_H */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/ports/stm32/boards/common_basic.ld b/ports/stm32/boards/common_basic.ld
new file mode 100644
index 000000000..2e428aa62
--- /dev/null
+++ b/ports/stm32/boards/common_basic.ld
@@ -0,0 +1,86 @@
+/* Memory layout for basic configuration:
+
+ FLASH .isr_vector
+ FLASH .text
+ FLASH .data
+
+ RAM .data
+ RAM .bss
+ RAM .heap
+ RAM .stack
+*/
+
+ENTRY(Reset_Handler)
+
+/* define output sections */
+SECTIONS
+{
+ /* The startup code goes first into FLASH */
+ .isr_vector :
+ {
+ . = ALIGN(4);
+ KEEP(*(.isr_vector)) /* Startup code */
+
+ . = ALIGN(4);
+ } >FLASH
+
+ /* The program code and other data goes into FLASH */
+ .text :
+ {
+ . = ALIGN(4);
+ *(.text*) /* .text* sections (code) */
+ *(.rodata*) /* .rodata* sections (constants, strings, etc.) */
+ /* *(.glue_7) */ /* glue arm to thumb code */
+ /* *(.glue_7t) */ /* glue thumb to arm code */
+
+ . = ALIGN(4);
+ _etext = .; /* define a global symbol at end of code */
+ } >FLASH
+
+ /* used by the startup to initialize data */
+ _sidata = LOADADDR(.data);
+
+ /* This is the initialized data section
+ The program executes knowing that the data is in the RAM
+ but the loader puts the initial values in the FLASH (inidata).
+ It is one task of the startup to copy the initial values from FLASH to RAM. */
+ .data :
+ {
+ . = ALIGN(4);
+ _sdata = .; /* create a global symbol at data start; used by startup code in order to initialise the .data section in RAM */
+ *(.data*) /* .data* sections */
+
+ . = ALIGN(4);
+ _edata = .; /* define a global symbol at data end; used by startup code in order to initialise the .data section in RAM */
+ } >RAM AT> FLASH
+
+ /* Uninitialized data section */
+ .bss :
+ {
+ . = ALIGN(4);
+ _sbss = .; /* define a global symbol at bss start; used by startup code */
+ *(.bss*)
+ *(COMMON)
+
+ . = ALIGN(4);
+ _ebss = .; /* define a global symbol at bss end; used by startup code and GC */
+ } >RAM
+
+ /* this is to define the start of the heap, and make sure we have a minimum size */
+ .heap :
+ {
+ . = ALIGN(4);
+ . = . + _minimum_heap_size;
+ . = ALIGN(4);
+ } >RAM
+
+ /* this just checks there is enough RAM for the stack */
+ .stack :
+ {
+ . = ALIGN(4);
+ . = . + _minimum_stack_size;
+ . = ALIGN(4);
+ } >RAM
+
+ .ARM.attributes 0 : { *(.ARM.attributes) }
+}
diff --git a/ports/stm32/boards/common_bl.ld b/ports/stm32/boards/common_bl.ld
new file mode 100644
index 000000000..52b2a677d
--- /dev/null
+++ b/ports/stm32/boards/common_bl.ld
@@ -0,0 +1,86 @@
+/* Memory layout for bootloader configuration (this here describes the app part):
+
+ FLASH_APP .isr_vector
+ FLASH_APP .text
+ FLASH_APP .data
+
+ RAM .data
+ RAM .bss
+ RAM .heap
+ RAM .stack
+*/
+
+ENTRY(Reset_Handler)
+
+/* define output sections */
+SECTIONS
+{
+ /* The startup code goes first into FLASH */
+ .isr_vector :
+ {
+ . = ALIGN(4);
+ KEEP(*(.isr_vector)) /* Startup code */
+
+ . = ALIGN(4);
+ } >FLASH_APP
+
+ /* The program code and other data goes into FLASH */
+ .text :
+ {
+ . = ALIGN(4);
+ *(.text*) /* .text* sections (code) */
+ *(.rodata*) /* .rodata* sections (constants, strings, etc.) */
+ /* *(.glue_7) */ /* glue arm to thumb code */
+ /* *(.glue_7t) */ /* glue thumb to arm code */
+
+ . = ALIGN(4);
+ _etext = .; /* define a global symbol at end of code */
+ } >FLASH_APP
+
+ /* used by the startup to initialize data */
+ _sidata = LOADADDR(.data);
+
+ /* This is the initialized data section
+ The program executes knowing that the data is in the RAM
+ but the loader puts the initial values in the FLASH (inidata).
+ It is one task of the startup to copy the initial values from FLASH to RAM. */
+ .data :
+ {
+ . = ALIGN(4);
+ _sdata = .; /* create a global symbol at data start; used by startup code in order to initialise the .data section in RAM */
+ *(.data*) /* .data* sections */
+
+ . = ALIGN(4);
+ _edata = .; /* define a global symbol at data end; used by startup code in order to initialise the .data section in RAM */
+ } >RAM AT> FLASH_APP
+
+ /* Uninitialized data section */
+ .bss :
+ {
+ . = ALIGN(4);
+ _sbss = .; /* define a global symbol at bss start; used by startup code */
+ *(.bss*)
+ *(COMMON)
+
+ . = ALIGN(4);
+ _ebss = .; /* define a global symbol at bss end; used by startup code and GC */
+ } >RAM
+
+ /* this is to define the start of the heap, and make sure we have a minimum size */
+ .heap :
+ {
+ . = ALIGN(4);
+ . = . + _minimum_heap_size;
+ . = ALIGN(4);
+ } >RAM
+
+ /* this just checks there is enough RAM for the stack */
+ .stack :
+ {
+ . = ALIGN(4);
+ . = . + _minimum_stack_size;
+ . = ALIGN(4);
+ } >RAM
+
+ .ARM.attributes 0 : { *(.ARM.attributes) }
+}
diff --git a/ports/stm32/boards/common.ld b/ports/stm32/boards/common_ifs.ld
index e5dea49d0..74b2ffb41 100644
--- a/ports/stm32/boards/common.ld
+++ b/ports/stm32/boards/common_ifs.ld
@@ -1,3 +1,16 @@
+/* Memory layout for internal flash storage configuration:
+
+ FLASH_ISR .isr_vector
+
+ FLASH_TEXT .text
+ FLASH_TEXT .data
+
+ RAM .data
+ RAM .bss
+ RAM .heap
+ RAM .stack
+*/
+
ENTRY(Reset_Handler)
/* define output sections */
diff --git a/ports/stm32/boards/make-pins.py b/ports/stm32/boards/make-pins.py
index 210c7b63c..70f154fde 100755
--- a/ports/stm32/boards/make-pins.py
+++ b/ports/stm32/boards/make-pins.py
@@ -16,6 +16,7 @@ SUPPORTED_FN = {
'UART' : ['RX', 'TX', 'CTS', 'RTS'],
'SPI' : ['NSS', 'SCK', 'MISO', 'MOSI'],
'SDMMC' : ['CK', 'CMD', 'D0', 'D1', 'D2', 'D3'],
+ 'CAN' : ['TX', 'RX'],
}
CONDITIONAL_VAR = {
@@ -25,6 +26,7 @@ CONDITIONAL_VAR = {
'UART' : 'MICROPY_HW_UART{num}_TX',
'USART' : 'MICROPY_HW_UART{num}_TX',
'SDMMC' : 'MICROPY_HW_SDMMC{num}_CK',
+ 'CAN' : 'MICROPY_HW_CAN{num}_TX',
}
def parse_port_pin(name_str):
@@ -207,18 +209,18 @@ class Pin(object):
print("// ", end='')
print('};')
print('')
- print('const pin_obj_t pin_{:s} = PIN({:s}, {:d}, {:s}, {:s}, {:d});'.format(
+ print('const pin_obj_t pin_{:s}_obj = PIN({:s}, {:d}, {:s}, {:s}, {:d});'.format(
self.cpu_pin_name(), self.port_letter(), self.pin,
self.alt_fn_name(null_if_0=True),
self.adc_num_str(), self.adc_channel))
print('')
def print_header(self, hdr_file):
- hdr_file.write('extern const pin_obj_t pin_{:s};\n'.
- format(self.cpu_pin_name()))
+ n = self.cpu_pin_name()
+ hdr_file.write('extern const pin_obj_t pin_{:s}_obj;\n'.format(n))
+ hdr_file.write('#define pin_{:s} (&pin_{:s}_obj)\n'.format(n, n))
if self.alt_fn_count > 0:
- hdr_file.write('extern const pin_af_obj_t pin_{:s}_af[];\n'.
- format(self.cpu_pin_name()))
+ hdr_file.write('extern const pin_af_obj_t pin_{:s}_af[];\n'.format(n))
def qstr_list(self):
result = []
@@ -287,7 +289,7 @@ class Pins(object):
for named_pin in named_pins:
pin = named_pin.pin()
if pin.is_board_pin():
- print(' {{ MP_ROM_QSTR(MP_QSTR_{:s}), MP_ROM_PTR(&pin_{:s}) }},'.format(named_pin.name(), pin.cpu_pin_name()))
+ print(' {{ MP_ROM_QSTR(MP_QSTR_{:s}), MP_ROM_PTR(&pin_{:s}_obj) }},'.format(named_pin.name(), pin.cpu_pin_name()))
print('};')
print('MP_DEFINE_CONST_DICT(pin_{:s}_pins_locals_dict, pin_{:s}_pins_locals_dict_table);'.format(label, label));
@@ -305,13 +307,13 @@ class Pins(object):
print('const pin_obj_t * const pin_adc{:d}[] = {{'.format(adc_num))
for channel in range(17):
if channel == 16:
- print('#if defined(MCU_SERIES_L4)')
+ print('#if defined(STM32L4)')
adc_found = False
for named_pin in self.cpu_pins:
pin = named_pin.pin()
if (pin.is_board_pin() and
(pin.adc_num & (1 << (adc_num - 1))) and (pin.adc_channel == channel)):
- print(' &pin_{:s}, // {:d}'.format(pin.cpu_pin_name(), channel))
+ print(' &pin_{:s}_obj, // {:d}'.format(pin.cpu_pin_name(), channel))
adc_found = True
break
if not adc_found:
diff --git a/ports/stm32/boards/startup_stm32f0.s b/ports/stm32/boards/startup_stm32f0.s
new file mode 100644
index 000000000..eb5c4961e
--- /dev/null
+++ b/ports/stm32/boards/startup_stm32f0.s
@@ -0,0 +1,303 @@
+/**
+ ******************************************************************************
+ * @file startup_stm32f091xc.s
+ * @author MCD Application Team
+ * @brief STM32F091xC devices vector table for GCC toolchain.
+ * This module performs:
+ * - Set the initial SP
+ * - Set the initial PC == Reset_Handler,
+ * - Set the vector table entries with the exceptions ISR address
+ * - Branches to main in the C library (which eventually
+ * calls main()).
+ * After Reset the Cortex-M0 processor is in Thread mode,
+ * priority is Privileged, and the Stack is set to Main.
+ ******************************************************************************
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of STMicroelectronics nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ******************************************************************************
+ */
+
+ .syntax unified
+ .cpu cortex-m0
+ .fpu softvfp
+ .thumb
+
+.global g_pfnVectors
+.global Default_Handler
+
+/* start address for the initialization values of the .data section.
+defined in linker script */
+.word _sidata
+/* start address for the .data section. defined in linker script */
+.word _sdata
+/* end address for the .data section. defined in linker script */
+.word _edata
+/* start address for the .bss section. defined in linker script */
+.word _sbss
+/* end address for the .bss section. defined in linker script */
+.word _ebss
+
+ .section .text.Reset_Handler
+ .weak Reset_Handler
+ .type Reset_Handler, %function
+Reset_Handler:
+ ldr r0, =_estack
+ mov sp, r0 /* set stack pointer */
+
+/* Copy the data segment initializers from flash to SRAM */
+ ldr r0, =_sdata
+ ldr r1, =_edata
+ ldr r2, =_sidata
+ movs r3, #0
+ b LoopCopyDataInit
+
+CopyDataInit:
+ ldr r4, [r2, r3]
+ str r4, [r0, r3]
+ adds r3, r3, #4
+
+LoopCopyDataInit:
+ adds r4, r0, r3
+ cmp r4, r1
+ bcc CopyDataInit
+
+/* Zero fill the bss segment. */
+ ldr r2, =_sbss
+ ldr r4, =_ebss
+ movs r3, #0
+ b LoopFillZerobss
+
+FillZerobss:
+ str r3, [r2]
+ adds r2, r2, #4
+
+LoopFillZerobss:
+ cmp r2, r4
+ bcc FillZerobss
+
+/* Call the clock system intitialization function.*/
+ bl SystemInit
+/* Call static constructors */
+ /*bl __libc_init_array*/
+/* Call the application's entry point.*/
+ bl main
+
+LoopForever:
+ b LoopForever
+
+
+.size Reset_Handler, .-Reset_Handler
+
+/**
+ * @brief This is the code that gets called when the processor receives an
+ * unexpected interrupt. This simply enters an infinite loop, preserving
+ * the system state for examination by a debugger.
+ *
+ * @param None
+ * @retval : None
+*/
+ .section .text.Default_Handler,"ax",%progbits
+Default_Handler:
+Infinite_Loop:
+ b Infinite_Loop
+ .size Default_Handler, .-Default_Handler
+/******************************************************************************
+*
+* The minimal vector table for a Cortex M0. Note that the proper constructs
+* must be placed on this to ensure that it ends up at physical address
+* 0x0000.0000.
+*
+******************************************************************************/
+ .section .isr_vector,"a",%progbits
+ .type g_pfnVectors, %object
+ .size g_pfnVectors, .-g_pfnVectors
+
+
+g_pfnVectors:
+ .word _estack
+ .word Reset_Handler
+ .word NMI_Handler
+ .word HardFault_Handler
+ .word 0
+ .word 0
+ .word 0
+ .word 0
+ .word 0
+ .word 0
+ .word 0
+ .word SVC_Handler
+ .word 0
+ .word 0
+ .word PendSV_Handler
+ .word SysTick_Handler
+ .word WWDG_IRQHandler /* Window WatchDog */
+ .word PVD_VDDIO2_IRQHandler /* PVD and VDDIO2 through EXTI Line detect */
+ .word RTC_IRQHandler /* RTC through the EXTI line */
+ .word FLASH_IRQHandler /* FLASH */
+ .word RCC_CRS_IRQHandler /* RCC and CRS */
+ .word EXTI0_1_IRQHandler /* EXTI Line 0 and 1 */
+ .word EXTI2_3_IRQHandler /* EXTI Line 2 and 3 */
+ .word EXTI4_15_IRQHandler /* EXTI Line 4 to 15 */
+ .word TSC_IRQHandler /* TSC */
+ .word DMA1_Ch1_IRQHandler /* DMA1 Channel 1 */
+ .word DMA1_Ch2_3_DMA2_Ch1_2_IRQHandler /* DMA1 Channel 2 and 3 & DMA2 Channel 1 and 2 */
+ .word DMA1_Ch4_7_DMA2_Ch3_5_IRQHandler /* DMA1 Channel 4 to 7 & DMA2 Channel 3 to 5 */
+ .word ADC1_COMP_IRQHandler /* ADC1, COMP1 and COMP2 */
+ .word TIM1_BRK_UP_TRG_COM_IRQHandler /* TIM1 Break, Update, Trigger and Commutation */
+ .word TIM1_CC_IRQHandler /* TIM1 Capture Compare */
+ .word TIM2_IRQHandler /* TIM2 */
+ .word TIM3_IRQHandler /* TIM3 */
+ .word TIM6_DAC_IRQHandler /* TIM6 and DAC */
+ .word TIM7_IRQHandler /* TIM7 */
+ .word TIM14_IRQHandler /* TIM14 */
+ .word TIM15_IRQHandler /* TIM15 */
+ .word TIM16_IRQHandler /* TIM16 */
+ .word TIM17_IRQHandler /* TIM17 */
+ .word I2C1_IRQHandler /* I2C1 */
+ .word I2C2_IRQHandler /* I2C2 */
+ .word SPI1_IRQHandler /* SPI1 */
+ .word SPI2_IRQHandler /* SPI2 */
+ .word USART1_IRQHandler /* USART1 */
+ .word USART2_IRQHandler /* USART2 */
+ .word USART3_8_IRQHandler /* USART3, USART4, USART5, USART6, USART7, USART8 */
+ .word CEC_CAN_IRQHandler /* CEC and CAN */
+
+/*******************************************************************************
+*
+* Provide weak aliases for each Exception handler to the Default_Handler.
+* As they are weak aliases, any function with the same name will override
+* this definition.
+*
+*******************************************************************************/
+
+ .weak NMI_Handler
+ .thumb_set NMI_Handler,Default_Handler
+
+ .weak HardFault_Handler
+ .thumb_set HardFault_Handler,Default_Handler
+
+ .weak SVC_Handler
+ .thumb_set SVC_Handler,Default_Handler
+
+ .weak PendSV_Handler
+ .thumb_set PendSV_Handler,Default_Handler
+
+ .weak SysTick_Handler
+ .thumb_set SysTick_Handler,Default_Handler
+
+ .weak WWDG_IRQHandler
+ .thumb_set WWDG_IRQHandler,Default_Handler
+
+ .weak PVD_VDDIO2_IRQHandler
+ .thumb_set PVD_VDDIO2_IRQHandler,Default_Handler
+
+ .weak RTC_IRQHandler
+ .thumb_set RTC_IRQHandler,Default_Handler
+
+ .weak FLASH_IRQHandler
+ .thumb_set FLASH_IRQHandler,Default_Handler
+
+ .weak RCC_CRS_IRQHandler
+ .thumb_set RCC_CRS_IRQHandler,Default_Handler
+
+ .weak EXTI0_1_IRQHandler
+ .thumb_set EXTI0_1_IRQHandler,Default_Handler
+
+ .weak EXTI2_3_IRQHandler
+ .thumb_set EXTI2_3_IRQHandler,Default_Handler
+
+ .weak EXTI4_15_IRQHandler
+ .thumb_set EXTI4_15_IRQHandler,Default_Handler
+
+ .weak TSC_IRQHandler
+ .thumb_set TSC_IRQHandler,Default_Handler
+
+ .weak DMA1_Ch1_IRQHandler
+ .thumb_set DMA1_Ch1_IRQHandler,Default_Handler
+
+ .weak DMA1_Ch2_3_DMA2_Ch1_2_IRQHandler
+ .thumb_set DMA1_Ch2_3_DMA2_Ch1_2_IRQHandler,Default_Handler
+
+ .weak DMA1_Ch4_7_DMA2_Ch3_5_IRQHandler
+ .thumb_set DMA1_Ch4_7_DMA2_Ch3_5_IRQHandler,Default_Handler
+
+ .weak ADC1_COMP_IRQHandler
+ .thumb_set ADC1_COMP_IRQHandler,Default_Handler
+
+ .weak TIM1_BRK_UP_TRG_COM_IRQHandler
+ .thumb_set TIM1_BRK_UP_TRG_COM_IRQHandler,Default_Handler
+
+ .weak TIM1_CC_IRQHandler
+ .thumb_set TIM1_CC_IRQHandler,Default_Handler
+
+ .weak TIM2_IRQHandler
+ .thumb_set TIM2_IRQHandler,Default_Handler
+
+ .weak TIM3_IRQHandler
+ .thumb_set TIM3_IRQHandler,Default_Handler
+
+ .weak TIM6_DAC_IRQHandler
+ .thumb_set TIM6_DAC_IRQHandler,Default_Handler
+
+ .weak TIM7_IRQHandler
+ .thumb_set TIM7_IRQHandler,Default_Handler
+
+ .weak TIM14_IRQHandler
+ .thumb_set TIM14_IRQHandler,Default_Handler
+
+ .weak TIM15_IRQHandler
+ .thumb_set TIM15_IRQHandler,Default_Handler
+
+ .weak TIM16_IRQHandler
+ .thumb_set TIM16_IRQHandler,Default_Handler
+
+ .weak TIM17_IRQHandler
+ .thumb_set TIM17_IRQHandler,Default_Handler
+
+ .weak I2C1_IRQHandler
+ .thumb_set I2C1_IRQHandler,Default_Handler
+
+ .weak I2C2_IRQHandler
+ .thumb_set I2C2_IRQHandler,Default_Handler
+
+ .weak SPI1_IRQHandler
+ .thumb_set SPI1_IRQHandler,Default_Handler
+
+ .weak SPI2_IRQHandler
+ .thumb_set SPI2_IRQHandler,Default_Handler
+
+ .weak USART1_IRQHandler
+ .thumb_set USART1_IRQHandler,Default_Handler
+
+ .weak USART2_IRQHandler
+ .thumb_set USART2_IRQHandler,Default_Handler
+
+ .weak USART3_8_IRQHandler
+ .thumb_set USART3_8_IRQHandler,Default_Handler
+
+ .weak CEC_CAN_IRQHandler
+ .thumb_set CEC_CAN_IRQHandler,Default_Handler
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
+
diff --git a/ports/stm32/boards/startup_stm32f4.s b/ports/stm32/boards/startup_stm32f4.s
new file mode 100644
index 000000000..3e29a79a5
--- /dev/null
+++ b/ports/stm32/boards/startup_stm32f4.s
@@ -0,0 +1,530 @@
+/**
+ ******************************************************************************
+ * @file startup_stm32.S
+ * @author MCD Application Team
+ * @version V2.0.0
+ * @date 18-February-2014
+ * @brief STM32Fxxxxx Devices vector table for Atollic TrueSTUDIO toolchain.
+ * This module performs:
+ * - Set the initial SP
+ * - Set the initial PC == Reset_Handler,
+ * - Set the vector table entries with the exceptions ISR address
+ * - Branches to main in the C library (which eventually
+ * calls main()).
+ * After Reset the Cortex-M4/M7 processor is in Thread mode,
+ * priority is Privileged, and the Stack is set to Main.
+ ******************************************************************************
+ * @attention
+ *
+ * <h2><center>&copy; COPYRIGHT 2014 STMicroelectronics</center></h2>
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of STMicroelectronics nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ******************************************************************************
+ */
+
+ .syntax unified
+ .cpu cortex-m4
+ .fpu softvfp
+ .thumb
+
+.global g_pfnVectors
+.global Default_Handler
+
+/* start address for the initialization values of the .data section.
+defined in linker script */
+.word _sidata
+/* start address for the .data section. defined in linker script */
+.word _sdata
+/* end address for the .data section. defined in linker script */
+.word _edata
+/* start address for the .bss section. defined in linker script */
+.word _sbss
+/* end address for the .bss section. defined in linker script */
+.word _ebss
+/* stack used for SystemInit_ExtMemCtl; always internal RAM used */
+
+/**
+ * @brief This is the code that gets called when the processor first
+ * starts execution following a reset event. Only the absolutely
+ * necessary set is performed, after which the application
+ * supplied main() routine is called.
+ * @param None
+ * @retval : None
+*/
+
+ .section .text.Reset_Handler
+ .weak Reset_Handler
+ .type Reset_Handler, %function
+Reset_Handler:
+ ldr sp, =_estack /* set stack pointer */
+
+/* Copy the data segment initializers from flash to SRAM */
+ movs r1, #0
+ b LoopCopyDataInit
+
+CopyDataInit:
+ ldr r3, =_sidata
+ ldr r3, [r3, r1]
+ str r3, [r0, r1]
+ adds r1, r1, #4
+
+LoopCopyDataInit:
+ ldr r0, =_sdata
+ ldr r3, =_edata
+ adds r2, r0, r1
+ cmp r2, r3
+ bcc CopyDataInit
+ ldr r2, =_sbss
+ b LoopFillZerobss
+/* Zero fill the bss segment. */
+FillZerobss:
+ movs r3, #0
+ str r3, [r2], #4
+
+LoopFillZerobss:
+ ldr r3, = _ebss
+ cmp r2, r3
+ bcc FillZerobss
+
+/* Call the clock system initialization function.*/
+ bl SystemInit
+/* Call static constructors */
+ /*bl __libc_init_array*/
+/* Call the application's entry point.*/
+ bl main
+ bx lr
+.size Reset_Handler, .-Reset_Handler
+
+/**
+ * @brief This is the code that gets called when the processor receives an
+ * unexpected interrupt. This simply enters an infinite loop, preserving
+ * the system state for examination by a debugger.
+ * @param None
+ * @retval None
+*/
+ .section .text.Default_Handler,"ax",%progbits
+Default_Handler:
+Infinite_Loop:
+ b Infinite_Loop
+ .size Default_Handler, .-Default_Handler
+/******************************************************************************
+*
+* The minimal vector table for a Cortex M4/M7. Note that the proper constructs
+* must be placed on this to ensure that it ends up at physical address
+* 0x0000.0000.
+*
+*******************************************************************************/
+ .section .isr_vector,"a",%progbits
+ .type g_pfnVectors, %object
+ .size g_pfnVectors, .-g_pfnVectors
+
+
+g_pfnVectors:
+ .word _estack
+ .word Reset_Handler
+ .word NMI_Handler
+ .word HardFault_Handler
+ .word MemManage_Handler
+ .word BusFault_Handler
+ .word UsageFault_Handler
+ .word 0
+ .word 0
+ .word 0
+ .word 0
+ .word SVC_Handler
+ .word DebugMon_Handler
+ .word 0
+ .word PendSV_Handler
+ .word SysTick_Handler
+
+ /* External Interrupts */
+ .word WWDG_IRQHandler /* Window WatchDog */
+ .word PVD_IRQHandler /* PVD through EXTI Line detection */
+ .word TAMP_STAMP_IRQHandler /* Tamper and TimeStamps through the EXTI line */
+ .word RTC_WKUP_IRQHandler /* RTC Wakeup through the EXTI line */
+ .word FLASH_IRQHandler /* FLASH */
+ .word RCC_IRQHandler /* RCC */
+ .word EXTI0_IRQHandler /* EXTI Line0 */
+ .word EXTI1_IRQHandler /* EXTI Line1 */
+ .word EXTI2_IRQHandler /* EXTI Line2 */
+ .word EXTI3_IRQHandler /* EXTI Line3 */
+ .word EXTI4_IRQHandler /* EXTI Line4 */
+ .word DMA1_Stream0_IRQHandler /* DMA1 Stream 0 */
+ .word DMA1_Stream1_IRQHandler /* DMA1 Stream 1 */
+ .word DMA1_Stream2_IRQHandler /* DMA1 Stream 2 */
+ .word DMA1_Stream3_IRQHandler /* DMA1 Stream 3 */
+ .word DMA1_Stream4_IRQHandler /* DMA1 Stream 4 */
+ .word DMA1_Stream5_IRQHandler /* DMA1 Stream 5 */
+ .word DMA1_Stream6_IRQHandler /* DMA1 Stream 6 */
+ .word ADC_IRQHandler /* ADC1, ADC2 and ADC3s */
+ .word CAN1_TX_IRQHandler /* CAN1 TX */
+ .word CAN1_RX0_IRQHandler /* CAN1 RX0 */
+ .word CAN1_RX1_IRQHandler /* CAN1 RX1 */
+ .word CAN1_SCE_IRQHandler /* CAN1 SCE */
+ .word EXTI9_5_IRQHandler /* External Line[9:5]s */
+ .word TIM1_BRK_TIM9_IRQHandler /* TIM1 Break and TIM9 */
+ .word TIM1_UP_TIM10_IRQHandler /* TIM1 Update and TIM10 */
+ .word TIM1_TRG_COM_TIM11_IRQHandler /* TIM1 Trigger and Commutation and TIM11 */
+ .word TIM1_CC_IRQHandler /* TIM1 Capture Compare */
+ .word TIM2_IRQHandler /* TIM2 */
+ .word TIM3_IRQHandler /* TIM3 */
+ .word TIM4_IRQHandler /* TIM4 */
+ .word I2C1_EV_IRQHandler /* I2C1 Event */
+ .word I2C1_ER_IRQHandler /* I2C1 Error */
+ .word I2C2_EV_IRQHandler /* I2C2 Event */
+ .word I2C2_ER_IRQHandler /* I2C2 Error */
+ .word SPI1_IRQHandler /* SPI1 */
+ .word SPI2_IRQHandler /* SPI2 */
+ .word USART1_IRQHandler /* USART1 */
+ .word USART2_IRQHandler /* USART2 */
+ .word USART3_IRQHandler /* USART3 */
+ .word EXTI15_10_IRQHandler /* External Line[15:10]s */
+ .word RTC_Alarm_IRQHandler /* RTC Alarm (A and B) through EXTI Line */
+ .word OTG_FS_WKUP_IRQHandler /* USB OTG FS Wakeup through EXTI line */
+ .word TIM8_BRK_TIM12_IRQHandler /* TIM8 Break and TIM12 */
+ .word TIM8_UP_TIM13_IRQHandler /* TIM8 Update and TIM13 */
+ .word TIM8_TRG_COM_TIM14_IRQHandler /* TIM8 Trigger and Commutation and TIM14 */
+ .word TIM8_CC_IRQHandler /* TIM8 Capture Compare */
+ .word DMA1_Stream7_IRQHandler /* DMA1 Stream7 */
+ .word FSMC_IRQHandler /* FSMC */
+ .word SDIO_IRQHandler /* SDIO */
+ .word TIM5_IRQHandler /* TIM5 */
+ .word SPI3_IRQHandler /* SPI3 */
+ .word UART4_IRQHandler /* UART4 */
+ .word UART5_IRQHandler /* UART5 */
+ .word TIM6_DAC_IRQHandler /* TIM6 and DAC1&2 underrun errors */
+ .word TIM7_IRQHandler /* TIM7 */
+ .word DMA2_Stream0_IRQHandler /* DMA2 Stream 0 */
+ .word DMA2_Stream1_IRQHandler /* DMA2 Stream 1 */
+ .word DMA2_Stream2_IRQHandler /* DMA2 Stream 2 */
+ .word DMA2_Stream3_IRQHandler /* DMA2 Stream 3 */
+ .word DMA2_Stream4_IRQHandler /* DMA2 Stream 4 */
+ .word ETH_IRQHandler /* Ethernet */
+ .word ETH_WKUP_IRQHandler /* Ethernet Wakeup through EXTI line */
+ .word CAN2_TX_IRQHandler /* CAN2 TX */
+ .word CAN2_RX0_IRQHandler /* CAN2 RX0 */
+ .word CAN2_RX1_IRQHandler /* CAN2 RX1 */
+ .word CAN2_SCE_IRQHandler /* CAN2 SCE */
+ .word OTG_FS_IRQHandler /* USB OTG FS */
+ .word DMA2_Stream5_IRQHandler /* DMA2 Stream 5 */
+ .word DMA2_Stream6_IRQHandler /* DMA2 Stream 6 */
+ .word DMA2_Stream7_IRQHandler /* DMA2 Stream 7 */
+ .word USART6_IRQHandler /* USART6 */
+ .word I2C3_EV_IRQHandler /* I2C3 event */
+ .word I2C3_ER_IRQHandler /* I2C3 error */
+ .word OTG_HS_EP1_OUT_IRQHandler /* USB OTG HS End Point 1 Out */
+ .word OTG_HS_EP1_IN_IRQHandler /* USB OTG HS End Point 1 In */
+ .word OTG_HS_WKUP_IRQHandler /* USB OTG HS Wakeup through EXTI */
+ .word OTG_HS_IRQHandler /* USB OTG HS */
+ .word DCMI_IRQHandler /* DCMI */
+ .word 0 /* CRYP crypto */
+ .word HASH_RNG_IRQHandler /* Hash and Rng */
+ .word FPU_IRQHandler /* FPU */
+ .word UART7_IRQHandler /* UART7 */
+ .word UART8_IRQHandler /* UART8 */
+
+/*******************************************************************************
+*
+* Provide weak aliases for each Exception handler to the Default_Handler.
+* As they are weak aliases, any function with the same name will override
+* this definition.
+*
+*******************************************************************************/
+ .weak NMI_Handler
+ .thumb_set NMI_Handler,Default_Handler
+
+ .weak HardFault_Handler
+ .thumb_set HardFault_Handler,Default_Handler
+
+ .weak MemManage_Handler
+ .thumb_set MemManage_Handler,Default_Handler
+
+ .weak BusFault_Handler
+ .thumb_set BusFault_Handler,Default_Handler
+
+ .weak UsageFault_Handler
+ .thumb_set UsageFault_Handler,Default_Handler
+
+ .weak SVC_Handler
+ .thumb_set SVC_Handler,Default_Handler
+
+ .weak DebugMon_Handler
+ .thumb_set DebugMon_Handler,Default_Handler
+
+ .weak PendSV_Handler
+ .thumb_set PendSV_Handler,Default_Handler
+
+ .weak SysTick_Handler
+ .thumb_set SysTick_Handler,Default_Handler
+
+ .weak WWDG_IRQHandler
+ .thumb_set WWDG_IRQHandler,Default_Handler
+
+ .weak PVD_IRQHandler
+ .thumb_set PVD_IRQHandler,Default_Handler
+
+ .weak TAMP_STAMP_IRQHandler
+ .thumb_set TAMP_STAMP_IRQHandler,Default_Handler
+
+ .weak RTC_WKUP_IRQHandler
+ .thumb_set RTC_WKUP_IRQHandler,Default_Handler
+
+ .weak FLASH_IRQHandler
+ .thumb_set FLASH_IRQHandler,Default_Handler
+
+ .weak RCC_IRQHandler
+ .thumb_set RCC_IRQHandler,Default_Handler
+
+ .weak EXTI0_IRQHandler
+ .thumb_set EXTI0_IRQHandler,Default_Handler
+
+ .weak EXTI1_IRQHandler
+ .thumb_set EXTI1_IRQHandler,Default_Handler
+
+ .weak EXTI2_IRQHandler
+ .thumb_set EXTI2_IRQHandler,Default_Handler
+
+ .weak EXTI3_IRQHandler
+ .thumb_set EXTI3_IRQHandler,Default_Handler
+
+ .weak EXTI4_IRQHandler
+ .thumb_set EXTI4_IRQHandler,Default_Handler
+
+ .weak DMA1_Stream0_IRQHandler
+ .thumb_set DMA1_Stream0_IRQHandler,Default_Handler
+
+ .weak DMA1_Stream1_IRQHandler
+ .thumb_set DMA1_Stream1_IRQHandler,Default_Handler
+
+ .weak DMA1_Stream2_IRQHandler
+ .thumb_set DMA1_Stream2_IRQHandler,Default_Handler
+
+ .weak DMA1_Stream3_IRQHandler
+ .thumb_set DMA1_Stream3_IRQHandler,Default_Handler
+
+ .weak DMA1_Stream4_IRQHandler
+ .thumb_set DMA1_Stream4_IRQHandler,Default_Handler
+
+ .weak DMA1_Stream5_IRQHandler
+ .thumb_set DMA1_Stream5_IRQHandler,Default_Handler
+
+ .weak DMA1_Stream6_IRQHandler
+ .thumb_set DMA1_Stream6_IRQHandler,Default_Handler
+
+ .weak ADC_IRQHandler
+ .thumb_set ADC_IRQHandler,Default_Handler
+
+ .weak CAN1_TX_IRQHandler
+ .thumb_set CAN1_TX_IRQHandler,Default_Handler
+
+ .weak CAN1_RX0_IRQHandler
+ .thumb_set CAN1_RX0_IRQHandler,Default_Handler
+
+ .weak CAN1_RX1_IRQHandler
+ .thumb_set CAN1_RX1_IRQHandler,Default_Handler
+
+ .weak CAN1_SCE_IRQHandler
+ .thumb_set CAN1_SCE_IRQHandler,Default_Handler
+
+ .weak EXTI9_5_IRQHandler
+ .thumb_set EXTI9_5_IRQHandler,Default_Handler
+
+ .weak TIM1_BRK_TIM9_IRQHandler
+ .thumb_set TIM1_BRK_TIM9_IRQHandler,Default_Handler
+
+ .weak TIM1_UP_TIM10_IRQHandler
+ .thumb_set TIM1_UP_TIM10_IRQHandler,Default_Handler
+
+ .weak TIM1_TRG_COM_TIM11_IRQHandler
+ .thumb_set TIM1_TRG_COM_TIM11_IRQHandler,Default_Handler
+
+ .weak TIM1_CC_IRQHandler
+ .thumb_set TIM1_CC_IRQHandler,Default_Handler
+
+ .weak TIM2_IRQHandler
+ .thumb_set TIM2_IRQHandler,Default_Handler
+
+ .weak TIM3_IRQHandler
+ .thumb_set TIM3_IRQHandler,Default_Handler
+
+ .weak TIM4_IRQHandler
+ .thumb_set TIM4_IRQHandler,Default_Handler
+
+ .weak I2C1_EV_IRQHandler
+ .thumb_set I2C1_EV_IRQHandler,Default_Handler
+
+ .weak I2C1_ER_IRQHandler
+ .thumb_set I2C1_ER_IRQHandler,Default_Handler
+
+ .weak I2C2_EV_IRQHandler
+ .thumb_set I2C2_EV_IRQHandler,Default_Handler
+
+ .weak I2C2_ER_IRQHandler
+ .thumb_set I2C2_ER_IRQHandler,Default_Handler
+
+ .weak SPI1_IRQHandler
+ .thumb_set SPI1_IRQHandler,Default_Handler
+
+ .weak SPI2_IRQHandler
+ .thumb_set SPI2_IRQHandler,Default_Handler
+
+ .weak USART1_IRQHandler
+ .thumb_set USART1_IRQHandler,Default_Handler
+
+ .weak USART2_IRQHandler
+ .thumb_set USART2_IRQHandler,Default_Handler
+
+ .weak USART3_IRQHandler
+ .thumb_set USART3_IRQHandler,Default_Handler
+
+ .weak EXTI15_10_IRQHandler
+ .thumb_set EXTI15_10_IRQHandler,Default_Handler
+
+ .weak RTC_Alarm_IRQHandler
+ .thumb_set RTC_Alarm_IRQHandler,Default_Handler
+
+ .weak OTG_FS_WKUP_IRQHandler
+ .thumb_set OTG_FS_WKUP_IRQHandler,Default_Handler
+
+ .weak TIM8_BRK_TIM12_IRQHandler
+ .thumb_set TIM8_BRK_TIM12_IRQHandler,Default_Handler
+
+ .weak TIM8_UP_TIM13_IRQHandler
+ .thumb_set TIM8_UP_TIM13_IRQHandler,Default_Handler
+
+ .weak TIM8_TRG_COM_TIM14_IRQHandler
+ .thumb_set TIM8_TRG_COM_TIM14_IRQHandler,Default_Handler
+
+ .weak TIM8_CC_IRQHandler
+ .thumb_set TIM8_CC_IRQHandler,Default_Handler
+
+ .weak DMA1_Stream7_IRQHandler
+ .thumb_set DMA1_Stream7_IRQHandler,Default_Handler
+
+ .weak FSMC_IRQHandler
+ .thumb_set FSMC_IRQHandler,Default_Handler
+
+ .weak SDIO_IRQHandler
+ .thumb_set SDIO_IRQHandler,Default_Handler
+
+ .weak TIM5_IRQHandler
+ .thumb_set TIM5_IRQHandler,Default_Handler
+
+ .weak SPI3_IRQHandler
+ .thumb_set SPI3_IRQHandler,Default_Handler
+
+ .weak UART4_IRQHandler
+ .thumb_set UART4_IRQHandler,Default_Handler
+
+ .weak UART5_IRQHandler
+ .thumb_set UART5_IRQHandler,Default_Handler
+
+ .weak TIM6_DAC_IRQHandler
+ .thumb_set TIM6_DAC_IRQHandler,Default_Handler
+
+ .weak TIM7_IRQHandler
+ .thumb_set TIM7_IRQHandler,Default_Handler
+
+ .weak DMA2_Stream0_IRQHandler
+ .thumb_set DMA2_Stream0_IRQHandler,Default_Handler
+
+ .weak DMA2_Stream1_IRQHandler
+ .thumb_set DMA2_Stream1_IRQHandler,Default_Handler
+
+ .weak DMA2_Stream2_IRQHandler
+ .thumb_set DMA2_Stream2_IRQHandler,Default_Handler
+
+ .weak DMA2_Stream3_IRQHandler
+ .thumb_set DMA2_Stream3_IRQHandler,Default_Handler
+
+ .weak DMA2_Stream4_IRQHandler
+ .thumb_set DMA2_Stream4_IRQHandler,Default_Handler
+
+ .weak ETH_IRQHandler
+ .thumb_set ETH_IRQHandler,Default_Handler
+
+ .weak ETH_WKUP_IRQHandler
+ .thumb_set ETH_WKUP_IRQHandler,Default_Handler
+
+ .weak CAN2_TX_IRQHandler
+ .thumb_set CAN2_TX_IRQHandler,Default_Handler
+
+ .weak CAN2_RX0_IRQHandler
+ .thumb_set CAN2_RX0_IRQHandler,Default_Handler
+
+ .weak CAN2_RX1_IRQHandler
+ .thumb_set CAN2_RX1_IRQHandler,Default_Handler
+
+ .weak CAN2_SCE_IRQHandler
+ .thumb_set CAN2_SCE_IRQHandler,Default_Handler
+
+ .weak OTG_FS_IRQHandler
+ .thumb_set OTG_FS_IRQHandler,Default_Handler
+
+ .weak DMA2_Stream5_IRQHandler
+ .thumb_set DMA2_Stream5_IRQHandler,Default_Handler
+
+ .weak DMA2_Stream6_IRQHandler
+ .thumb_set DMA2_Stream6_IRQHandler,Default_Handler
+
+ .weak DMA2_Stream7_IRQHandler
+ .thumb_set DMA2_Stream7_IRQHandler,Default_Handler
+
+ .weak USART6_IRQHandler
+ .thumb_set USART6_IRQHandler,Default_Handler
+
+ .weak I2C3_EV_IRQHandler
+ .thumb_set I2C3_EV_IRQHandler,Default_Handler
+
+ .weak I2C3_ER_IRQHandler
+ .thumb_set I2C3_ER_IRQHandler,Default_Handler
+
+ .weak OTG_HS_EP1_OUT_IRQHandler
+ .thumb_set OTG_HS_EP1_OUT_IRQHandler,Default_Handler
+
+ .weak OTG_HS_EP1_IN_IRQHandler
+ .thumb_set OTG_HS_EP1_IN_IRQHandler,Default_Handler
+
+ .weak OTG_HS_WKUP_IRQHandler
+ .thumb_set OTG_HS_WKUP_IRQHandler,Default_Handler
+
+ .weak OTG_HS_IRQHandler
+ .thumb_set OTG_HS_IRQHandler,Default_Handler
+
+ .weak DCMI_IRQHandler
+ .thumb_set DCMI_IRQHandler,Default_Handler
+
+ .weak HASH_RNG_IRQHandler
+ .thumb_set HASH_RNG_IRQHandler,Default_Handler
+
+ .weak FPU_IRQHandler
+ .thumb_set FPU_IRQHandler,Default_Handler
+
+ .weak UART7_IRQHandler
+ .thumb_set UART7_IRQHandler,Default_Handler
+
+ .weak UART8_IRQHandler
+ .thumb_set UART8_IRQHandler,Default_Handler
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/ports/stm32/startup_stm32.S b/ports/stm32/boards/startup_stm32f7.s
index a688cd067..633ba01e9 100644
--- a/ports/stm32/startup_stm32.S
+++ b/ports/stm32/boards/startup_stm32f7.s
@@ -44,13 +44,7 @@
*/
.syntax unified
-#if defined(MCU_SERIES_F7)
.cpu cortex-m7
-#elif defined(MCU_SERIES_F4) || defined(MCU_SERIES_L4)
- .cpu cortex-m4
-#else
- #error "Unknown MCU Series"
-#endif
.fpu softvfp
.thumb
@@ -166,11 +160,7 @@ g_pfnVectors:
/* External Interrupts */
.word WWDG_IRQHandler /* Window WatchDog */
-#if defined(MCU_SERIES_L4)
- .word PVD_PVM_IRQHandler /* PVD and PVM through EXTI line detection */
-#else
.word PVD_IRQHandler /* PVD through EXTI Line detection */
-#endif
.word TAMP_STAMP_IRQHandler /* Tamper and TimeStamps through the EXTI line */
.word RTC_WKUP_IRQHandler /* RTC Wakeup through the EXTI line */
.word FLASH_IRQHandler /* FLASH */
@@ -180,16 +170,6 @@ g_pfnVectors:
.word EXTI2_IRQHandler /* EXTI Line2 */
.word EXTI3_IRQHandler /* EXTI Line3 */
.word EXTI4_IRQHandler /* EXTI Line4 */
-#if defined(MCU_SERIES_L4)
- .word DMA1_Channel1_IRQHandler /* DMA1 Channel 1 */
- .word DMA1_Channel2_IRQHandler /* DMA1 Channel 2 */
- .word DMA1_Channel3_IRQHandler /* DMA1 Channel 3 */
- .word DMA1_Channel4_IRQHandler /* DMA1 Channel 4 */
- .word DMA1_Channel5_IRQHandler /* DMA1 Channel 5 */
- .word DMA1_Channel6_IRQHandler /* DMA1 Channel 6 */
- .word DMA1_Channel7_IRQHandler /* DMA1 Channel 7 */
- .word ADC1_2_IRQHandler /* ADC1 and ADC2 */
-#else
.word DMA1_Stream0_IRQHandler /* DMA1 Stream 0 */
.word DMA1_Stream1_IRQHandler /* DMA1 Stream 1 */
.word DMA1_Stream2_IRQHandler /* DMA1 Stream 2 */
@@ -198,21 +178,14 @@ g_pfnVectors:
.word DMA1_Stream5_IRQHandler /* DMA1 Stream 5 */
.word DMA1_Stream6_IRQHandler /* DMA1 Stream 6 */
.word ADC_IRQHandler /* ADC1, ADC2 and ADC3s */
-#endif
.word CAN1_TX_IRQHandler /* CAN1 TX */
.word CAN1_RX0_IRQHandler /* CAN1 RX0 */
.word CAN1_RX1_IRQHandler /* CAN1 RX1 */
.word CAN1_SCE_IRQHandler /* CAN1 SCE */
.word EXTI9_5_IRQHandler /* External Line[9:5]s */
-#if defined(MCU_SERIES_L4)
- .word TIM1_BRK_TIM15_IRQHandler /* TIM1 Break and TIM15 */
- .word TIM1_UP_TIM16_IRQHandler /* TIM1 Update and TIM16 */
- .word TIM1_TRG_COM_TIM17_IRQHandler /* TIM1 Trigger and Commutation and TIM17 */
-#else
.word TIM1_BRK_TIM9_IRQHandler /* TIM1 Break and TIM9 */
.word TIM1_UP_TIM10_IRQHandler /* TIM1 Update and TIM10 */
.word TIM1_TRG_COM_TIM11_IRQHandler /* TIM1 Trigger and Commutation and TIM11 */
-#endif
.word TIM1_CC_IRQHandler /* TIM1 Capture Compare */
.word TIM2_IRQHandler /* TIM2 */
.word TIM3_IRQHandler /* TIM3 */
@@ -228,49 +201,20 @@ g_pfnVectors:
.word USART3_IRQHandler /* USART3 */
.word EXTI15_10_IRQHandler /* External Line[15:10]s */
.word RTC_Alarm_IRQHandler /* RTC Alarm (A and B) through EXTI Line */
-#if defined(MCU_SERIES_L4)
- .word DFSDM3_IRQHandler /* Digital filter for sigma delta modulator 3 */
- .word TIM8_BRK_IRQHandler /* TIM8 Break */
- .word TIM8_UP_IRQHandler /* TIM8 Update */
- .word TIM8_TRG_COM_IRQHandler /* TIM8 Trigger and Commutation */
-#else
.word OTG_FS_WKUP_IRQHandler /* USB OTG FS Wakeup through EXTI line */
.word TIM8_BRK_TIM12_IRQHandler /* TIM8 Break and TIM12 */
.word TIM8_UP_TIM13_IRQHandler /* TIM8 Update and TIM13 */
.word TIM8_TRG_COM_TIM14_IRQHandler /* TIM8 Trigger and Commutation and TIM14 */
-#endif
.word TIM8_CC_IRQHandler /* TIM8 Capture Compare */
-#if defined(MCU_SERIES_L4)
- .word ADC3_IRQHandler /* ADC3 global interrupt */
-#else
.word DMA1_Stream7_IRQHandler /* DMA1 Stream7 */
-#endif
-#if defined(MCU_SERIES_F7) || defined(MCU_SERIES_L4)
.word FMC_IRQHandler /* FMC */
.word SDMMC1_IRQHandler /* SDMMC1 */
-#else
- .word FSMC_IRQHandler /* FSMC */
- .word SDIO_IRQHandler /* SDIO */
-#endif
.word TIM5_IRQHandler /* TIM5 */
.word SPI3_IRQHandler /* SPI3 */
.word UART4_IRQHandler /* UART4 */
.word UART5_IRQHandler /* UART5 */
.word TIM6_DAC_IRQHandler /* TIM6 and DAC1&2 underrun errors */
.word TIM7_IRQHandler /* TIM7 */
-#if defined(MCU_SERIES_L4)
- .word DMA2_Channel1_IRQHandler /* DMA2 Channel 1 */
- .word DMA2_Channel2_IRQHandler /* DMA2 Channel 2 */
- .word DMA2_Channel3_IRQHandler /* DMA2 Channel 3 */
- .word DMA2_Channel4_IRQHandler /* DMA2 Channel 4 */
- .word DMA2_Channel5_IRQHandler /* DMA2 Channel 5 */
- .word DFSDM0_IRQHandler /* Digital filter for sigma delta modulator 0 */
- .word DFSDM1_IRQHandler /* Digital filter for sigma delta modulator 1 */
- .word DFSDM2_IRQHandler /* Digital filter for sigma delta modulator 2 */
- .word COMP_IRQHandler /* Comporator thru EXTI line */
- .word LPTIM1_IRQHandler /* Low power timer 1 */
- .word LPTIM2_IRQHandler /* Low power timer 2 */
-#else
.word DMA2_Stream0_IRQHandler /* DMA2 Stream 0 */
.word DMA2_Stream1_IRQHandler /* DMA2 Stream 1 */
.word DMA2_Stream2_IRQHandler /* DMA2 Stream 2 */
@@ -282,43 +226,21 @@ g_pfnVectors:
.word CAN2_RX0_IRQHandler /* CAN2 RX0 */
.word CAN2_RX1_IRQHandler /* CAN2 RX1 */
.word CAN2_SCE_IRQHandler /* CAN2 SCE */
-#endif
.word OTG_FS_IRQHandler /* USB OTG FS */
-#if defined(MCU_SERIES_L4)
- .word DMA2_Channel6_IRQHandler /* DMA2 Channel 6 */
- .word DMA2_Channel7_IRQHandler /* DMA2 Channel 7 */
- .word LPUART1_IRQHandler /* Low power UART */
- .word QUADSPI_IRQHandler /* Quad SPI */
-#else
.word DMA2_Stream5_IRQHandler /* DMA2 Stream 5 */
.word DMA2_Stream6_IRQHandler /* DMA2 Stream 6 */
.word DMA2_Stream7_IRQHandler /* DMA2 Stream 7 */
.word USART6_IRQHandler /* USART6 */
-#endif
.word I2C3_EV_IRQHandler /* I2C3 event */
.word I2C3_ER_IRQHandler /* I2C3 error */
-#if defined(MCU_SERIES_L4)
- .word SAI1_IRQHandler /* Serial audio interface 1 */
- .word SAI2_IRQHandler /* Serial audio interface 2 */
- .word SWPMI1_IRQHandler /* Single wire protocole 1 */
- .word TSC_IRQHandler /* Touch sensig controller */
- .word LCD_IRQHandler /* LCD */
-#else
.word OTG_HS_EP1_OUT_IRQHandler /* USB OTG HS End Point 1 Out */
.word OTG_HS_EP1_IN_IRQHandler /* USB OTG HS End Point 1 In */
.word OTG_HS_WKUP_IRQHandler /* USB OTG HS Wakeup through EXTI */
.word OTG_HS_IRQHandler /* USB OTG HS */
.word DCMI_IRQHandler /* DCMI */
-#endif
.word 0 /* CRYP crypto */
-#if defined(MCU_SERIES_L4)
- .word RNG_IRQHandler /* Random number generator */
-#else
.word HASH_RNG_IRQHandler /* Hash and Rng */
-#endif
.word FPU_IRQHandler /* FPU */
-
-#if defined(MCU_SERIES_F7)
.word UART7_IRQHandler /* UART7 */
.word UART8_IRQHandler /* UART8 */
.word SPI4_IRQHandler /* SPI4 */
@@ -341,7 +263,6 @@ g_pfnVectors:
.word DFSDM1_FLT2_IRQHandler /* DFSDM1 filter 2 */
.word DFSDM1_FLT3_IRQHandler /* DFSDM1 filter 3 */
.word SDMMC2_IRQHandler /* SDMMC2 */
-#endif
/*******************************************************************************
*
@@ -380,13 +301,8 @@ g_pfnVectors:
.weak WWDG_IRQHandler
.thumb_set WWDG_IRQHandler,Default_Handler
-#if defined(MCU_SERIES_L4)
- .weak PVD_PVM_IRQHandler
- .thumb_set PVD_PVM_IRQHandler,Default_Handler
-#else
.weak PVD_IRQHandler
.thumb_set PVD_IRQHandler,Default_Handler
-#endif
.weak TAMP_STAMP_IRQHandler
.thumb_set TAMP_STAMP_IRQHandler,Default_Handler
@@ -415,31 +331,6 @@ g_pfnVectors:
.weak EXTI4_IRQHandler
.thumb_set EXTI4_IRQHandler,Default_Handler
-#if defined(MCU_SERIES_L4)
- .weak DMA1_Channel1_IRQHandler
- .thumb_set DMA1_Channel1_IRQHandler,Default_Handler
-
- .weak DMA1_Channel2_IRQHandler
- .thumb_set DMA1_Channel2_IRQHandler,Default_Handler
-
- .weak DMA1_Channel3_IRQHandler
- .thumb_set DMA1_Channel3_IRQHandler,Default_Handler
-
- .weak DMA1_Channel4_IRQHandler
- .thumb_set DMA1_Channel4_IRQHandler,Default_Handler
-
- .weak DMA1_Channel5_IRQHandler
- .thumb_set DMA1_Channel5_IRQHandler,Default_Handler
-
- .weak DMA1_Channel6_IRQHandler
- .thumb_set DMA1_Channel6_IRQHandler,Default_Handler
-
- .weak DMA1_Channel7_IRQHandler
- .thumb_set DMA1_Channel7_IRQHandler,Default_Handler
-
- .weak ADC1_2_IRQHandler
- .thumb_set ADC1_2_IRQHandler,Default_Handler
-#else
.weak DMA1_Stream0_IRQHandler
.thumb_set DMA1_Stream0_IRQHandler,Default_Handler
@@ -463,7 +354,6 @@ g_pfnVectors:
.weak ADC_IRQHandler
.thumb_set ADC_IRQHandler,Default_Handler
-#endif
.weak CAN1_TX_IRQHandler
.thumb_set CAN1_TX_IRQHandler,Default_Handler
@@ -480,16 +370,6 @@ g_pfnVectors:
.weak EXTI9_5_IRQHandler
.thumb_set EXTI9_5_IRQHandler,Default_Handler
-#if defined(MCU_SERIES_L4)
- .weak TIM1_BRK_TIM15_IRQHandler
- .thumb_set TIM1_BRK_TIM15_IRQHandler,Default_Handler
-
- .weak TIM1_UP_TIM16_IRQHandler
- .thumb_set TIM1_UP_TIM16_IRQHandler,Default_Handler
-
- .weak TIM1_TRG_COM_TIM17_IRQHandler
- .thumb_set TIM1_TRG_COM_TIM17_IRQHandler,Default_Handler
-#else
.weak TIM1_BRK_TIM9_IRQHandler
.thumb_set TIM1_BRK_TIM9_IRQHandler,Default_Handler
@@ -498,7 +378,6 @@ g_pfnVectors:
.weak TIM1_TRG_COM_TIM11_IRQHandler
.thumb_set TIM1_TRG_COM_TIM11_IRQHandler,Default_Handler
-#endif
.weak TIM1_CC_IRQHandler
.thumb_set TIM1_CC_IRQHandler,Default_Handler
@@ -545,19 +424,6 @@ g_pfnVectors:
.weak RTC_Alarm_IRQHandler
.thumb_set RTC_Alarm_IRQHandler,Default_Handler
-#if defined(MCU_SERIES_L4)
- .weak DFSDM3_IRQHandler
- .thumb_set DFSDM3_IRQHandler,Default_Handler
-
- .weak TIM8_BRK_IRQHandler
- .thumb_set TIM8_BRK_IRQHandler,Default_Handler
-
- .weak TIM8_UP_IRQHandler
- .thumb_set TIM8_UP_IRQHandler,Default_Handler
-
- .weak TIM8_TRG_COM_IRQHandler
- .thumb_set TIM8_TRG_COM_IRQHandler,Default_Handler
-#else
.weak OTG_FS_WKUP_IRQHandler
.thumb_set OTG_FS_WKUP_IRQHandler,Default_Handler
@@ -569,32 +435,18 @@ g_pfnVectors:
.weak TIM8_TRG_COM_TIM14_IRQHandler
.thumb_set TIM8_TRG_COM_TIM14_IRQHandler,Default_Handler
-#endif
.weak TIM8_CC_IRQHandler
.thumb_set TIM8_CC_IRQHandler,Default_Handler
-#if defined(MCU_SERIES_L4)
- .weak ADC3_IRQHandler
- .thumb_set ADC3_IRQHandler,Default_Handler
-#else
.weak DMA1_Stream7_IRQHandler
.thumb_set DMA1_Stream7_IRQHandler,Default_Handler
-#endif
-#if defined(MCU_SERIES_F7) || defined(MCU_SERIES_L4)
.weak FMC_IRQHandler
.thumb_set FMC_IRQHandler,Default_Handler
.weak SDMMC1_IRQHandler
.thumb_set SDMMC1_IRQHandler,Default_Handler
-#else
- .weak FSMC_IRQHandler
- .thumb_set FSMC_IRQHandler,Default_Handler
-
- .weak SDIO_IRQHandler
- .thumb_set SDIO_IRQHandler,Default_Handler
-#endif
.weak TIM5_IRQHandler
.thumb_set TIM5_IRQHandler,Default_Handler
@@ -614,40 +466,6 @@ g_pfnVectors:
.weak TIM7_IRQHandler
.thumb_set TIM7_IRQHandler,Default_Handler
-#if defined(MCU_SERIES_L4)
- .weak DMA2_Channel1_IRQHandler
- .thumb_set DMA2_Channel1_IRQHandler,Default_Handler
-
- .weak DMA2_Channel2_IRQHandler
- .thumb_set DMA2_Channel2_IRQHandler,Default_Handler
-
- .weak DMA2_Channel3_IRQHandler
- .thumb_set DMA2_Channel3_IRQHandler,Default_Handler
-
- .weak DMA2_Channel4_IRQHandler
- .thumb_set DMA2_Channel4_IRQHandler,Default_Handler
-
- .weak DMA2_Channel5_IRQHandler
- .thumb_set DMA2_Channel5_IRQHandler,Default_Handler
-
- .weak DFSDM0_IRQHandler
- .thumb_set DFSDM0_IRQHandler,Default_Handler
-
- .weak DFSDM1_IRQHandler
- .thumb_set DFSDM1_IRQHandler,Default_Handler
-
- .weak DFSDM2_IRQHandler
- .thumb_set DFSDM2_IRQHandler,Default_Handler
-
- .weak COMP_IRQHandler
- .thumb_set COMP_IRQHandler,Default_Handler
-
- .weak LPTIM1_IRQHandler
- .thumb_set LPTIM1_IRQHandler,Default_Handler
-
- .weak LPTIM2_IRQHandler
- .thumb_set LPTIM2_IRQHandler,Default_Handler
-#else
.weak DMA2_Stream0_IRQHandler
.thumb_set DMA2_Stream0_IRQHandler,Default_Handler
@@ -680,24 +498,10 @@ g_pfnVectors:
.weak CAN2_SCE_IRQHandler
.thumb_set CAN2_SCE_IRQHandler,Default_Handler
-#endif
.weak OTG_FS_IRQHandler
.thumb_set OTG_FS_IRQHandler,Default_Handler
-#if defined(MCU_SERIES_L4)
- .weak DMA2_Channel6_IRQHandler
- .thumb_set DMA2_Channel6_IRQHandler,Default_Handler
-
- .weak DMA2_Channel7_IRQHandler
- .thumb_set DMA2_Channel7_IRQHandler,Default_Handler
-
- .weak LPUART1_IRQHandler
- .thumb_set LPUART1_IRQHandler,Default_Handler
-
- .weak QUADSPI_IRQHandler
- .thumb_set QUADSPI_IRQHandler,Default_Handler
-#else
.weak DMA2_Stream5_IRQHandler
.thumb_set DMA2_Stream5_IRQHandler,Default_Handler
@@ -709,7 +513,6 @@ g_pfnVectors:
.weak USART6_IRQHandler
.thumb_set USART6_IRQHandler,Default_Handler
-#endif
.weak I2C3_EV_IRQHandler
.thumb_set I2C3_EV_IRQHandler,Default_Handler
@@ -717,25 +520,6 @@ g_pfnVectors:
.weak I2C3_ER_IRQHandler
.thumb_set I2C3_ER_IRQHandler,Default_Handler
-#if defined(MCU_SERIES_L4)
- .weak SAI1_IRQHandler
- .thumb_set SAI1_IRQHandler,Default_Handler
-
- .weak SAI2_IRQHandler
- .thumb_set SAI2_IRQHandler,Default_Handler
-
- .weak SWPMI1_IRQHandler
- .thumb_set SWPMI1_IRQHandler,Default_Handler
-
- .weak TSC_IRQHandler
- .thumb_set TSC_IRQHandler,Default_Handler
-
- .weak LCD_IRQHandler
- .thumb_set LCD_IRQHandler,Default_Handler
-
- .weak RNG_IRQHandler
- .thumb_set RNG_IRQHandler,Default_Handler
-#else
.weak OTG_HS_EP1_OUT_IRQHandler
.thumb_set OTG_HS_EP1_OUT_IRQHandler,Default_Handler
@@ -753,11 +537,10 @@ g_pfnVectors:
.weak HASH_RNG_IRQHandler
.thumb_set HASH_RNG_IRQHandler,Default_Handler
-#endif
.weak FPU_IRQHandler
.thumb_set FPU_IRQHandler,Default_Handler
-#if defined(MCU_SERIES_F7)
+
.weak UART7_IRQHandler
.thumb_set UART7_IRQHandler,Default_Handler
@@ -817,6 +600,5 @@ g_pfnVectors:
.weak SDMMC2_IRQHandler
.thumb_set SDMMC2_IRQHandler,Default_Handler
-#endif
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/ports/stm32/boards/startup_stm32h7.s b/ports/stm32/boards/startup_stm32h7.s
new file mode 100644
index 000000000..53d46205f
--- /dev/null
+++ b/ports/stm32/boards/startup_stm32h7.s
@@ -0,0 +1,763 @@
+/**
+ ******************************************************************************
+ * @file startup_stm32h743xx.s
+ * @author MCD Application Team
+ * @version V1.2.0
+ * @date 29-December-2017
+ * @brief STM32H743xx Devices vector table for GCC based toolchain.
+ * This module performs:
+ * - Set the initial SP
+ * - Set the initial PC == Reset_Handler,
+ * - Set the vector table entries with the exceptions ISR address
+ * - Branches to main in the C library (which eventually
+ * calls main()).
+ * After Reset the Cortex-M processor is in Thread mode,
+ * priority is Privileged, and the Stack is set to Main.
+ ******************************************************************************
+ * @attention
+ *
+ * <h2><center>&copy; COPYRIGHT 2017 STMicroelectronics</center></h2>
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of STMicroelectronics nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ******************************************************************************
+ */
+
+ .syntax unified
+ .cpu cortex-m7
+ .fpu softvfp
+ .thumb
+
+.global g_pfnVectors
+.global Default_Handler
+
+/* start address for the initialization values of the .data section.
+defined in linker script */
+.word _sidata
+/* start address for the .data section. defined in linker script */
+.word _sdata
+/* end address for the .data section. defined in linker script */
+.word _edata
+/* start address for the .bss section. defined in linker script */
+.word _sbss
+/* end address for the .bss section. defined in linker script */
+.word _ebss
+/* stack used for SystemInit_ExtMemCtl; always internal RAM used */
+
+/**
+ * @brief This is the code that gets called when the processor first
+ * starts execution following a reset event. Only the absolutely
+ * necessary set is performed, after which the application
+ * supplied main() routine is called.
+ * @param None
+ * @retval : None
+*/
+
+ .section .text.Reset_Handler
+ .weak Reset_Handler
+ .type Reset_Handler, %function
+Reset_Handler:
+ ldr sp, =_estack /* set stack pointer */
+
+/* Copy the data segment initializers from flash to SRAM */
+ movs r1, #0
+ b LoopCopyDataInit
+
+CopyDataInit:
+ ldr r3, =_sidata
+ ldr r3, [r3, r1]
+ str r3, [r0, r1]
+ adds r1, r1, #4
+
+LoopCopyDataInit:
+ ldr r0, =_sdata
+ ldr r3, =_edata
+ adds r2, r0, r1
+ cmp r2, r3
+ bcc CopyDataInit
+ ldr r2, =_sbss
+ b LoopFillZerobss
+/* Zero fill the bss segment. */
+FillZerobss:
+ movs r3, #0
+ str r3, [r2], #4
+
+LoopFillZerobss:
+ ldr r3, = _ebss
+ cmp r2, r3
+ bcc FillZerobss
+
+/* Call the clock system intitialization function.*/
+ bl SystemInit
+/* Call static constructors */
+/* bl __libc_init_array */
+/* Call the application's entry point.*/
+ bl main
+ bx lr
+.size Reset_Handler, .-Reset_Handler
+
+/**
+ * @brief This is the code that gets called when the processor receives an
+ * unexpected interrupt. This simply enters an infinite loop, preserving
+ * the system state for examination by a debugger.
+ * @param None
+ * @retval None
+*/
+ .section .text.Default_Handler,"ax",%progbits
+Default_Handler:
+Infinite_Loop:
+ b Infinite_Loop
+ .size Default_Handler, .-Default_Handler
+/******************************************************************************
+*
+* The minimal vector table for a Cortex M. Note that the proper constructs
+* must be placed on this to ensure that it ends up at physical address
+* 0x0000.0000.
+*
+*******************************************************************************/
+ .section .isr_vector,"a",%progbits
+ .type g_pfnVectors, %object
+ .size g_pfnVectors, .-g_pfnVectors
+
+
+g_pfnVectors:
+ .word _estack
+ .word Reset_Handler
+
+ .word NMI_Handler
+ .word HardFault_Handler
+ .word MemManage_Handler
+ .word BusFault_Handler
+ .word UsageFault_Handler
+ .word 0
+ .word 0
+ .word 0
+ .word 0
+ .word SVC_Handler
+ .word DebugMon_Handler
+ .word 0
+ .word PendSV_Handler
+ .word SysTick_Handler
+
+ /* External Interrupts */
+ .word WWDG_IRQHandler /* Window WatchDog */
+ .word PVD_AVD_IRQHandler /* PVD/AVD through EXTI Line detection */
+ .word TAMP_STAMP_IRQHandler /* Tamper and TimeStamps through the EXTI line */
+ .word RTC_WKUP_IRQHandler /* RTC Wakeup through the EXTI line */
+ .word FLASH_IRQHandler /* FLASH */
+ .word RCC_IRQHandler /* RCC */
+ .word EXTI0_IRQHandler /* EXTI Line0 */
+ .word EXTI1_IRQHandler /* EXTI Line1 */
+ .word EXTI2_IRQHandler /* EXTI Line2 */
+ .word EXTI3_IRQHandler /* EXTI Line3 */
+ .word EXTI4_IRQHandler /* EXTI Line4 */
+ .word DMA1_Stream0_IRQHandler /* DMA1 Stream 0 */
+ .word DMA1_Stream1_IRQHandler /* DMA1 Stream 1 */
+ .word DMA1_Stream2_IRQHandler /* DMA1 Stream 2 */
+ .word DMA1_Stream3_IRQHandler /* DMA1 Stream 3 */
+ .word DMA1_Stream4_IRQHandler /* DMA1 Stream 4 */
+ .word DMA1_Stream5_IRQHandler /* DMA1 Stream 5 */
+ .word DMA1_Stream6_IRQHandler /* DMA1 Stream 6 */
+ .word ADC_IRQHandler /* ADC1, ADC2 and ADC3s */
+ .word FDCAN1_IT0_IRQHandler /* FDCAN1 interrupt line 0 */
+ .word FDCAN2_IT0_IRQHandler /* FDCAN2 interrupt line 0 */
+ .word FDCAN1_IT1_IRQHandler /* FDCAN1 interrupt line 1 */
+ .word FDCAN2_IT1_IRQHandler /* FDCAN2 interrupt line 1 */
+ .word EXTI9_5_IRQHandler /* External Line[9:5]s */
+ .word TIM1_BRK_IRQHandler /* TIM1 Break interrupt */
+ .word TIM1_UP_IRQHandler /* TIM1 Update interrupt */
+ .word TIM1_TRG_COM_IRQHandler /* TIM1 Trigger and Commutation interrupt */
+ .word TIM1_CC_IRQHandler /* TIM1 Capture Compare */
+ .word TIM2_IRQHandler /* TIM2 */
+ .word TIM3_IRQHandler /* TIM3 */
+ .word TIM4_IRQHandler /* TIM4 */
+ .word I2C1_EV_IRQHandler /* I2C1 Event */
+ .word I2C1_ER_IRQHandler /* I2C1 Error */
+ .word I2C2_EV_IRQHandler /* I2C2 Event */
+ .word I2C2_ER_IRQHandler /* I2C2 Error */
+ .word SPI1_IRQHandler /* SPI1 */
+ .word SPI2_IRQHandler /* SPI2 */
+ .word USART1_IRQHandler /* USART1 */
+ .word USART2_IRQHandler /* USART2 */
+ .word USART3_IRQHandler /* USART3 */
+ .word EXTI15_10_IRQHandler /* External Line[15:10]s */
+ .word RTC_Alarm_IRQHandler /* RTC Alarm (A and B) through EXTI Line */
+ .word 0 /* Reserved */
+ .word TIM8_BRK_TIM12_IRQHandler /* TIM8 Break and TIM12 */
+ .word TIM8_UP_TIM13_IRQHandler /* TIM8 Update and TIM13 */
+ .word TIM8_TRG_COM_TIM14_IRQHandler /* TIM8 Trigger and Commutation and TIM14 */
+ .word TIM8_CC_IRQHandler /* TIM8 Capture Compare */
+ .word DMA1_Stream7_IRQHandler /* DMA1 Stream7 */
+ .word FMC_IRQHandler /* FMC */
+ .word SDMMC1_IRQHandler /* SDMMC1 */
+ .word TIM5_IRQHandler /* TIM5 */
+ .word SPI3_IRQHandler /* SPI3 */
+ .word UART4_IRQHandler /* UART4 */
+ .word UART5_IRQHandler /* UART5 */
+ .word TIM6_DAC_IRQHandler /* TIM6 and DAC1&2 underrun errors */
+ .word TIM7_IRQHandler /* TIM7 */
+ .word DMA2_Stream0_IRQHandler /* DMA2 Stream 0 */
+ .word DMA2_Stream1_IRQHandler /* DMA2 Stream 1 */
+ .word DMA2_Stream2_IRQHandler /* DMA2 Stream 2 */
+ .word DMA2_Stream3_IRQHandler /* DMA2 Stream 3 */
+ .word DMA2_Stream4_IRQHandler /* DMA2 Stream 4 */
+ .word ETH_IRQHandler /* Ethernet */
+ .word ETH_WKUP_IRQHandler /* Ethernet Wakeup through EXTI line */
+ .word FDCAN_CAL_IRQHandler /* FDCAN calibration unit interrupt*/
+ .word 0 /* Reserved */
+ .word 0 /* Reserved */
+ .word 0 /* Reserved */
+ .word 0 /* Reserved */
+ .word DMA2_Stream5_IRQHandler /* DMA2 Stream 5 */
+ .word DMA2_Stream6_IRQHandler /* DMA2 Stream 6 */
+ .word DMA2_Stream7_IRQHandler /* DMA2 Stream 7 */
+ .word USART6_IRQHandler /* USART6 */
+ .word I2C3_EV_IRQHandler /* I2C3 event */
+ .word I2C3_ER_IRQHandler /* I2C3 error */
+ .word OTG_HS_EP1_OUT_IRQHandler /* USB OTG HS End Point 1 Out */
+ .word OTG_HS_EP1_IN_IRQHandler /* USB OTG HS End Point 1 In */
+ .word OTG_HS_WKUP_IRQHandler /* USB OTG HS Wakeup through EXTI */
+ .word OTG_HS_IRQHandler /* USB OTG HS */
+ .word DCMI_IRQHandler /* DCMI */
+ .word 0 /* Reserved */
+ .word RNG_IRQHandler /* Rng */
+ .word FPU_IRQHandler /* FPU */
+ .word UART7_IRQHandler /* UART7 */
+ .word UART8_IRQHandler /* UART8 */
+ .word SPI4_IRQHandler /* SPI4 */
+ .word SPI5_IRQHandler /* SPI5 */
+ .word SPI6_IRQHandler /* SPI6 */
+ .word SAI1_IRQHandler /* SAI1 */
+ .word LTDC_IRQHandler /* LTDC */
+ .word LTDC_ER_IRQHandler /* LTDC error */
+ .word DMA2D_IRQHandler /* DMA2D */
+ .word SAI2_IRQHandler /* SAI2 */
+ .word QUADSPI_IRQHandler /* QUADSPI */
+ .word LPTIM1_IRQHandler /* LPTIM1 */
+ .word CEC_IRQHandler /* HDMI_CEC */
+ .word I2C4_EV_IRQHandler /* I2C4 Event */
+ .word I2C4_ER_IRQHandler /* I2C4 Error */
+ .word SPDIF_RX_IRQHandler /* SPDIF_RX */
+ .word OTG_FS_EP1_OUT_IRQHandler /* USB OTG FS End Point 1 Out */
+ .word OTG_FS_EP1_IN_IRQHandler /* USB OTG FS End Point 1 In */
+ .word OTG_FS_WKUP_IRQHandler /* USB OTG FS Wakeup through EXTI */
+ .word OTG_FS_IRQHandler /* USB OTG FS */
+ .word DMAMUX1_OVR_IRQHandler /* DMAMUX1 Overrun interrupt */
+ .word HRTIM1_Master_IRQHandler /* HRTIM Master Timer global Interrupt */
+ .word HRTIM1_TIMA_IRQHandler /* HRTIM Timer A global Interrupt */
+ .word HRTIM1_TIMB_IRQHandler /* HRTIM Timer B global Interrupt */
+ .word HRTIM1_TIMC_IRQHandler /* HRTIM Timer C global Interrupt */
+ .word HRTIM1_TIMD_IRQHandler /* HRTIM Timer D global Interrupt */
+ .word HRTIM1_TIME_IRQHandler /* HRTIM Timer E global Interrupt */
+ .word HRTIM1_FLT_IRQHandler /* HRTIM Fault global Interrupt */
+ .word DFSDM1_FLT0_IRQHandler /* DFSDM Filter0 Interrupt */
+ .word DFSDM1_FLT1_IRQHandler /* DFSDM Filter1 Interrupt */
+ .word DFSDM1_FLT2_IRQHandler /* DFSDM Filter2 Interrupt */
+ .word DFSDM1_FLT3_IRQHandler /* DFSDM Filter3 Interrupt */
+ .word SAI3_IRQHandler /* SAI3 global Interrupt */
+ .word SWPMI1_IRQHandler /* Serial Wire Interface 1 global interrupt */
+ .word TIM15_IRQHandler /* TIM15 global Interrupt */
+ .word TIM16_IRQHandler /* TIM16 global Interrupt */
+ .word TIM17_IRQHandler /* TIM17 global Interrupt */
+ .word MDIOS_WKUP_IRQHandler /* MDIOS Wakeup Interrupt */
+ .word MDIOS_IRQHandler /* MDIOS global Interrupt */
+ .word JPEG_IRQHandler /* JPEG global Interrupt */
+ .word MDMA_IRQHandler /* MDMA global Interrupt */
+ .word 0 /* Reserved */
+ .word SDMMC2_IRQHandler /* SDMMC2 global Interrupt */
+ .word HSEM1_IRQHandler /* HSEM1 global Interrupt */
+ .word 0 /* Reserved */
+ .word ADC3_IRQHandler /* ADC3 global Interrupt */
+ .word DMAMUX2_OVR_IRQHandler /* DMAMUX Overrun interrupt */
+ .word BDMA_Channel0_IRQHandler /* BDMA Channel 0 global Interrupt */
+ .word BDMA_Channel1_IRQHandler /* BDMA Channel 1 global Interrupt */
+ .word BDMA_Channel2_IRQHandler /* BDMA Channel 2 global Interrupt */
+ .word BDMA_Channel3_IRQHandler /* BDMA Channel 3 global Interrupt */
+ .word BDMA_Channel4_IRQHandler /* BDMA Channel 4 global Interrupt */
+ .word BDMA_Channel5_IRQHandler /* BDMA Channel 5 global Interrupt */
+ .word BDMA_Channel6_IRQHandler /* BDMA Channel 6 global Interrupt */
+ .word BDMA_Channel7_IRQHandler /* BDMA Channel 7 global Interrupt */
+ .word COMP1_IRQHandler /* COMP1 global Interrupt */
+ .word LPTIM2_IRQHandler /* LP TIM2 global interrupt */
+ .word LPTIM3_IRQHandler /* LP TIM3 global interrupt */
+ .word LPTIM4_IRQHandler /* LP TIM4 global interrupt */
+ .word LPTIM5_IRQHandler /* LP TIM5 global interrupt */
+ .word LPUART1_IRQHandler /* LP UART1 interrupt */
+ .word 0 /* Reserved */
+ .word CRS_IRQHandler /* Clock Recovery Global Interrupt */
+ .word 0 /* Reserved */
+ .word SAI4_IRQHandler /* SAI4 global interrupt */
+ .word 0 /* Reserved */
+ .word 0 /* Reserved */
+ .word WAKEUP_PIN_IRQHandler /* Interrupt for all 6 wake-up pins */
+
+/*******************************************************************************
+*
+* Provide weak aliases for each Exception handler to the Default_Handler.
+* As they are weak aliases, any function with the same name will override
+* this definition.
+*
+*******************************************************************************/
+ .weak NMI_Handler
+ .thumb_set NMI_Handler,Default_Handler
+
+ .weak HardFault_Handler
+ .thumb_set HardFault_Handler,Default_Handler
+
+ .weak MemManage_Handler
+ .thumb_set MemManage_Handler,Default_Handler
+
+ .weak BusFault_Handler
+ .thumb_set BusFault_Handler,Default_Handler
+
+ .weak UsageFault_Handler
+ .thumb_set UsageFault_Handler,Default_Handler
+
+ .weak SVC_Handler
+ .thumb_set SVC_Handler,Default_Handler
+
+ .weak DebugMon_Handler
+ .thumb_set DebugMon_Handler,Default_Handler
+
+ .weak PendSV_Handler
+ .thumb_set PendSV_Handler,Default_Handler
+
+ .weak SysTick_Handler
+ .thumb_set SysTick_Handler,Default_Handler
+
+ .weak WWDG_IRQHandler
+ .thumb_set WWDG_IRQHandler,Default_Handler
+
+ .weak PVD_AVD_IRQHandler
+ .thumb_set PVD_AVD_IRQHandler,Default_Handler
+
+ .weak TAMP_STAMP_IRQHandler
+ .thumb_set TAMP_STAMP_IRQHandler,Default_Handler
+
+ .weak RTC_WKUP_IRQHandler
+ .thumb_set RTC_WKUP_IRQHandler,Default_Handler
+
+ .weak FLASH_IRQHandler
+ .thumb_set FLASH_IRQHandler,Default_Handler
+
+ .weak RCC_IRQHandler
+ .thumb_set RCC_IRQHandler,Default_Handler
+
+ .weak EXTI0_IRQHandler
+ .thumb_set EXTI0_IRQHandler,Default_Handler
+
+ .weak EXTI1_IRQHandler
+ .thumb_set EXTI1_IRQHandler,Default_Handler
+
+ .weak EXTI2_IRQHandler
+ .thumb_set EXTI2_IRQHandler,Default_Handler
+
+ .weak EXTI3_IRQHandler
+ .thumb_set EXTI3_IRQHandler,Default_Handler
+
+ .weak EXTI4_IRQHandler
+ .thumb_set EXTI4_IRQHandler,Default_Handler
+
+ .weak DMA1_Stream0_IRQHandler
+ .thumb_set DMA1_Stream0_IRQHandler,Default_Handler
+
+ .weak DMA1_Stream1_IRQHandler
+ .thumb_set DMA1_Stream1_IRQHandler,Default_Handler
+
+ .weak DMA1_Stream2_IRQHandler
+ .thumb_set DMA1_Stream2_IRQHandler,Default_Handler
+
+ .weak DMA1_Stream3_IRQHandler
+ .thumb_set DMA1_Stream3_IRQHandler,Default_Handler
+
+ .weak DMA1_Stream4_IRQHandler
+ .thumb_set DMA1_Stream4_IRQHandler,Default_Handler
+
+ .weak DMA1_Stream5_IRQHandler
+ .thumb_set DMA1_Stream5_IRQHandler,Default_Handler
+
+ .weak DMA1_Stream6_IRQHandler
+ .thumb_set DMA1_Stream6_IRQHandler,Default_Handler
+
+ .weak ADC_IRQHandler
+ .thumb_set ADC_IRQHandler,Default_Handler
+
+ .weak FDCAN1_IT0_IRQHandler
+ .thumb_set FDCAN1_IT0_IRQHandler,Default_Handler
+
+ .weak FDCAN2_IT0_IRQHandler
+ .thumb_set FDCAN2_IT0_IRQHandler,Default_Handler
+
+ .weak FDCAN1_IT1_IRQHandler
+ .thumb_set FDCAN1_IT1_IRQHandler,Default_Handler
+
+ .weak FDCAN2_IT1_IRQHandler
+ .thumb_set FDCAN2_IT1_IRQHandler,Default_Handler
+
+ .weak EXTI9_5_IRQHandler
+ .thumb_set EXTI9_5_IRQHandler,Default_Handler
+
+ .weak TIM1_BRK_IRQHandler
+ .thumb_set TIM1_BRK_IRQHandler,Default_Handler
+
+ .weak TIM1_UP_IRQHandler
+ .thumb_set TIM1_UP_IRQHandler,Default_Handler
+
+ .weak TIM1_TRG_COM_IRQHandler
+ .thumb_set TIM1_TRG_COM_IRQHandler,Default_Handler
+
+ .weak TIM1_CC_IRQHandler
+ .thumb_set TIM1_CC_IRQHandler,Default_Handler
+
+ .weak TIM2_IRQHandler
+ .thumb_set TIM2_IRQHandler,Default_Handler
+
+ .weak TIM3_IRQHandler
+ .thumb_set TIM3_IRQHandler,Default_Handler
+
+ .weak TIM4_IRQHandler
+ .thumb_set TIM4_IRQHandler,Default_Handler
+
+ .weak I2C1_EV_IRQHandler
+ .thumb_set I2C1_EV_IRQHandler,Default_Handler
+
+ .weak I2C1_ER_IRQHandler
+ .thumb_set I2C1_ER_IRQHandler,Default_Handler
+
+ .weak I2C2_EV_IRQHandler
+ .thumb_set I2C2_EV_IRQHandler,Default_Handler
+
+ .weak I2C2_ER_IRQHandler
+ .thumb_set I2C2_ER_IRQHandler,Default_Handler
+
+ .weak SPI1_IRQHandler
+ .thumb_set SPI1_IRQHandler,Default_Handler
+
+ .weak SPI2_IRQHandler
+ .thumb_set SPI2_IRQHandler,Default_Handler
+
+ .weak USART1_IRQHandler
+ .thumb_set USART1_IRQHandler,Default_Handler
+
+ .weak USART2_IRQHandler
+ .thumb_set USART2_IRQHandler,Default_Handler
+
+ .weak USART3_IRQHandler
+ .thumb_set USART3_IRQHandler,Default_Handler
+
+ .weak EXTI15_10_IRQHandler
+ .thumb_set EXTI15_10_IRQHandler,Default_Handler
+
+ .weak RTC_Alarm_IRQHandler
+ .thumb_set RTC_Alarm_IRQHandler,Default_Handler
+
+ .weak TIM8_BRK_TIM12_IRQHandler
+ .thumb_set TIM8_BRK_TIM12_IRQHandler,Default_Handler
+
+ .weak TIM8_UP_TIM13_IRQHandler
+ .thumb_set TIM8_UP_TIM13_IRQHandler,Default_Handler
+
+ .weak TIM8_TRG_COM_TIM14_IRQHandler
+ .thumb_set TIM8_TRG_COM_TIM14_IRQHandler,Default_Handler
+
+ .weak TIM8_CC_IRQHandler
+ .thumb_set TIM8_CC_IRQHandler,Default_Handler
+
+ .weak DMA1_Stream7_IRQHandler
+ .thumb_set DMA1_Stream7_IRQHandler,Default_Handler
+
+ .weak FMC_IRQHandler
+ .thumb_set FMC_IRQHandler,Default_Handler
+
+ .weak SDMMC1_IRQHandler
+ .thumb_set SDMMC1_IRQHandler,Default_Handler
+
+ .weak TIM5_IRQHandler
+ .thumb_set TIM5_IRQHandler,Default_Handler
+
+ .weak SPI3_IRQHandler
+ .thumb_set SPI3_IRQHandler,Default_Handler
+
+ .weak UART4_IRQHandler
+ .thumb_set UART4_IRQHandler,Default_Handler
+
+ .weak UART5_IRQHandler
+ .thumb_set UART5_IRQHandler,Default_Handler
+
+ .weak TIM6_DAC_IRQHandler
+ .thumb_set TIM6_DAC_IRQHandler,Default_Handler
+
+ .weak TIM7_IRQHandler
+ .thumb_set TIM7_IRQHandler,Default_Handler
+
+ .weak DMA2_Stream0_IRQHandler
+ .thumb_set DMA2_Stream0_IRQHandler,Default_Handler
+
+ .weak DMA2_Stream1_IRQHandler
+ .thumb_set DMA2_Stream1_IRQHandler,Default_Handler
+
+ .weak DMA2_Stream2_IRQHandler
+ .thumb_set DMA2_Stream2_IRQHandler,Default_Handler
+
+ .weak DMA2_Stream3_IRQHandler
+ .thumb_set DMA2_Stream3_IRQHandler,Default_Handler
+
+ .weak DMA2_Stream4_IRQHandler
+ .thumb_set DMA2_Stream4_IRQHandler,Default_Handler
+
+ .weak ETH_IRQHandler
+ .thumb_set ETH_IRQHandler,Default_Handler
+
+ .weak ETH_WKUP_IRQHandler
+ .thumb_set ETH_WKUP_IRQHandler,Default_Handler
+
+ .weak FDCAN_CAL_IRQHandler
+ .thumb_set FDCAN_CAL_IRQHandler,Default_Handler
+
+ .weak DMA2_Stream5_IRQHandler
+ .thumb_set DMA2_Stream5_IRQHandler,Default_Handler
+
+ .weak DMA2_Stream6_IRQHandler
+ .thumb_set DMA2_Stream6_IRQHandler,Default_Handler
+
+ .weak DMA2_Stream7_IRQHandler
+ .thumb_set DMA2_Stream7_IRQHandler,Default_Handler
+
+ .weak USART6_IRQHandler
+ .thumb_set USART6_IRQHandler,Default_Handler
+
+ .weak I2C3_EV_IRQHandler
+ .thumb_set I2C3_EV_IRQHandler,Default_Handler
+
+ .weak I2C3_ER_IRQHandler
+ .thumb_set I2C3_ER_IRQHandler,Default_Handler
+
+ .weak OTG_HS_EP1_OUT_IRQHandler
+ .thumb_set OTG_HS_EP1_OUT_IRQHandler,Default_Handler
+
+ .weak OTG_HS_EP1_IN_IRQHandler
+ .thumb_set OTG_HS_EP1_IN_IRQHandler,Default_Handler
+
+ .weak OTG_HS_WKUP_IRQHandler
+ .thumb_set OTG_HS_WKUP_IRQHandler,Default_Handler
+
+ .weak OTG_HS_IRQHandler
+ .thumb_set OTG_HS_IRQHandler,Default_Handler
+
+ .weak DCMI_IRQHandler
+ .thumb_set DCMI_IRQHandler,Default_Handler
+
+ .weak RNG_IRQHandler
+ .thumb_set RNG_IRQHandler,Default_Handler
+
+ .weak FPU_IRQHandler
+ .thumb_set FPU_IRQHandler,Default_Handler
+
+ .weak UART7_IRQHandler
+ .thumb_set UART7_IRQHandler,Default_Handler
+
+ .weak UART8_IRQHandler
+ .thumb_set UART8_IRQHandler,Default_Handler
+
+ .weak SPI4_IRQHandler
+ .thumb_set SPI4_IRQHandler,Default_Handler
+
+ .weak SPI5_IRQHandler
+ .thumb_set SPI5_IRQHandler,Default_Handler
+
+ .weak SPI6_IRQHandler
+ .thumb_set SPI6_IRQHandler,Default_Handler
+
+ .weak SAI1_IRQHandler
+ .thumb_set SAI1_IRQHandler,Default_Handler
+
+ .weak LTDC_IRQHandler
+ .thumb_set LTDC_IRQHandler,Default_Handler
+
+ .weak LTDC_ER_IRQHandler
+ .thumb_set LTDC_ER_IRQHandler,Default_Handler
+
+ .weak DMA2D_IRQHandler
+ .thumb_set DMA2D_IRQHandler,Default_Handler
+
+ .weak SAI2_IRQHandler
+ .thumb_set SAI2_IRQHandler,Default_Handler
+
+ .weak QUADSPI_IRQHandler
+ .thumb_set QUADSPI_IRQHandler,Default_Handler
+
+ .weak LPTIM1_IRQHandler
+ .thumb_set LPTIM1_IRQHandler,Default_Handler
+
+ .weak CEC_IRQHandler
+ .thumb_set CEC_IRQHandler,Default_Handler
+
+ .weak I2C4_EV_IRQHandler
+ .thumb_set I2C4_EV_IRQHandler,Default_Handler
+
+ .weak I2C4_ER_IRQHandler
+ .thumb_set I2C4_ER_IRQHandler,Default_Handler
+
+ .weak SPDIF_RX_IRQHandler
+ .thumb_set SPDIF_RX_IRQHandler,Default_Handler
+
+ .weak OTG_FS_EP1_OUT_IRQHandler
+ .thumb_set OTG_FS_EP1_OUT_IRQHandler,Default_Handler
+
+ .weak OTG_FS_EP1_IN_IRQHandler
+ .thumb_set OTG_FS_EP1_IN_IRQHandler,Default_Handler
+
+ .weak OTG_FS_WKUP_IRQHandler
+ .thumb_set OTG_FS_WKUP_IRQHandler,Default_Handler
+
+ .weak OTG_FS_IRQHandler
+ .thumb_set OTG_FS_IRQHandler,Default_Handler
+
+ .weak DMAMUX1_OVR_IRQHandler
+ .thumb_set DMAMUX1_OVR_IRQHandler,Default_Handler
+
+ .weak HRTIM1_Master_IRQHandler
+ .thumb_set HRTIM1_Master_IRQHandler,Default_Handler
+
+ .weak HRTIM1_TIMA_IRQHandler
+ .thumb_set HRTIM1_TIMA_IRQHandler,Default_Handler
+
+ .weak HRTIM1_TIMB_IRQHandler
+ .thumb_set HRTIM1_TIMB_IRQHandler,Default_Handler
+
+ .weak HRTIM1_TIMC_IRQHandler
+ .thumb_set HRTIM1_TIMC_IRQHandler,Default_Handler
+
+ .weak HRTIM1_TIMD_IRQHandler
+ .thumb_set HRTIM1_TIMD_IRQHandler,Default_Handler
+
+ .weak HRTIM1_TIME_IRQHandler
+ .thumb_set HRTIM1_TIME_IRQHandler,Default_Handler
+
+ .weak HRTIM1_FLT_IRQHandler
+ .thumb_set HRTIM1_FLT_IRQHandler,Default_Handler
+
+ .weak DFSDM1_FLT0_IRQHandler
+ .thumb_set DFSDM1_FLT0_IRQHandler,Default_Handler
+
+ .weak DFSDM1_FLT1_IRQHandler
+ .thumb_set DFSDM1_FLT1_IRQHandler,Default_Handler
+
+ .weak DFSDM1_FLT2_IRQHandler
+ .thumb_set DFSDM1_FLT2_IRQHandler,Default_Handler
+
+ .weak DFSDM1_FLT3_IRQHandler
+ .thumb_set DFSDM1_FLT3_IRQHandler,Default_Handler
+
+ .weak SAI3_IRQHandler
+ .thumb_set SAI3_IRQHandler,Default_Handler
+
+ .weak SWPMI1_IRQHandler
+ .thumb_set SWPMI1_IRQHandler,Default_Handler
+
+ .weak TIM15_IRQHandler
+ .thumb_set TIM15_IRQHandler,Default_Handler
+
+ .weak TIM16_IRQHandler
+ .thumb_set TIM16_IRQHandler,Default_Handler
+
+ .weak TIM17_IRQHandler
+ .thumb_set TIM17_IRQHandler,Default_Handler
+
+ .weak MDIOS_WKUP_IRQHandler
+ .thumb_set MDIOS_WKUP_IRQHandler,Default_Handler
+
+ .weak MDIOS_IRQHandler
+ .thumb_set MDIOS_IRQHandler,Default_Handler
+
+ .weak JPEG_IRQHandler
+ .thumb_set JPEG_IRQHandler,Default_Handler
+
+ .weak MDMA_IRQHandler
+ .thumb_set MDMA_IRQHandler,Default_Handler
+
+ .weak SDMMC2_IRQHandler
+ .thumb_set SDMMC2_IRQHandler,Default_Handler
+
+ .weak HSEM1_IRQHandler
+ .thumb_set HSEM1_IRQHandler,Default_Handler
+
+ .weak ADC3_IRQHandler
+ .thumb_set ADC3_IRQHandler,Default_Handler
+
+ .weak DMAMUX2_OVR_IRQHandler
+ .thumb_set DMAMUX2_OVR_IRQHandler,Default_Handler
+
+ .weak BDMA_Channel0_IRQHandler
+ .thumb_set BDMA_Channel0_IRQHandler,Default_Handler
+
+ .weak BDMA_Channel1_IRQHandler
+ .thumb_set BDMA_Channel1_IRQHandler,Default_Handler
+
+ .weak BDMA_Channel2_IRQHandler
+ .thumb_set BDMA_Channel2_IRQHandler,Default_Handler
+
+ .weak BDMA_Channel3_IRQHandler
+ .thumb_set BDMA_Channel3_IRQHandler,Default_Handler
+
+ .weak BDMA_Channel4_IRQHandler
+ .thumb_set BDMA_Channel4_IRQHandler,Default_Handler
+
+ .weak BDMA_Channel5_IRQHandler
+ .thumb_set BDMA_Channel5_IRQHandler,Default_Handler
+
+ .weak BDMA_Channel6_IRQHandler
+ .thumb_set BDMA_Channel6_IRQHandler,Default_Handler
+
+ .weak BDMA_Channel7_IRQHandler
+ .thumb_set BDMA_Channel7_IRQHandler,Default_Handler
+
+ .weak COMP1_IRQHandler
+ .thumb_set COMP1_IRQHandler,Default_Handler
+
+ .weak LPTIM2_IRQHandler
+ .thumb_set LPTIM2_IRQHandler,Default_Handler
+
+ .weak LPTIM3_IRQHandler
+ .thumb_set LPTIM3_IRQHandler,Default_Handler
+
+ .weak LPTIM4_IRQHandler
+ .thumb_set LPTIM4_IRQHandler,Default_Handler
+
+ .weak LPTIM5_IRQHandler
+ .thumb_set LPTIM5_IRQHandler,Default_Handler
+
+ .weak LPUART1_IRQHandler
+ .thumb_set LPUART1_IRQHandler,Default_Handler
+
+ .weak CRS_IRQHandler
+ .thumb_set CRS_IRQHandler,Default_Handler
+
+ .weak SAI4_IRQHandler
+ .thumb_set SAI4_IRQHandler,Default_Handler
+
+ .weak WAKEUP_PIN_IRQHandler
+ .thumb_set WAKEUP_PIN_IRQHandler,Default_Handler
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
+
diff --git a/ports/stm32/boards/startup_stm32l4.s b/ports/stm32/boards/startup_stm32l4.s
new file mode 100644
index 000000000..3225723ff
--- /dev/null
+++ b/ports/stm32/boards/startup_stm32l4.s
@@ -0,0 +1,549 @@
+/**
+ ******************************************************************************
+ * @file startup_stm32l496xx.s
+ * @author MCD Application Team
+ * @brief STM32L496xx devices vector table GCC toolchain.
+ * This module performs:
+ * - Set the initial SP
+ * - Set the initial PC == Reset_Handler,
+ * - Set the vector table entries with the exceptions ISR address,
+ * - Branches to main in the C library (which eventually
+ * calls main()).
+ * After Reset the Cortex-M4 processor is in Thread mode,
+ * priority is Privileged, and the Stack is set to Main.
+ * Taken from STM32L4 template code for stm32l496 in STM32Cube_FW_L4_V1.11.0
+ ******************************************************************************
+ * @attention
+ *
+ * <h2><center>&copy; COPYRIGHT 2017 STMicroelectronics</center></h2>
+ *
+ * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
+ * You may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.st.com/software_license_agreement_liberty_v2
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************
+ */
+
+ .syntax unified
+ .cpu cortex-m4
+ .fpu softvfp
+ .thumb
+
+.global g_pfnVectors
+.global Default_Handler
+
+/* start address for the initialization values of the .data section.
+defined in linker script */
+.word _sidata
+/* start address for the .data section. defined in linker script */
+.word _sdata
+/* end address for the .data section. defined in linker script */
+.word _edata
+/* start address for the .bss section. defined in linker script */
+.word _sbss
+/* end address for the .bss section. defined in linker script */
+.word _ebss
+/* stack used for SystemInit_ExtMemCtl; always internal RAM used */
+
+.equ BootRAM, 0xF1E0F85F
+/**
+ * @brief This is the code that gets called when the processor first
+ * starts execution following a reset event. Only the absolutely
+ * necessary set is performed, after which the application
+ * supplied main() routine is called.
+ * @param None
+ * @retval : None
+*/
+
+ .section .text.Reset_Handler
+ .weak Reset_Handler
+ .type Reset_Handler, %function
+Reset_Handler:
+ ldr sp, =_estack /* set stack pointer */
+
+/* Copy the data segment initializers from flash to SRAM */
+ movs r1, #0
+ b LoopCopyDataInit
+
+CopyDataInit:
+ ldr r3, =_sidata
+ ldr r3, [r3, r1]
+ str r3, [r0, r1]
+ adds r1, r1, #4
+
+LoopCopyDataInit:
+ ldr r0, =_sdata
+ ldr r3, =_edata
+ adds r2, r0, r1
+ cmp r2, r3
+ bcc CopyDataInit
+ ldr r2, =_sbss
+ b LoopFillZerobss
+/* Zero fill the bss segment. */
+FillZerobss:
+ movs r3, #0
+ str r3, [r2], #4
+
+LoopFillZerobss:
+ ldr r3, = _ebss
+ cmp r2, r3
+ bcc FillZerobss
+
+/* Call the clock system initialization function.*/
+ bl SystemInit
+/* Call static constructors */
+ /*bl __libc_init_array*/
+/* Call the application's entry point.*/
+ bl main
+ bx lr
+.size Reset_Handler, .-Reset_Handler
+
+/**
+ * @brief This is the code that gets called when the processor receives an
+ * unexpected interrupt. This simply enters an infinite loop, preserving
+ * the system state for examination by a debugger.
+ *
+ * @param None
+ * @retval None
+*/
+ .section .text.Default_Handler,"ax",%progbits
+Default_Handler:
+Infinite_Loop:
+ b Infinite_Loop
+ .size Default_Handler, .-Default_Handler
+/******************************************************************************
+*
+* The minimal vector table for a Cortex-M4. Note that the proper constructs
+* must be placed on this to ensure that it ends up at physical address
+* 0x0000.0000.
+*
+*******************************************************************************/
+ .section .isr_vector,"a",%progbits
+ .type g_pfnVectors, %object
+ .size g_pfnVectors, .-g_pfnVectors
+
+
+g_pfnVectors:
+ .word _estack
+ .word Reset_Handler
+ .word NMI_Handler
+ .word HardFault_Handler
+ .word MemManage_Handler
+ .word BusFault_Handler
+ .word UsageFault_Handler
+ .word 0
+ .word 0
+ .word 0
+ .word 0
+ .word SVC_Handler
+ .word DebugMon_Handler
+ .word 0
+ .word PendSV_Handler
+ .word SysTick_Handler
+
+ /* External Interrupts */
+ .word WWDG_IRQHandler /* Window WatchDog */
+ .word PVD_PVM_IRQHandler /* PVD and PVM through EXTI line detection */
+ .word TAMP_STAMP_IRQHandler /* Tamper and TimeStamps through the EXTI line */
+ .word RTC_WKUP_IRQHandler /* RTC Wakeup through the EXTI line */
+ .word FLASH_IRQHandler /* FLASH */
+ .word RCC_IRQHandler /* RCC */
+ .word EXTI0_IRQHandler /* EXTI Line0 */
+ .word EXTI1_IRQHandler /* EXTI Line1 */
+ .word EXTI2_IRQHandler /* EXTI Line2 */
+ .word EXTI3_IRQHandler /* EXTI Line3 */
+ .word EXTI4_IRQHandler /* EXTI Line4 */
+ .word DMA1_Channel1_IRQHandler /* DMA1 Channel 1 */
+ .word DMA1_Channel2_IRQHandler /* DMA1 Channel 2 */
+ .word DMA1_Channel3_IRQHandler /* DMA1 Channel 3 */
+ .word DMA1_Channel4_IRQHandler /* DMA1 Channel 4 */
+ .word DMA1_Channel5_IRQHandler /* DMA1 Channel 5 */
+ .word DMA1_Channel6_IRQHandler /* DMA1 Channel 6 */
+ .word DMA1_Channel7_IRQHandler /* DMA1 Channel 7 */
+ .word ADC1_2_IRQHandler /* ADC1 and ADC2 */
+ .word CAN1_TX_IRQHandler /* CAN1 TX */
+ .word CAN1_RX0_IRQHandler /* CAN1 RX0 */
+ .word CAN1_RX1_IRQHandler /* CAN1 RX1 */
+ .word CAN1_SCE_IRQHandler /* CAN1 SCE */
+ .word EXTI9_5_IRQHandler /* External Line[9:5]s */
+ .word TIM1_BRK_TIM15_IRQHandler /* TIM1 Break and TIM15 */
+ .word TIM1_UP_TIM16_IRQHandler /* TIM1 Update and TIM16 */
+ .word TIM1_TRG_COM_TIM17_IRQHandler /* TIM1 Trigger and Commutation and TIM17 */
+ .word TIM1_CC_IRQHandler /* TIM1 Capture Compare */
+ .word TIM2_IRQHandler /* TIM2 */
+ .word TIM3_IRQHandler /* TIM3 */
+ .word TIM4_IRQHandler /* TIM4 */
+ .word I2C1_EV_IRQHandler /* I2C1 Event */
+ .word I2C1_ER_IRQHandler /* I2C1 Error */
+ .word I2C2_EV_IRQHandler /* I2C2 Event */
+ .word I2C2_ER_IRQHandler /* I2C2 Error */
+ .word SPI1_IRQHandler /* SPI1 */
+ .word SPI2_IRQHandler /* SPI2 */
+ .word USART1_IRQHandler /* USART1 */
+ .word USART2_IRQHandler /* USART2 */
+ .word USART3_IRQHandler /* USART3 */
+ .word EXTI15_10_IRQHandler /* External Line[15:10]s */
+ .word RTC_Alarm_IRQHandler /* RTC Alarm (A and B) through EXTI Line */
+ .word DFSDM1_FLT3_IRQHandler /* Digital filter 3 for sigma delta modulator */
+ .word TIM8_BRK_IRQHandler /* TIM8 Break */
+ .word TIM8_UP_IRQHandler /* TIM8 Update */
+ .word TIM8_TRG_COM_IRQHandler /* TIM8 Trigger and Commutation */
+ .word TIM8_CC_IRQHandler /* TIM8 Capture Compare */
+ .word ADC3_IRQHandler /* ADC3 global interrupt */
+ .word FMC_IRQHandler /* FMC */
+ .word SDMMC1_IRQHandler /* SDMMC1 */
+ .word TIM5_IRQHandler /* TIM5 */
+ .word SPI3_IRQHandler /* SPI3 */
+ .word UART4_IRQHandler /* UART4 */
+ .word UART5_IRQHandler /* UART5 */
+ .word TIM6_DAC_IRQHandler /* TIM6 and DAC1&2 underrun errors */
+ .word TIM7_IRQHandler /* TIM7 */
+ .word DMA2_Channel1_IRQHandler /* DMA2 Channel 1 */
+ .word DMA2_Channel2_IRQHandler /* DMA2 Channel 2 */
+ .word DMA2_Channel3_IRQHandler /* DMA2 Channel 3 */
+ .word DMA2_Channel4_IRQHandler /* DMA2 Channel 4 */
+ .word DMA2_Channel5_IRQHandler /* DMA2 Channel 5 */
+ .word DFSDM1_FLT0_IRQHandler /* Digital filter 0 for sigma delta modulator */
+ .word DFSDM1_FLT1_IRQHandler /* Digital filter 1 for sigma delta modulator */
+ .word DFSDM1_FLT2_IRQHandler /* Digital filter 2 for sigma delta modulator */
+ .word COMP_IRQHandler /* Comporator thru EXTI line */
+ .word LPTIM1_IRQHandler /* Low power timer 1 */
+ .word LPTIM2_IRQHandler /* Low power timer 2 */
+ .word OTG_FS_IRQHandler /* USB OTG FS */
+ .word DMA2_Channel6_IRQHandler /* DMA2 Channel 6 */
+ .word DMA2_Channel7_IRQHandler /* DMA2 Channel 7 */
+ .word LPUART1_IRQHandler /* Low power UART */
+ .word QUADSPI_IRQHandler /* Quad SPI */
+ .word I2C3_EV_IRQHandler /* I2C3 event */
+ .word I2C3_ER_IRQHandler /* I2C3 error */
+ .word SAI1_IRQHandler /* Serial audio interface 1 */
+ .word SAI2_IRQHandler /* Serial audio interface 2 */
+ .word SWPMI1_IRQHandler /* Single wire protocole 1 */
+ .word TSC_IRQHandler /* Touch sensig controller */
+ .word LCD_IRQHandler /* LCD */
+ .word 0 /* CRYP crypto */
+ .word RNG_IRQHandler /* Random number generator */
+ .word FPU_IRQHandler /* FPU */
+ /* Following Handlers are only used on L496/4A6xx devices */
+ .word CRS_IRQHandler /* HASH and CRS interrupt */
+ .word I2C4_EV_IRQHandler /* I2C4 event interrupt */
+ .word I2C4_ER_IRQHandler /* I2C4 error interrupt */
+ .word DCMI_IRQHandler /* DCMI global interrupt */
+ .word CAN2_TX_IRQHandler /* CAN2 TX interrupt */
+ .word CAN2_RX0_IRQHandler /* CAN2 RX0 interrupt */
+ .word CAN2_RX1_IRQHandler /* CAN2 RX1 interrupt */
+ .word CAN2_SCE_IRQHandler /* CAN SCE interrupt */
+ .word DMA2D_IRQHandler /* DMA2D global interrupt */
+
+/*******************************************************************************
+*
+* Provide weak aliases for each Exception handler to the Default_Handler.
+* As they are weak aliases, any function with the same name will override
+* this definition.
+*
+*******************************************************************************/
+ .weak NMI_Handler
+ .thumb_set NMI_Handler,Default_Handler
+
+ .weak HardFault_Handler
+ .thumb_set HardFault_Handler,Default_Handler
+
+ .weak MemManage_Handler
+ .thumb_set MemManage_Handler,Default_Handler
+
+ .weak BusFault_Handler
+ .thumb_set BusFault_Handler,Default_Handler
+
+ .weak UsageFault_Handler
+ .thumb_set UsageFault_Handler,Default_Handler
+
+ .weak SVC_Handler
+ .thumb_set SVC_Handler,Default_Handler
+
+ .weak DebugMon_Handler
+ .thumb_set DebugMon_Handler,Default_Handler
+
+ .weak PendSV_Handler
+ .thumb_set PendSV_Handler,Default_Handler
+
+ .weak SysTick_Handler
+ .thumb_set SysTick_Handler,Default_Handler
+
+ .weak WWDG_IRQHandler
+ .thumb_set WWDG_IRQHandler,Default_Handler
+
+ .weak PVD_PVM_IRQHandler
+ .thumb_set PVD_PVM_IRQHandler,Default_Handler
+
+ .weak TAMP_STAMP_IRQHandler
+ .thumb_set TAMP_STAMP_IRQHandler,Default_Handler
+
+ .weak RTC_WKUP_IRQHandler
+ .thumb_set RTC_WKUP_IRQHandler,Default_Handler
+
+ .weak FLASH_IRQHandler
+ .thumb_set FLASH_IRQHandler,Default_Handler
+
+ .weak RCC_IRQHandler
+ .thumb_set RCC_IRQHandler,Default_Handler
+
+ .weak EXTI0_IRQHandler
+ .thumb_set EXTI0_IRQHandler,Default_Handler
+
+ .weak EXTI1_IRQHandler
+ .thumb_set EXTI1_IRQHandler,Default_Handler
+
+ .weak EXTI2_IRQHandler
+ .thumb_set EXTI2_IRQHandler,Default_Handler
+
+ .weak EXTI3_IRQHandler
+ .thumb_set EXTI3_IRQHandler,Default_Handler
+
+ .weak EXTI4_IRQHandler
+ .thumb_set EXTI4_IRQHandler,Default_Handler
+
+ .weak DMA1_Channel1_IRQHandler
+ .thumb_set DMA1_Channel1_IRQHandler,Default_Handler
+
+ .weak DMA1_Channel2_IRQHandler
+ .thumb_set DMA1_Channel2_IRQHandler,Default_Handler
+
+ .weak DMA1_Channel3_IRQHandler
+ .thumb_set DMA1_Channel3_IRQHandler,Default_Handler
+
+ .weak DMA1_Channel4_IRQHandler
+ .thumb_set DMA1_Channel4_IRQHandler,Default_Handler
+
+ .weak DMA1_Channel5_IRQHandler
+ .thumb_set DMA1_Channel5_IRQHandler,Default_Handler
+
+ .weak DMA1_Channel6_IRQHandler
+ .thumb_set DMA1_Channel6_IRQHandler,Default_Handler
+
+ .weak DMA1_Channel7_IRQHandler
+ .thumb_set DMA1_Channel7_IRQHandler,Default_Handler
+
+ .weak ADC1_2_IRQHandler
+ .thumb_set ADC1_2_IRQHandler,Default_Handler
+
+ .weak CAN1_TX_IRQHandler
+ .thumb_set CAN1_TX_IRQHandler,Default_Handler
+
+ .weak CAN1_RX0_IRQHandler
+ .thumb_set CAN1_RX0_IRQHandler,Default_Handler
+
+ .weak CAN1_RX1_IRQHandler
+ .thumb_set CAN1_RX1_IRQHandler,Default_Handler
+
+ .weak CAN1_SCE_IRQHandler
+ .thumb_set CAN1_SCE_IRQHandler,Default_Handler
+
+ .weak EXTI9_5_IRQHandler
+ .thumb_set EXTI9_5_IRQHandler,Default_Handler
+
+ .weak TIM1_BRK_TIM15_IRQHandler
+ .thumb_set TIM1_BRK_TIM15_IRQHandler,Default_Handler
+
+ .weak TIM1_UP_TIM16_IRQHandler
+ .thumb_set TIM1_UP_TIM16_IRQHandler,Default_Handler
+
+ .weak TIM1_TRG_COM_TIM17_IRQHandler
+ .thumb_set TIM1_TRG_COM_TIM17_IRQHandler,Default_Handler
+
+ .weak TIM1_CC_IRQHandler
+ .thumb_set TIM1_CC_IRQHandler,Default_Handler
+
+ .weak TIM2_IRQHandler
+ .thumb_set TIM2_IRQHandler,Default_Handler
+
+ .weak TIM3_IRQHandler
+ .thumb_set TIM3_IRQHandler,Default_Handler
+
+ .weak TIM4_IRQHandler
+ .thumb_set TIM4_IRQHandler,Default_Handler
+
+ .weak I2C1_EV_IRQHandler
+ .thumb_set I2C1_EV_IRQHandler,Default_Handler
+
+ .weak I2C1_ER_IRQHandler
+ .thumb_set I2C1_ER_IRQHandler,Default_Handler
+
+ .weak I2C2_EV_IRQHandler
+ .thumb_set I2C2_EV_IRQHandler,Default_Handler
+
+ .weak I2C2_ER_IRQHandler
+ .thumb_set I2C2_ER_IRQHandler,Default_Handler
+
+ .weak SPI1_IRQHandler
+ .thumb_set SPI1_IRQHandler,Default_Handler
+
+ .weak SPI2_IRQHandler
+ .thumb_set SPI2_IRQHandler,Default_Handler
+
+ .weak USART1_IRQHandler
+ .thumb_set USART1_IRQHandler,Default_Handler
+
+ .weak USART2_IRQHandler
+ .thumb_set USART2_IRQHandler,Default_Handler
+
+ .weak USART3_IRQHandler
+ .thumb_set USART3_IRQHandler,Default_Handler
+
+ .weak EXTI15_10_IRQHandler
+ .thumb_set EXTI15_10_IRQHandler,Default_Handler
+
+ .weak RTC_Alarm_IRQHandler
+ .thumb_set RTC_Alarm_IRQHandler,Default_Handler
+
+ .weak DFSDM1_FLT3_IRQHandler
+ .thumb_set DFSDM1_FLT3_IRQHandler,Default_Handler
+
+ .weak TIM8_BRK_IRQHandler
+ .thumb_set TIM8_BRK_IRQHandler,Default_Handler
+
+ .weak TIM8_UP_IRQHandler
+ .thumb_set TIM8_UP_IRQHandler,Default_Handler
+
+ .weak TIM8_TRG_COM_IRQHandler
+ .thumb_set TIM8_TRG_COM_IRQHandler,Default_Handler
+
+ .weak TIM8_CC_IRQHandler
+ .thumb_set TIM8_CC_IRQHandler,Default_Handler
+
+ .weak ADC3_IRQHandler
+ .thumb_set ADC3_IRQHandler,Default_Handler
+
+ .weak FMC_IRQHandler
+ .thumb_set FMC_IRQHandler,Default_Handler
+
+ .weak SDMMC1_IRQHandler
+ .thumb_set SDMMC1_IRQHandler,Default_Handler
+
+ .weak TIM5_IRQHandler
+ .thumb_set TIM5_IRQHandler,Default_Handler
+
+ .weak SPI3_IRQHandler
+ .thumb_set SPI3_IRQHandler,Default_Handler
+
+ .weak UART4_IRQHandler
+ .thumb_set UART4_IRQHandler,Default_Handler
+
+ .weak UART5_IRQHandler
+ .thumb_set UART5_IRQHandler,Default_Handler
+
+ .weak TIM6_DAC_IRQHandler
+ .thumb_set TIM6_DAC_IRQHandler,Default_Handler
+
+ .weak TIM7_IRQHandler
+ .thumb_set TIM7_IRQHandler,Default_Handler
+
+ .weak DMA2_Channel1_IRQHandler
+ .thumb_set DMA2_Channel1_IRQHandler,Default_Handler
+
+ .weak DMA2_Channel2_IRQHandler
+ .thumb_set DMA2_Channel2_IRQHandler,Default_Handler
+
+ .weak DMA2_Channel3_IRQHandler
+ .thumb_set DMA2_Channel3_IRQHandler,Default_Handler
+
+ .weak DMA2_Channel4_IRQHandler
+ .thumb_set DMA2_Channel4_IRQHandler,Default_Handler
+
+ .weak DMA2_Channel5_IRQHandler
+ .thumb_set DMA2_Channel5_IRQHandler,Default_Handler
+
+ .weak DFSDM1_FLT0_IRQHandler
+ .thumb_set DFSDM1_FLT0_IRQHandler,Default_Handler
+
+ .weak DFSDM1_FLT1_IRQHandler
+ .thumb_set DFSDM1_FLT1_IRQHandler,Default_Handler
+
+ .weak DFSDM1_FLT2_IRQHandler
+ .thumb_set DFSDM1_FLT2_IRQHandler,Default_Handler
+
+ .weak COMP_IRQHandler
+ .thumb_set COMP_IRQHandler,Default_Handler
+
+ .weak LPTIM1_IRQHandler
+ .thumb_set LPTIM1_IRQHandler,Default_Handler
+
+ .weak LPTIM2_IRQHandler
+ .thumb_set LPTIM2_IRQHandler,Default_Handler
+
+ .weak OTG_FS_IRQHandler
+ .thumb_set OTG_FS_IRQHandler,Default_Handler
+
+ .weak DMA2_Channel6_IRQHandler
+ .thumb_set DMA2_Channel6_IRQHandler,Default_Handler
+
+ .weak DMA2_Channel7_IRQHandler
+ .thumb_set DMA2_Channel7_IRQHandler,Default_Handler
+
+ .weak LPUART1_IRQHandler
+ .thumb_set LPUART1_IRQHandler,Default_Handler
+
+ .weak QUADSPI_IRQHandler
+ .thumb_set QUADSPI_IRQHandler,Default_Handler
+
+ .weak I2C3_EV_IRQHandler
+ .thumb_set I2C3_EV_IRQHandler,Default_Handler
+
+ .weak I2C3_ER_IRQHandler
+ .thumb_set I2C3_ER_IRQHandler,Default_Handler
+
+ .weak SAI1_IRQHandler
+ .thumb_set SAI1_IRQHandler,Default_Handler
+
+ .weak SAI2_IRQHandler
+ .thumb_set SAI2_IRQHandler,Default_Handler
+
+ .weak SWPMI1_IRQHandler
+ .thumb_set SWPMI1_IRQHandler,Default_Handler
+
+ .weak TSC_IRQHandler
+ .thumb_set TSC_IRQHandler,Default_Handler
+
+ .weak LCD_IRQHandler
+ .thumb_set LCD_IRQHandler,Default_Handler
+
+ .weak RNG_IRQHandler
+ .thumb_set RNG_IRQHandler,Default_Handler
+
+ .weak FPU_IRQHandler
+ .thumb_set FPU_IRQHandler,Default_Handler
+
+ .weak CRS_IRQHandler
+ .thumb_set CRS_IRQHandler,Default_Handler
+
+ .weak I2C4_EV_IRQHandler
+ .thumb_set I2C4_EV_IRQHandler,Default_Handler
+
+ .weak I2C4_ER_IRQHandler
+ .thumb_set I2C4_ER_IRQHandler,Default_Handler
+
+ .weak DCMI_IRQHandler
+ .thumb_set DCMI_IRQHandler,Default_Handler
+
+ .weak CAN2_TX_IRQHandler
+ .thumb_set CAN2_TX_IRQHandler,Default_Handler
+
+ .weak CAN2_RX0_IRQHandler
+ .thumb_set CAN2_RX0_IRQHandler,Default_Handler
+
+ .weak CAN2_RX1_IRQHandler
+ .thumb_set CAN2_RX1_IRQHandler,Default_Handler
+
+ .weak CAN2_SCE_IRQHandler
+ .thumb_set CAN2_SCE_IRQHandler,Default_Handler
+
+ .weak DMA2D_IRQHandler
+ .thumb_set DMA2D_IRQHandler,Default_Handler
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/ports/stm32/boards/stm32f091_af.csv b/ports/stm32/boards/stm32f091_af.csv
new file mode 100644
index 000000000..38e134f8a
--- /dev/null
+++ b/ports/stm32/boards/stm32f091_af.csv
@@ -0,0 +1,89 @@
+Port,Pin,AF0,AF1,AF2,AF3,AF4,AF5,AF6,AF7,,,,,,,,,
+,,AF0,AF1,AF2,AF3,AF4,AF5,AF6,AF7,,,,,,,,,ADC
+PortA,PA0,,USART2_CTS,TIM2_CH1_ETR,TSC_G1_IO1,USART4_TX,,,COMP1_OUT,,,,,,,,,ADC1_IN0
+PortA,PA1,EVENTOUT,USART2_RTS,TIM2_CH2,TSC_G1_IO2,USART4_RX,TIM15_CH1N,,,,,,,,,,,ADC1_IN1
+PortA,PA2,TIM15_CH1,USART2_TX,TIM2_CH3,TSC_G1_IO3,,,,COMP2_OUT,,,,,,,,,ADC1_IN2
+PortA,PA3,TIM15_CH2,USART2_RX,TIM2_CH4,TSC_G1_IO4,,,,,,,,,,,,,ADC1_IN3
+PortA,PA4,SPI1_NSS/I2S1_WS,USART2_CK,,TSC_G2_IO1,TIM14_CH1,USART6_TX,,,,,,,,,,,ADC1_IN4
+PortA,PA5,SPI1_SCK/I2S1_CK,CEC,TIM2_CH1_ETR,TSC_G2_IO2,,USART6_RX,,,,,,,,,,,ADC1_IN5
+PortA,PA6,SPI1_MISO/I2S1_MCK,TIM3_CH1,TIM1_BKIN,TSC_G2_IO3,USART3_CTS,TIM16_CH1,EVENTOUT,COMP1_OUT,,,,,,,,,ADC1_IN6
+PortA,PA7,SPI1_MOSI/I2S1_SD,TIM3_CH2,TIM1_CH1N,TSC_G2_IO4,TIM14_CH1,TIM17_CH1,EVENTOUT,COMP2_OUT,,,,,,,,,ADC1_IN7
+PortA,PA8,MCO,USART1_CK,TIM1_CH1,EVENTOUT,CRS_SYNC,,,,,,,,,,,,
+PortA,PA9,TIM15_BKIN,USART1_TX,TIM1_CH2,TSC_G4_IO1,I2C1_SCL,MCO,,,,,,,,,,,
+PortA,PA10,TIM17_BKIN,USART1_RX,TIM1_CH3,TSC_G4_IO2,I2C1_SDA,,,,,,,,,,,,
+PortA,PA11,EVENTOUT,USART1_CTS,TIM1_CH4,TSC_G4_IO3,CAN1_RX,I2C2_SCL,,COMP1_OUT,,,,,,,,,
+PortA,PA12,EVENTOUT,USART1_RTS,TIM1_ETR,TSC_G4_IO4,CAN1_TX,I2C2_SDA,,COMP2_OUT,,,,,,,,,
+PortA,PA13,SWDIO,IR_OUT,,,,,,,,,,,,,,,
+PortA,PA14,SWCLK,USART2_TX,,,,,,,,,,,,,,,
+PortA,PA15,SPI1_NSS/I2S1_WS,USART2_RX,TIM2_CH1_ETR,EVENTOUT,USART4_RTS,,,,,,,,,,,,
+PortB,PB0,EVENTOUT,TIM3_CH3,TIM1_CH2N,TSC_G3_IO2,USART3_CK,,,,,,,,,,,,ADC1_IN8
+PortB,PB1,TIM14_CH1,TIM3_CH4,TIM1_CH3N,TSC_G3_IO3,USART3_RTS,,,,,,,,,,,,ADC1_IN9
+PortB,PB2,,,,TSC_G3_IO4,,,,,,,,,,,,,
+PortB,PB3,SPI1_SCK/I2S1_CK,EVENTOUT,TIM2_CH2,TSC_G5_IO1,USART5_TX,,,,,,,,,,
+PortB,PB4,SPI1_MISO/I2S1_MCK,TIM3_CH1,EVENTOUT,TSC_G5_IO2,USART5_RX,TIM17_BKIN,,,,,,,,,
+PortB,PB5,SPI1_MOSI/I2S1_SD,TIM3_CH2,TIM16_BKIN,I2C1_SMBA,USART5_CK/USART5_RTS,,,,,,,,,,
+PortB,PB6,USART1_TX,I2C1_SCL,TIM16_CH1N,TSC_G5_IO3,,,,,,,,,,,
+PortB,PB7,USART1_RX,I2C1_SDA,TIM17_CH1N,TSC_G5_IO4,USART4_CTS,,,,,,,,,,
+PortB,PB8,CEC,I2C1_SCL,TIM16_CH1,TSC_SYNC,CAN1_RX,,,,,,,,,,
+PortB,PB9,IR_OUT,I2C1_SDA,TIM17_CH1,EVENTOUT,CAN1_TX,SPI2_NSS/I2S2_WS,,,,,,,,,
+PortB,PB10,CEC,I2C2_SCL,TIM2_CH3,TSC_SYNC,USART3_TX,SPI2_SCK/I2S2_CK,,,,,,,,,
+PortB,PB11,EVENTOUT,I2C2_SDA,TIM2_CH4,TSC_G6_IO1,USART3_RX,,,,,,,,,,
+PortB,PB12,SPI2_NSS/I2S2_WS,EVENTOUT,TIM1_BKIN,TSC_G6_IO2,USART3_CK,TIM15_BKIN,,,,,,,,,
+PortB,PB13,SPI2_SCK/I2S2_CK,,TIM1_CH1N,TSC_G6_IO3,USART3_CTS,I2C2_SCL,,,,,,,,,
+PortB,PB14,SPI2_MISO/I2S2_MCK,TIM15_CH1,TIM1_CH2N,TSC_G6_IO4,USART3_RTS,I2C2_SDA,,,,,,,,,
+PortB,PB15,SPI2_MOSI/I2S2_SD,TIM15_CH2,TIM1_CH3N,TIM15_CH1N,,,,,,,,,,,
+PortC,PC0,EVENTOUT,USART7_TX,USART6_TX,,,,,,,,,,,,,,ADC1_IN10
+PortC,PC1,EVENTOUT,USART7_RX,USART6_RX,,,,,,,,,,,,,,ADC1_IN11
+PortC,PC2,EVENTOUT,SPI2_MISO/I2S2_MCK,USART8_TX,,,,,,,,,,,,,,ADC1_IN12
+PortC,PC3,EVENTOUT,SPI2_MOSI/I2S2_SD,USART8_RX,,,,,,,,,,,,,,ADC1_IN13
+PortC,PC4,EVENTOUT,USART3_TX,,,,,,,,,,,,,,,ADC1_IN14
+PortC,PC5,TSC_G3_IO1,USART3_RX,,,,,,,,,,,,,,,ADC1_IN15
+PortC,PC6,TIM3_CH1,USART7_TX,,,,,,,,,,,,,,,
+PortC,PC7,TIM3_CH2,USART7_RX,,,,,,,,,,,,,,,
+PortC,PC8,TIM3_CH3,USART8_TX,,,,,,,,,,,,,,,
+PortC,PC9,TIM3_CH4,USART8_RX,,,,,,,,,,,,,,,
+PortC,PC10,USART4_TX,USART3_TX,,,,,,,,,,,,,,,
+PortC,PC11,USART4_RX,USART3_RX,,,,,,,,,,,,,,,
+PortC,PC12,USART4_CK,USART3_CK,USART5_TX,,,,,,,,,,,,,,
+PortC,PC13,,,,,,,,,,,,,,,,,
+PortC,PC14,,,,,,,,,,,,,,,,,
+PortC,PC15,,,,,,,,,,,,,,,,,
+PortD,PD0,CAN1_RX,SPI2_NSS/I2S2_WS,,,,,,,,,,,,,,,
+PortD,PD1,CAN1_TX,SPI2_SCK/I2S2_CK,,,,,,,,,,,,,,,
+PortD,PD2,TIM3_ETR,USART3_RTS,USART5_RX,,,,,,,,,,,,,,
+PortD,PD3,USART2_CTS,SPI2_MISO/I2S2_MCK,,,,,,,,,,,,,,,
+PortD,PD4,USART2_RTS,SPI2_MOSI/I2S2_SD,,,,,,,,,,,,,,,
+PortD,PD5,USART2_TX,,,,,,,,,,,,,,,,
+PortD,PD6,USART2_RX,,,,,,,,,,,,,,,,
+PortD,PD7,USART2_CK,,,,,,,,,,,,,,,,
+PortD,PD8,USART3_TX,,,,,,,,,,,,,,,,
+PortD,PD9,USART3_RX,,,,,,,,,,,,,,,,
+PortD,PD10,USART3_CK,,,,,,,,,,,,,,,,
+PortD,PD11,USART3_CTS,,,,,,,,,,,,,,,,
+PortD,PD12,USART3_RTS,TSC_G8_IO1,USART8_CK/USART8_RTS,,,,,,,,,,,,,,
+PortD,PD13,USART8_TX,TSC_G8_IO2,,,,,,,,,,,,,,,
+PortD,PD14,USART8_RX,TSC_G8_IO3,,,,,,,,,,,,,,,
+PortD,PD15,CRS_SYNC,TSC_G8_IO4,USART7_CK/USART7_RTS,,,,,,,,,,,,,,
+PortE,PE0,TIM16_CH1,EVENTOUT,,,,,,,,,,,,,,,
+PortE,PE1,TIM17_CH1,EVENTOUT,,,,,,,,,,,,,,,
+PortE,PE2,TIM3_ETR,TSC_G7_IO1,,,,,,,,,,,,,,,
+PortE,PE3,TIM3_CH1,TSC_G7_IO2,,,,,,,,,,,,,,,
+PortE,PE4,TIM3_CH2,TSC_G7_IO3,,,,,,,,,,,,,,,
+PortE,PE5,TIM3_CH3,TSC_G7_IO4,,,,,,,,,,,,,,,
+PortE,PE6,TIM3_CH4,,,,,,,,,,,,,,,,
+PortE,PE7,TIM1_ETR,USART5_CK/USART5_RTS,,,,,,,,,,,,,,,
+PortE,PE8,TIM1_CH1N,USART4_TX,,,,,,,,,,,,,,,
+PortE,PE9,TIM1_CH1,USART4_RX,,,,,,,,,,,,,,,
+PortE,PE10,TIM1_CH2N,USART5_TX,,,,,,,,,,,,,,,
+PortE,PE11,TIM1_CH2,USART5_RX,,,,,,,,,,,,,,,
+PortE,PE12,TIM1_CH3N,SPI1_NSS/I2S1_WS,,,,,,,,,,,,,,,
+PortE,PE13,TIM1_CH3,SPI1_SCK/I2S1_CK,,,,,,,,,,,,,,,
+PortE,PE14,TIM1_CH4,SPI1_MISO/I2S1_MCK,,,,,,,,,,,,,,,
+PortE,PE15,TIM1_BKIN,SPI1_MOSI/I2S1_SD,,,,,,,,,,,,,,,
+PortF,PF0,CRS_SYNC,I2C1_SDA,,,,,,,,,,,,,,,
+PortF,PF1,,I2C1_SCL,,,,,,,,,,,,,,,
+PortF,PF2,EVENTOUT,USART7_TX,USART7_CK/USART7_RTS,,,,,,,,,,,,,,
+PortF,PF3,EVENTOUT,USART7_RX,USART6_CK/USART6_RTS,,,,,,,,,,,,,,
+PortF,PF6,,,,,,,,,,,,,,,,,
+PortF,PF9,TIM15_CH1,USART6_TX,,,,,,,,,,,,,,,
+PortF,PF10,TIM15_CH2,USART6_RX,,,,,,,,,,,,,,,
diff --git a/ports/stm32/boards/stm32f091xc.ld b/ports/stm32/boards/stm32f091xc.ld
new file mode 100644
index 000000000..73b844295
--- /dev/null
+++ b/ports/stm32/boards/stm32f091xc.ld
@@ -0,0 +1,26 @@
+/*
+ GNU linker script for STM32F091xC
+*/
+
+/* Specify the memory areas */
+MEMORY
+{
+ FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 256K
+ FLASH_TEXT (rx) : ORIGIN = 0x08000000, LENGTH = 256K
+ RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 32K
+}
+
+/* produce a link error if there is not this amount of RAM for these sections */
+_minimum_stack_size = 2K;
+_minimum_heap_size = 16K;
+
+/* Define tho top end of the stack. The stack is full descending so begins just
+ above last byte of RAM. Note that EABI requires the stack to be 8-byte
+ aligned for a call. */
+_estack = ORIGIN(RAM) + LENGTH(RAM);
+
+/* RAM extents for the garbage collector */
+_ram_start = ORIGIN(RAM);
+_ram_end = ORIGIN(RAM) + LENGTH(RAM);
+_heap_start = _ebss; /* heap starts just after statically allocated memory */
+_heap_end = 0x20006800; /* room for a 6k stack */
diff --git a/ports/stm32/boards/stm32f401_af.csv b/ports/stm32/boards/stm32f401_af.csv
index 3b29e1349..1acb8e431 100644
--- a/ports/stm32/boards/stm32f401_af.csv
+++ b/ports/stm32/boards/stm32f401_af.csv
@@ -13,13 +13,13 @@ PortA,PA9,,TIM1_CH2,,,I2C3_SMBA,,,USART1_TX,,,OTG_FS_VBUS,,,,,EVENTOUT,
PortA,PA10,,TIM1_CH3,,,,,,USART1_RX,,,OTG_FS_ID,,,,,EVENTOUT,
PortA,PA11,,TIM1_CH4,,,,,,USART1_CTS,USART6_TX,,OTG_FS_DM,,,,,EVENTOUT,
PortA,PA12,,TIM1_ETR,,,,,,USART1_RTS,USART6_RX,,OTG_FS_DP,,,,,EVENTOUT,
-PortA,PA13,JTMS_SWDIO,,,,,,,,,,,,,,,EVENTOUT,
-PortA,PA14,JTCK_SWCLK,,,,,,,,,,,,,,,EVENTOUT,
+PortA,PA13,JTMS/SWDIO,,,,,,,,,,,,,,,EVENTOUT,
+PortA,PA14,JTCK/SWCLK,,,,,,,,,,,,,,,EVENTOUT,
PortA,PA15,JTDI,TIM2_CH1/TIM2_ETR,,,,SPI1_NSS,SPI3_NSS/I2S3_WS,,,,,,,,,EVENTOUT,
PortB,PB0,,TIM1_CH2N,TIM3_CH3,,,,,,,,,,,,,EVENTOUT,ADC1_IN8
PortB,PB1,,TIM1_CH3N,TIM3_CH4,,,,,,,,,,,,,EVENTOUT,ADC1_IN9
PortB,PB2,,,,,,,,,,,,,,,,EVENTOUT,
-PortB,PB3,JTDO_SWO,TIM2_CH2,,,,SPI1_SCK,SPI3_SCK/I2S3_CK,,,I2C2_SDA,,,,,,EVENTOUT,
+PortB,PB3,JTDO/TRACESWO,TIM2_CH2,,,,SPI1_SCK,SPI3_SCK/I2S3_CK,,,I2C2_SDA,,,,,,EVENTOUT,
PortB,PB4,JTRST,,TIM3_CH1,,,SPI1_MISO,SPI3_MISO,I2S3ext_SD,,I2C3_SDA,,,,,,EVENTOUT,
PortB,PB5,,,TIM3_CH2,,I2C1_SMBA,SPI1_MOSI,SPI3_MOSI/I2S3_SD,,,,,,,,,EVENTOUT,
PortB,PB6,,,TIM4_CH1,,I2C1_SCL,,,USART1_TX,,,,,,,,EVENTOUT,
diff --git a/ports/stm32/boards/stm32f401xd.ld b/ports/stm32/boards/stm32f401xd.ld
index 89f605609..7c0e79018 100644
--- a/ports/stm32/boards/stm32f401xd.ld
+++ b/ports/stm32/boards/stm32f401xd.ld
@@ -21,9 +21,6 @@ _minimum_heap_size = 16K;
aligned for a call. */
_estack = ORIGIN(RAM) + LENGTH(RAM);
-/* define common sections and symbols */
-INCLUDE common.ld
-
/* RAM extents for the garbage collector */
_ram_start = ORIGIN(RAM);
_ram_end = ORIGIN(RAM) + LENGTH(RAM);
diff --git a/ports/stm32/boards/stm32f401xe.ld b/ports/stm32/boards/stm32f401xe.ld
index ae2f89904..e76bbad1c 100644
--- a/ports/stm32/boards/stm32f401xe.ld
+++ b/ports/stm32/boards/stm32f401xe.ld
@@ -21,9 +21,6 @@ _minimum_heap_size = 16K;
aligned for a call. */
_estack = ORIGIN(RAM) + LENGTH(RAM);
-/* define common sections and symbols */
-INCLUDE common.ld
-
/* RAM extents for the garbage collector */
_ram_start = ORIGIN(RAM);
_ram_end = ORIGIN(RAM) + LENGTH(RAM);
diff --git a/ports/stm32/boards/stm32f405.ld b/ports/stm32/boards/stm32f405.ld
index c6107913f..0375491f6 100644
--- a/ports/stm32/boards/stm32f405.ld
+++ b/ports/stm32/boards/stm32f405.ld
@@ -22,9 +22,6 @@ _minimum_heap_size = 16K;
aligned for a call. */
_estack = ORIGIN(RAM) + LENGTH(RAM);
-/* define common sections and symbols */
-INCLUDE common.ld
-
/* RAM extents for the garbage collector */
_ram_start = ORIGIN(RAM);
_ram_end = ORIGIN(RAM) + LENGTH(RAM);
diff --git a/ports/stm32/boards/stm32f405_af.csv b/ports/stm32/boards/stm32f405_af.csv
index 81f5e80ed..e6d8fcc2b 100644
--- a/ports/stm32/boards/stm32f405_af.csv
+++ b/ports/stm32/boards/stm32f405_af.csv
@@ -13,8 +13,8 @@ PortA,PA9,,TIM1_CH2,,,I2C3_SMBA,,,USART1_TX,,,,,,DCMI_D0,,EVENTOUT,
PortA,PA10,,TIM1_CH3,,,,,,USART1_RX,,,OTG_FS_ID,,,DCMI_D1,,EVENTOUT,
PortA,PA11,,TIM1_CH4,,,,,,USART1_CTS,,CAN1_RX,OTG_FS_DM,,,,,EVENTOUT,
PortA,PA12,,TIM1_ETR,,,,,,USART1_RTS,,CAN1_TX,OTG_FS_DP,,,,,EVENTOUT,
-PortA,PA13,JTMS-SWDIO,,,,,,,,,,,,,,,EVENTOUT,
-PortA,PA14,JTCK-SWCLK,,,,,,,,,,,,,,,EVENTOUT,
+PortA,PA13,JTMS/SWDIO,,,,,,,,,,,,,,,EVENTOUT,
+PortA,PA14,JTCK/SWCLK,,,,,,,,,,,,,,,EVENTOUT,
PortA,PA15,JTDI,TIM2_CH1/TIM2_ETR,,,,SPI1_NSS,SPI3_NSS/I2S3_WS,,,,,,,,,EVENTOUT,
PortB,PB0,,TIM1_CH2N,TIM3_CH3,TIM8_CH2N,,,,,,,OTG_HS_ULPI_D1,ETH_MII_RXD2,,,,EVENTOUT,ADC12_IN8
PortB,PB1,,TIM1_CH3N,TIM3_CH4,TIM8_CH3N,,,,,,,OTG_HS_ULPI_D2,ETH_MII_RXD3,,,,EVENTOUT,ADC12_IN9
diff --git a/ports/stm32/boards/stm32f411.ld b/ports/stm32/boards/stm32f411.ld
index 7adfa35c9..9e3e6bc15 100644
--- a/ports/stm32/boards/stm32f411.ld
+++ b/ports/stm32/boards/stm32f411.ld
@@ -21,9 +21,6 @@ _minimum_heap_size = 16K;
aligned for a call. */
_estack = ORIGIN(RAM) + LENGTH(RAM);
-/* define common sections and symbols */
-INCLUDE common.ld
-
/* RAM extents for the garbage collector */
_ram_start = ORIGIN(RAM);
_ram_end = ORIGIN(RAM) + LENGTH(RAM);
diff --git a/ports/stm32/boards/stm32f411_af.csv b/ports/stm32/boards/stm32f411_af.csv
index 29267b1d9..d5b7a61de 100644
--- a/ports/stm32/boards/stm32f411_af.csv
+++ b/ports/stm32/boards/stm32f411_af.csv
@@ -13,13 +13,13 @@ PortA,PA9,,TIM1_CH2,,,I2C3_SMBA,,,USART1_TX,,,USB_FS_VBUS,,SDIO_D2,,,EVENTOUT,
PortA,PA10,,TIM1_CH3,,,,,SPI5_MOSI/I2S5_SD,USART1_RX,,,USB_FS_ID,,,,,EVENTOUT,
PortA,PA11,,TIM1_CH4,,,,,SPI4_MISO,USART1_CTS,USART6_TX,,USB_FS_DM,,,,,EVENTOUT,
PortA,PA12,,TIM1_ETR,,,,,SPI5_MISO,USART1_RTS,USART6_RX,,USB_FS_DP,,,,,EVENTOUT,
-PortA,PA13,JTMS-SWDIO,,,,,,,,,,,,,,,EVENTOUT,
-PortA,PA14,JTCK-SWCLK,,,,,,,,,,,,,,,EVENTOUT,
+PortA,PA13,JTMS/SWDIO,,,,,,,,,,,,,,,EVENTOUT,
+PortA,PA14,JTCK/SWCLK,,,,,,,,,,,,,,,EVENTOUT,
PortA,PA15,JTDI,TIM2_CH1/TIM2_ETR,,,,SPI1_NSS/I2S1_WS,SPI3_NSS/I2S3_WS,USART1_TX,,,,,,,,EVENTOUT,
PortB,PB0,,TIM1_CH2N,TIM3_CH3,,,,SPI5_SCK/I2S5_CK,,,,,,,,,EVENTOUT,ADC1_IN8
PortB,PB1,,TIM1_CH3N,TIM3_CH4,,,,SPI5_NSS/I2S5_WS,,,,,,,,,EVENTOUT,ADC1_IN9
PortB,PB2,,,,,,,,,,,,,,,,EVENTOUT,
-PortB,PB3,JTDO-SWO,TIM2_CH2,,,,SPI1_SCK/I2S1_CK,SPI3_SCK/I2S3_CK,USART1_RX,,I2C2_SDA,,,,,,EVENTOUT,
+PortB,PB3,JTDO/TRACESWO,TIM2_CH2,,,,SPI1_SCK/I2S1_CK,SPI3_SCK/I2S3_CK,USART1_RX,,I2C2_SDA,,,,,,EVENTOUT,
PortB,PB4,JTRST,,TIM3_CH1,,,SPI1_MISO,SPI3_MISO,I2S3ext_SD,,I2C3_SDA,,,SDIO_D0,,,EVENTOUT,
PortB,PB5,,,TIM3_CH2,,I2C1_SMBA,SPI1_MOSI/I2S1_SD,SPI3_MOSI/I2S3_SD,,,,,,SDIO_D3,,,EVENTOUT,
PortB,PB6,,,TIM4_CH1,,I2C1_SCL,,,USART1_TX,,,,,,,,EVENTOUT,
diff --git a/ports/stm32/boards/stm32f429.ld b/ports/stm32/boards/stm32f429.ld
index a0931684d..d80f7f541 100644
--- a/ports/stm32/boards/stm32f429.ld
+++ b/ports/stm32/boards/stm32f429.ld
@@ -22,9 +22,6 @@ _minimum_heap_size = 16K;
aligned for a call. */
_estack = ORIGIN(RAM) + LENGTH(RAM);
-/* define common sections and symbols */
-INCLUDE common.ld
-
/* RAM extents for the garbage collector */
_ram_start = ORIGIN(RAM);
_ram_end = ORIGIN(RAM) + LENGTH(RAM);
diff --git a/ports/stm32/boards/stm32f429_af.csv b/ports/stm32/boards/stm32f429_af.csv
index 2e501ade0..4ee8edd70 100644
--- a/ports/stm32/boards/stm32f429_af.csv
+++ b/ports/stm32/boards/stm32f429_af.csv
@@ -13,8 +13,8 @@ PortA,PA9,,TIM1_CH2,,,I2C3_SMBA,,,USART1_TX,,,,,,DCMI_D0,,EVENTOUT,
PortA,PA10,,TIM1_CH3,,,,,,USART1_RX,,,OTG_FS_ID,,,DCMI_D1,,EVENTOUT,
PortA,PA11,,TIM1_CH4,,,,,,USART1_CTS,,CAN1_RX,OTG_FS_DM,,,,LCD_R4,EVENTOUT,
PortA,PA12,,TIM1_ETR,,,,,,USART1_RTS,,CAN1_TX,OTG_FS_DP,,,,LCD_R5,EVENTOUT,
-PortA,PA13,JTMS-SWDIO,,,,,,,,,,,,,,,EVENTOUT,
-PortA,PA14,JTCK-SWCLK,,,,,,,,,,,,,,,EVENTOUT,
+PortA,PA13,JTMS/SWDIO,,,,,,,,,,,,,,,EVENTOUT,
+PortA,PA14,JTCK/SWCLK,,,,,,,,,,,,,,,EVENTOUT,
PortA,PA15,JTDI,TIM2_CH1/TIM2_ETR,,,,SPI1_NSS,SPI3_NSS/I2S3_WS,,,,,,,,,EVENTOUT,
PortB,PB0,,TIM1_CH2N,TIM3_CH3,TIM8_CH2N,,,,,,LCD_R3,OTG_HS_ULPI_D1,ETH_MII_RXD2,,,,EVENTOUT,ADC12_IN8
PortB,PB1,,TIM1_CH3N,TIM3_CH4,TIM8_CH3N,,,,,,LCD_R6,OTG_HS_ULPI_D2,ETH_MII_RXD3,,,,EVENTOUT,ADC12_IN9
diff --git a/ports/stm32/boards/stm32f439.ld b/ports/stm32/boards/stm32f439.ld
index a76a0ebc7..16c606ecc 100644
--- a/ports/stm32/boards/stm32f439.ld
+++ b/ports/stm32/boards/stm32f439.ld
@@ -21,9 +21,6 @@ _minimum_heap_size = 16K;
/* top end of the stack */
_estack = ORIGIN(RAM) + LENGTH(RAM);
-/* define common sections and symbols */
-INCLUDE common.ld
-
/* RAM extents for the garbage collector */
_ram_start = ORIGIN(RAM);
_ram_end = ORIGIN(RAM) + LENGTH(RAM);
diff --git a/ports/stm32/boards/stm32f439_af.csv b/ports/stm32/boards/stm32f439_af.csv
index 5d5c3e72d..4fc1f1116 100644
--- a/ports/stm32/boards/stm32f439_af.csv
+++ b/ports/stm32/boards/stm32f439_af.csv
@@ -13,8 +13,8 @@ PortA,PA9,,TIM1_CH2,,,I2C3_SMBA,,,USART1_TX,,,,,,DCMI_D0,,EVENTOUT,
PortA,PA10,,TIM1_CH3,,,,,,USART1_RX,,,OTG_FS_ID,,,DCMI_D1,,EVENTOUT,
PortA,PA11,,TIM1_CH4,,,,,,USART1_CTS,,CAN1_RX,OTG_FS_DM,,,,LCD_R4,EVENTOUT,
PortA,PA12,,TIM1_ETR,,,,,,USART1_RTS,,CAN1_TX,OTG_FS_DP,,,,LCD_R5,EVENTOUT,
-PortA,PA13,JTMS-SWDIO,,,,,,,,,,,,,,,EVENTOUT,
-PortA,PA14,JTCK-SWCLK,,,,,,,,,,,,,,,EVENTOUT,
+PortA,PA13,JTMS/SWDIO,,,,,,,,,,,,,,,EVENTOUT,
+PortA,PA14,JTCK/SWCLK,,,,,,,,,,,,,,,EVENTOUT,
PortA,PA15,JTDI,TIM2_CH1/TIM2_ETR,,,,SPI1_NSS,SPI3_NSS/I2S3_WS,,,,,,,,,EVENTOUT,
PortB,PB0,,TIM1_CH2N,TIM3_CH3,TIM8_CH2N,,,,,,LCD_R3,OTG_HS_ULPI_D1,ETH_MII_RXD2,,,,EVENTOUT,ADC12_IN8
PortB,PB1,,TIM1_CH3N,TIM3_CH4,TIM8_CH3N,,,,,,LCD_R6,OTG_HS_ULPI_D2,ETH_MII_RXD3,,,,EVENTOUT,ADC12_IN9
@@ -64,15 +64,15 @@ PortD,PD12,,,TIM4_CH1,,,,,USART3_RTS,,,,,FMC_A17,,,EVENTOUT,
PortD,PD13,,,TIM4_CH2,,,,,,,,,,FMC_A18,,,EVENTOUT,
PortD,PD14,,,TIM4_CH3,,,,,,,,,,FMC_D0,,,EVENTOUT,
PortD,PD15,,,TIM4_CH4,,,,,,,,,,FMC_D1,,,EVENTOUT,
-PortE,PE0,,,TIM4_ETR,,,,,,UART8_Rx,,,,FMC_NBL0,DCMI_D2,,EVENTOUT,
-PortE,PE1,,,,,,,,,UART8_Tx,,,,FMC_NBL1,DCMI_D3,,EVENTOUT,
+PortE,PE0,,,TIM4_ETR,,,,,,UART8_RX,,,,FMC_NBL0,DCMI_D2,,EVENTOUT,
+PortE,PE1,,,,,,,,,UART8_TX,,,,FMC_NBL1,DCMI_D3,,EVENTOUT,
PortE,PE2,TRACECLK,,,,,SPI4_SCK,SAI1_MCLK_A,,,,,ETH_MII_TXD3,FMC_A23,,,EVENTOUT,
PortE,PE3,TRACED0,,,,,,SAI1_SD_B,,,,,,FMC_A19,,,EVENTOUT,
PortE,PE4,TRACED1,,,,,SPI4_NSS,SAI1_FS_A,,,,,,FMC_A20,DCMI_D4,LCD_B0,EVENTOUT,
PortE,PE5,TRACED2,,,TIM9_CH1,,SPI4_MISO,SAI1_SCK_A,,,,,,FMC_A21,DCMI_D6,LCD_G0,EVENTOUT,
PortE,PE6,TRACED3,,,TIM9_CH2,,SPI4_MOSI,SAI1_SD_A,,,,,,FMC_A22,DCMI_D7,LCD_G1,EVENTOUT,
-PortE,PE7,,TIM1_ETR,,,,,,,UART7_Rx,,,,FMC_D4,,,EVENTOUT,
-PortE,PE8,,TIM1_CH1N,,,,,,,UART7_Tx,,,,FMC_D5,,,EVENTOUT,
+PortE,PE7,,TIM1_ETR,,,,,,,UART7_RX,,,,FMC_D4,,,EVENTOUT,
+PortE,PE8,,TIM1_CH1N,,,,,,,UART7_TX,,,,FMC_D5,,,EVENTOUT,
PortE,PE9,,TIM1_CH1,,,,,,,,,,,FMC_D6,,,EVENTOUT,
PortE,PE10,,TIM1_CH2N,,,,,,,,,,,FMC_D7,,,EVENTOUT,
PortE,PE11,,TIM1_CH2,,,,SPI4_NSS,SPI3_NSS,,,,,,FMC_D8,,LCD_G3,EVENTOUT,
@@ -86,8 +86,8 @@ PortF,PF2,,,,,I2C2_SMBA,,,,,,,,FMC_A2,,,EVENTOUT,
PortF,PF3,,,,,,,,,,,,,FMC_A3,,,EVENTOUT,ADC3_IN9
PortF,PF4,,,,,,,,,,,,,FMC_A4,,,EVENTOUT,ADC3_IN14
PortF,PF5,,,,,,,,,,,,,FMC_A5,,,EVENTOUT,ADC3_IN15
-PortF,PF6,,,,TIM10_CH1,,SPI5_NSS,SAI1_SD_B,,UART7_Rx,,,,FMC_NIORD,,,EVENTOUT,ADC3_IN4
-PortF,PF7,,,,TIM11_CH1,,SPI5_SCK,SAI1_MCLK_B,,UART7_Tx,,,,FMC_NREG,,,EVENTOUT,ADC3_IN5
+PortF,PF6,,,,TIM10_CH1,,SPI5_NSS,SAI1_SD_B,,UART7_RX,,,,FMC_NIORD,,,EVENTOUT,ADC3_IN4
+PortF,PF7,,,,TIM11_CH1,,SPI5_SCK,SAI1_MCLK_B,,UART7_TX,,,,FMC_NREG,,,EVENTOUT,ADC3_IN5
PortF,PF8,,,,,,SPI5_MISO,SAI1_SCK_B,,,TIM13_CH1,,,FMC_NIOWR,,,EVENTOUT,ADC3_IN6
PortF,PF9,,,,,,SPI5_MOSI,SAI1_FS_B,,,TIM14_CH1,,,FMC_CD,,,EVENTOUT,ADC3_IN7
PortF,PF10,,,,,,,,,,,,,FMC_INTR,DCMI_D11,LCD_DE,EVENTOUT,ADC3_IN8
diff --git a/ports/stm32/boards/stm32f4xx_prefix.c b/ports/stm32/boards/stm32f4xx_prefix.c
index f4ffdab68..3bcd6e641 100644
--- a/ports/stm32/boards/stm32f4xx_prefix.c
+++ b/ports/stm32/boards/stm32f4xx_prefix.c
@@ -14,7 +14,7 @@
.fn = AF_FN_ ## af_fn, \
.unit = (af_unit), \
.type = AF_PIN_TYPE_ ## af_fn ## _ ## af_type, \
- .af_fn = (af_ptr) \
+ .reg = (af_ptr) \
}
#define PIN(p_port, p_pin, p_af, p_adc_num, p_adc_channel) \
diff --git a/ports/stm32/boards/stm32f722.ld b/ports/stm32/boards/stm32f722.ld
new file mode 100644
index 000000000..f2a1d8511
--- /dev/null
+++ b/ports/stm32/boards/stm32f722.ld
@@ -0,0 +1,27 @@
+/*
+ GNU linker script for STM32F722, STM32F723, STM32F732, STM32F733
+*/
+
+/* Specify the memory areas */
+MEMORY
+{
+ FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 512K
+ FLASH_ISR (rx) : ORIGIN = 0x08000000, LENGTH = 32K /* sectors 0,1 */
+ FLASH_APP (rx) : ORIGIN = 0x08008000, LENGTH = 480K /* sectors 2-7 */
+ RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 256K /* DTCM+SRAM1+SRAM2 */
+}
+
+/* produce a link error if there is not this amount of RAM for these sections */
+_minimum_stack_size = 2K;
+_minimum_heap_size = 16K;
+
+/* Define tho top end of the stack. The stack is full descending so begins just
+ above last byte of RAM. Note that EABI requires the stack to be 8-byte
+ aligned for a call. */
+_estack = ORIGIN(RAM) + LENGTH(RAM);
+
+/* RAM extents for the garbage collector */
+_ram_start = ORIGIN(RAM);
+_ram_end = ORIGIN(RAM) + LENGTH(RAM);
+_heap_start = _ebss; /* heap starts just after statically allocated memory */
+_heap_end = 0x20038000; /* tunable */
diff --git a/ports/stm32/boards/stm32f722_af.csv b/ports/stm32/boards/stm32f722_af.csv
new file mode 100644
index 000000000..24500f505
--- /dev/null
+++ b/ports/stm32/boards/stm32f722_af.csv
@@ -0,0 +1,146 @@
+Port,,AF0,AF1,AF2,AF3,AF4,AF5,AF6,AF7,AF8,AF9,AF10,AF11,AF12,AF13,AF14,AF15,
+,,SYS,TIM1/2,TIM3/4/5,TIM8/9/10/11/LPTIM1,I2C1/2/3/USART1,SPI1/I2S1/SPI2/I2S2/SPI3/I2S3/SPI4/5,SPI2/I2S2/SPI3/I2S3/SPI3/I2S3/SAI1/UART4,SPI2/I2S2/SPI3/I2S3/USART1/2/3/UART5,SAI2/USART6/UART4/5/7/8/OTG1_FS,CAN1/TIM12/13/14/QUADSPI/FMC/OTG2_HS,SAI2/QUADSPI/SDMMC2/OTG2_HS/OTG1_FS,SDMMC2,UART7/FMC/SDMMC1/OTG2_FS,,,SYS,ADC
+PortA,PA0,,TIM2_CH1/TIM2_ETR,TIM5_CH1,TIM8_ETR,,,,USART2_CTS,UART4_TX,,SAI2_SD_B,,,,,EVENTOUT,ADC123_IN0
+PortA,PA1,,TIM2_CH2,TIM5_CH2,,,,,USART2_RTS,UART4_RX,QUADSPI_BK1_IO3,SAI2_MCK_B,,,,,EVENTOUT,ADC123_IN1
+PortA,PA2,,TIM2_CH3,TIM5_CH3,TIM9_CH1,,,,USART2_TX,SAI2_SCK_B,,,,,,,EVENTOUT,ADC123_IN2
+PortA,PA3,,TIM2_CH4,TIM5_CH4,TIM9_CH2,,,,USART2_RX,,,OTG_HS_ULPI_D0,,,,,EVENTOUT,ADC123_IN3
+PortA,PA4,,,,,,SPI1_NSS/I2S1_WS,SPI3_NSS/I2S3_WS,USART2_CK,,,,,OTG_HS_SOF,,,EVENTOUT,ADC12_IN4
+PortA,PA5,,TIM2_CH1/TIM2_ETR,,TIM8_CH1N,,SPI1_SCK/I2S1_CK,,,,,OTG_HS_ULPI_CK,,,,,EVENTOUT,ADC12_IN5
+PortA,PA6,,TIM1_BKIN,TIM3_CH1,TIM8_BKIN,,SPI1_MISO,,,,TIM13_CH1,,,,,,EVENTOUT,ADC12_IN6
+PortA,PA7,,TIM1_CH1N,TIM3_CH2,TIM8_CH1N,,SPI1_MOSI/I2S1_SD,,,,TIM14_CH1,,,FMC_SDNWE,,,EVENTOUT,ADC12_IN7
+PortA,PA8,MCO1,TIM1_CH1,,TIM8_BKIN2,I2C3_SCL,,,USART1_CK,,,OTG_FS_SOF,,,,,EVENTOUT,
+PortA,PA9,,TIM1_CH2,,,I2C3_SMBA,SPI2_SCK/I2S2_CK,,USART1_TX,,,,,,,,EVENTOUT,
+PortA,PA10,,TIM1_CH3,,,,,,USART1_RX,,,OTG_FS_ID,,,,,EVENTOUT,
+PortA,PA11,,TIM1_CH4,,,,,,USART1_CTS,,CAN1_RX,OTG_FS_DM,,,,,EVENTOUT,
+PortA,PA12,,TIM1_ETR,,,,,,USART1_RTS,SAI2_FS_B,CAN1_TX,OTG_FS_DP,,,,,EVENTOUT,
+PortA,PA13,JTMS/SWDIO,,,,,,,,,,,,,,,EVENTOUT,
+PortA,PA14,JTCK/SWCLK,,,,,,,,,,,,,,,EVENTOUT,
+PortA,PA15,JTDI,TIM2_CH1/TIM2_ETR,,,,SPI1_NSS/I2S1_WS,SPI3_NSS/I2S3_WS,,UART4_RTS,,,,,,,EVENTOUT,
+PortB,PB0,,TIM1_CH2N,TIM3_CH3,TIM8_CH2N,,,,,UART4_CTS,,OTG_HS_ULPI_D1,,,,,EVENTOUT,ADC12_IN8
+PortB,PB1,,TIM1_CH3N,TIM3_CH4,TIM8_CH3N,,,,,,,OTG_HS_ULPI_D2,,,,,EVENTOUT,ADC12_IN9
+PortB,PB2,,,,,,,SAI1_SD_A,SPI3_MOSI/I2S3_SD,,QUADSPI_CLK,,,,,,EVENTOUT,
+PortB,PB3,JTDO/TRACESWO,TIM2_CH2,,,,SPI1_SCK/I2S1_CK,SPI3_SCK/I2S3_CK,,,,SDMMC2_D2,,,,,EVENTOUT,
+PortB,PB4,NJTRST,,TIM3_CH1,,,SPI1_MISO,SPI3_MISO,SPI2_NSS/I2S2_WS,,,SDMMC2_D3,,,,,EVENTOUT,
+PortB,PB5,,,TIM3_CH2,,I2C1_SMBA,SPI1_MOSI/I2S1_SD,SPI3_MOSI/I2S3_SD,,,,OTG_HS_ULPI_D7,,FMC_SDCKE1,,,EVENTOUT,
+PortB,PB6,,,TIM4_CH1,,I2C1_SCL,,,USART1_TX,,,QUADSPI_BK1_NCS,,FMC_SDNE1,,,EVENTOUT,
+PortB,PB7,,,TIM4_CH2,,I2C1_SDA,,,USART1_RX,,,,,FMC_NL,,,EVENTOUT,
+PortB,PB8,,,TIM4_CH3,TIM10_CH1,I2C1_SCL,,,,,CAN1_RX,SDMMC2_D4,,SDMMC1_D4,,,EVENTOUT,
+PortB,PB9,,,TIM4_CH4,TIM11_CH1,I2C1_SDA,SPI2_NSS/I2S2_WS,,,,CAN1_TX,SDMMC2_D5,,SDMMC1_D5,,,EVENTOUT,
+PortB,PB10,,TIM2_CH3,,,I2C2_SCL,SPI2_SCK/I2S2_CK,,USART3_TX,,,OTG_HS_ULPI_D3,,,,,EVENTOUT,
+PortB,PB11,,TIM2_CH4,,,I2C2_SDA,,,USART3_RX,,,OTG_HS_ULPI_D4,,,,,EVENTOUT,
+PortB,PB12,,TIM1_BKIN,,,I2C2_SMBA,SPI2_NSS/I2S2_WS,,USART3_CK,,,OTG_HS_ULPI_D5,,OTG_HS_ID,,,EVENTOUT,
+PortB,PB13,,TIM1_CH1N,,,,SPI2_SCK/I2S2_CK,,USART3_CTS,,,OTG_HS_ULPI_D6,,,,,EVENTOUT,
+PortB,PB14,,TIM1_CH2N,,TIM8_CH2N,,SPI2_MISO,,USART3_RTS,,TIM12_CH1,SDMMC2_D0,,OTG_HS_DM,,,EVENTOUT,
+PortB,PB15,RTC_REFIN,TIM1_CH3N,,TIM8_CH3N,,SPI2_MOSI/I2S2_SD,,,,TIM12_CH2,SDMMC2_D1,,OTG_HS_DP,,,EVENTOUT,
+PortC,PC0,,,,,,,,,SAI2_FS_B,,OTG_HS_ULPI_STP,,FMC_SDNWE,,,EVENTOUT,ADC123_IN10
+PortC,PC1,TRACED0,,,,,SPI2_MOSI/I2S2_SD,SAI1_SD_A,,,,,,,,,EVENTOUT,ADC123_IN11
+PortC,PC2,,,,,,SPI2_MISO,,,,,OTG_HS_ULPI_DIR,,FMC_SDNE0,,,EVENTOUT,ADC123_IN12
+PortC,PC3,,,,,,SPI2_MOSI/I2S2_SD,,,,,OTG_HS_ULPI_NXT,,FMC_SDCKE0,,,EVENTOUT,ADC123_IN13
+PortC,PC4,,,,,,I2S1_MCK,,,,,,,FMC_SDNE0,,,EVENTOUT,ADC12_IN14
+PortC,PC5,,,,,,,,,,,,,FMC_SDCKE0,,,EVENTOUT,ADC12_IN15
+PortC,PC6,,,TIM3_CH1,TIM8_CH1,,I2S2_MCK,,,USART6_TX,,SDMMC2_D6,,SDMMC1_D6,,,EVENTOUT,
+PortC,PC7,,,TIM3_CH2,TIM8_CH2,,,I2S3_MCK,,USART6_RX,,SDMMC2_D7,,SDMMC1_D7,,,EVENTOUT,
+PortC,PC8,TRACED1,,TIM3_CH3,TIM8_CH3,,,,UART5_RTS,USART6_CK,,,,SDMMC1_D0,,,EVENTOUT,
+PortC,PC9,MCO2,,TIM3_CH4,TIM8_CH4,I2C3_SDA,I2S_CKIN,,UART5_CTS,,QUADSPI_BK1_IO0,,,SDMMC1_D1,,,EVENTOUT,
+PortC,PC10,,,,,,,SPI3_SCK/I2S3_CK,USART3_TX,UART4_TX,QUADSPI_BK1_IO1,,,SDMMC1_D2,,,EVENTOUT,
+PortC,PC11,,,,,,,SPI3_MISO,USART3_RX,UART4_RX,QUADSPI_BK2_NCS,,,SDMMC1_D3,,,EVENTOUT,
+PortC,PC12,TRACED3,,,,,,SPI3_MOSI/I2S3_SD,USART3_CK,UART5_TX,,,,SDMMC1_CK,,,EVENTOUT,
+PortC,PC13,,,,,,,,,,,,,,,,EVENTOUT,
+PortC,PC14,,,,,,,,,,,,,,,,EVENTOUT,
+PortC,PC15,,,,,,,,,,,,,,,,EVENTOUT,
+PortD,PD0,,,,,,,,,,CAN1_RX,,,FMC_D2,,,EVENTOUT,
+PortD,PD1,,,,,,,,,,CAN1_TX,,,FMC_D3,,,EVENTOUT,
+PortD,PD2,TRACED2,,TIM3_ETR,,,,,,UART5_RX,,,,SDMMC1_CMD,,,EVENTOUT,
+PortD,PD3,,,,,,SPI2_SCK/I2S2_CK,,USART2_CTS,,,,,FMC_CLK,,,EVENTOUT,
+PortD,PD4,,,,,,,,USART2_RTS,,,,,FMC_NOE,,,EVENTOUT,
+PortD,PD5,,,,,,,,USART2_TX,,,,,FMC_NWE,,,EVENTOUT,
+PortD,PD6,,,,,,SPI3_MOSI/I2S3_SD,SAI1_SD_A,USART2_RX,,,,SDMMC2_CK,FMC_NWAIT,,,EVENTOUT,
+PortD,PD7,,,,,,,,USART2_CK,,,,SDMMC2_CMD,FMC_NE1,,,EVENTOUT,
+PortD,PD8,,,,,,,,USART3_TX,,,,,FMC_D13,,,EVENTOUT,
+PortD,PD9,,,,,,,,USART3_RX,,,,,FMC_D14,,,EVENTOUT,
+PortD,PD10,,,,,,,,USART3_CK,,,,,FMC_D15,,,EVENTOUT,
+PortD,PD11,,,,,,,,USART3_CTS,,QUADSPI_BK1_IO0,SAI2_SD_A,,FMC_A16/FMC_CLE,,,EVENTOUT,
+PortD,PD12,,,TIM4_CH1,LPTIM1_IN1,,,,USART3_RTS,,QUADSPI_BK1_IO1,SAI2_FS_A,,FMC_A17/FMC_ALE,,,EVENTOUT,
+PortD,PD13,,,TIM4_CH2,LPTIM1_OUT,,,,,,QUADSPI_BK1_IO3,SAI2_SCK_A,,FMC_A18,,,EVENTOUT,
+PortD,PD14,,,TIM4_CH3,,,,,,UART8_CTS,,,,FMC_D0,,,EVENTOUT,
+PortD,PD15,,,TIM4_CH4,,,,,,UART8_RTS,,,,FMC_D1,,,EVENTOUT,
+PortE,PE0,,,TIM4_ETR,LPTIM1_ETR,,,,,UART8_RX,,SAI2_MCK_A,,FMC_NBL0,,,EVENTOUT,
+PortE,PE1,,,,LPTIM1_IN2,,,,,UART8_TX,,,,FMC_NBL1,,,EVENTOUT,
+PortE,PE2,TRACECLK,,,,,SPI4_SCK,SAI1_MCLK_A,,,QUADSPI_BK1_IO2,,,FMC_A23,,,EVENTOUT,
+PortE,PE3,TRACED0,,,,,,SAI1_SD_B,,,,,,FMC_A19,,,EVENTOUT,
+PortE,PE4,TRACED1,,,,,SPI4_NSS,SAI1_FS_A,,,,,,FMC_A20,,,EVENTOUT,
+PortE,PE5,TRACED2,,,TIM9_CH1,,SPI4_MISO,SAI1_SCK_A,,,,,,FMC_A21,,,EVENTOUT,
+PortE,PE6,TRACED3,TIM1_BKIN2,,TIM9_CH2,,SPI4_MOSI,SAI1_SD_A,,,,SAI2_MCK_B,,FMC_A22,,,EVENTOUT,
+PortE,PE7,,TIM1_ETR,,,,,,,UART7_RX,,QUADSPI_BK2_IO0,,FMC_D4,,,EVENTOUT,
+PortE,PE8,,TIM1_CH1N,,,,,,,UART7_TX,,QUADSPI_BK2_IO1,,FMC_D5,,,EVENTOUT,
+PortE,PE9,,TIM1_CH1,,,,,,,UART7_RTS,,QUADSPI_BK2_IO2,,FMC_D6,,,EVENTOUT,
+PortE,PE10,,TIM1_CH2N,,,,,,,UART7_CTS,,QUADSPI_BK2_IO3,,FMC_D7,,,EVENTOUT,
+PortE,PE11,,TIM1_CH2,,,,SPI4_NSS,,,,,SAI2_SD_B,,FMC_D8,,,EVENTOUT,
+PortE,PE12,,TIM1_CH3N,,,,SPI4_SCK,,,,,SAI2_SCK_B,,FMC_D9,,,EVENTOUT,
+PortE,PE13,,TIM1_CH3,,,,SPI4_MISO,,,,,SAI2_FS_B,,FMC_D10,,,EVENTOUT,
+PortE,PE14,,TIM1_CH4,,,,SPI4_MOSI,,,,,SAI2_MCK_B,,FMC_D11,,,EVENTOUT,
+PortE,PE15,,TIM1_BKIN,,,,,,,,,,,FMC_D12,,,EVENTOUT,
+PortF,PF0,,,,,I2C2_SDA,,,,,,,,FMC_A0,,,EVENTOUT,
+PortF,PF1,,,,,I2C2_SCL,,,,,,,,FMC_A1,,,EVENTOUT,
+PortF,PF2,,,,,I2C2_SMBA,,,,,,,,FMC_A2,,,EVENTOUT,
+PortF,PF3,,,,,,,,,,,,,FMC_A3,,,EVENTOUT,ADC3_IN9
+PortF,PF4,,,,,,,,,,,,,FMC_A4,,,EVENTOUT,ADC3_IN14
+PortF,PF5,,,,,,,,,,,,,FMC_A5,,,EVENTOUT,ADC3_IN15
+PortF,PF6,,,,TIM10_CH1,,SPI5_NSS,SAI1_SD_B,,UART7_RX,QUADSPI_BK1_IO3,,,,,,EVENTOUT,ADC3_IN4
+PortF,PF7,,,,TIM11_CH1,,SPI5_SCK,SAI1_MCLK_B,,UART7_TX,QUADSPI_BK1_IO2,,,,,,EVENTOUT,ADC3_IN5
+PortF,PF8,,,,,,SPI5_MISO,SAI1_SCK_B,,UART7_RTS,TIM13_CH1,QUADSPI_BK1_IO0,,,,,EVENTOUT,ADC3_IN6
+PortF,PF9,,,,,,SPI5_MOSI,SAI1_FS_B,,UART7_CTS,TIM14_CH1,QUADSPI_BK1_IO1,,,,,EVENTOUT,ADC3_IN7
+PortF,PF10,,,,,,,,,,,,,,,,EVENTOUT,ADC3_IN8
+PortF,PF11,,,,,,SPI5_MOSI,,,,,SAI2_SD_B,,FMC_SDNRAS,,,EVENTOUT,
+PortF,PF12,,,,,,,,,,,,,FMC_A6,,,EVENTOUT,
+PortF,PF13,,,,,,,,,,,,,FMC_A7,,,EVENTOUT,
+PortF,PF14,,,,,,,,,,,,,FMC_A8,,,EVENTOUT,
+PortF,PF15,,,,,,,,,,,,,FMC_A9,,,EVENTOUT,
+PortG,PG0,,,,,,,,,,,,,FMC_A10,,,EVENTOUT,
+PortG,PG1,,,,,,,,,,,,,FMC_A11,,,EVENTOUT,
+PortG,PG2,,,,,,,,,,,,,FMC_A12,,,EVENTOUT,
+PortG,PG3,,,,,,,,,,,,,FMC_A13,,,EVENTOUT,
+PortG,PG4,,,,,,,,,,,,,FMC_A14/FMC_BA0,,,EVENTOUT,
+PortG,PG5,,,,,,,,,,,,,FMC_A15/FMC_BA1,,,EVENTOUT,
+PortG,PG6,,,,,,,,,,,,,,,,EVENTOUT,
+PortG,PG7,,,,,,,,,USART6_CK,,,,FMC_INT,,,EVENTOUT,
+PortG,PG8,,,,,,,,,USART6_RTS,,,,FMC_SDCLK,,,EVENTOUT,
+PortG,PG9,,,,,,,,,USART6_RX,QUADSPI_BK2_IO2,SAI2_FS_B,SDMMC2_D0,FMC_NE2/FMC_NCE,,,EVENTOUT,
+PortG,PG10,,,,,,,,,,,SAI2_SD_B,SDMMC2_D1,FMC_NE3,,,EVENTOUT,
+PortG,PG11,,,,,,,,,,,SDMMC2_D2,,,,,EVENTOUT,
+PortG,PG12,,,,LPTIM1_IN1,,,,,USART6_RTS,,,SDMMC2_D3,FMC_NE4,,,EVENTOUT,
+PortG,PG13,TRACED0,,,LPTIM1_OUT,,,,,USART6_CTS,,,,FMC_A24,,,EVENTOUT,
+PortG,PG14,TRACED1,,,LPTIM1_ETR,,,,,USART6_TX,QUADSPI_BK2_IO3,,,FMC_A25,,,EVENTOUT,
+PortG,PG15,,,,,,,,,USART6_CTS,,,,FMC_SDNCAS,,,EVENTOUT,
+PortH,PH0,,,,,,,,,,,,,,,,EVENTOUT,
+PortH,PH1,,,,,,,,,,,,,,,,EVENTOUT,
+PortH,PH2,,,,LPTIM1_IN2,,,,,,QUADSPI_BK2_IO0,SAI2_SCK_B,,FMC_SDCKE0,,,EVENTOUT,
+PortH,PH3,,,,,,,,,,QUADSPI_BK2_IO1,SAI2_MCK_B,,FMC_SDNE0,,,EVENTOUT,
+PortH,PH4,,,,,I2C2_SCL,,,,,,OTG_HS_ULPI_NXT,,,,,EVENTOUT,
+PortH,PH5,,,,,I2C2_SDA,SPI5_NSS,,,,,,,FMC_SDNWE,,,EVENTOUT,
+PortH,PH6,,,,,I2C2_SMBA,SPI5_SCK,,,,TIM12_CH1,,,FMC_SDNE1,,,EVENTOUT,
+PortH,PH7,,,,,I2C3_SCL,SPI5_MISO,,,,,,,FMC_SDCKE1,,,EVENTOUT,
+PortH,PH8,,,,,I2C3_SDA,,,,,,,,FMC_D16,,,EVENTOUT,
+PortH,PH9,,,,,I2C3_SMBA,,,,,TIM12_CH2,,,FMC_D17,,,EVENTOUT,
+PortH,PH10,,,TIM5_CH1,,,,,,,,,,FMC_D18,,,EVENTOUT,
+PortH,PH11,,,TIM5_CH2,,,,,,,,,,FMC_D19,,,EVENTOUT,
+PortH,PH12,,,TIM5_CH3,,,,,,,,,,FMC_D20,,,EVENTOUT,
+PortH,PH13,,,,TIM8_CH1N,,,,,UART4_TX,CAN1_TX,,,FMC_D21,,,EVENTOUT,
+PortH,PH14,,,,TIM8_CH2N,,,,,UART4_RX,CAN1_RX,,,FMC_D22,,,EVENTOUT,
+PortH,PH15,,,,TIM8_CH3N,,,,,,,,,FMC_D23,,,EVENTOUT,
+PortI,PI0,,,TIM5_CH4,,,SPI2_NSS/I2S2_WS,,,,,,,FMC_D24,,,EVENTOUT,
+PortI,PI1,,,,TIM8_BKIN2,,SPI2_SCK/I2S2_CK,,,,,,,FMC_D25,,,EVENTOUT,
+PortI,PI2,,,,TIM8_CH4,,SPI2_MISO,,,,,,,FMC_D26,,,EVENTOUT,
+PortI,PI3,,,,TIM8_ETR,,SPI2_MOSI/I2S2_SD,,,,,,,FMC_D27,,,EVENTOUT,
+PortI,PI4,,,,TIM8_BKIN,,,,,,,SAI2_MCK_A,,FMC_NBL2,,,EVENTOUT,
+PortI,PI5,,,,TIM8_CH1,,,,,,,SAI2_SCK_A,,FMC_NBL3,,,EVENTOUT,
+PortI,PI6,,,,TIM8_CH2,,,,,,,SAI2_SD_A,,FMC_D28,,,EVENTOUT,
+PortI,PI7,,,,TIM8_CH3,,,,,,,SAI2_FS_A,,FMC_D29,,,EVENTOUT,
+PortI,PI8,,,,,,,,,,,,,,,,EVENTOUT,
+PortI,PI9,,,,,,,,,UART4_RX,CAN1_RX,,,FMC_D30,,,EVENTOUT,
+PortI,PI10,,,,,,,,,,,,,FMC_D31,,,EVENTOUT,
+PortI,PI11,,,,,,,,,,,OTG_HS_ULPI_DIR,,,,,EVENTOUT,
+PortI,PI12,,,,,,,,,,,,,,,,EVENTOUT,
+PortI,PI13,,,,,,,,,,,,,,,,EVENTOUT,
+PortI,PI14,,,,,,,,,,,,,,,,EVENTOUT,
+PortI,PI15,,,,,,,,,,,,,,,,EVENTOUT,
diff --git a/ports/stm32/boards/stm32f746.ld b/ports/stm32/boards/stm32f746.ld
index ce5e85bb6..b5864453d 100644
--- a/ports/stm32/boards/stm32f746.ld
+++ b/ports/stm32/boards/stm32f746.ld
@@ -22,9 +22,6 @@ _minimum_heap_size = 16K;
aligned for a call. */
_estack = ORIGIN(RAM) + LENGTH(RAM);
-/* define common sections and symbols */
-INCLUDE common.ld
-
/* RAM extents for the garbage collector */
_ram_start = ORIGIN(RAM);
_ram_end = ORIGIN(RAM) + LENGTH(RAM);
diff --git a/ports/stm32/boards/stm32f746_af.csv b/ports/stm32/boards/stm32f746_af.csv
index eabc9ab3b..8069edc7b 100644
--- a/ports/stm32/boards/stm32f746_af.csv
+++ b/ports/stm32/boards/stm32f746_af.csv
@@ -5,7 +5,7 @@ PortA,PA1,,TIM2_CH2,TIM5_CH2,,,,,USART2_RTS,UART4_RX,QUADSPI_BK1_IO3,SAI2_MCK_B,
PortA,PA2,,TIM2_CH3,TIM5_CH3,TIM9_CH1,,,,USART2_TX,SAI2_SCK_B,,,ETH_MDIO,,,LCD_R1,EVENTOUT
PortA,PA3,,TIM2_CH4,TIM5_CH4,TIM9_CH2,,,,USART2_RX,,,OTG_HS_ULPI_D0,ETH_MII_COL,,,LCD_B5,EVENTOUT
PortA,PA4,,,,,,SPI1_NSS/I2S1_WS,SPI3_NSS/I2S3_WS,USART2_CK,,,,,OTG_HS_SOF,DCMI_HSYNC,LCD_VSYNC,EVENTOUT
-PortA,PA5,,TIM2_CH1/TIM2_ETR,TIM8_CH1N,SPI1_SCK/I2S1_CK,,,,,,,OTG_HS_ULPI_CK,,,,LCD_R4,EVENTOUT
+PortA,PA5,,TIM2_CH1/TIM2_ETR,,TIM8_CH1N,,SPI1_SCK/I2S1_CK,,,,,OTG_HS_ULPI_CK,,,,LCD_R4,EVENTOUT
PortA,PA6,,TIM1_BKIN,TIM3_CH1,TIM8_BKIN,,SPI1_MISO,,,,TIM13_CH1,,,,DCMI_PIXCLK,LCD_G2,EVENTOUT
PortA,PA7,,TIM1_CH1N,TIM3_CH2,TIM8_CH1N,,SPI1_MOSI/I2S1_SD,,,,TIM14_CH1,,ETH_MII_RX_DV/ETH_RMII_CRS_DV,FMC_SDNWE,,,EVENTOUT
PortA,PA8,MCO1,TIM1_CH1,,TIM8_BKIN2,I2C3_SCL,,,USART1_CK,,,OTG_FS_SOF,,,,LCD_R6,EVENTOUT
@@ -13,16 +13,16 @@ PortA,PA9,,TIM1_CH2,,,I2C3_SMBA,SPI2_SCK/I2S2_CK,,USART1_TX,,,,,,DCMI_D0,,EVENTO
PortA,PA10,,TIM1_CH3,,,,,,USART1_RX,,,OTG_FS_ID,,,DCMI_D1,,EVENTOUT
PortA,PA11,,TIM1_CH4,,,,,,USART1_CTS,,CAN1_RX,OTG_FS_DM,,,,LCD_R4,EVENTOUT
PortA,PA12,,TIM1_ETR,,,,,,USART1_RTS,SAI2_FS_B,CAN1_TX,OTG_FS_DP,,,,LCD_R5,EVENTOUT
-PortA,PA13,JTMS,SWDIO,,,,,,,,,,,,,,EVENTOUT
-PortA,PA14,JTCK,SWCLK,,,,,,,,,,,,,,EVENTOUT
-PortA,PA15,JTDI,TIM2_CH1/TIM2_ETR,,,HDMICE,CSPI1_NSS/I2S1_WS,SPI3_NSS/I2S3_WS,,UART4_RTS,,,,,,,EVENTOUT
-PortB,PB0,,TIM1_CH2N,TIM3_CH3T,IM8_CH2N,,,,,UART4_CTS,LCD_R3,OTG_HS_ULPI_D1,ETH_MII_RXD2,,,,EVENTOUT
-PortB,PB1,,TIM1_CH3N,TIM3_CH4T,IM8_CH3N,,,,,,LCD_R6,OTG_HS_ULPI_D2,ETH_MII_RXD3,,,,EVENTOUT
+PortA,PA13,JTMS/SWDIO,,,,,,,,,,,,,,,EVENTOUT
+PortA,PA14,JTCK/SWCLK,,,,,,,,,,,,,,,EVENTOUT
+PortA,PA15,JTDI,TIM2_CH1/TIM2_ETR,,,HDMI_CEC,SPI1_NSS/I2S1_WS,SPI3_NSS/I2S3_WS,,UART4_RTS,,,,,,,EVENTOUT
+PortB,PB0,,TIM1_CH2N,TIM3_CH3,TIM8_CH2N,,,,,UART4_CTS,LCD_R3,OTG_HS_ULPI_D1,ETH_MII_RXD2,,,,EVENTOUT
+PortB,PB1,,TIM1_CH3N,TIM3_CH4,TIM8_CH3N,,,,,,LCD_R6,OTG_HS_ULPI_D2,ETH_MII_RXD3,,,,EVENTOUT
PortB,PB2,,,,,,,SAI1_SD_A,SPI3_MOSI/I2S3_SD,,QUADSPI_CLK,,,,,,EVENTOUT
PortB,PB3,JTDO/TRACESWO,TIM2_CH2,,,,SPI1_SCK/I2S1_CK,SPI3_SCK/I2S3_CK,,,,,,,,,EVENTOUT
PortB,PB4,NJTRST,,TIM3_CH1,,,SPI1_MISO,SPI3_MISO,SPI2_NSS/I2S2_WS,,,,,,,,EVENTOUT
PortB,PB5,,,TIM3_CH2,,I2C1_SMBA,SPI1_MOSI/I2S1_SD,SPI3_MOSI/I2S3_SD,,,CAN2_RX,OTG_HS_ULPI_D7,ETH_PPS_OUT,FMC_SDCKE1,DCMI_D10,,EVENTOUT
-PortB,PB6,,,TIM4_CH1,HDMICEC,I2C1_SCL,,,USART1_TX,,CAN2_TX,QUADSPI_BK1_NCS,,FMC_SDNE1,DCMI_D5,,EVENTOUT
+PortB,PB6,,,TIM4_CH1,HDMI_CEC,I2C1_SCL,,,USART1_TX,,CAN2_TX,QUADSPI_BK1_NCS,,FMC_SDNE1,DCMI_D5,,EVENTOUT
PortB,PB7,,,TIM4_CH2,,I2C1_SDA,,,USART1_RX,,,,,FMC_NL,DCMI_VSYNC,,EVENTOUT
PortB,PB8,,,TIM4_CH3,TIM10_CH1,I2C1_SCL,,,,,CAN1_RX,,ETH_MII_TXD3,SDMMC1_D4,DCMI_D6,LCD_B6,EVENTOUT
PortB,PB9,,,TIM4_CH4,TIM11_CH1,I2C1_SDA,SPI2_NSS/I2S2_WS,,,,CAN1_TX,,,SDMMC1_D5,DCMI_D7,LCD_B7,EVENTOUT
@@ -168,4 +168,3 @@ PortK,PK4,,,,,,,,,,,,,,,LCD_B5,EVENTOUT
PortK,PK5,,,,,,,,,,,,,,,LCD_B6,EVENTOUT
PortK,PK6,,,,,,,,,,,,,,,LCD_B7,EVENTOUT
PortK,PK7,,,,,,,,,,,,,,,LCD_DE,EVENTOUT
-
diff --git a/ports/stm32/boards/stm32f767.ld b/ports/stm32/boards/stm32f767.ld
index 225abd810..c05fd8021 100644
--- a/ports/stm32/boards/stm32f767.ld
+++ b/ports/stm32/boards/stm32f767.ld
@@ -7,6 +7,7 @@ MEMORY
{
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1024K
FLASH_ISR (rx) : ORIGIN = 0x08000000, LENGTH = 32K /* sector 0, 32K */
+ FLASH_APP (rx) : ORIGIN = 0x08008000, LENGTH = 2016K /* sectors 1-11 3x32K 1*128K 7*256K */
FLASH_FS (r) : ORIGIN = 0x08008000, LENGTH = 96K /* sectors 1, 2, 3 (32K each) */
FLASH_TEXT (rx) : ORIGIN = 0x08020000, LENGTH = 896K /* sectors 4-7 1*128Kib 3*256KiB = 896K */
DTCM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K /* Used for storage cache */
@@ -22,9 +23,6 @@ _minimum_heap_size = 16K;
aligned for a call. */
_estack = ORIGIN(RAM) + LENGTH(RAM);
-/* define common sections and symbols */
-INCLUDE common.ld
-
/* RAM extents for the garbage collector */
_ram_start = ORIGIN(RAM);
_ram_end = ORIGIN(RAM) + LENGTH(RAM);
diff --git a/ports/stm32/boards/stm32f767_af.csv b/ports/stm32/boards/stm32f767_af.csv
index 1708dfcca..0c8069ec2 100644
--- a/ports/stm32/boards/stm32f767_af.csv
+++ b/ports/stm32/boards/stm32f767_af.csv
@@ -1,170 +1,170 @@
-Port,,AF0,AF1,AF2,AF3,AF4,AF5,AF6,AF7,AF8,AF9,AF10,AF11,AF12,AF13,AF14,AF15
-,,SYS,TIM1/2,TIM3/4/5,TIM8/9/10/11/LPTIM1/CEC,I2C1/2/3/4/CEC,SPI1/2/3/4/5/6,SPI3/SAI1,SPI2/3/USART1/2/3/UART5/SPDIFRX,SAI2/USART6/UART4/5/7/8/SPDIFRX,CAN1/2/TIM12/13/14/QUADSPI/LCD,SAI2/QUADSPI/SDMMC2/OTG2_HS/OTG1_FS,SDMMC2/ETH,FMC/SDMMC1/OTG2_FS,DCMI,LCD,SYS
-PortA,PA0,,TIM2_CH1/TIM2_ETR,TIM5_CH1,TIM8_ETR,,,,USART2_CTS,UART4_TX,,SAI2_SD_B,ETH_MII_CRS,,,,EVENTOUT
-PortA,PA1,,TIM2_CH2,TIM5_CH2,,,,,USART2_RTS,UART4_RX,QUADSPI_BK1_IO3,SAI2_MCK_B,ETH_MII_RX_CLK/ETH_RMII_REF_CLK,,,LCD_R2,EVENTOUT
-PortA,PA2,,TIM2_CH3,TIM5_CH3,TIM9_CH1,,,,USART2_TX,SAI2_SCK_B,,,ETH_MDIO,,,LCD_R1,EVENTOUT
-PortA,PA3,,TIM2_CH4,TIM5_CH4,TIM9_CH2,,,,USART2_RX,,,OTG_HS_ULPI_D0,ETH_MII_COL,,,LCD_B5,EVENTOUT
-PortA,PA4,,,,,,SPI1_NSS/I2S1_WS,SPI3_NSS/I2S3_WS,USART2_CK,,,,,OTG_HS_SOF,DCMI_HSYNC,LCD_VSYNC,EVENTOUT
-PortA,PA5,,TIM2_CH1/TIM2_ETR,,TIM8_CH1N,,SPI1_SCK/I2S1_CK,,,,,OTG_HS_ULPI_CK,,,,LCD_R4,EVENTOUT
-PortA,PA6,,TIM1_BKIN,TIM3_CH1,TIM8_BKIN,,SPI1_MISO,,,,TIM13_CH1,,,,DCMI_PIXCLK,LCD_G2,EVENTOUT
-PortA,PA7,,TIM1_CH1N,TIM3_CH2,TIM8_CH1N,,SPI1_MOSI/I2S1_SD,,,,TIM14_CH1,,ETH_MII_RX_DV/ETH_RMII_CRS_DV,FMC_SDNWE,,,EVENTOUT
-PortA,PA8,MCO1,TIM1_CH1,,TIM8_BKIN2,I2C3_SCL,,,USART1_CK,,,OTG_FS_SOF,,,,LCD_R6,EVENTOUT
-PortA,PA9,,TIM1_CH2,,,I2C3_SMBA,SPI2_SCK/I2S2_CK,,USART1_TX,,,,,,DCMI_D0,,EVENTOUT
-PortA,PA10,,TIM1_CH3,,,,,,USART1_RX,,,OTG_FS_ID,,,DCMI_D1,,EVENTOUT
-PortA,PA11,,TIM1_CH4,,,,,,USART1_CTS,,CAN1_RX,OTG_FS_DM,,,,LCD_R4,EVENTOUT
-PortA,PA12,,TIM1_ETR,,,,,,USART1_RTS,SAI2_FS_B,CAN1_TX,OTG_FS_DP,,,,LCD_R5,EVENTOUT
-PortA,PA13,JTMS,SWDIO,,,,,,,,,,,,,,EVENTOUT
-PortA,PA14,JTCK,SWCLK,,,,,,,,,,,,,,EVENTOUT
-PortA,PA15,JTDI,TIM2_CH1/TIM2_ETR,,,HDMICEC,SPI1_NSS/I2S1_WS,SPI3_NSS/I2S3_WS,,UART4_RTS,,,,,,,EVENTOUT
-PortB,PB0,,TIM1_CH2N,TIM3_CH3T,TIM8_CH2N,,,,,UART4_CTS,LCD_R3,OTG_HS_ULPI_D1,ETH_MII_RXD2,,,,EVENTOUT
-PortB,PB1,,TIM1_CH3N,TIM3_CH4T,TIM8_CH3N,,,,,,LCD_R6,OTG_HS_ULPI_D2,ETH_MII_RXD3,,,,EVENTOUT
-PortB,PB2,,,,,,,SAI1_SD_A,SPI3_MOSI/I2S3_SD,,QUADSPI_CLK,,,,,,EVENTOUT
-PortB,PB3,JTDO/TRACESWO,TIM2_CH2,,,,SPI1_SCK/I2S1_CK,SPI3_SCK/I2S3_CK,,,,SDMMC2_D2,,,,,EVENTOUT
-PortB,PB4,NJTRST,,TIM3_CH1,,,SPI1_MISO,SPI3_MISO,SPI2_NSS/I2S2_WS,,,SDMMC2_D3,,,,,EVENTOUT
-PortB,PB5,,,TIM3_CH2,,I2C1_SMBA,SPI1_MOSI/I2S1_SD,SPI3_MOSI/I2S3_SD,,,CAN2_RX,OTG_HS_ULPI_D7,ETH_PPS_OUT,FMC_SDCKE1,DCMI_D10,,EVENTOUT
-PortB,PB6,,,TIM4_CH1,HDMICEC,I2C1_SCL,,,USART1_TX,,CAN2_TX,QUADSPI_BK1_NCS,,FMC_SDNE1,DCMI_D5,,EVENTOUT
-PortB,PB7,,,TIM4_CH2,,I2C1_SDA,,,USART1_RX,,,,,FMC_NL,DCMI_VSYNC,,EVENTOUT
-PortB,PB8,,,TIM4_CH3,TIM10_CH1,I2C1_SCL,,,,,CAN1_RX,SDMMC2_D4,ETH_MII_TXD3,SDMMC1_D4,DCMI_D6,LCD_B6,EVENTOUT
-PortB,PB9,,,TIM4_CH4,TIM11_CH1,I2C1_SDA,SPI2_NSS/I2S2_WS,,,,CAN1_TX,SDMMC2_D5,,SDMMC1_D5,DCMI_D7,LCD_B7,EVENTOUT
-PortB,PB10,,TIM2_CH3,,,I2C2_SCL,SPI2_SCK/I2S2_CK,,USART3_TX,,,OTG_HS_ULPI_D3,ETH_MII_RX_ER,,,LCD_G4,EVENTOUT
-PortB,PB11,,TIM2_CH4,,,I2C2_SDA,,,USART3_RX,,,OTG_HS_ULPI_D4,ETH_MII_TX_EN/ETH_RMII_TX_EN,,,LCD_G5,EVENTOUT
-PortB,PB12,,TIM1_BKIN,,,I2C2_SMBA,SPI2_NSS/I2S2_WS,,USART3_CK,,CAN2_RX,OTG_HS_ULPI_D5,ETH_MII_TXD0/ETH_RMII_TXD0,OTG_HS_ID,,,EVENTOUT
-PortB,PB13,,TIM1_CH1N,,,,SPI2_SCK/I2S2_CK,,USART3_CTS,,CAN2_TX,OTG_HS_ULPI_D6,ETH_MII_TXD1/ETH_RMII_TXD1,,,,EVENTOUT
-PortB,PB14,,TIM1_CH2N,,TIM8_CH2N,,SPI2_MISO,,USART3_RTS,,TIM12_CH1,SDMMC2_D0,,OTG_HS_DM,,,EVENTOUT
-PortB,PB15,RTC_REFIN,TIM1_CH3N,,TIM8_CH3N,,SPI2_MOSI/I2S2_SD,,,,TIM12_CH2,SDMMC2_D1,,OTG_HS_DP,,,EVENTOUT
-PortC,PC0,,,,,,,,,SAI2_FS_B,,OTG_HS_ULPI_STP,,FMC_SDNWE,,LCD_R5,EVENTOUT
-PortC,PC1,TRACED0,,,,,SPI2_MOSI/I2S2_SD,SAI1_SD_A,,,,,ETH_MDC,,,,EVENTOUT
-PortC,PC2,,,,,,SPI2_MISO,,,,,OTG_HS_ULPI_DIR,ETH_MII_TXD2,FMC_SDNE0,,,EVENTOUT
-PortC,PC3,,,,,,SPI2_MOSI/I2S2_SD,,,,,OTG_HS_ULPI_NXT,ETH_MII_TX_CLK,FMC_SDCKE0,,,EVENTOUT
-PortC,PC4,,,,,,I2S1_MCK,,,SPDIFRX_IN2,,,ETH_MII_RXD0/ETH_RMII_RXD0,FMC_SDNE0,,,EVENTOUT
-PortC,PC5,,,,,,,,,SPDIFRX_IN3,,,ETH_MII_RXD1/ETH_RMII_RXD1,FMC_SDCKE0,,,EVENTOUT
-PortC,PC6,,,TIM3_CH1,TIM8_CH1,,I2S2_MCK,,,USART6_TX,,SDMMC2_D6,,SDMMC1_D6,DCMI_D0,LCD_HSYNC,EVENTOUT
-PortC,PC7,,,TIM3_CH2,TIM8_CH2,,,I2S3_MCK,,USART6_RX,,SDMMC2_D7,,SDMMC1_D7,DCMI_D1,LCD_G6,EVENTOUT
-PortC,PC8,TRACED1,,TIM3_CH3,TIM8_CH3,,,,UART5_RTS,USART6_CK,,,,SDMMC1_D0,DCMI_D2,,EVENTOUT
-PortC,PC9,MCO2,,TIM3_CH4,TIM8_CH4,I2C3_SDA,I2S2_CKIN,,UART5_CTS,,QUADSPI_BK1_IO0,,,SDMMC1_D1,DCMI_D3,,EVENTOUT
-PortC,PC10,,,,,,,SPI3_SCK/I2S3_CK,USART3_TX,UART4_TX,QUADSPI_BK1_IO1,,,SDMMC1_D2,DCMI_D8,LCD_R2,EVENTOUT
-PortC,PC11,,,,,,,SPI3_MISO,USART3_RX,UART4_RX,QUADSPI_BK2_NCS,,,SDMMC1_D3,DCMI_D4,,EVENTOUT
-PortC,PC12,TRACED3,,,,,,SPI3_MOSI/I2S3_SD,USART3_CK,UART5_TX,,,,SDMMC1_CK,DCMI_D9,,EVENTOUT
-PortC,PC13,,,,,,,,,,,,,,,,EVENTOUT
-PortC,PC14,,,,,,,,,,,,,,,,EVENTOUT
-PortC,PC15,,,,,,,,,,,,,,,,EVENTOUT
-PortD,PD0,,,,,,,,,,CAN1_RX,,,FMC_D2,,,EVENTOUT
-PortD,PD1,,,,,,,,,,CAN1_TX,,,FMC_D3,,,EVENTOUT
-PortD,PD2,TRACED2,,TIM3_ETR,,,,,,UART5_RX,,,,SDMMC1_CMD,DCMI_D11,,EVENTOUT
-PortD,PD3,,,,,,SPI2_SCK/I2S2_CK,,USART2_CTS,,,,,FMC_CLK,DCMI_D5,LCD_G7,EVENTOUT
-PortD,PD4,,,,,,,,USART2_RTS,,,,,FMC_NOE,,,EVENTOUT
-PortD,PD5,,,,,,,,USART2_TX,,,,,FMC_NWE,,,EVENTOUT
-PortD,PD6,,,,,,SPI3_MOSI/I2S3_SD,SAI1_SD_A,USART2_RX,,,,SDMMC2_CK,FMC_NWAIT,DCMI_D10,LCD_B2,EVENTOUT
-PortD,PD7,,,,,,,,USART2_CK,SPDIFRX_IN0,,,SDMMC2_CMD,FMC_NE1,,,EVENTOUT
-PortD,PD8,,,,,,,,USART3_TX,SPDIFRX_IN1,,,,FMC_D13,,,EVENTOUT
-PortD,PD9,,,,,,,,USART3_RX,,,,,FMC_D14,,,EVENTOUT
-PortD,PD10,,,,,,,,USART3_CK,,,,,FMC_D15,,LCD_B3,EVENTOUT
-PortD,PD11,,,,,I2C4_SMBA,,,USART3_CTS,,QUADSPI_BK1_IO0,SAI2_SD_A,,FMC_A16/FMC_CLE,,,EVENTOUT
-PortD,PD12,,,TIM4_CH1,LPTIM1_IN1,I2C4_SCL,,,USART3_RTS,,QUADSPI_BK1_IO1,SAI2_FS_A,,FMC_A17/FMC_ALE,,,EVENTOUT
-PortD,PD13,,,TIM4_CH2,LPTIM1_OUT,I2C4_SDA,,,,,QUADSPI_BK1_IO3,SAI2_SCK_A,,FMC_A18,,,EVENTOUT
-PortD,PD14,,,TIM4_CH3,,,,,,UART8_CTS,,,,FMC_D0,,,EVENTOUT
-PortD,PD15,,,TIM4_CH4,,,,,,UART8_RTS,,,,FMC_D1,,,EVENTOUT
-PortE,PE0,,,TIM4_ETR,LPTIM1_ETR,,,,,UART8_RX,,SAI2_MCK_A,,FMC_NBL0,DCMI_D2,,EVENTOUT
-PortE,PE1,,,,LPTIM1_IN2,,,,,UART8_TX,,,,FMC_NBL1,DCMI_D3,,EVENTOUT
-PortE,PE2,TRACECLK,,,,,SPI4_SCK,SAI1_MCLK_A,,,QUADSPI_BK1_IO2,,ETH_MII_TXD3,FMC_A23,,,EVENTOUT
-PortE,PE3,TRACED0,,,,,,SAI1_SD_B,,,,,,FMC_A19,,,EVENTOUT
-PortE,PE4,TRACED1,,,,,SPI4_NSS,SAI1_FS_A,,,,,,FMC_A20,DCMI_D4,LCD_B0,EVENTOUT
-PortE,PE5,TRACED2,,,TIM9_CH1,,SPI4_MISO,SAI1_SCK_A,,,,,,FMC_A21,DCMI_D6,LCD_G0,EVENTOUT
-PortE,PE6,TRACED3,TIM1_BKIN2,,TIM9_CH2,,SPI4_MOSI,SAI1_SD_A,,,,SAI2_MCK_B,,FMC_A22,DCMI_D7,LCD_G1,EVENTOUT
-PortE,PE7,,TIM1_ETR,,,,,,,UART7_RX,,QUADSPI_BK2_IO0,,FMC_D4,,,EVENTOUT
-PortE,PE8,,TIM1_CH1N,,,,,,,UART7_TX,,QUADSPI_BK2_IO1,,FMC_D5,,,EVENTOUT
-PortE,PE9,,TIM1_CH1,,,,,,,UART7_RTS,,QUADSPI_BK2_IO2,,FMC_D6,,,EVENTOUT
-PortE,PE10,,TIM1_CH2N,,,,,,,UART7_CTS,,QUADSPI_BK2_IO3,,FMC_D7,,,EVENTOUT
-PortE,PE11,,TIM1_CH2,,,,SPI4_NSS,,,,,SAI2_SD_B,,FMC_D8,,LCD_G3,EVENTOUT
-PortE,PE12,,TIM1_CH3N,,,,SPI4_SCK,,,,,SAI2_SCK_B,,FMC_D9,,LCD_B4,EVENTOUT
-PortE,PE13,,TIM1_CH3,,,,SPI4_MISO,,,,,SAI2_FS_B,,FMC_D10,,LCD_DE,EVENTOUT
-PortE,PE14,,TIM1_CH4,,,,SPI4_MOSI,,,,,SAI2_MCK_B,,FMC_D11,,LCD_CLK,EVENTOUT
-PortE,PE15,,TIM1_BKIN,,,,,,,,,,,FMC_D12,,LCD_R7,EVENTOUT
-PortF,PF0,,,,,I2C2_SDA,,,,,,,,FMC_A0,,,EVENTOUT
-PortF,PF1,,,,,I2C2_SCL,,,,,,,,FMC_A1,,,EVENTOUT
-PortF,PF2,,,,,I2C2_SMBA,,,,,,,,FMC_A2,,,EVENTOUT
-PortF,PF3,,,,,,,,,,,,,FMC_A3,,,EVENTOUT
-PortF,PF4,,,,,,,,,,,,,FMC_A4,,,EVENTOUT
-PortF,PF5,,,,,,,,,,,,,FMC_A5,,,EVENTOUT
-PortF,PF6,,,,TIM10_CH1,,SPI5_NSS,SAI1_SD_B,,UART7_RX,QUADSPI_BK1_IO3,,,,,,EVENTOUT
-PortF,PF7,,,,TIM11_CH1,,SPI5_SCK,SAI1_MCLK_B,,UART7_TX,QUADSPI_BK1_IO2,,,,,,EVENTOUT
-PortF,PF8,,,,,,SPI5_MISO,SAI1_SCK_B,,UART7_RTS,TIM13_CH1,QUADSPI_BK1_IO0,,,,,EVENTOUT
-PortF,PF9,,,,,,SPI5_MOSI,SAI1_FS_B,,UART7_CTS,TIM14_CH1,QUADSPI_BK1_IO1,,,,,EVENTOUT
-PortF,PF10,,,,,,,,,,,,,,DCMI_D11,LCD_DE,EVENTOUT
-PortF,PF11,,,,,,SPI5_MOSI,,,,,SAI2_SD_B,,FMC_SDNRAS,DCMI_D12,,EVENTOUT
-PortF,PF12,,,,,,,,,,,,,FMC_A6,,,EVENTOUT
-PortF,PF13,,,,,I2C4_SMBA,,,,,,,,FMC_A7,,,EVENTOUT
-PortF,PF14,,,,,I2C4_SCL,,,,,,,,FMC_A8,,,EVENTOUT
-PortF,PF15,,,,,I2C4_SDA,,,,,,,,FMC_A9,,,EVENTOUT
-PortG,PG0,,,,,,,,,,,,,FMC_A10,,,EVENTOUT
-PortG,PG1,,,,,,,,,,,,,FMC_A11,,,EVENTOUT
-PortG,PG2,,,,,,,,,,,,,FMC_A12,,,EVENTOUT
-PortG,PG3,,,,,,,,,,,,,FMC_A13,,,EVENTOUT
-PortG,PG4,,,,,,,,,,,,,FMC_A14/FMC_BA0,,,EVENTOUT
-PortG,PG5,,,,,,,,,,,,,FMC_A15/FMC_BA1,,,EVENTOUT
-PortG,PG6,,,,,,,,,,,,,,DCMI_D12,LCD_R7,EVENTOUT
-PortG,PG7,,,,,,,,,USART6_CK,,,,FMC_INT,DCMI_D13,LCD_CLK,EVENTOUT
-PortG,PG8,,,,,,SPI6_NSS,,SPDIFRX_IN2,USART6_RTS,,,ETH_PPS_OUT,FMC_SDCLK,,,EVENTOUT
-PortG,PG9,,,,,,,,SPDIFRX_IN3,USART6_RX,QUADSPI_BK2_IO2,SAI2_FS_B,SDMMC2_D0,FMC_NE2/FMC_NCE,DCMI_VSYNC,,EVENTOUT
-PortG,PG10,,,,,,,,,,LCD_G3,SAI2_SD_B,SDMMC2_D1,FMC_NE3,DCMI_D2,LCD_B2,EVENTOUT
-PortG,PG11,,,,,,,,SPDIFRX_IN0,,,SDMMC2_D2,ETH_MII_TX_EN/ETH_RMII_TX_EN,,DCMI_D3,LCD_B3,EVENTOUT
-PortG,PG12,,,,LPTIM1_IN1,,SPI6_MISO,,SPDIFRX_IN1,USART6_RTS,LCD_B4,,SDMMC2_D3,FMC_NE4,,LCD_B1,EVENTOUT
-PortG,PG13,TRACED0,,,LPTIM1_OUT,,SPI6_SCK,,,USART6_CTS,,,ETH_MII_TXD0/ETH_RMII_TXD0,FMC_A24,,LCD_R0,EVENTOUT
-PortG,PG14,TRACED1,,,LPTIM1_ETR,,SPI6_MOSI,,,USART6_TX,QUADSPI_BK2_IO3,,ETH_MII_TXD1/ETH_RMII_TXD1,FMC_A25,,LCD_B0,EVENTOUT
-PortG,PG15,,,,,,,,,USART6_CTS,,,,FMC_SDNCAS,DCMI_D13,,EVENTOUT
-PortH,PH0,,,,,,,,,,,,,,,,EVENTOUT
-PortH,PH1,,,,,,,,,,,,,,,,EVENTOUT
-PortH,PH2,,,,LPTIM1_IN2,,,,,,QUADSPI_BK2_IO0,SAI2_SCK_B,ETH_MII_CRS,FMC_SDCKE0,,LCD_R0,EVENTOUT
-PortH,PH3,,,,,,,,,,QUADSPI_BK2_IO1,SAI2_MCK_B,ETH_MII_COL,FMC_SDNE0,,LCD_R1,EVENTOUT
-PortH,PH4,,,,,I2C2_SCL,,,,,,OTG_HS_ULPI_NXT,,,,,EVENTOUT
-PortH,PH5,,,,,I2C2_SDA,SPI5_NSS,,,,,,,FMC_SDNWE,,,EVENTOUT
-PortH,PH6,,,,,I2C2_SMBA,SPI5_SCK,,,,TIM12_CH1,,ETH_MII_RXD2,FMC_SDNE1,DCMI_D8,,EVENTOUT
-PortH,PH7,,,,,I2C3_SCL,SPI5_MISO,,,,,,ETH_MII_RXD3,FMC_SDCKE1,DCMI_D9,,EVENTOUT
-PortH,PH8,,,,,I2C3_SDA,,,,,,,,FMC_D16,DCMI_HSYNC,LCD_R2,EVENTOUT
-PortH,PH9,,,,,I2C3_SMBA,,,,,TIM12_CH2,,,FMC_D17,DCMI_D0,LCD_R3,EVENTOUT
-PortH,PH10,,,TIM5_CH1,,I2C4_SMBA,,,,,,,,FMC_D18,DCMI_D1,LCD_R4,EVENTOUT
-PortH,PH11,,,TIM5_CH2,,I2C4_SCL,,,,,,,,FMC_D19,DCMI_D2,LCD_R5,EVENTOUT
-PortH,PH12,,,TIM5_CH3,,I2C4_SDA,,,,,,,,FMC_D20,DCMI_D3,LCD_R6,EVENTOUT
-PortH,PH13,,,,TIM8_CH1N,,,,,,CAN1_TX,,,FMC_D21,,LCD_G2,EVENTOUT
-PortH,PH14,,,,TIM8_CH2N,,,,,,,,,FMC_D22,DCMI_D4,LCD_G3,EVENTOUT
-PortH,PH15,,,,TIM8_CH3N,,,,,,,,,FMC_D23,DCMI_D11,LCD_G4,EVENTOUT
-PortI,PI0,,,TIM5_CH4,,,SPI2_NSS/I2S2_WS,,,,,,,FMC_D24,DCMI_D13,LCD_G5,EVENTOUT
-PortI,PI1,,,,TIM8_BKIN2,,SPI2_SCK/I2S2_CK,,,,,,,FMC_D25,DCMI_D8,LCD_G6,EVENTOUT
-PortI,PI2,,,,TIM8_CH4,,SPI2_MISO,,,,,,,FMC_D26,DCMI_D9,LCD_G7,EVENTOUT
-PortI,PI3,,,,TIM8_ETR,,SPI2_MOSI/I2S2_SD,,,,,,,FMC_D27,DCMI_D10,,EVENTOUT
-PortI,PI4,,,,TIM8_BKIN,,,,,,,SAI2_MCK_A,,FMC_NBL2,DCMI_D5,LCD_B4,EVENTOUT
-PortI,PI5,,,,TIM8_CH1,,,,,,,SAI2_SCK_A,,FMC_NBL3,DCMI_VSYNC,LCD_B5,EVENTOUT
-PortI,PI6,,,,TIM8_CH2,,,,,,,SAI2_SD_A,,FMC_D28,DCMI_D6,LCD_B6,EVENTOUT
-PortI,PI7,,,,TIM8_CH3,,,,,,,SAI2_FS_A,,FMC_D29,DCMI_D7,LCD_B7,EVENTOUT
-PortI,PI8,,,,,,,,,,,,,,,,EVENTOUT
-PortI,PI9,,,,,,,,,,CAN1_RX,,,FMC_D30,,LCD_VSYNC,EVENTOUT
-PortI,PI10,,,,,,,,,,,,ETH_MII_RX_ER,FMC_D31,,LCD_HSYNC,EVENTOUT
-PortI,PI11,,,,,,,,,,,OTG_HS_ULPI_DIR,,,,,EVENTOUT
-PortI,PI12,,,,,,,,,,,,,,,LCD_HSYNC,EVENTOUT
-PortI,PI13,,,,,,,,,,,,,,,LCD_VSYNC,EVENTOUT
-PortI,PI14,,,,,,,,,,,,,,,LCD_CLK,EVENTOUT
-PortI,PI15,,,,,,,,,,,,,,,LCD_R0,EVENTOUT
-PortJ,PJ0,,,,,,,,,,,,,,,LCD_R1,EVENTOUT
-PortJ,PJ1,,,,,,,,,,,,,,,LCD_R2,EVENTOUT
-PortJ,PJ2,,,,,,,,,,,,,,,LCD_R3,EVENTOUT
-PortJ,PJ3,,,,,,,,,,,,,,,LCD_R4,EVENTOUT
-PortJ,PJ4,,,,,,,,,,,,,,,LCD_R5,EVENTOUT
-PortJ,PJ5,,,,,,,,,,,,,,,LCD_R6,EVENTOUT
-PortJ,PJ6,,,,,,,,,,,,,,,LCD_R7,EVENTOUT
-PortJ,PJ7,,,,,,,,,,,,,,,LCD_G0,EVENTOUT
-PortJ,PJ8,,,,,,,,,,,,,,,LCD_G1,EVENTOUT
-PortJ,PJ9,,,,,,,,,,,,,,,LCD_G2,EVENTOUT
-PortJ,PJ10,,,,,,,,,,,,,,,LCD_G3,EVENTOUT
-PortJ,PJ11,,,,,,,,,,,,,,,LCD_G4,EVENTOUT
-PortJ,PJ12,,,,,,,,,,,,,,,LCD_B0,EVENTOUT
-PortJ,PJ13,,,,,,,,,,,,,,,LCD_B1,EVENTOUT
-PortJ,PJ14,,,,,,,,,,,,,,,LCD_B2,EVENTOUT
-PortJ,PJ15,,,,,,,,,,,,,,,LCD_B3,EVENTOUT
-PortK,PK0,,,,,,,,,,,,,,,LCD_G5,EVENTOUT
-PortK,PK1,,,,,,,,,,,,,,,LCD_G6,EVENTOUT
-PortK,PK2,,,,,,,,,,,,,,,LCD_G7,EVENTOUT
-PortK,PK3,,,,,,,,,,,,,,,LCD_B4,EVENTOUT
-PortK,PK4,,,,,,,,,,,,,,,LCD_B5,EVENTOUT
-PortK,PK5,,,,,,,,,,,,,,,LCD_B6,EVENTOUT
-PortK,PK6,,,,,,,,,,,,,,,LCD_B7,EVENTOUT
-PortK,PK7,,,,,,,,,,,,,,,LCD_DE,EVENTOUT
+Port,,AF0,AF1,AF2,AF3,AF4,AF5,AF6,AF7,AF8,AF9,AF10,AF11,AF12,AF13,AF14,AF15,
+,,SYS,I2C4/UART5/TIM1/2,TIM3/4/5,TIM8/9/10/11/LPTIM1/DFSDM1/CEC,I2C1/2/3/4/USART1/CEC,SPI1/I2S1/SPI2/I2S2/SPI3/I2S3/SPI4/5/6,SPI2/I2S2/SPI3/I2S3/SAI1/I2C4/UART4/DFSDM1,SPI2/I2S2/SPI3/I2S3/SPI6/USART1/2/3/UART5/DFSDM1/SPDIF,SPI6/SAI2/USART6/UART4/5/7/8/OTG_FS/SPDIF,CAN1/2/TIM12/13/14/QUADSPI/FMC/LCD,SAI2/QUADSPI/SDMMC2/DFSDM1/OTG2_HS/OTG1_FS/LCD,I2C4/CAN3/SDMMC2/ETH,UART7/FMC/SDMMC1/MDIOS/OTG2_FS,DCMI/LCD/DSI,LCD,SYS,ADC
+PortA,PA0,,TIM2_CH1/TIM2_ETR,TIM5_CH1,TIM8_ETR,,,,USART2_CTS,UART4_TX,,SAI2_SD_B,ETH_MII_CRS,,,,EVENTOUT,ADC123_IN0
+PortA,PA1,,TIM2_CH2,TIM5_CH2,,,,,USART2_RTS,UART4_RX,QUADSPI_BK1_IO3,SAI2_MCK_B,ETH_MII_RX_CLK/ETH_RMII_REF_CLK,,,LCD_R2,EVENTOUT,ADC123_IN1
+PortA,PA2,,TIM2_CH3,TIM5_CH3,TIM9_CH1,,,,USART2_TX,SAI2_SCK_B,,,ETH_MDIO,MDIOS_MDIO,,LCD_R1,EVENTOUT,ADC123_IN2
+PortA,PA3,,TIM2_CH4,TIM5_CH4,TIM9_CH2,,,,USART2_RX,,LCD_B2,OTG_HS_ULPI_D0,ETH_MII_COL,,,LCD_B5,EVENTOUT,ADC123_IN3
+PortA,PA4,,,,,,SPI1_NSS/I2S1_WS,SPI3_NSS/I2S3_WS,USART2_CK,SPI6_NSS,,,,OTG_HS_SOF,DCMI_HSYNC,LCD_VSYNC,EVENTOUT,ADC12_IN4
+PortA,PA5,,TIM2_CH1/TIM2_ETR,,TIM8_CH1N,,SPI1_SCK/I2S1_CK,,,SPI6_SCK,,OTG_HS_ULPI_CK,,,,LCD_R4,EVENTOUT,ADC12_IN5
+PortA,PA6,,TIM1_BKIN,TIM3_CH1,TIM8_BKIN,,SPI1_MISO,,,SPI6_MISO,TIM13_CH1,,,MDIOS_MDC,DCMI_PIXCLK,LCD_G2,EVENTOUT,ADC12_IN6
+PortA,PA7,,TIM1_CH1N,TIM3_CH2,TIM8_CH1N,,SPI1_MOSI/I2S1_SD,,,SPI6_MOSI,TIM14_CH1,,ETH_MII_RX_DV/ETH_RMII_CRS_DV,FMC_SDNWE,,,EVENTOUT,ADC12_IN7
+PortA,PA8,MCO1,TIM1_CH1,,TIM8_BKIN2,I2C3_SCL,,,USART1_CK,,,OTG_FS_SOF,CAN3_RX,UART7_RX,LCD_B3,LCD_R6,EVENTOUT,
+PortA,PA9,,TIM1_CH2,,,I2C3_SMBA,SPI2_SCK/I2S2_CK,,USART1_TX,,,,,,DCMI_D0,LCD_R5,EVENTOUT,
+PortA,PA10,,TIM1_CH3,,,,,,USART1_RX,,LCD_B4,OTG_FS_ID,,MDIOS_MDIO,DCMI_D1,LCD_B1,EVENTOUT,
+PortA,PA11,,TIM1_CH4,,,,SPI2_NSS/I2S2_WS,UART4_RX,USART1_CTS,,CAN1_RX,OTG_FS_DM,,,,LCD_R4,EVENTOUT,
+PortA,PA12,,TIM1_ETR,,,,SPI2_SCK/I2S2_CK,UART4_TX,USART1_RTS,SAI2_FS_B,CAN1_TX,OTG_FS_DP,,,,LCD_R5,EVENTOUT,
+PortA,PA13,JTMS/SWDIO,,,,,,,,,,,,,,,EVENTOUT,
+PortA,PA14,JTCK/SWCLK,,,,,,,,,,,,,,,EVENTOUT,
+PortA,PA15,JTDI,TIM2_CH1/TIM2_ETR,,,HDMI_CEC,SPI1_NSS/I2S1_WS,SPI3_NSS/I2S3_WS,SPI6_NSS,UART4_RTS,,,CAN3_TX,UART7_TX,,,EVENTOUT,
+PortB,PB0,,TIM1_CH2N,TIM3_CH3,TIM8_CH2N,,,DFSDM1_CKOUT,,UART4_CTS,LCD_R3,OTG_HS_ULPI_D1,ETH_MII_RXD2,,,LCD_G1,EVENTOUT,ADC12_IN8
+PortB,PB1,,TIM1_CH3N,TIM3_CH4,TIM8_CH3N,,,DFSDM1_DATAIN1,,,LCD_R6,OTG_HS_ULPI_D2,ETH_MII_RXD3,,,LCD_G0,EVENTOUT,ADC12_IN9
+PortB,PB2,,,,,,,SAI1_SD_A,SPI3_MOSI/I2S3_SD,,QUADSPI_CLK,DFSDM1_CKIN1,,,,,EVENTOUT,
+PortB,PB3,JTDO/TRACESWO,TIM2_CH2,,,,SPI1_SCK/I2S1_CK,SPI3_SCK/I2S3_CK,,SPI6_SCK,,SDMMC2_D2,CAN3_RX,UART7_RX,,,EVENTOUT,
+PortB,PB4,NJTRST,,TIM3_CH1,,,SPI1_MISO,SPI3_MISO,SPI2_NSS/I2S2_WS,SPI6_MISO,,SDMMC2_D3,CAN3_TX,UART7_TX,,,EVENTOUT,
+PortB,PB5,,UART5_RX,TIM3_CH2,,I2C1_SMBA,SPI1_MOSI/I2S1_SD,SPI3_MOSI/I2S3_SD,,SPI6_MOSI,CAN2_RX,OTG_HS_ULPI_D7,ETH_PPS_OUT,FMC_SDCKE1,DCMI_D10,LCD_G7,EVENTOUT,
+PortB,PB6,,UART5_TX,TIM4_CH1,HDMI_CEC,I2C1_SCL,,DFSDM1_DATAIN5,USART1_TX,,CAN2_TX,QUADSPI_BK1_NCS,I2C4_SCL,FMC_SDNE1,DCMI_D5,,EVENTOUT,
+PortB,PB7,,,TIM4_CH2,,I2C1_SDA,,DFSDM1_CKIN5,USART1_RX,,,,I2C4_SDA,FMC_NL,DCMI_VSYNC,,EVENTOUT,
+PortB,PB8,,I2C4_SCL,TIM4_CH3,TIM10_CH1,I2C1_SCL,,DFSDM1_CKIN7,UART5_RX,,CAN1_RX,SDMMC2_D4,ETH_MII_TXD3,SDMMC1_D4,DCMI_D6,LCD_B6,EVENTOUT,
+PortB,PB9,,I2C4_SDA,TIM4_CH4,TIM11_CH1,I2C1_SDA,SPI2_NSS/I2S2_WS,DFSDM1_DATAIN7,UART5_TX,,CAN1_TX,SDMMC2_D5,I2C4_SMBA,SDMMC1_D5,DCMI_D7,LCD_B7,EVENTOUT,
+PortB,PB10,,TIM2_CH3,,,I2C2_SCL,SPI2_SCK/I2S2_CK,DFSDM1_DATAIN7,USART3_TX,,QUADSPI_BK1_NCS,OTG_HS_ULPI_D3,ETH_MII_RX_ER,,,LCD_G4,EVENTOUT,
+PortB,PB11,,TIM2_CH4,,,I2C2_SDA,,DFSDM1_CKIN7,USART3_RX,,,OTG_HS_ULPI_D4,ETH_MII_TX_EN/ETH_RMII_TX_EN,,DSI_TE,LCD_G5,EVENTOUT,
+PortB,PB12,,TIM1_BKIN,,,I2C2_SMBA,SPI2_NSS/I2S2_WS,DFSDM1_DATAIN1,USART3_CK,UART5_RX,CAN2_RX,OTG_HS_ULPI_D5,ETH_MII_TXD0/ETH_RMII_TXD0,OTG_HS_ID,,,EVENTOUT,
+PortB,PB13,,TIM1_CH1N,,,,SPI2_SCK/I2S2_CK,DFSDM1_CKIN1,USART3_CTS,UART5_TX,CAN2_TX,OTG_HS_ULPI_D6,ETH_MII_TXD1/ETH_RMII_TXD1,,,,EVENTOUT,
+PortB,PB14,,TIM1_CH2N,,TIM8_CH2N,USART1_TX,SPI2_MISO,DFSDM1_DATAIN2,USART3_RTS,UART4_RTS,TIM12_CH1,SDMMC2_D0,,OTG_HS_DM,,,EVENTOUT,
+PortB,PB15,RTC_REFIN,TIM1_CH3N,,TIM8_CH3N,USART1_RX,SPI2_MOSI/I2S2_SD,DFSDM1_CKIN2,,UART4_CTS,TIM12_CH2,SDMMC2_D1,,OTG_HS_DP,,,EVENTOUT,
+PortC,PC0,,,,DFSDM1_CKIN0,,,DFSDM1_DATAIN4,,SAI2_FS_B,,OTG_HS_ULPI_STP,,FMC_SDNWE,,LCD_R5,EVENTOUT,ADC123_IN10
+PortC,PC1,TRACED0,,,DFSDM1_DATAIN0,,SPI2_MOSI/I2S2_SD,SAI1_SD_A,,,,DFSDM1_CKIN4,ETH_MDC,MDIOS_MDC,,,EVENTOUT,ADC123_IN11
+PortC,PC2,,,,DFSDM1_CKIN1,,SPI2_MISO,DFSDM1_CKOUT,,,,OTG_HS_ULPI_DIR,ETH_MII_TXD2,FMC_SDNE0,,,EVENTOUT,ADC123_IN12
+PortC,PC3,,,,DFSDM1_DATAIN1,,SPI2_MOSI/I2S2_SD,,,,,OTG_HS_ULPI_NXT,ETH_MII_TX_CLK,FMC_SDCKE0,,,EVENTOUT,ADC123_IN13
+PortC,PC4,,,,DFSDM1_CKIN2,,I2S1_MCK,,,SPDIFRX_IN2,,,ETH_MII_RXD0/ETH_RMII_RXD0,FMC_SDNE0,,,EVENTOUT,ADC12_IN14
+PortC,PC5,,,,DFSDM1_DATAIN2,,,,,SPDIFRX_IN3,,,ETH_MII_RXD1/ETH_RMII_RXD1,FMC_SDCKE0,,,EVENTOUT,ADC12_IN15
+PortC,PC6,,,TIM3_CH1,TIM8_CH1,,I2S2_MCK,,DFSDM1_CKIN3,USART6_TX,FMC_NWAIT,SDMMC2_D6,,SDMMC1_D6,DCMI_D0,LCD_HSYNC,EVENTOUT,
+PortC,PC7,,,TIM3_CH2,TIM8_CH2,,,I2S3_MCK,DFSDM1_DATAIN3,USART6_RX,FMC_NE1,SDMMC2_D7,,SDMMC1_D7,DCMI_D1,LCD_G6,EVENTOUT,
+PortC,PC8,TRACED1,,TIM3_CH3,TIM8_CH3,,,,UART5_RTS,USART6_CK,FMC_NE2/FMC_NCE,,,SDMMC1_D0,DCMI_D2,,EVENTOUT,
+PortC,PC9,MCO2,,TIM3_CH4,TIM8_CH4,I2C3_SDA,I2S_CKIN,,UART5_CTS,,QUADSPI_BK1_IO0,LCD_G3,,SDMMC1_D1,DCMI_D3,LCD_B2,EVENTOUT,
+PortC,PC10,,,,DFSDM1_CKIN5,,,SPI3_SCK/I2S3_CK,USART3_TX,UART4_TX,QUADSPI_BK1_IO1,,,SDMMC1_D2,DCMI_D8,LCD_R2,EVENTOUT,
+PortC,PC11,,,,DFSDM1_DATAIN5,,,SPI3_MISO,USART3_RX,UART4_RX,QUADSPI_BK2_NCS,,,SDMMC1_D3,DCMI_D4,,EVENTOUT,
+PortC,PC12,TRACED3,,,,,,SPI3_MOSI/I2S3_SD,USART3_CK,UART5_TX,,,,SDMMC1_CK,DCMI_D9,,EVENTOUT,
+PortC,PC13,,,,,,,,,,,,,,,,EVENTOUT,
+PortC,PC14,,,,,,,,,,,,,,,,EVENTOUT,
+PortC,PC15,,,,,,,,,,,,,,,,EVENTOUT,
+PortD,PD0,,,,DFSDM1_CKIN6,,,DFSDM1_DATAIN7,,UART4_RX,CAN1_RX,,,FMC_D2,,,EVENTOUT,
+PortD,PD1,,,,DFSDM1_DATAIN6,,,DFSDM1_CKIN7,,UART4_TX,CAN1_TX,,,FMC_D3,,,EVENTOUT,
+PortD,PD2,TRACED2,,TIM3_ETR,,,,,,UART5_RX,,,,SDMMC1_CMD,DCMI_D11,,EVENTOUT,
+PortD,PD3,,,,DFSDM1_CKOUT,,SPI2_SCK/I2S2_CK,DFSDM1_DATAIN0,USART2_CTS,,,,,FMC_CLK,DCMI_D5,LCD_G7,EVENTOUT,
+PortD,PD4,,,,,,,DFSDM1_CKIN0,USART2_RTS,,,,,FMC_NOE,,,EVENTOUT,
+PortD,PD5,,,,,,,,USART2_TX,,,,,FMC_NWE,,,EVENTOUT,
+PortD,PD6,,,,DFSDM1_CKIN4,,SPI3_MOSI/I2S3_SD,SAI1_SD_A,USART2_RX,,,DFSDM1_DATAIN1,SDMMC2_CK,FMC_NWAIT,DCMI_D10,LCD_B2,EVENTOUT,
+PortD,PD7,,,,DFSDM1_DATAIN4,,SPI1_MOSI/I2S1_SD,DFSDM1_CKIN1,USART2_CK,SPDIFRX_IN0,,,SDMMC2_CMD,FMC_NE1,,,EVENTOUT,
+PortD,PD8,,,,DFSDM1_CKIN3,,,,USART3_TX,SPDIFRX_IN1,,,,FMC_D13,,,EVENTOUT,
+PortD,PD9,,,,DFSDM1_DATAIN3,,,,USART3_RX,,,,,FMC_D14,,,EVENTOUT,
+PortD,PD10,,,,DFSDM1_CKOUT,,,,USART3_CK,,,,,FMC_D15,,LCD_B3,EVENTOUT,
+PortD,PD11,,,,,I2C4_SMBA,,,USART3_CTS,,QUADSPI_BK1_IO0,SAI2_SD_A,,FMC_A16/FMC_CLE,,,EVENTOUT,
+PortD,PD12,,,TIM4_CH1,LPTIM1_IN1,I2C4_SCL,,,USART3_RTS,,QUADSPI_BK1_IO1,SAI2_FS_A,,FMC_A17/FMC_ALE,,,EVENTOUT,
+PortD,PD13,,,TIM4_CH2,LPTIM1_OUT,I2C4_SDA,,,,,QUADSPI_BK1_IO3,SAI2_SCK_A,,FMC_A18,,,EVENTOUT,
+PortD,PD14,,,TIM4_CH3,,,,,,UART8_CTS,,,,FMC_D0,,,EVENTOUT,
+PortD,PD15,,,TIM4_CH4,,,,,,UART8_RTS,,,,FMC_D1,,,EVENTOUT,
+PortE,PE0,,,TIM4_ETR,LPTIM1_ETR,,,,,UART8_RX,,SAI2_MCK_A,,FMC_NBL0,DCMI_D2,,EVENTOUT,
+PortE,PE1,,,,LPTIM1_IN2,,,,,UART8_TX,,,,FMC_NBL1,DCMI_D3,,EVENTOUT,
+PortE,PE2,TRACECLK,,,,,SPI4_SCK,SAI1_MCLK_A,,,QUADSPI_BK1_IO2,,ETH_MII_TXD3,FMC_A23,,,EVENTOUT,
+PortE,PE3,TRACED0,,,,,,SAI1_SD_B,,,,,,FMC_A19,,,EVENTOUT,
+PortE,PE4,TRACED1,,,,,SPI4_NSS,SAI1_FS_A,,,,DFSDM1_DATAIN3,,FMC_A20,DCMI_D4,LCD_B0,EVENTOUT,
+PortE,PE5,TRACED2,,,TIM9_CH1,,SPI4_MISO,SAI1_SCK_A,,,,DFSDM1_CKIN3,,FMC_A21,DCMI_D6,LCD_G0,EVENTOUT,
+PortE,PE6,TRACED3,TIM1_BKIN2,,TIM9_CH2,,SPI4_MOSI,SAI1_SD_A,,,,SAI2_MCK_B,,FMC_A22,DCMI_D7,LCD_G1,EVENTOUT,
+PortE,PE7,,TIM1_ETR,,,,,DFSDM1_DATAIN2,,UART7_RX,,QUADSPI_BK2_IO0,,FMC_D4,,,EVENTOUT,
+PortE,PE8,,TIM1_CH1N,,,,,DFSDM1_CKIN2,,UART7_TX,,QUADSPI_BK2_IO1,,FMC_D5,,,EVENTOUT,
+PortE,PE9,,TIM1_CH1,,,,,DFSDM1_CKOUT,,UART7_RTS,,QUADSPI_BK2_IO2,,FMC_D6,,,EVENTOUT,
+PortE,PE10,,TIM1_CH2N,,,,,DFSDM1_DATAIN4,,UART7_CTS,,QUADSPI_BK2_IO3,,FMC_D7,,,EVENTOUT,
+PortE,PE11,,TIM1_CH2,,,,SPI4_NSS,DFSDM1_CKIN4,,,,SAI2_SD_B,,FMC_D8,,LCD_G3,EVENTOUT,
+PortE,PE12,,TIM1_CH3N,,,,SPI4_SCK,DFSDM1_DATAIN5,,,,SAI2_SCK_B,,FMC_D9,,LCD_B4,EVENTOUT,
+PortE,PE13,,TIM1_CH3,,,,SPI4_MISO,DFSDM1_CKIN5,,,,SAI2_FS_B,,FMC_D10,,LCD_DE,EVENTOUT,
+PortE,PE14,,TIM1_CH4,,,,SPI4_MOSI,,,,,SAI2_MCK_B,,FMC_D11,,LCD_CLK,EVENTOUT,
+PortE,PE15,,TIM1_BKIN,,,,,,,,,,,FMC_D12,,LCD_R7,EVENTOUT,
+PortF,PF0,,,,,I2C2_SDA,,,,,,,,FMC_A0,,,EVENTOUT,
+PortF,PF1,,,,,I2C2_SCL,,,,,,,,FMC_A1,,,EVENTOUT,
+PortF,PF2,,,,,I2C2_SMBA,,,,,,,,FMC_A2,,,EVENTOUT,
+PortF,PF3,,,,,,,,,,,,,FMC_A3,,,EVENTOUT,ADC3_IN9
+PortF,PF4,,,,,,,,,,,,,FMC_A4,,,EVENTOUT,ADC3_IN14
+PortF,PF5,,,,,,,,,,,,,FMC_A5,,,EVENTOUT,ADC3_IN15
+PortF,PF6,,,,TIM10_CH1,,SPI5_NSS,SAI1_SD_B,,UART7_RX,QUADSPI_BK1_IO3,,,,,,EVENTOUT,ADC3_IN4
+PortF,PF7,,,,TIM11_CH1,,SPI5_SCK,SAI1_MCLK_B,,UART7_TX,QUADSPI_BK1_IO2,,,,,,EVENTOUT,ADC3_IN5
+PortF,PF8,,,,,,SPI5_MISO,SAI1_SCK_B,,UART7_RTS,TIM13_CH1,QUADSPI_BK1_IO0,,,,,EVENTOUT,ADC3_IN6
+PortF,PF9,,,,,,SPI5_MOSI,SAI1_FS_B,,UART7_CTS,TIM14_CH1,QUADSPI_BK1_IO1,,,,,EVENTOUT,ADC3_IN7
+PortF,PF10,,,,,,,,,,QUADSPI_CLK,,,,DCMI_D11,LCD_DE,EVENTOUT,ADC3_IN8
+PortF,PF11,,,,,,SPI5_MOSI,,,,,SAI2_SD_B,,FMC_SDNRAS,DCMI_D12,,EVENTOUT,
+PortF,PF12,,,,,,,,,,,,,FMC_A6,,,EVENTOUT,
+PortF,PF13,,,,,I2C4_SMBA,,DFSDM1_DATAIN6,,,,,,FMC_A7,,,EVENTOUT,
+PortF,PF14,,,,,I2C4_SCL,,DFSDM1_CKIN6,,,,,,FMC_A8,,,EVENTOUT,
+PortF,PF15,,,,,I2C4_SDA,,,,,,,,FMC_A9,,,EVENTOUT,
+PortG,PG0,,,,,,,,,,,,,FMC_A10,,,EVENTOUT,
+PortG,PG1,,,,,,,,,,,,,FMC_A11,,,EVENTOUT,
+PortG,PG2,,,,,,,,,,,,,FMC_A12,,,EVENTOUT,
+PortG,PG3,,,,,,,,,,,,,FMC_A13,,,EVENTOUT,
+PortG,PG4,,,,,,,,,,,,,FMC_A14/FMC_BA0,,,EVENTOUT,
+PortG,PG5,,,,,,,,,,,,,FMC_A15/FMC_BA1,,,EVENTOUT,
+PortG,PG6,,,,,,,,,,,,,FMC_NE3,DCMI_D12,LCD_R7,EVENTOUT,
+PortG,PG7,,,,,,,SAI1_MCLK_A,,USART6_CK,,,,FMC_INT,DCMI_D13,LCD_CLK,EVENTOUT,
+PortG,PG8,,,,,,SPI6_NSS,,SPDIFRX_IN2,USART6_RTS,,,ETH_PPS_OUT,FMC_SDCLK,,LCD_G7,EVENTOUT,
+PortG,PG9,,,,,,SPI1_MISO,,SPDIFRX_IN3,USART6_RX,QUADSPI_BK2_IO2,SAI2_FS_B,SDMMC2_D0,FMC_NE2/FMC_NCE,DCMI_VSYNC,,EVENTOUT,
+PortG,PG10,,,,,,SPI1_NSS/I2S1_WS,,,,LCD_G3,SAI2_SD_B,SDMMC2_D1,FMC_NE3,DCMI_D2,LCD_B2,EVENTOUT,
+PortG,PG11,,,,,,SPI1_SCK/I2S1_CK,,SPDIFRX_IN0,,,SDMMC2_D2,ETH_MII_TX_EN/ETH_RMII_TX_EN,,DCMI_D3,LCD_B3,EVENTOUT,
+PortG,PG12,,,,LPTIM1_IN1,,SPI6_MISO,,SPDIFRX_IN1,USART6_RTS,LCD_B4,,SDMMC2_D3,FMC_NE4,,LCD_B1,EVENTOUT,
+PortG,PG13,TRACED0,,,LPTIM1_OUT,,SPI6_SCK,,,USART6_CTS,,,ETH_MII_TXD0/ETH_RMII_TXD0,FMC_A24,,LCD_R0,EVENTOUT,
+PortG,PG14,TRACED1,,,LPTIM1_ETR,,SPI6_MOSI,,,USART6_TX,QUADSPI_BK2_IO3,,ETH_MII_TXD1/ETH_RMII_TXD1,FMC_A25,,LCD_B0,EVENTOUT,
+PortG,PG15,,,,,,,,,USART6_CTS,,,,FMC_SDNCAS,DCMI_D13,,EVENTOUT,
+PortH,PH0,,,,,,,,,,,,,,,,EVENTOUT,
+PortH,PH1,,,,,,,,,,,,,,,,EVENTOUT,
+PortH,PH2,,,,LPTIM1_IN2,,,,,,QUADSPI_BK2_IO0,SAI2_SCK_B,ETH_MII_CRS,FMC_SDCKE0,,LCD_R0,EVENTOUT,
+PortH,PH3,,,,,,,,,,QUADSPI_BK2_IO1,SAI2_MCK_B,ETH_MII_COL,FMC_SDNE0,,LCD_R1,EVENTOUT,
+PortH,PH4,,,,,I2C2_SCL,,,,,LCD_G5,OTG_HS_ULPI_NXT,,,,LCD_G4,EVENTOUT,
+PortH,PH5,,,,,I2C2_SDA,SPI5_NSS,,,,,,,FMC_SDNWE,,,EVENTOUT,
+PortH,PH6,,,,,I2C2_SMBA,SPI5_SCK,,,,TIM12_CH1,,ETH_MII_RXD2,FMC_SDNE1,DCMI_D8,,EVENTOUT,
+PortH,PH7,,,,,I2C3_SCL,SPI5_MISO,,,,,,ETH_MII_RXD3,FMC_SDCKE1,DCMI_D9,,EVENTOUT,
+PortH,PH8,,,,,I2C3_SDA,,,,,,,,FMC_D16,DCMI_HSYNC,LCD_R2,EVENTOUT,
+PortH,PH9,,,,,I2C3_SMBA,,,,,TIM12_CH2,,,FMC_D17,DCMI_D0,LCD_R3,EVENTOUT,
+PortH,PH10,,,TIM5_CH1,,I2C4_SMBA,,,,,,,,FMC_D18,DCMI_D1,LCD_R4,EVENTOUT,
+PortH,PH11,,,TIM5_CH2,,I2C4_SCL,,,,,,,,FMC_D19,DCMI_D2,LCD_R5,EVENTOUT,
+PortH,PH12,,,TIM5_CH3,,I2C4_SDA,,,,,,,,FMC_D20,DCMI_D3,LCD_R6,EVENTOUT,
+PortH,PH13,,,,TIM8_CH1N,,,,,UART4_TX,CAN1_TX,,,FMC_D21,,LCD_G2,EVENTOUT,
+PortH,PH14,,,,TIM8_CH2N,,,,,UART4_RX,CAN1_RX,,,FMC_D22,DCMI_D4,LCD_G3,EVENTOUT,
+PortH,PH15,,,,TIM8_CH3N,,,,,,,,,FMC_D23,DCMI_D11,LCD_G4,EVENTOUT,
+PortI,PI0,,,TIM5_CH4,,,SPI2_NSS/I2S2_WS,,,,,,,FMC_D24,DCMI_D13,LCD_G5,EVENTOUT,
+PortI,PI1,,,,TIM8_BKIN2,,SPI2_SCK/I2S2_CK,,,,,,,FMC_D25,DCMI_D8,LCD_G6,EVENTOUT,
+PortI,PI2,,,,TIM8_CH4,,SPI2_MISO,,,,,,,FMC_D26,DCMI_D9,LCD_G7,EVENTOUT,
+PortI,PI3,,,,TIM8_ETR,,SPI2_MOSI/I2S2_SD,,,,,,,FMC_D27,DCMI_D10,,EVENTOUT,
+PortI,PI4,,,,TIM8_BKIN,,,,,,,SAI2_MCK_A,,FMC_NBL2,DCMI_D5,LCD_B4,EVENTOUT,
+PortI,PI5,,,,TIM8_CH1,,,,,,,SAI2_SCK_A,,FMC_NBL3,DCMI_VSYNC,LCD_B5,EVENTOUT,
+PortI,PI6,,,,TIM8_CH2,,,,,,,SAI2_SD_A,,FMC_D28,DCMI_D6,LCD_B6,EVENTOUT,
+PortI,PI7,,,,TIM8_CH3,,,,,,,SAI2_FS_A,,FMC_D29,DCMI_D7,LCD_B7,EVENTOUT,
+PortI,PI8,,,,,,,,,,,,,,,,EVENTOUT,
+PortI,PI9,,,,,,,,,UART4_RX,CAN1_RX,,,FMC_D30,,LCD_VSYNC,EVENTOUT,
+PortI,PI10,,,,,,,,,,,,ETH_MII_RX_ER,FMC_D31,,LCD_HSYNC,EVENTOUT,
+PortI,PI11,,,,,,,,,,LCD_G6,OTG_HS_ULPI_DIR,,,,,EVENTOUT,
+PortI,PI12,,,,,,,,,,,,,,,LCD_HSYNC,EVENTOUT,
+PortI,PI13,,,,,,,,,,,,,,,LCD_VSYNC,EVENTOUT,
+PortI,PI14,,,,,,,,,,,,,,,LCD_CLK,EVENTOUT,
+PortI,PI15,,,,,,,,,,LCD_G2,,,,,LCD_R0,EVENTOUT,
+PortJ,PJ0,,,,,,,,,,LCD_R7,,,,,LCD_R1,EVENTOUT,
+PortJ,PJ1,,,,,,,,,,,,,,,LCD_R2,EVENTOUT,
+PortJ,PJ2,,,,,,,,,,,,,,DSI_TE,LCD_R3,EVENTOUT,
+PortJ,PJ3,,,,,,,,,,,,,,,LCD_R4,EVENTOUT,
+PortJ,PJ4,,,,,,,,,,,,,,,LCD_R5,EVENTOUT,
+PortJ,PJ5,,,,,,,,,,,,,,,LCD_R6,EVENTOUT,
+PortJ,PJ6,,,,,,,,,,,,,,,LCD_R7,EVENTOUT,
+PortJ,PJ7,,,,,,,,,,,,,,,LCD_G0,EVENTOUT,
+PortJ,PJ8,,,,,,,,,,,,,,,LCD_G1,EVENTOUT,
+PortJ,PJ9,,,,,,,,,,,,,,,LCD_G2,EVENTOUT,
+PortJ,PJ10,,,,,,,,,,,,,,,LCD_G3,EVENTOUT,
+PortJ,PJ11,,,,,,,,,,,,,,,LCD_G4,EVENTOUT,
+PortJ,PJ12,,,,,,,,,,LCD_G3,,,,,LCD_B0,EVENTOUT,
+PortJ,PJ13,,,,,,,,,,LCD_G4,,,,,LCD_B1,EVENTOUT,
+PortJ,PJ14,,,,,,,,,,,,,,,LCD_B2,EVENTOUT,
+PortJ,PJ15,,,,,,,,,,,,,,,LCD_B3,EVENTOUT,
+PortK,PK0,,,,,,,,,,,,,,,LCD_G5,EVENTOUT,
+PortK,PK1,,,,,,,,,,,,,,,LCD_G6,EVENTOUT,
+PortK,PK2,,,,,,,,,,,,,,,LCD_G7,EVENTOUT,
+PortK,PK3,,,,,,,,,,,,,,,LCD_B4,EVENTOUT,
+PortK,PK4,,,,,,,,,,,,,,,LCD_B5,EVENTOUT,
+PortK,PK5,,,,,,,,,,,,,,,LCD_B6,EVENTOUT,
+PortK,PK6,,,,,,,,,,,,,,,LCD_B7,EVENTOUT,
+PortK,PK7,,,,,,,,,,,,,,,LCD_DE,EVENTOUT,
diff --git a/ports/stm32/boards/stm32f769.ld b/ports/stm32/boards/stm32f769.ld
index c4cabe7a4..d6da43943 100644
--- a/ports/stm32/boards/stm32f769.ld
+++ b/ports/stm32/boards/stm32f769.ld
@@ -22,9 +22,6 @@ _minimum_heap_size = 16K;
aligned for a call. */
_estack = ORIGIN(RAM) + LENGTH(RAM);
-/* define common sections and symbols */
-INCLUDE common.ld
-
/* RAM extents for the garbage collector */
_ram_start = ORIGIN(RAM);
_ram_end = ORIGIN(RAM) + LENGTH(RAM);
diff --git a/ports/stm32/boards/stm32h743.ld b/ports/stm32/boards/stm32h743.ld
new file mode 100644
index 000000000..77bbfacb1
--- /dev/null
+++ b/ports/stm32/boards/stm32h743.ld
@@ -0,0 +1,29 @@
+/*
+ GNU linker script for STM32H743
+*/
+
+/* Specify the memory areas */
+MEMORY
+{
+ FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1024K
+ FLASH_ISR (rx) : ORIGIN = 0x08000000, LENGTH = 128K /* sector 0, 128K */
+ FLASH_FS (r) : ORIGIN = 0x08020000, LENGTH = 128K /* sector 1, 128K */
+ FLASH_TEXT (rx) : ORIGIN = 0x08040000, LENGTH = 1792K /* sectors 6*128 + 8*128 */
+ DTCM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K /* Used for storage cache */
+ RAM (xrw) : ORIGIN = 0x24000000, LENGTH = 512K /* AXI SRAM */
+}
+
+/* produce a link error if there is not this amount of RAM for these sections */
+_minimum_stack_size = 2K;
+_minimum_heap_size = 16K;
+
+/* Define tho top end of the stack. The stack is full descending so begins just
+ above last byte of RAM. Note that EABI requires the stack to be 8-byte
+ aligned for a call. */
+_estack = ORIGIN(RAM) + LENGTH(RAM);
+
+/* RAM extents for the garbage collector */
+_ram_start = ORIGIN(RAM);
+_ram_end = ORIGIN(RAM) + LENGTH(RAM);
+_heap_start = _ebss; /* heap starts just after statically allocated memory */
+_heap_end = 0x2407C000; /* tunable */
diff --git a/ports/stm32/boards/stm32h743_af.csv b/ports/stm32/boards/stm32h743_af.csv
new file mode 100644
index 000000000..d008ba68b
--- /dev/null
+++ b/ports/stm32/boards/stm32h743_af.csv
@@ -0,0 +1,170 @@
+Port,,AF0,AF1,AF2,AF3,AF4,AF5,AF6,AF7,AF8,AF9,AF10,AF11,AF12,AF13,AF14,AF15,
+,,SYS,TIM1/2/16/17/LPTIM1/HRTIM1,SAI1/TIM3/4/5/12/HRTIM1,LPUART/TIM8/LPTIM2/3/4/5/HRTIM1/DFSDM,I2C1/2/3/4/USART1/TIM15/LPTIM2/DFSDM/CEC,SPI1/2/3/4/5/6/CEC,SPI2/3/SAI1/3/I2C4/UART4/DFSDM,SPI2/3/6/USART1/2/3/6/UART7/SDMMC1,SPI6/SAI2/4/UART4/5/8/LPUART/SDMMC1/SPDIFRX,SAI4/FDCAN1/2/TIM13/14/QUADSPI/FMC/SDMMC2/LCD/SPDIFRX,SAI2/4/TIM8/QUADSPI/SDMMC2/OTG1_HS/OTG2_FS/LCD,I2C4/UART7/SWPMI1/TIM1/8/DFSDM/SDMMC2/MDIOS/ETH,TIM1/8/FMC/SDMMC1/MDIOS/OTG1_FS/LCD,TIM1/DCMI/LCD/COMP,UART5/LCD,SYS,ADC
+PortA,PA0,,TIM2_CH1/TIM2_ETR,TIM5_CH1,TIM8_ETR,TIM15_BKIN,,,USART2_CTS/USART2_NSS,UART4_TX,SDMMC2_CMD,SAI2_SD_B,ETH_MII_CRS,,,,EVENTOUT,
+PortA,PA1,,TIM2_CH2,TIM5_CH2,LPTIM3_OUT,TIM15_CH1N,,,USART2_RTS,UART4_RX,QUADSPI_BK1_IO3,SAI2_MCK_B,ETH_MII_RX_CLK/ETH_RMII_REF_CLK,,,LCD_R2,EVENTOUT,
+PortA,PA2,,TIM2_CH3,TIM5_CH3,LPTIM4_OUT,TIM15_CH1,,,USART2_TX,SAI2_SCK_B,,,ETH_MDIO,MDIOS_MDIO,,LCD_R1,EVENTOUT,
+PortA,PA3,,TIM2_CH4,TIM5_CH4,LPTIM5_OUT,TIM15_CH2,,,USART2_RX,,LCD_B2,OTG_HS_ULPI_D0,ETH_MII_COL,,,LCD_B5,EVENTOUT,
+PortA,PA4,,,TIM5_ETR,,,SPI1_NSS/I2S1_WS,SPI3_NSS/I2S3_WS,USART2_CK,SPI6_NSS,,,,OTG_HS_SOF,DCMI_HSYNC,LCD_VSYNC,EVENTOUT,
+PortA,PA5,,TIM2_CH1/TIM2_ETR,,TIM8_CH1N,,SPI1_SCK/I2S1_CK,,,SPI6_SCK,,OTG_HS_ULPI_CK,,,,LCD_R4,EVENTOUT,
+PortA,PA6,,TIM1_BKIN,TIM3_CH1,TIM8_BKIN,,SPI1_MISO/I2S1_SDI,,,SPI6_MISO,TIM13_CH1,TIM8_BKIN_COMP12,MDIOS_MDC,TIM1_BKIN_COMP12,DCMI_PIXCLK,LCD_G2,EVENTOUT,
+PortA,PA7,,TIM1_CH1N,TIM3_CH2,TIM8_CH1N,,SPI1_MOSI/I2S1_SDO,,,SPI6_MOSI,TIM14_CH1,,ETH_MII_RX_DV/ETH_RMII_CRS_DV,FMC_SDNWE,,,EVENTOUT,
+PortA,PA8,MCO1,TIM1_CH1,HRTIM_CHB2,TIM8_BKIN2,I2C3_SCL,,,USART1_CK,,,OTG_FS_SOF,UART7_RX,TIM8_BKIN2_COMP12,LCD_B3,LCD_R6,EVENTOUT,
+PortA,PA9,,TIM1_CH2,HRTIM_CHC1,LPUART1_TX,I2C3_SMBA,SPI2_SCK/I2S2_CK,,USART1_TX,,CAN1_RXFD,,ETH_TX_ER,,DCMI_D0,LCD_R5,EVENTOUT,
+PortA,PA10,,TIM1_CH3,HRTIM_CHC2,LPUART1_RX,,,,USART1_RX,,CAN1_TXFD,OTG_FS_ID,MDIOS_MDIO,LCD_B4,DCMI_D1,LCD_B1,EVENTOUT,
+PortA,PA11,,TIM1_CH4,HRTIM_CHD1,LPUART1_CTS,,SPI2_NSS/I2S2_WS,UART4_RX,USART1_CTS/USART1_NSS,,CAN1_RX,OTG_FS_DM,,,,LCD_R4,EVENTOUT,
+PortA,PA12,,TIM1_ETR,HRTIM_CHD2,LPUART1_RTS,,SPI2_SCK/I2S2_CK,UART4_TX,USART1_RTS,SAI2_FS_B,CAN1_TX,OTG_FS_DP,,,,LCD_R5,EVENTOUT,
+PortA,PA13,JTMS/SWDIO,,,,,,,,,,,,,,,EVENTOUT,
+PortA,PA14,JTCK/SWCLK,,,,,,,,,,,,,,,EVENTOUT,
+PortA,PA15,JTDI,TIM2_CH1/TIM2_ETR,HRTIM_FLT1,,HDMI_CEC,SPI1_NSS/I2S1_WS,SPI3_NSS/I2S3_WS,SPI6_NSS,UART4_RTS,,,UART7_TX,,,,EVENTOUT,
+PortB,PB0,,TIM1_CH2N,TIM3_CH3,TIM8_CH2N,,,DFSDM_CKOUT,,UART4_CTS,LCD_R3,OTG_HS_ULPI_D1,ETH_MII_RXD2,,,LCD_G1,EVENTOUT,
+PortB,PB1,,TIM1_CH3N,TIM3_CH4,TIM8_CH3N,,,DFSDM_DATIN1,,,LCD_R6,OTG_HS_ULPI_D2,ETH_MII_RXD3,,,LCD_G0,EVENTOUT,
+PortB,PB2,,,SAI1_D1,,DFSDM_CKIN1,,SAI1_SD_A,SPI3_MOSI/I2S3_SDO,SAI4_SD_A,QUADSPI_CLK,SAI4_D1,ETH_TX_ER,,,,EVENTOUT,
+PortB,PB3,JTDO/TRACESWO,TIM2_CH2,HRTIM_FLT4,,,SPI1_SCK/I2S1_CK,SPI3_SCK/I2S3_CK,,SPI6_SCK,SDMMC2_D2,,UART7_RX,,,,EVENTOUT,
+PortB,PB4,NJTRST,TIM16_BKIN,TIM3_CH1,HRTIM_EEV6,,SPI1_MISO/I2S1_SDI,SPI3_MISO/I2S3_SDI,SPI2_NSS/I2S2_WS,SPI6_MISO,SDMMC2_D3,,UART7_TX,,,,EVENTOUT,
+PortB,PB5,,TIM17_BKIN,TIM3_CH2,HRTIM_EEV7,I2C1_SMBA,SPI1_MOSI/I2S1_SDO,I2C4_SMBA,SPI3_MOSI/I2S3_SDO,SPI6_MOSI,CAN2_RX,OTG_HS_ULPI_D7,ETH_PPS_OUT,FMC_SDCKE1,DCMI_D10,UART5_RX,EVENTOUT,
+PortB,PB6,,TIM16_CH1N,TIM4_CH1,HRTIM_EEV8,I2C1_SCL,HDMI_CEC,I2C4_SCL,USART1_TX,LPUART1_TX,CAN2_TX,QUADSPI_BK1_NCS,DFSDM_DATIN5,FMC_SDNE1,DCMI_D5,UART5_TX,EVENTOUT,
+PortB,PB7,,TIM17_CH1N,TIM4_CH2,HRTIM_EEV9,I2C1_SDA,,I2C4_SDA,USART1_RX,LPUART1_RX,CAN2_TXFD,,DFSDM_CKIN5,FMC_NL,DCMI_VSYNC,,EVENTOUT,
+PortB,PB8,,TIM16_CH1,TIM4_CH3,DFSDM_CKIN7,I2C1_SCL,,I2C4_SCL,SDMMC1_CKIN,UART4_RX,CAN1_RX,SDMMC2_D4,ETH_MII_TXD3,SDMMC1_D4,DCMI_D6,LCD_B6,EVENTOUT,
+PortB,PB9,,TIM17_CH1,TIM4_CH4,DFSDM_DATIN7,I2C1_SDA,SPI2_NSS/I2S2_WS,I2C4_SDA,SDMMC1_CDIR,UART4_TX,CAN1_TX,SDMMC2_D5,I2C4_SMBA,SDMMC1_D5,DCMI_D7,LCD_B7,EVENTOUT,
+PortB,PB10,,TIM2_CH3,HRTIM_SCOUT,LPTIM2_IN1,I2C2_SCL,SPI2_SCK/I2S2_CK,DFSDM_DATIN7,USART3_TX,,QUADSPI_BK1_NCS,OTG_HS_ULPI_D3,ETH_MII_RX_ER,,,LCD_G4,EVENTOUT,
+PortB,PB11,,TIM2_CH4,HRTIM_SCIN,LPTIM2_ETR,I2C2_SDA,,DFSDM_CKIN7,USART3_RX,,,OTG_HS_ULPI_D4,ETH_MII_TX_EN/ETH_RMII_TX_EN,,,LCD_G5,EVENTOUT,
+PortB,PB12,,TIM1_BKIN,,,I2C2_SMBA,SPI2_NSS/I2S2_WS,DFSDM_DATIN1,USART3_CK,,CAN2_RX,OTG_HS_ULPI_D5,ETH_MII_TXD0/ETH_RMII_TXD0,OTG_HS_ID,TIM1_BKIN_COMP12,UART5_RX,EVENTOUT,
+PortB,PB13,,TIM1_CH1N,,LPTIM2_OUT,,SPI2_SCK/I2S2_CK,DFSDM_CKIN1,USART3_CTS/USART3_NSS,,CAN2_TX,OTG_HS_ULPI_D6,ETH_MII_TXD1/ETH_RMII_TXD1,,,UART5_TX,EVENTOUT,
+PortB,PB14,,TIM1_CH2N,TIM12_CH1,TIM8_CH2N,USART1_TX,SPI2_MISO/I2S2_SDI,DFSDM_DATIN2,USART3_RTS,UART4_RTS,SDMMC2_D0,,,OTG_HS_DM,,,EVENTOUT,
+PortB,PB15,RTC_REFIN,TIM1_CH3N,TIM12_CH2,TIM8_CH3N,USART1_RX,SPI2_MOSI/I2S2_SDO,DFSDM_CKIN2,,UART4_CTS,SDMMC2_D1,,,OTG_HS_DP,,,EVENTOUT,
+PortC,PC0,,,,DFSDM_CKIN0,,,DFSDM_DATIN4,,SAI2_FS_B,,OTG_HS_ULPI_STP,,FMC_SDNWE,,LCD_R5,EVENTOUT,
+PortC,PC1,TRACED0,,SAI1_D1,DFSDM_DATIN0,DFSDM_CKIN4,SPI2_MOSI/I2S2_SDO,SAI1_SD_A,,SAI4_SD_A,SDMMC2_CK,SAI4_D1,ETH_MDC,MDIOS_MDC,,,EVENTOUT,
+PortC,PC2,,,,DFSDM_CKIN1,,SPI2_MISO/I2S2_SDI,DFSDM_CKOUT,,,,OTG_HS_ULPI_DIR,ETH_MII_TXD2,FMC_SDNE0,,,EVENTOUT,
+PortC,PC3,,,,DFSDM_DATIN1,,SPI2_MOSI/I2S2_SDO,,,,,OTG_HS_ULPI_NXT,ETH_MII_TX_CLK,FMC_SDCKE0,,,EVENTOUT,
+PortC,PC4,,,,DFSDM_CKIN2,,I2S1_MCK,,,,SPDIFRX_IN2,,ETH_MII_RXD0/ETH_RMII_RXD0,FMC_SDNE0,,,EVENTOUT,
+PortC,PC5,,,SAI1_D3,DFSDM_DATIN2,,,,,,SPDIFRX_IN3,SAI4_D3,ETH_MII_RXD1/ETH_RMII_RXD1,FMC_SDCKE0,COMP_1_OUT,,EVENTOUT,
+PortC,PC6,,HRTIM_CHA1,TIM3_CH1,TIM8_CH1,DFSDM_CKIN3,I2S2_MCK,,USART6_TX,SDMMC1_D0DIR,FMC_NWAIT,SDMMC2_D6,,SDMMC1_D6,DCMI_D0,LCD_HSYNC,EVENTOUT,
+PortC,PC7,TRGIO,HRTIM_CHA2,TIM3_CH2,TIM8_CH2,DFSDM_DATIN3,,I2S3_MCK,USART6_RX,SDMMC1_D123DIR,FMC_NE1,SDMMC2_D7,SWPMI_TX,SDMMC1_D7,DCMI_D1,LCD_G6,EVENTOUT,
+PortC,PC8,TRACED1,HRTIM_CHB1,TIM3_CH3,TIM8_CH3,,,,USART6_CK,UART5_RTS,FMC_NE2/FMC_NCE,,SWPMI_RX,SDMMC1_D0,DCMI_D2,,EVENTOUT,
+PortC,PC9,MCO2,,TIM3_CH4,TIM8_CH4,I2C3_SDA,I2S_CKIN,,,UART5_CTS,QUADSPI_BK1_IO0,LCD_G3,SWPMI_SUSPEND,SDMMC1_D1,DCMI_D3,LCD_B2,EVENTOUT,
+PortC,PC10,,,HRTIM_EEV1,DFSDM_CKIN5,,,SPI3_SCK/I2S3_CK,USART3_TX,UART4_TX,QUADSPI_BK1_IO1,,,SDMMC1_D2,DCMI_D8,LCD_R2,EVENTOUT,
+PortC,PC11,,,HRTIM_FLT2,DFSDM_DATIN5,,,SPI3_MISO/I2S3_SDI,USART3_RX,UART4_RX,QUADSPI_BK2_NCS,,,SDMMC1_D3,DCMI_D4,,EVENTOUT,
+PortC,PC12,TRACED3,,HRTIM_EEV2,,,,SPI3_MOSI/I2S3_SDO,USART3_CK,UART5_TX,,,,SDMMC1_CK,DCMI_D9,,EVENTOUT,
+PortC,PC13,,,,,,,,,,,,,,,,EVENTOUT,
+PortC,PC14,,,,,,,,,,,,,,,,EVENTOUT,
+PortC,PC15,,,,,,,,,,,,,,,,EVENTOUT,
+PortD,PD0,,,,DFSDM_CKIN6,,,SAI3_SCK_A,,UART4_RX,CAN1_RX,,,FMC_D2/FMC_DA2,,,EVENTOUT,
+PortD,PD1,,,,DFSDM_DATIN6,,,SAI3_SD_A,,UART4_TX,CAN1_TX,,,FMC_D3/FMC_DA3,,,EVENTOUT,
+PortD,PD2,TRACED2,,TIM3_ETR,,,,,,UART5_RX,,,,SDMMC1_CMD,DCMI_D11,,EVENTOUT,
+PortD,PD3,,,,DFSDM_CKOUT,,SPI2_SCK/I2S2_CK,,USART2_CTS/USART2_NSS,,,,,FMC_CLK,DCMI_D5,LCD_G7,EVENTOUT,
+PortD,PD4,,,HRTIM_FLT3,,,,SAI3_FS_A,USART2_RTS,,CAN1_RXFD,,,FMC_NOE,,,EVENTOUT,
+PortD,PD5,,,HRTIM_EEV3,,,,,USART2_TX,,CAN1_TXFD,,,FMC_NWE,,,EVENTOUT,
+PortD,PD6,,,SAI1_D1,DFSDM_CKIN4,DFSDM_DATIN1,SPI3_MOSI/I2S3_SDO,SAI1_SD_A,USART2_RX,SAI4_SD_A,CAN2_RXFD,SAI4_D1,SDMMC2_CK,FMC_NWAIT,DCMI_D10,LCD_B2,EVENTOUT,
+PortD,PD7,,,,DFSDM_DATIN4,,SPI1_MOSI/I2S1_SDO,DFSDM_CKIN1,USART2_CK,,SPDIFRX_IN0,,SDMMC2_CMD,FMC_NE1,,,EVENTOUT,
+PortD,PD8,,,,DFSDM_CKIN3,,,SAI3_SCK_B,USART3_TX,,SPDIFRX_IN1,,,FMC_D13/FMC_DA13,,,EVENTOUT,
+PortD,PD9,,,,DFSDM_DATIN3,,,SAI3_SD_B,USART3_RX,,CAN2_RXFD,,,FMC_D14/FMC_DA14,,,EVENTOUT,
+PortD,PD10,,,,DFSDM_CKOUT,,,SAI3_FS_B,USART3_CK,,CAN2_TXFD,,,FMC_D15/FMC_DA15,,LCD_B3,EVENTOUT,
+PortD,PD11,,,,LPTIM2_IN2,I2C4_SMBA,,,USART3_CTS/USART3_NSS,,QUADSPI_BK1_IO0,SAI2_SD_A,,FMC_A16,,,EVENTOUT,
+PortD,PD12,,LPTIM1_IN1,TIM4_CH1,LPTIM2_IN1,I2C4_SCL,,,USART3_RTS,,QUADSPI_BK1_IO1,SAI2_FS_A,,FMC_A17,,,EVENTOUT,
+PortD,PD13,,LPTIM1_OUT,TIM4_CH2,,I2C4_SDA,,,,,QUADSPI_BK1_IO3,SAI2_SCK_A,,FMC_A18,,,EVENTOUT,
+PortD,PD14,,,TIM4_CH3,,,,SAI3_MCLK_B,,UART8_CTS,,,,FMC_D0/FMC_DA0,,,EVENTOUT,
+PortD,PD15,,,TIM4_CH4,,,,SAI3_MCLK_A,,UART8_RTS,,,,FMC_D1/FMC_DA1,,,EVENTOUT,
+PortE,PE0,,LPTIM1_ETR,TIM4_ETR,HRTIM_SCIN,LPTIM2_ETR,,,,UART8_RX,CAN1_RXFD,SAI2_MCK_A,,FMC_NBL0,DCMI_D2,,EVENTOUT,
+PortE,PE1,,LPTIM1_IN2,,HRTIM_SCOUT,,,,,UART8_TX,CAN1_TXFD,,,FMC_NBL1,DCMI_D3,,EVENTOUT,
+PortE,PE2,TRACECLK,,SAI1_CK1,,,SPI4_SCK,SAI1_MCLK_A,,SAI4_MCLK_A,QUADSPI_BK1_IO2,SAI4_CK1,ETH_MII_TXD3,FMC_A23,,,EVENTOUT,
+PortE,PE3,TRACED0,,,,TIM15_BKIN,,SAI1_SD_B,,SAI4_SD_B,,,,FMC_A19,,,EVENTOUT,
+PortE,PE4,TRACED1,,SAI1_D2,DFSDM_DATIN3,TIM15_CH1N,SPI4_NSS,SAI1_FS_A,,SAI4_FS_A,,SAI4_D2,,FMC_A20,DCMI_D4,LCD_B0,EVENTOUT,
+PortE,PE5,TRACED2,,SAI1_CK2,DFSDM_CKIN3,TIM15_CH1,SPI4_MISO,SAI1_SCK_A,,SAI4_SCK_A,,SAI4_CK2,,FMC_A21,DCMI_D6,LCD_G0,EVENTOUT,
+PortE,PE6,TRACED3,TIM1_BKIN2,SAI1_D1,,TIM15_CH2,SPI4_MOSI,SAI1_SD_A,,SAI4_SD_A,SAI4_D1,SAI2_MCK_B,TIM1_BKIN2_COMP12,FMC_A22,DCMI_D7,LCD_G1,EVENTOUT,
+PortE,PE7,,TIM1_ETR,,DFSDM_DATIN2,,,,UART7_RX,,,QUADSPI_BK2_IO0,,FMC_D4/FMC_DA4,,,EVENTOUT,
+PortE,PE8,,TIM1_CH1N,,DFSDM_CKIN2,,,,UART7_TX,,,QUADSPI_BK2_IO1,,FMC_D5/FMC_DA5,COMP_2_OUT,,EVENTOUT,
+PortE,PE9,,TIM1_CH1,,DFSDM_CKOUT,,,,UART7_RTS,,,QUADSPI_BK2_IO2,,FMC_D6/FMC_DA6,,,EVENTOUT,
+PortE,PE10,,TIM1_CH2N,,DFSDM_DATIN4,,,,UART7_CTS,,,QUADSPI_BK2_IO3,,FMC_D7/FMC_DA7,,,EVENTOUT,
+PortE,PE11,,TIM1_CH2,,DFSDM_CKIN4,,SPI4_NSS,,,,,SAI2_SD_B,,FMC_D8/FMC_DA8,,LCD_G3,EVENTOUT,
+PortE,PE12,,TIM1_CH3N,,DFSDM_DATIN5,,SPI4_SCK,,,,,SAI2_SCK_B,,FMC_D9/FMC_DA9,COMP_1_OUT,LCD_B4,EVENTOUT,
+PortE,PE13,,TIM1_CH3,,DFSDM_CKIN5,,SPI4_MISO,,,,,SAI2_FS_B,,FMC_D10/FMC_DA10,COMP_2_OUT,LCD_DE,EVENTOUT,
+PortE,PE14,,TIM1_CH4,,,,SPI4_MOSI,,,,,SAI2_MCK_B,,FMC_D11/FMC_DA11,,LCD_CLK,EVENTOUT,
+PortE,PE15,,TIM1_BKIN,,,,HDMI__TIM1_BKIN,,,,,,,FMC_D12/FMC_DA12,TIM1_BKIN_COMP12,LCD_R7,EVENTOUT,
+PortF,PF0,,,,,I2C2_SDA,,,,,,,,FMC_A0,,,EVENTOUT,
+PortF,PF1,,,,,I2C2_SCL,,,,,,,,FMC_A1,,,EVENTOUT,
+PortF,PF2,,,,,I2C2_SMBA,,,,,,,,FMC_A2,,,EVENTOUT,
+PortF,PF3,,,,,,,,,,,,,FMC_A3,,,EVENTOUT,
+PortF,PF4,,,,,,,,,,,,,FMC_A4,,,EVENTOUT,
+PortF,PF5,,,,,,,,,,,,,FMC_A5,,,EVENTOUT,
+PortF,PF6,,TIM16_CH1,,,,SPI5_NSS,SAI1_SD_B,UART7_RX,SAI4_SD_B,QUADSPI_BK1_IO3,,,,,,EVENTOUT,
+PortF,PF7,,TIM17_CH1,,,,SPI5_SCK,SAI1_MCLK_B,UART7_TX,SAI4_MCLK_B,QUADSPI_BK1_IO2,,,,,,EVENTOUT,
+PortF,PF8,,TIM16_CH1N,,,,SPI5_MISO,SAI1_SCK_B,UART7_RTS,SAI4_SCK_B,TIM13_CH1,QUADSPI_BK1_IO0,,,,,EVENTOUT,
+PortF,PF9,,TIM17_CH1N,,,,SPI5_MOSI,SAI1_FS_B,UART7_CTS,SAI4_FS_B,TIM14_CH1,QUADSPI_BK1_IO1,,,,,EVENTOUT,
+PortF,PF10,,TIM16_BKIN,SAI1_D3,,,,,,,QUADSPI_CLK,SAI4_D3,,,DCMI_D11,LCD_DE,EVENTOUT,
+PortF,PF11,,,,,,SPI5_MOSI,,,,,SAI2_SD_B,,FMC_SDNRAS,DCMI_D12,,EVENTOUT,
+PortF,PF12,,,,,,,,,,,,,FMC_A6,,,EVENTOUT,
+PortF,PF13,,,,DFSDM_DATIN6,I2C4_SMBA,,,,,,,,FMC_A7,,,EVENTOUT,
+PortF,PF14,,,,DFSDM_CKIN6,I2C4_SCL,,,,,,,,FMC_A8,,,EVENTOUT,
+PortF,PF15,,,,,I2C4_SDA,,,,,,,,FMC_A9,,,EVENTOUT,
+PortG,PG0,,,,,,,,,,,,,FMC_A10,,,EVENTOUT,
+PortG,PG1,,,,,,,,,,,,,FMC_A11,,,EVENTOUT,
+PortG,PG2,,,,TIM8_BKIN,,,,,,,,TIM8_BKIN_COMP12,FMC_A12,,,EVENTOUT,
+PortG,PG3,,,,TIM8_BKIN2,,,,,,,,TIM8_BKIN2_COMP12,FMC_A13,,,EVENTOUT,
+PortG,PG4,,TIM1_BKIN2,,,,,,,,,,TIM1_BKIN2_COMP12,FMC_A14/FMC_BA0,,,EVENTOUT,
+PortG,PG5,,TIM1_ETR,,,,,,,,,,,FMC_A15/FMC_BA1,,,EVENTOUT,
+PortG,PG6,,TIM17_BKIN,HRTIM_CHE1,,,,,,,,QUADSPI_BK1_NCS,,FMC_NE3,DCMI_D12,LCD_R7,EVENTOUT,
+PortG,PG7,,,HRTIM_CHE2,,,,SAI1_MCLK_A,USART6_CK,,,,,FMC_INT,DCMI_D13,LCD_CLK,EVENTOUT,
+PortG,PG8,,,,TIM8_ETR,,SPI6_NSS,,USART6_RTS,SPDIFRX_IN2,,,ETH_PPS_OUT,FMC_SDCLK,,LCD_G7,EVENTOUT,
+PortG,PG9,,,,,,SPI1_MISO/I2S1_SDI,,USART6_RX,SPDIFRX_IN3,QUADSPI_BK2_IO2,SAI2_FS_B,,FMC_NE2/FMC_NCE,DCMI_VSYNC,,EVENTOUT,
+PortG,PG10,,,HRTIM_FLT5,,,SPI1_NSS/I2S1_WS,,,,LCD_G3,SAI2_SD_B,,FMC_NE3,DCMI_D2,LCD_B2,EVENTOUT,
+PortG,PG11,,,HRTIM_EEV4,,,SPI1_SCK/I2S1_CK,,,SPDIFRX_IN0,,SDMMC2_D2,ETH_MII_TX_EN/ETH_RMII_TX_EN,,DCMI_D3,LCD_B3,EVENTOUT,
+PortG,PG12,,LPTIM1_IN1,HRTIM_EEV5,,,SPI6_MISO,,USART6_RTS,SPDIFRX_IN1,LCD_B4,,ETH_MII_TXD1/ETH_RMII_TXD1,FMC_NE4,,LCD_B1,EVENTOUT,
+PortG,PG13,TRACED0,LPTIM1_OUT,HRTIM_EEV10,,,SPI6_SCK,,USART6_CTS/USART6_NSS,,,,ETH_MII_TXD0/ETH_RMII_TXD0,FMC_A24,,LCD_R0,EVENTOUT,
+PortG,PG14,TRACED1,LPTIM1_ETR,,,,SPI6_MOSI,,USART6_TX,,QUADSPI_BK2_IO3,,ETH_MII_TXD1/ETH_RMII_TXD1,FMC_A25,,LCD_B0,EVENTOUT,
+PortG,PG15,,,,,,,,USART6_CTS/USART6_NSS,,,,,FMC_SDNCAS,DCMI_D13,,EVENTOUT,
+PortH,PH0,,,,,,,,,,,,,,,,EVENTOUT,
+PortH,PH1,,,,,,,,,,,,,,,,EVENTOUT,
+PortH,PH2,,LPTIM1_IN2,,,,,,,,QUADSPI_BK2_IO0,SAI2_SCK_B,ETH_MII_CRS,FMC_SDCKE0,,LCD_R0,EVENTOUT,
+PortH,PH3,,,,,,,,,,QUADSPI_BK2_IO1,SAI2_MCK_B,ETH_MII_COL,FMC_SDNE0,,LCD_R1,EVENTOUT,
+PortH,PH4,,,,,I2C2_SCL,,,,,LCD_G5,OTG_HS_ULPI_NXT,,,,LCD_G4,EVENTOUT,
+PortH,PH5,,,,,I2C2_SDA,SPI5_NSS,,,,,,,FMC_SDNWE,,,EVENTOUT,
+PortH,PH6,,,TIM12_CH1,,I2C2_SMBA,SPI5_SCK,,,,,,ETH_MII_RXD2,FMC_SDNE1,DCMI_D8,,EVENTOUT,
+PortH,PH7,,,,,I2C3_SCL,SPI5_MISO,,,,,,ETH_MII_RXD3,FMC_SDCKE1,DCMI_D9,,EVENTOUT,
+PortH,PH8,,,TIM5_ETR,,I2C3_SDA,,,,,,,,FMC_D16,DCMI_HSYNC,LCD_R2,EVENTOUT,
+PortH,PH9,,,TIM12_CH2,,I2C3_SMBA,,,,,,,,FMC_D17,DCMI_D0,LCD_R3,EVENTOUT,
+PortH,PH10,,,TIM5_CH1,,I2C4_SMBA,,,,,,,,FMC_D18,DCMI_D1,LCD_R4,EVENTOUT,
+PortH,PH11,,,TIM5_CH2,,I2C4_SCL,,,,,,,,FMC_D19,DCMI_D2,LCD_R5,EVENTOUT,
+PortH,PH12,,,TIM5_CH3,,I2C4_SDA,,,,,,,,FMC_D20,DCMI_D3,LCD_R6,EVENTOUT,
+PortH,PH13,,,,TIM8_CH1N,,,,,UART4_TX,CAN1_TX,,,FMC_D21,,LCD_G2,EVENTOUT,
+PortH,PH14,,,,TIM8_CH2N,,,,,UART4_RX,CAN1_RX,,,FMC_D22,DCMI_D4,LCD_G3,EVENTOUT,
+PortH,PH15,,,,TIM8_CH3N,,,,,,CAN1_TXFD,,,FMC_D23,DCMI_D11,LCD_G4,EVENTOUT,
+PortI,PI0,,,TIM5_CH4,,,SPI2_NSS/I2S2_WS,,,,CAN1_RXFD,,,FMC_D24,DCMI_D13,LCD_G5,EVENTOUT,
+PortI,PI1,,,,TIM8_BKIN2,,SPI2_SCK/I2S2_CK,,,,,,TIM8_BKIN2_COMP12,FMC_D25,DCMI_D8,LCD_G6,EVENTOUT,
+PortI,PI2,,,,TIM8_CH4,,SPI2_MISO/I2S2_SDI,,,,,,,FMC_D26,DCMI_D9,LCD_G7,EVENTOUT,
+PortI,PI3,,,,TIM8_ETR,,SPI2_MOSI/I2S2_SDO,,,,,,,FMC_D27,DCMI_D10,,EVENTOUT,
+PortI,PI4,,,,TIM8_BKIN,,,,,,,SAI2_MCK_A,TIM8_BKIN_COMP12,FMC_NBL2,DCMI_D5,LCD_B4,EVENTOUT,
+PortI,PI5,,,,TIM8_CH1,,,,,,,SAI2_SCK_A,,FMC_NBL3,DCMI_VSYNC,LCD_B5,EVENTOUT,
+PortI,PI6,,,,TIM8_CH2,,,,,,,SAI2_SD_A,,FMC_D28,DCMI_D6,LCD_B6,EVENTOUT,
+PortI,PI7,,,,TIM8_CH3,,,,,,,SAI2_FS_A,,FMC_D29,DCMI_D7,LCD_B7,EVENTOUT,
+PortI,PI8,,,,,,,,,,,,,,,,EVENTOUT,
+PortI,PI9,,,,,,,,,UART4_RX,CAN1_RX,,,FMC_D30,,LCD_VSYNC,EVENTOUT,
+PortI,PI10,,,,,,,,,,CAN1_RXFD,,ETH_MII_RX_ER,FMC_D31,,LCD_HSYNC,EVENTOUT,
+PortI,PI11,,,,,,,,,,LCD_G6,OTG_HS_ULPI_DIR,,,,,EVENTOUT,
+PortI,PI12,,,,,,,,,,,,ETH_TX_ER,,,LCD_HSYNC,EVENTOUT,
+PortI,PI13,,,,,,,,,,,,,,,LCD_VSYNC,EVENTOUT,
+PortI,PI14,,,,,,,,,,,,,,,LCD_CLK,EVENTOUT,
+PortI,PI15,,,,,,,,,,LCD_G2,,,,,LCD_R0,EVENTOUT,
+PortJ,PJ0,,,,,,,,,,LCD_R7,,,,,LCD_R1,EVENTOUT,
+PortJ,PJ1,,,,,,,,,,,,,,,LCD_R2,EVENTOUT,
+PortJ,PJ2,,,,,,,,,,,,,,,LCD_R3,EVENTOUT,
+PortJ,PJ3,,,,,,,,,,,,,,,LCD_R4,EVENTOUT,
+PortJ,PJ4,,,,,,,,,,,,,,,LCD_R5,EVENTOUT,
+PortJ,PJ5,,,,,,,,,,,,,,,LCD_R6,EVENTOUT,
+PortJ,PJ6,,,,TIM8_CH2,,,,,,,,,,,LCD_R7,EVENTOUT,
+PortJ,PJ7,TRGIN,,,TIM8_CH2N,,,,,,,,,,,LCD_G0,EVENTOUT,
+PortJ,PJ8,,TIM1_CH3N,,TIM8_CH1,,,,,UART8_TX,,,,,,LCD_G1,EVENTOUT,
+PortJ,PJ9,,TIM1_CH3,,TIM8_CH1N,,,,,UART8_RX,,,,,,LCD_G2,EVENTOUT,
+PortJ,PJ10,,TIM1_CH2N,,TIM8_CH2,,SPI5_MOSI,,,,,,,,,LCD_G3,EVENTOUT,
+PortJ,PJ11,,TIM1_CH2,,TIM8_CH2N,,SPI5_MISO,,,,,,,,,LCD_G4,EVENTOUT,
+PortJ,PJ12,TRGOUT,,,,,,,,,LCD_G3,,,,,LCD_B0,EVENTOUT,
+PortJ,PJ13,,,,,,,,,,LCD_B4,,,,,LCD_B1,EVENTOUT,
+PortJ,PJ14,,,,,,,,,,,,,,,LCD_B2,EVENTOUT,
+PortJ,PJ15,,,,,,,,,,,,,,,LCD_B3,EVENTOUT,
+PortK,PK0,,TIM1_CH1N,,TIM8_CH3,,SPI5_SCK,,,,,,,,,LCD_G5,EVENTOUT,
+PortK,PK1,,TIM1_CH1,,TIM8_CH3N,,SPI5_NSS,,,,,,,,,LCD_G6,EVENTOUT,
+PortK,PK2,,TIM1_BKIN,,TIM8_BKIN,,,,,,,TIM8_BKIN_COMP12,TIM1_BKIN_COMP12,,,LCD_G7,EVENTOUT,
+PortK,PK3,,,,,,,,,,,,,,,LCD_B4,EVENTOUT,
+PortK,PK4,,,,,,,,,,,,,,,LCD_B5,EVENTOUT,
+PortK,PK5,,,,,,,,,,,,,,,LCD_B6,EVENTOUT,
+PortK,PK6,,,,,,,,,,,,,,,LCD_B7,EVENTOUT,
+PortK,PK7,,,,,,,,,,,,,,,LCD_DE,EVENTOUT,
diff --git a/ports/stm32/boards/stm32l476_af.csv b/ports/stm32/boards/stm32l476_af.csv
index d67c33880..01db89572 100644
--- a/ports/stm32/boards/stm32l476_af.csv
+++ b/ports/stm32/boards/stm32l476_af.csv
@@ -1,7 +1,7 @@
Port,,AF0,AF1,AF2,AF3,AF4,AF5,AF6,AF7,AF8,AF9,AF10,AF11,AF12,AF13,AF14,AF15,,
,,SYS_AF,TIM1/TIM2/TIM5/TIM8/LPTIM1,TIM1/TIM2/TIM3/TIM4/TIM5,TIM8,I2C1/I2C2/I2C3,SPI1/SPI2,SPI3/DFSDM,USART1/USART2/USART3,UART4/UART5/LPUART1,CAN1/TSC,OTG_FS/QUADSPI,LCD,SDMMC1/COMP1/COMP2/FMC/SWPMI1,SAI1/SAI2,TIM2/TIM15/TIM16/TIM17/LPTIM2,EVENTOUT,ADC,COMP
PortA,PA0,,TIM2_CH1,TIM5_CH1,TIM8_ETR,,,,USART2_CTS,UART4_TX,,,,,SAI1_EXTCLK,TIM2_ETR,EVENTOUT,ADC12_IN5,
-PortA,PA1,,TIM2_CH2,TIM5_CH2,,,,,USART2_RTS_DE,UART4_RX,,,LCD_SEG0,,,TIM15_CH1N,EVENTOUT,ADC12_IN6,
+PortA,PA1,,TIM2_CH2,TIM5_CH2,,,,,USART2_RTS/USART2_DE,UART4_RX,,,LCD_SEG0,,,TIM15_CH1N,EVENTOUT,ADC12_IN6,
PortA,PA2,,TIM2_CH3,TIM5_CH3,,,,,USART2_TX,,,,LCD_SEG1,,SAI2_EXTCLK,TIM15_CH1,EVENTOUT,ADC12_IN7,
PortA,PA3,,TIM2_CH4,TIM5_CH4,,,,,USART2_RX,,,,LCD_SEG2,,,TIM15_CH2,EVENTOUT,ADC12_IN8,
PortA,PA4,,,,,,SPI1_NSS,SPI3_NSS,USART2_CK,,,,,,SAI1_FS_B,LPTIM2_OUT,EVENTOUT,ADC12_IN9,
@@ -12,15 +12,15 @@ PortA,PA8,MCO,TIM1_CH1,,,,,,USART1_CK,,,OTG_FS_SOF,LCD_COM0,,,LPTIM2_OUT,EVENTOU
PortA,PA9,,TIM1_CH2,,,,,,USART1_TX,,,,LCD_COM1,,,TIM15_BKIN,EVENTOUT,,
PortA,PA10,,TIM1_CH3,,,,,,USART1_RX,,,OTG_FS_ID,LCD_COM2,,,TIM17_BKIN,EVENTOUT,,
PortA,PA11,,TIM1_CH4,TIM1_BKIN2,,,,,USART1_CTS,,CAN1_RX,OTG_FS_DM,,TIM1_BKIN2_COMP1,,,EVENTOUT,,
-PortA,PA12,,TIM1_ETR,,,,,,USART1_RTS_DE,,CAN1_TX,OTG_FS_DP,,,,,EVENTOUT,,
-PortA,PA13,JTMS-SWDIO,IR_OUT,,,,,,,,,OTG_FS_NOE,,,,,EVENTOUT,,
-PortA,PA14,JTCK-SWCLK,,,,,,,,,,,,,,,EVENTOUT,,
-PortA,PA15,JTDI,TIM2_CH1,TIM2_ETR,,,SPI1_NSS,SPI3_NSS,,UART4_RTS_DE,TSC_G3_IO1,,LCD_SEG17,,SAI2_FS_B,,EVENTOUT,,
+PortA,PA12,,TIM1_ETR,,,,,,USART1_RTS/USART1_DE,,CAN1_TX,OTG_FS_DP,,,,,EVENTOUT,,
+PortA,PA13,JTMS/SWDIO,IR_OUT,,,,,,,,,OTG_FS_NOE,,,,,EVENTOUT,,
+PortA,PA14,JTCK/SWCLK,,,,,,,,,,,,,,,EVENTOUT,,
+PortA,PA15,JTDI,TIM2_CH1,TIM2_ETR,,,SPI1_NSS,SPI3_NSS,,UART4_RTS/UART4_DE,TSC_G3_IO1,,LCD_SEG17,,SAI2_FS_B,,EVENTOUT,,
PortB,PB0,,TIM1_CH2N,TIM3_CH3,TIM8_CH2N,,,,USART3_CK,,,QUADSPI_BK1_IO1,LCD_SEG5,COMP1_OUT,,,EVENTOUT,ADC12_IN15,
-PortB,PB1,,TIM1_CH3N,TIM3_CH4,TIM8_CH3N,,,DFSDM_DATIN0,USART3_RTS_DE,,,QUADSPI_BK1_IO0,LCD_SEG6,,,LPTIM2_IN1,EVENTOUT,ADC12_IN16,COMP1_INN
+PortB,PB1,,TIM1_CH3N,TIM3_CH4,TIM8_CH3N,,,DFSDM_DATIN0,USART3_RTS/USART3_DE,,,QUADSPI_BK1_IO0,LCD_SEG6,,,LPTIM2_IN1,EVENTOUT,ADC12_IN16,COMP1_INN
PortB,PB2,RTC_OUT,LPTIM1_OUT,,,I2C3_SMBA,,DFSDM_CKIN0,,,,,,,,,EVENTOUT,,COMP1_INP
-PortB,PB3,JTDO-TRACESWO,TIM2_CH2,,,,SPI1_SCK,SPI3_SCK,USART1_RTS_DE,,,,LCD_SEG7,,SAI1_SCK_B,,EVENTOUT,,COMP2_INM
-PortB,PB4,NJTRST,,TIM3_CH1,,,SPI1_MISO,SPI3_MISO,USART1_CTS,UART5_RTS_DE,TSC_G2_IO1,,LCD_SEG8,,SAI1_MCLK_B,TIM17_BKIN,EVENTOUT,,COMP2_INP
+PortB,PB3,JTDO/TRACESWO,TIM2_CH2,,,,SPI1_SCK,SPI3_SCK,USART1_RTS/USART1_DE,,,,LCD_SEG7,,SAI1_SCK_B,,EVENTOUT,,COMP2_INM
+PortB,PB4,NJTRST,,TIM3_CH1,,,SPI1_MISO,SPI3_MISO,USART1_CTS,UART5_RTS/UART5_DE,TSC_G2_IO1,,LCD_SEG8,,SAI1_MCLK_B,TIM17_BKIN,EVENTOUT,,COMP2_INP
PortB,PB5,,LPTIM1_IN1,TIM3_CH2,,I2C1_SMBA,SPI1_MOSI,SPI3_MOSI,USART1_CK,UART5_CTS,TSC_G2_IO2,,LCD_SEG9,COMP2_OUT,SAI1_SD_B,TIM16_BKIN,EVENTOUT,,
PortB,PB6,,LPTIM1_ETR,TIM4_CH1,TIM8_BKIN2,I2C1_SCL,,DFSDM_DATIN5,USART1_TX,,TSC_G2_IO3,,,TIM8_BKIN2_COMP2,SAI1_FS_B,TIM16_CH1N,EVENTOUT,,COMP2_INP
PortB,PB7,,LPTIM1_IN2,TIM4_CH2,TIM8_BKIN,I2C1_SDA,,DFSDM_CKIN5,USART1_RX,UART4_CTS,TSC_G2_IO4,,LCD_SEG21,FMC_NL,TIM8_BKIN_COMP1,TIM17_CH1N,EVENTOUT,,COMP2_INM
@@ -28,7 +28,7 @@ PortB,PB8,,,TIM4_CH3,,I2C1_SCL,,DFSDM_DATIN6,,,CAN1_RX,,LCD_SEG16,SDMMC1_D4,SAI1
PortB,PB9,,IR_OUT,TIM4_CH4,,I2C1_SDA,SPI2_NSS,DFSDM_CKIN6,,,CAN1_TX,,LCD_COM3,SDMMC1_D5,SAI1_FS_A,TIM17_CH1,EVENTOUT,,
PortB,PB10,,TIM2_CH3,,,I2C2_SCL,SPI2_SCK,DFSDM_DATIN7,USART3_TX,LPUART1_RX,,QUADSPI_CLK,LCD_SEG10,COMP1_OUT,SAI1_SCK_A,,EVENTOUT,,
PortB,PB11,,TIM2_CH4,,,I2C2_SDA,,DFSDM_CKIN7,USART3_RX,LPUART1_TX,,QUADSPI_NCS,LCD_SEG11,COMP2_OUT,,,EVENTOUT,,
-PortB,PB12,,TIM1_BKIN,,TIM1_BKIN_COMP2,I2C2_SMBA,SPI2_NSS,DFSDM_DATIN1,USART3_CK,LPUART1_RTS_DE,TSC_G1_IO1,,LCD_SEG12,SWPMI1_IO,SAI2_FS_A,TIM15_BKIN,EVENTOUT,,
+PortB,PB12,,TIM1_BKIN,,TIM1_BKIN_COMP2,I2C2_SMBA,SPI2_NSS,DFSDM_DATIN1,USART3_CK,LPUART1_RTS/LPUART1_DE,TSC_G1_IO1,,LCD_SEG12,SWPMI1_IO,SAI2_FS_A,TIM15_BKIN,EVENTOUT,,
PortB,PB13,,TIM1_CH1N,,,I2C2_SCL,SPI2_SCK,DFSDM_CKIN1,USART3_CTS,LPUART1_CTS,TSC_G1_IO2,,LCD_SEG13,SWPMI1_TX,SAI2_SCK_A,TIM15_CH1N,EVENTOUT,,
PortB,PB14,,TIM1_CH2N,,TIM8_CH2N,I2C2_SDA,SPI2_MISO,DFSDM_DATIN2,USART3_RTS_DE,,TSC_G1_IO3,,LCD_SEG14,SWPMI1_RX,SAI2_MCLK_A,TIM15_CH1,EVENTOUT,,
PortB,PB15,RTC_REFIN,TIM1_CH3N,,TIM8_CH3N,,SPI2_MOSI,DFSDM_CKIN2,,,TSC_G1_IO4,,LCD_SEG15,SWPMI1_SUSPEND,SAI2_SD_A,TIM15_CH2,EVENTOUT,,
@@ -50,9 +50,9 @@ PortC,PC14,,,,,,,,,,,,,,,,EVENTOUT,,
PortC,PC15,,,,,,,,,,,,,,,,EVENTOUT,,
PortD,PD0,,,,,,SPI2_NSS,DFSDM_DATIN7,,,CAN1_RX,,,FMC_D2,,,EVENTOUT,,
PortD,PD1,,,,,,SPI2_SCK,DFSDM_CKIN7,,,CAN1_TX,,,FMC_D3,,,EVENTOUT,,
-PortD,PD2,,,TIM3_ETR,,,,,USART3_RTS_DE,UART5_RX,TSC_SYNC,,LCD_COM7/LCD_SEG31/LCD_SEG43,SDMMC1_CMD,,,EVENTOUT,,
+PortD,PD2,,,TIM3_ETR,,,,,USART3_RTS/USART3_DE,UART5_RX,TSC_SYNC,,LCD_COM7/LCD_SEG31/LCD_SEG43,SDMMC1_CMD,,,EVENTOUT,,
PortD,PD3,,,,,,SPI2_MISO,DFSDM_DATIN0,USART2_CTS,,,,,FMC_CLK,,,EVENTOUT,,
-PortD,PD4,,,,,,SPI2_MOSI,DFSDM_CKIN0,USART2_RTS_DE,,,,,FMC_NOE,,,EVENTOUT,,
+PortD,PD4,,,,,,SPI2_MOSI,DFSDM_CKIN0,USART2_RTS/USART2_DE,,,,,FMC_NOE,,,EVENTOUT,,
PortD,PD5,,,,,,,,USART2_TX,,,,,FMC_NWE,,,EVENTOUT,,
PortD,PD6,,,,,,,DFSDM_DATIN1,USART2_RX,,,,,FMC_NWAIT,SAI1_SD_A,,EVENTOUT,,
PortD,PD7,,,,,,,DFSDM_CKIN1,USART2_CK,,,,,FMC_NE1,,,EVENTOUT,,
@@ -60,13 +60,13 @@ PortD,PD8,,,,,,,,USART3_TX,,,,LCD_SEG28,FMC_D13,,,EVENTOUT,,
PortD,PD9,,,,,,,,USART3_RX,,,,LCD_SEG29,FMC_D14,SAI2_MCLK_A,,EVENTOUT,,
PortD,PD10,,,,,,,,USART3_CK,,TSC_G6_IO1,,LCD_SEG30,FMC_D15,SAI2_SCK_A,,EVENTOUT,,
PortD,PD11,,,,,,,,USART3_CTS,,TSC_G6_IO2,,LCD_SEG31,FMC_A16,SAI2_SD_A,LPTIM2_ETR,EVENTOUT,,
-PortD,PD12,,,TIM4_CH1,,,,,USART3_RTS_DE,,TSC_G6_IO3,,LCD_SEG32,FMC_A17,SAI2_FS_A,LPTIM2_IN1,EVENTOUT,,
+PortD,PD12,,,TIM4_CH1,,,,,USART3_RTS/USART3_DE,,TSC_G6_IO3,,LCD_SEG32,FMC_A17,SAI2_FS_A,LPTIM2_IN1,EVENTOUT,,
PortD,PD13,,,TIM4_CH2,,,,,,,TSC_G6_IO4,,LCD_SEG33,FMC_A18,,LPTIM2_OUT,EVENTOUT,,
PortD,PD14,,,TIM4_CH3,,,,,,,,,LCD_SEG34,FMC_D0,,,EVENTOUT,,
PortD,PD15,,,TIM4_CH4,,,,,,,,,LCD_SEG35,FMC_D1,,,EVENTOUT,,
PortE,PE0,,,TIM4_ETR,,,,,,,,,LCD_SEG36,FMC_NBL0,,TIM16_CH1,EVENTOUT,,
PortE,PE1,,,,,,,,,,,,LCD_SEG37,FMC_NBL1,,TIM17_CH1,EVENTOUT,,
-PortE,PE2,TRACECK,,TIM3_ETR,,,,,,,TSC_G7_IO1,,LCD_SEG38,FMC_A23,SAI1_MCLK_A,,EVENTOUT,,
+PortE,PE2,TRACECLK,,TIM3_ETR,,,,,,,TSC_G7_IO1,,LCD_SEG38,FMC_A23,SAI1_MCLK_A,,EVENTOUT,,
PortE,PE3,TRACED0,,TIM3_CH1,,,,,,,TSC_G7_IO2,,LCD_SEG39,FMC_A19,SAI1_SD_B,,EVENTOUT,,
PortE,PE4,TRACED1,,TIM3_CH2,,,,DFSDM_DATIN3,,,TSC_G7_IO3,,,FMC_A20,SAI1_FS_A,,EVENTOUT,,
PortE,PE5,TRACED2,,TIM3_CH3,,,,DFSDM_CKIN3,,,TSC_G7_IO4,,,FMC_A21,SAI1_SCK_A,,EVENTOUT,,
@@ -102,13 +102,13 @@ PortG,PG2,,,,,,SPI1_SCK,,,,,,,FMC_A12,SAI2_SCK_B,,EVENTOUT,,
PortG,PG3,,,,,,SPI1_MISO,,,,,,,FMC_A13,SAI2_FS_B,,EVENTOUT,,
PortG,PG4,,,,,,SPI1_MOSI,,,,,,,FMC_A14,SAI2_MCLK_B,,EVENTOUT,,
PortG,PG5,,,,,,SPI1_NSS,,,LPUART1_CTS,,,,FMC_A15,SAI2_SD_B,,EVENTOUT,,
-PortG,PG6,,,,,I2C3_SMBA,,,,LPUART1_RTS_DE,,,,,,,EVENTOUT,,
+PortG,PG6,,,,,I2C3_SMBA,,,,LPUART1_RTS/LPUART1_DE,,,,,,,EVENTOUT,,
PortG,PG7,,,,,I2C3_SCL,,,,LPUART1_TX,,,,FMC_INT3,,,EVENTOUT,,
PortG,PG8,,,,,I2C3_SDA,,,,LPUART1_RX,,,,,,,EVENTOUT,,
PortG,PG9,,,,,,,SPI3_SCK,USART1_TX,,,,,FMC_NCE3/FMC_NE2,SAI2_SCK_A,TIM15_CH1N,EVENTOUT,,
PortG,PG10,,LPTIM1_IN1,,,,,SPI3_MISO,USART1_RX,,,,,FMC_NE3,SAI2_FS_A,TIM15_CH1,EVENTOUT,,
PortG,PG11,,LPTIM1_IN2,,,,,SPI3_MOSI,USART1_CTS,,,,,,SAI2_MCLK_A,TIM15_CH2,EVENTOUT,,
-PortG,PG12,,LPTIM1_ETR,,,,,SPI3_NSS,USART1_RTS_DE,,,,,FMC_NE4,SAI2_SD_A,,EVENTOUT,,
+PortG,PG12,,LPTIM1_ETR,,,,,SPI3_NSS,USART1_RTS/USART1_DE,,,,,FMC_NE4,SAI2_SD_A,,EVENTOUT,,
PortG,PG13,,,,,I2C1_SDA,,,USART1_CK,,,,,FMC_A24,,,EVENTOUT,,
PortG,PG14,,,,,I2C1_SCL,,,,,,,,FMC_A25,,,EVENTOUT,,
PortG,PG15,,LPTIM1_OUT,,,I2C1_SMBA,,,,,,,,,,,EVENTOUT,,
diff --git a/ports/stm32/boards/stm32l476xe.ld b/ports/stm32/boards/stm32l476xe.ld
index 11b2972ad..22c4466c6 100644
--- a/ports/stm32/boards/stm32l476xe.ld
+++ b/ports/stm32/boards/stm32l476xe.ld
@@ -11,6 +11,7 @@ MEMORY
FLASH_FS (r) : ORIGIN = 0x08060000, LENGTH = 128K /* sectors 192-255 */
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 96K
SRAM2 (xrw) : ORIGIN = 0x10000000, LENGTH = 32K
+ FS_CACHE(xrw) : ORIGIN = 0x10007800, LENGTH = 2K
}
/* produce a link error if there is not this amount of RAM for these sections */
@@ -22,10 +23,9 @@ _minimum_heap_size = 16K;
aligned for a call. */
_estack = ORIGIN(RAM) + LENGTH(RAM);
-/* define common sections and symbols */
-INCLUDE common.ld
-
/* RAM extents for the garbage collector */
+_ram_fs_cache_start = ORIGIN(FS_CACHE);
+_ram_fs_cache_block_size = LENGTH(FS_CACHE);
_ram_start = ORIGIN(RAM);
_ram_end = ORIGIN(RAM) + LENGTH(RAM);
_heap_start = _ebss; /* heap starts just after statically allocated memory */
diff --git a/ports/stm32/boards/stm32l476xg.ld b/ports/stm32/boards/stm32l476xg.ld
index a94fa2750..40d679ac3 100644
--- a/ports/stm32/boards/stm32l476xg.ld
+++ b/ports/stm32/boards/stm32l476xg.ld
@@ -11,10 +11,9 @@ MEMORY
FLASH_FS (r) : ORIGIN = 0x08080000, LENGTH = 512K /* sectors 256-511 */
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 96K
SRAM2 (xrw) : ORIGIN = 0x10000000, LENGTH = 32K
+ FS_CACHE(xrw) : ORIGIN = 0x10007800, LENGTH = 2K
}
-ENTRY(Reset_Handler)
-
/* produce a link error if there is not this amount of RAM for these sections */
_minimum_stack_size = 2K;
_minimum_heap_size = 16K;
@@ -24,10 +23,9 @@ _minimum_heap_size = 16K;
aligned for a call. */
_estack = ORIGIN(RAM) + LENGTH(RAM);
-/* define common sections and symbols */
-INCLUDE common.ld
-
/* RAM extents for the garbage collector */
+_ram_fs_cache_start = ORIGIN(FS_CACHE);
+_ram_fs_cache_block_size = LENGTH(FS_CACHE);
_ram_start = ORIGIN(RAM);
_ram_end = ORIGIN(RAM) + LENGTH(RAM);
_heap_start = _ebss; /* heap starts just after statically allocated memory */
diff --git a/ports/stm32/boards/stm32l496_af.csv b/ports/stm32/boards/stm32l496_af.csv
new file mode 100644
index 000000000..311770a05
--- /dev/null
+++ b/ports/stm32/boards/stm32l496_af.csv
@@ -0,0 +1,142 @@
+Port,,AF0,AF1,AF2,AF3,AF4,AF5,AF6,AF7,AF8,AF9,AF10,AF11,AF12,AF13,AF14,AF15,,,
+,,SYS_AF,TIM1/TIM2/TIM5/TIM8/LPTIM1,TIM1/TIM2/TIM3/TIM4/TIM5,TIM8,I2C1/I2C2/I2C3,SPI1/SPI2,SPI3/DFSDM,USART1/USART2/USART3,UART4/UART5/LPUART1,CAN1/TSC,OTG_FS/QUADSPI,LCD,SDMMC1/COMP1/COMP2/FMC/SWPMI1,SAI1/SAI2,TIM2/TIM15/TIM16/TIM17/LPTIM2,EVENTOUT,ADC,COMP,DAC
+PortA,PA0,,TIM2_CH1,TIM5_CH1,TIM8_ETR,,,,USART2_CTS,UART4_TX,,,,,SAI1_EXTCLK,TIM2_ETR,EVENTOUT,ADC12_IN5,,
+PortA,PA1,,TIM2_CH2,TIM5_CH2,,I2C1_SMBA,SPI1_SCK,,USART2_RTS/USART2_DE,UART4_RX,,,LCD_SEG0,,,TIM15_CH1N,EVENTOUT,ADC12_IN6,,
+PortA,PA2,,TIM2_CH3,TIM5_CH3,,,,,USART2_TX,LPUART1_TX,,QUADSPI_BK1_NCS,LCD_SEG1,,SAI2_EXTCLK,TIM15_CH1,EVENTOUT,ADC12_IN7,,
+PortA,PA3,,TIM2_CH4,TIM5_CH4,,,,,USART2_RX,LPUART1_RX,,QUADSPI_CLK,LCD_SEG2,,SAI1_MCLK_A,TIM15_CH2,EVENTOUT,ADC12_IN8,,
+PortA,PA4,,,,,,SPI1_NSS,SPI3_NSS,USART2_CK,,,DCMI_HSYNC,,,SAI1_FS_B,LPTIM2_OUT,EVENTOUT,ADC12_IN9,,DAC1_OUT1
+PortA,PA5,,TIM2_CH1,TIM2_ETR,TIM8_CH1N,,SPI1_SCK,,,,,,,,,LPTIM2_ETR,EVENTOUT,ADC12_IN10,,DAC1_OUT2
+PortA,PA6,,TIM1_BKIN,TIM3_CH1,TIM8_BKIN,DCMI_PIXCLK,SPI1_MISO,,USART3_CTS,LPUART1_CTS,,QUADSPI_BK1_IO3,LCD_SEG3,TIM1_BKIN_COMP2,TIM8_BKIN_COMP2,TIM16_CH1,EVENTOUT,ADC12_IN11,,
+PortA,PA7,,TIM1_CH1N,TIM3_CH2,TIM8_CH1N,I2C3_SCL,SPI1_MOSI,,,,,QUADSPI_BK1_IO2,LCD_SEG4,,,TIM17_CH1,EVENTOUT,ADC12_IN12,,
+PortA,PA8,MCO,TIM1_CH1,,,,,,USART1_CK,,,OTG_FS_SOF,LCD_COM0,SWPMI1_IO,SAI1_SCK_A,LPTIM2_OUT,EVENTOUT,,,
+PortA,PA9,,TIM1_CH2,,SPI2_SCK,I2C1_SCL,DCMI_D0,,USART1_TX,,,,LCD_COM1,,SAI1_FS_A,TIM15_BKIN,EVENTOUT,,,
+PortA,PA10,,TIM1_CH3,,,I2C1_SDA,DCMI_D1,,USART1_RX,,,OTG_FS_ID,LCD_COM2,,SAI1_SD_A,TIM17_BKIN,EVENTOUT,,,
+PortA,PA11,,TIM1_CH4,TIM1_BKIN2,,,SPI1_MISO,,USART1_CTS,,CAN1_RX,OTG_FS_DM,,TIM1_BKIN2_COMP1,,,EVENTOUT,,,
+PortA,PA12,,TIM1_ETR,,,,SPI1_MOSI,,USART1_RTS/USART1_DE,,CAN1_TX,OTG_FS_DP,,,,,EVENTOUT,,,
+PortA,PA13,JTMS/SWDIO,IR_OUT,,,,,,,,,OTG_FS_NOE,,SWPMI1_TX,SAI1_SD_B,,EVENTOUT,,,
+PortA,PA14,JTCK/SWCLK,LPTIM1_OUT,,,I2C1_SMBA,I2C4_SMBA,,,,,OTG_FS_SOF,,SWPMI1_RX,SAI1_FS_B,,EVENTOUT,,,
+PortA,PA15,JTDI,TIM2_CH1,TIM2_ETR,USART2_RX,,SPI1_NSS,SPI3_NSS,USART3_RTS/USART3_DE,UART4_RTS/UART4_DE,TSC_G3_IO1,,LCD_SEG17,SWPMI1_SUSPEND,SAI2_FS_B,,EVENTOUT,,,
+PortB,PB0,,TIM1_CH2N,TIM3_CH3,TIM8_CH2N,,SPI1_NSS,,USART3_CK,,,QUADSPI_BK1_IO1,LCD_SEG5,COMP1_OUT,SAI1_EXTCLK,,EVENTOUT,ADC12_IN15,,
+PortB,PB1,,TIM1_CH3N,TIM3_CH4,TIM8_CH3N,,,DFSDM1_DATIN0,USART3_RTS/USART3_DE,LPUART1_RTS/LPUART1_DE,,QUADSPI_BK1_IO0,LCD_SEG6,,,LPTIM2_IN1,EVENTOUT,ADC12_IN16,COMP1_INM,
+PortB,PB2,RTC_OUT,LPTIM1_OUT,,,I2C3_SMBA,,DFSDM1_CKIN0,,,,,LCD_VLCD,,,,EVENTOUT,,COMP1_INP,
+PortB,PB3,JTDO/TRACESWO,TIM2_CH2,,,,SPI1_SCK,SPI3_SCK,USART1_RTS/USART1_DE,,,OTG_FS_CRS_SYNC,LCD_SEG7,,SAI1_SCK_B,,EVENTOUT,,COMP2_INM,
+PortB,PB4,NJTRST,,TIM3_CH1,,I2C3_SDA,SPI1_MISO,SPI3_MISO,USART1_CTS,UART5_RTS/UART5_DE,TSC_G2_IO1,DCMI_D12,LCD_SEG8,,SAI1_MCLK_B,TIM17_BKIN,EVENTOUT,,COMP2_INP,
+PortB,PB5,,LPTIM1_IN1,TIM3_CH2,CAN2_RX,I2C1_SMBA,SPI1_MOSI,SPI3_MOSI,USART1_CK,UART5_CTS,TSC_G2_IO2,DCMI_D10,LCD_SEG9,COMP2_OUT,SAI1_SD_B,TIM16_BKIN,EVENTOUT,,,
+PortB,PB6,,LPTIM1_ETR,TIM4_CH1,TIM8_BKIN2,I2C1_SCL,I2C4_SCL,DFSDM1_DATIN5,USART1_TX,CAN2_TX,TSC_G2_IO3,DCMI_D5,,TIM8_BKIN2_COMP2,SAI1_FS_B,TIM16_CH1N,EVENTOUT,,COMP2_INP,
+PortB,PB7,,LPTIM1_IN2,TIM4_CH2,TIM8_BKIN,I2C1_SDA,I2C4_SDA,DFSDM1_CKIN5,USART1_RX,UART4_CTS,TSC_G2_IO4,DCMI_VSYNC,LCD_SEG21,FMC_NL,TIM8_BKIN_COMP1,TIM17_CH1N,EVENTOUT,,COMP2_INM,
+PortB,PB8,,,TIM4_CH3,,I2C1_SCL,,DFSDM1_DATIN6,,,CAN1_RX,DCMI_D6,LCD_SEG16,SDMMC1_D4,SAI1_MCLK_A,TIM16_CH1,EVENTOUT,,,
+PortB,PB9,,IR_OUT,TIM4_CH4,,I2C1_SDA,SPI2_NSS,DFSDM1_CKIN6,,,CAN1_TX,DCMI_D7,LCD_COM3,SDMMC1_D5,SAI1_FS_A,TIM17_CH1,EVENTOUT,,,
+PortB,PB10,,TIM2_CH3,,I2C4_SCL,I2C2_SCL,SPI2_SCK,DFSDM1_DATIN7,USART3_TX,LPUART1_RX,TSC_SYNC,QUADSPI_CLK,LCD_SEG10,COMP1_OUT,SAI1_SCK_A,,EVENTOUT,,,
+PortB,PB11,,TIM2_CH4,,I2C4_SDA,I2C2_SDA,,DFSDM1_CKIN7,USART3_RX,LPUART1_TX,,QUADSPI_BK1_NCS,LCD_SEG11,COMP2_OUT,,,EVENTOUT,,,
+PortB,PB12,,TIM1_BKIN,,TIM1_BKIN_COMP2,I2C2_SMBA,SPI2_NSS,DFSDM1_DATIN1,USART3_CK,LPUART1_RTS/LPUART1_DE,TSC_G1_IO1,CAN2_RX,LCD_SEG12,SWPMI1_IO,SAI2_FS_A,TIM15_BKIN,EVENTOUT,,,
+PortB,PB13,,TIM1_CH1N,,,I2C2_SCL,SPI2_SCK,DFSDM1_CKIN1,USART3_CTS,LPUART1_CTS,TSC_G1_IO2,CAN2_TX,LCD_SEG13,SWPMI1_TX,SAI2_SCK_A,TIM15_CH1N,EVENTOUT,,,
+PortB,PB14,,TIM1_CH2N,,TIM8_CH2N,I2C2_SDA,SPI2_MISO,DFSDM1_DATIN2,USART3_RTS/USART3_DE,,TSC_G1_IO3,,LCD_SEG14,SWPMI1_RX,SAI2_MCLK_A,TIM15_CH1,EVENTOUT,,,
+PortB,PB15,RTC_REFIN,TIM1_CH3N,,TIM8_CH3N,,SPI2_MOSI,DFSDM1_CKIN2,,,TSC_G1_IO4,,LCD_SEG15,SWPMI1_SUSPEND,SAI2_SD_A,TIM15_CH2,EVENTOUT,,,
+PortC,PC0,,LPTIM1_IN1,I2C4_SCL,,I2C3_SCL,,DFSDM1_DATIN4,,LPUART1_RX,,,LCD_SEG18,,,LPTIM2_IN1,EVENTOUT,ADC123_IN1,,
+PortC,PC1,TRACED0,LPTIM1_OUT,I2C4_SDA,SPI2_MOSI,I2C3_SDA,,DFSDM1_CKIN4,,LPUART1_TX,,QUADSPI_BK2_IO0,LCD_SEG19,,SAI1_SD_A,,EVENTOUT,ADC123_IN2,,
+PortC,PC2,,LPTIM1_IN2,,,,SPI2_MISO,DFSDM1_CKOUT,,,,QUADSPI_BK2_IO1,LCD_SEG20,,,,EVENTOUT,ADC123_IN3,,
+PortC,PC3,,LPTIM1_ETR,,,,SPI2_MOSI,,,,,QUADSPI_BK2_IO2,LCD_VLCD,,SAI1_SD_A,LPTIM2_ETR,EVENTOUT,ADC123_IN4,,
+PortC,PC4,,,,,,,,USART3_TX,,,QUADSPI_BK2_IO3,LCD_SEG22,,,,EVENTOUT,ADC12_IN13,COMP1_INM,
+PortC,PC5,,,,,,,,USART3_RX,,,,LCD_SEG23,,,,EVENTOUT,ADC12_IN14,COMP1_INP,
+PortC,PC6,,,TIM3_CH1,TIM8_CH1,,,DFSDM1_CKIN3,,,TSC_G4_IO1,DCMI_D0,LCD_SEG24,SDMMC1_D6,SAI2_MCLK_A,,EVENTOUT,,,
+PortC,PC7,,,TIM3_CH2,TIM8_CH2,,,DFSDM1_DATIN3,,,TSC_G4_IO2,DCMI_D1,LCD_SEG25,SDMMC1_D7,SAI2_MCLK_B,,EVENTOUT,,,
+PortC,PC8,,,TIM3_CH3,TIM8_CH3,,,,,,TSC_G4_IO3,DCMI_D2,LCD_SEG26,SDMMC1_D0,,,EVENTOUT,,,
+PortC,PC9,,TIM8_BKIN2,TIM3_CH4,TIM8_CH4,DCMI_D3,,I2C3_SDA,,,TSC_G4_IO4,OTG_FS_NOE,LCD_SEG27,SDMMC1_D1,SAI2_EXTCLK,TIM8_BKIN2_COMP1,EVENTOUT,,,
+PortC,PC10,TRACED1,,,,,,SPI3_SCK,USART3_TX,UART4_TX,TSC_G3_IO2,DCMI_D8,LCD_COM4/LCD_SEG28/LCD_SEG40,SDMMC1_D2,SAI2_SCK_B,,EVENTOUT,,,
+PortC,PC11,,,,,,QUADSPI_BK2_NCS,SPI3_MISO,USART3_RX,UART4_RX,TSC_G3_IO3,DCMI_D4,LCD_COM5/LCD_SEG29/LCD_SEG41,SDMMC1_D3,SAI2_MCLK_B,,EVENTOUT,,,
+PortC,PC12,TRACED3,,,,,,SPI3_MOSI,USART3_CK,UART5_TX,TSC_G3_IO4,DCMI_D9,LCD_COM6/LCD_SEG30/LCD_SEG42,SDMMC1_CK,SAI2_SD_B,,EVENTOUT,,,
+PortC,PC13,,,,,,,,,,,,,,,,EVENTOUT,,,
+PortC,PC14,,,,,,,,,,,,,,,,EVENTOUT,,,
+PortC,PC15,,,,,,,,,,,,,,,,EVENTOUT,,,
+PortD,PD0,,,,,,SPI2_NSS,DFSDM1_DATIN7,,,CAN1_RX,,,FMC_D2,,,EVENTOUT,,,
+PortD,PD1,,,,,,SPI2_SCK,DFSDM1_CKIN7,,,CAN1_TX,,,FMC_D3,,,EVENTOUT,,,
+PortD,PD2,TRACED2,,TIM3_ETR,,,,,USART3_RTS/USART3_DE,UART5_RX,TSC_SYNC,DCMI_D11,LCD_COM7/LCD_SEG31/LCD_SEG43,SDMMC1_CMD,,,EVENTOUT,,,
+PortD,PD3,,,,SPI2_SCK,DCMI_D5,SPI2_MISO,DFSDM1_DATIN0,USART2_CTS,,,QUADSPI_BK2_NCS,,FMC_CLK,,,EVENTOUT,,,
+PortD,PD4,,,,,,SPI2_MOSI,DFSDM1_CKIN0,USART2_RTS/USART2_DE,,,QUADSPI_BK2_IO0,,FMC_NOE,,,EVENTOUT,,,
+PortD,PD5,,,,,,,,USART2_TX,,,QUADSPI_BK2_IO1,,FMC_NWE,,,EVENTOUT,,,
+PortD,PD6,,,,,DCMI_D10,QUADSPI_BK2_IO1,DFSDM1_DATIN1,USART2_RX,,,QUADSPI_BK2_IO2,,FMC_NWAIT,SAI1_SD_A,,EVENTOUT,,,
+PortD,PD7,,,,,,,DFSDM1_CKIN1,USART2_CK,,,QUADSPI_BK2_IO3,,FMC_NE1,,,EVENTOUT,,,
+PortD,PD8,,,,,,,,USART3_TX,,,DCMI_HSYNC,LCD_SEG28,FMC_D13,,,EVENTOUT,,,
+PortD,PD9,,,,,,,,USART3_RX,,,DCMI_PIXCLK,LCD_SEG29,FMC_D14,SAI2_MCLK_A,,EVENTOUT,,,
+PortD,PD10,,,,,,,,USART3_CK,,TSC_G6_IO1,,LCD_SEG30,FMC_D15,SAI2_SCK_A,,EVENTOUT,,,
+PortD,PD11,,,,,I2C4_SMBA,,,USART3_CTS,,TSC_G6_IO2,,LCD_SEG31,FMC_A16,SAI2_SD_A,LPTIM2_ETR,EVENTOUT,,,
+PortD,PD12,,,TIM4_CH1,,I2C4_SCL,,,USART3_RTS/USART3_DE,,TSC_G6_IO3,,LCD_SEG32,FMC_A17,SAI2_FS_A,LPTIM2_IN1,EVENTOUT,,,
+PortD,PD13,,,TIM4_CH2,,I2C4_SDA,,,,,TSC_G6_IO4,,LCD_SEG33,FMC_A18,,LPTIM2_OUT,EVENTOUT,,,
+PortD,PD14,,,TIM4_CH3,,,,,,,,,LCD_SEG34,FMC_D0,,,EVENTOUT,,,
+PortD,PD15,,,TIM4_CH4,,,,,,,,,LCD_SEG35,FMC_D1,,,EVENTOUT,,,
+PortE,PE0,,,TIM4_ETR,,,,,,,,DCMI_D2,LCD_SEG36,FMC_NBL0,,TIM16_CH1,EVENTOUT,,,
+PortE,PE1,,,,,,,,,,,DCMI_D3,LCD_SEG37,FMC_NBL1,,TIM17_CH1,EVENTOUT,,,
+PortE,PE2,TRACECLK,,TIM3_ETR,,,,,,,TSC_G7_IO1,,LCD_SEG38,FMC_A23,SAI1_MCLK_A,,EVENTOUT,,,
+PortE,PE3,TRACED0,,TIM3_CH1,,,,,,,TSC_G7_IO2,,LCD_SEG39,FMC_A19,SAI1_SD_B,,EVENTOUT,,,
+PortE,PE4,TRACED1,,TIM3_CH2,,,,DFSDM1_DATIN3,,,TSC_G7_IO3,DCMI_D4,,FMC_A20,SAI1_FS_A,,EVENTOUT,,,
+PortE,PE5,TRACED2,,TIM3_CH3,,,,DFSDM1_CKIN3,,,TSC_G7_IO4,DCMI_D6,,FMC_A21,SAI1_SCK_A,,EVENTOUT,,,
+PortE,PE6,TRACED3,,TIM3_CH4,,,,,,,,DCMI_D7,,FMC_A22,SAI1_SD_A,,EVENTOUT,,,
+PortE,PE7,,TIM1_ETR,,,,,DFSDM1_DATIN2,,,,,,FMC_D4,SAI1_SD_B,,EVENTOUT,,,
+PortE,PE8,,TIM1_CH1N,,,,,DFSDM1_CKIN2,,,,,,FMC_D5,SAI1_SCK_B,,EVENTOUT,,,
+PortE,PE9,,TIM1_CH1,,,,,DFSDM1_CKOUT,,,,,,FMC_D6,SAI1_FS_B,,EVENTOUT,,,
+PortE,PE10,,TIM1_CH2N,,,,,DFSDM1_DATIN4,,,TSC_G5_IO1,QUADSPI_CLK,,FMC_D7,SAI1_MCLK_B,,EVENTOUT,,,
+PortE,PE11,,TIM1_CH2,,,,,DFSDM1_CKIN4,,,TSC_G5_IO2,QUADSPI_BK1_NCS,,FMC_D8,,,EVENTOUT,,,
+PortE,PE12,,TIM1_CH3N,,,,SPI1_NSS,DFSDM1_DATIN5,,,TSC_G5_IO3,QUADSPI_BK1_IO0,,FMC_D9,,,EVENTOUT,,,
+PortE,PE13,,TIM1_CH3,,,,SPI1_SCK,DFSDM1_CKIN5,,,TSC_G5_IO4,QUADSPI_BK1_IO1,,FMC_D10,,,EVENTOUT,,,
+PortE,PE14,,TIM1_CH4,TIM1_BKIN2,TIM1_BKIN2_COMP2,,SPI1_MISO,,,,,QUADSPI_BK1_IO2,,FMC_D11,,,EVENTOUT,,,
+PortE,PE15,,TIM1_BKIN,,TIM1_BKIN_COMP1,,SPI1_MOSI,,,,,QUADSPI_BK1_IO3,,FMC_D12,,,EVENTOUT,,,
+PortF,PF0,,,,,I2C2_SDA,,,,,,,,FMC_A0,,,EVENTOUT,,,
+PortF,PF1,,,,,I2C2_SCL,,,,,,,,FMC_A1,,,EVENTOUT,,,
+PortF,PF2,,,,,I2C2_SMBA,,,,,,,,FMC_A2,,,EVENTOUT,,,
+PortF,PF3,,,,,,,,,,,,,FMC_A3,,,EVENTOUT,ADC3_IN6,,
+PortF,PF4,,,,,,,,,,,,,FMC_A4,,,EVENTOUT,ADC3_IN7,,
+PortF,PF5,,,,,,,,,,,,,FMC_A5,,,EVENTOUT,ADC3_IN8,,
+PortF,PF6,,TIM5_ETR,TIM5_CH1,,,,,,,,QUADSPI_BK1_IO3,,,SAI1_SD_B,,EVENTOUT,ADC3_IN9,,
+PortF,PF7,,,TIM5_CH2,,,,,,,,QUADSPI_BK1_IO2,,,SAI1_MCLK_B,,EVENTOUT,ADC3_IN10,,
+PortF,PF8,,,TIM5_CH3,,,,,,,,QUADSPI_BK1_IO0,,,SAI1_SCK_B,,EVENTOUT,ADC3_IN11,,
+PortF,PF9,,,TIM5_CH4,,,,,,,,QUADSPI_BK1_IO1,,,SAI1_FS_B,TIM15_CH1,EVENTOUT,ADC3_IN12,,
+PortF,PF10,,,,QUADSPI_CLK,,,,,,,DCMI_D11,,,,TIM15_CH2,EVENTOUT,ADC3_IN13,,
+PortF,PF11,,,,,,,,,,,DCMI_D12,,,,,EVENTOUT,,,
+PortF,PF12,,,,,,,,,,,,,FMC_A6,,,EVENTOUT,,,
+PortF,PF13,,,,,I2C4_SMBA,,DFSDM1_DATIN6,,,,,,FMC_A7,,,EVENTOUT,,,
+PortF,PF14,,,,,I2C4_SCL,,DFSDM1_CKIN6,,,TSC_G8_IO1,,,FMC_A8,,,EVENTOUT,,,
+PortF,PF15,,,,,I2C4_SDA,,,,,TSC_G8_IO2,,,FMC_A9,,,EVENTOUT,,,
+PortG,PG0,,,,,,,,,,TSC_G8_IO3,,,FMC_A10,,,EVENTOUT,,,
+PortG,PG1,,,,,,,,,,TSC_G8_IO4,,,FMC_A11,,,EVENTOUT,,,
+PortG,PG2,,,,,,SPI1_SCK,,,,,,,FMC_A12,SAI2_SCK_B,,EVENTOUT,,,
+PortG,PG3,,,,,,SPI1_MISO,,,,,,,FMC_A13,SAI2_FS_B,,EVENTOUT,,,
+PortG,PG4,,,,,,SPI1_MOSI,,,,,,,FMC_A14,SAI2_MCLK_B,,EVENTOUT,,,
+PortG,PG5,,,,,,SPI1_NSS,,,LPUART1_CTS,,,,FMC_A15,SAI2_SD_B,,EVENTOUT,,,
+PortG,PG6,,,,,I2C3_SMBA,,,,LPUART1_RTS/LPUART1_DE,,,,,,,EVENTOUT,,,
+PortG,PG7,,,,,I2C3_SCL,,,,LPUART1_TX,,,,FMC_INT,SAI1_MCLK_A,,EVENTOUT,,,
+PortG,PG8,,,,,I2C3_SDA,,,,LPUART1_RX,,,,,,,EVENTOUT,,,
+PortG,PG9,,,,,,,SPI3_SCK,USART1_TX,,,,,FMC_NCE/FMC_NE2,SAI2_SCK_A,TIM15_CH1N,EVENTOUT,,,
+PortG,PG10,,LPTIM1_IN1,,,,,SPI3_MISO,USART1_RX,,,,,FMC_NE3,SAI2_FS_A,TIM15_CH1,EVENTOUT,,,
+PortG,PG11,,LPTIM1_IN2,,,,,SPI3_MOSI,USART1_CTS,,,,,,SAI2_MCLK_A,TIM15_CH2,EVENTOUT,,,
+PortG,PG12,,LPTIM1_ETR,,,,,SPI3_NSS,USART1_RTS/USART1_DE,,,,,FMC_NE4,SAI2_SD_A,,EVENTOUT,,,
+PortG,PG13,,,,,I2C1_SDA,,,USART1_CK,,,,,FMC_A24,,,EVENTOUT,,,
+PortG,PG14,,,,,I2C1_SCL,,,,,,,,FMC_A25,,,EVENTOUT,,,
+PortG,PG15,,LPTIM1_OUT,,,I2C1_SMBA,,,,,,DCMI_D13,,,,,EVENTOUT,,,
+PortH,PH0,,,,,,,,,,,,,,,,EVENTOUT,,,
+PortH,PH1,,,,,,,,,,,,,,,,EVENTOUT,,,
+PortH,PH2,,,,QUADSPI_BK2_IO0,,,,,,,,,,,,EVENTOUT,,,
+PortH,PH3,,,,,,,,,,,,,,,,EVENTOUT,,,
+PortH,PH4,,,,,I2C2_SCL,,,,,,,,,,,EVENTOUT,,,
+PortH,PH5,,,,,I2C2_SDA,,,,,,DCMI_PIXCLK,,,,,EVENTOUT,,,
+PortH,PH6,,,,,I2C2_SMBA,,,,,,DCMI_D8,,,,,EVENTOUT,,,
+PortH,PH7,,,,,I2C3_SCL,,,,,,DCMI_D9,,,,,EVENTOUT,,,
+PortH,PH8,,,,,I2C3_SDA,,,,,,DCMI_HSYNC,,,,,EVENTOUT,,,
+PortH,PH9,,,,,I2C3_SMBA,,,,,,DCMI_D0,,,,,EVENTOUT,,,
+PortH,PH10,,,TIM5_CH1,,,,,,,,DCMI_D1,,,,,EVENTOUT,,,
+PortH,PH11,,,TIM5_CH2,,,,,,,,DCMI_D2,,,,,EVENTOUT,,,
+PortH,PH12,,,TIM5_CH3,,,,,,,,DCMI_D3,,,,,EVENTOUT,,,
+PortH,PH13,,,,TIM8_CH1N,,,,,,CAN1_TX,,,,,,EVENTOUT,,,
+PortH,PH14,,,,TIM8_CH2N,,,,,,,DCMI_D4,,,,,EVENTOUT,,,
+PortH,PH15,,,,TIM8_CH3N,,,,,,,DCMI_D11,,,,,EVENTOUT,,,
+PortI,PI0,,,TIM5_CH4,,,SPI2_NSS,,,,,DCMI_D13,,,,,EVENTOUT,,,
+PortI,PI1,,,,,,SPI2_SCK,,,,,DCMI_D8,,,,,EVENTOUT,,,
+PortI,PI2,,,,TIM8_CH4,,SPI2_MISO,,,,,DCMI_D9,,,,,EVENTOUT,,,
+PortI,PI3,,,,TIM8_ETR,,SPI2_MOSI,,,,,DCMI_D10,,,,,EVENTOUT,,,
+PortI,PI4,,,,TIM8_BKIN,,,,,,,DCMI_D5,,,,,EVENTOUT,,,
+PortI,PI5,,,,TIM8_CH1,,,,,,,DCMI_VSYNC,,,,,EVENTOUT,,,
+PortI,PI6,,,,TIM8_CH2,,,,,,,DCMI_D6,,,,,EVENTOUT,,,
+PortI,PI7,,,,TIM8_CH3,,,,,,,DCMI_D7,,,,,EVENTOUT,,,
+PortI,PI8,,,,,,,,,,,DCMI_D12,,,,,EVENTOUT,,,
+PortI,PI9,,,,,,,,,,CAN1_RX,,,,,,EVENTOUT,,,
+PortI,PI10,,,,,,,,,,,,,,,,EVENTOUT,,,
+PortI,PI11,,,,,,,,,,,,,,,,EVENTOUT,,,
diff --git a/ports/stm32/boards/stm32l496xg.ld b/ports/stm32/boards/stm32l496xg.ld
new file mode 100644
index 000000000..88221170b
--- /dev/null
+++ b/ports/stm32/boards/stm32l496xg.ld
@@ -0,0 +1,35 @@
+/*
+ GNU linker script for STM32L496XG
+*/
+
+/* Specify the memory areas */
+MEMORY
+{
+ FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1024K
+ FLASH_ISR (rx) : ORIGIN = 0x08000000, LENGTH = 16K /* sectors 0-7 */
+ FLASH_TEXT (rx) : ORIGIN = 0x08004000, LENGTH = 596K /* sectors 8-305 */
+ FLASH_FS (r) : ORIGIN = 0x08099000, LENGTH = 412K /* sectors 306-511 412 KiB */
+ RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 256K
+ SRAM2 (xrw) : ORIGIN = 0x20040000, LENGTH = 62K /* leave 2K for flash fs cache */
+ FS_CACHE(xrw) : ORIGIN = 0x2004f800, LENGTH = 2K
+}
+
+/* produce a link error if there is not this amount of RAM for these sections */
+_minimum_stack_size = 2K;
+_minimum_heap_size = 16K;
+
+/* Define the top end of the stack. The stack is full descending so begins just
+ above last byte of RAM. Note that EABI requires the stack to be 8-byte
+ aligned for a call. */
+_estack = ORIGIN(RAM) + LENGTH(RAM) + LENGTH(SRAM2);
+
+/* RAM extents for the garbage collector */
+_ram_fs_cache_start = ORIGIN(FS_CACHE);
+_ram_fs_cache_block_size = LENGTH(FS_CACHE);
+_ram_start = ORIGIN(RAM);
+_ram_end = ORIGIN(RAM) + LENGTH(RAM) + LENGTH(SRAM2);
+_heap_start = _ebss; /* heap starts just after statically allocated memory */
+_heap_end = 0x2001C000; /* tunable */
+
+_flash_fs_start = ORIGIN(FLASH_FS);
+_flash_fs_end = ORIGIN(FLASH_FS) + LENGTH(FLASH_FS);
diff --git a/ports/stm32/bufhelper.h b/ports/stm32/bufhelper.h
index c1967bf43..12c79c2fd 100644
--- a/ports/stm32/bufhelper.h
+++ b/ports/stm32/bufhelper.h
@@ -23,10 +23,10 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
-#ifndef MICROPY_INCLUDED_STMHAL_BUFHELPER_H
-#define MICROPY_INCLUDED_STMHAL_BUFHELPER_H
+#ifndef MICROPY_INCLUDED_STM32_BUFHELPER_H
+#define MICROPY_INCLUDED_STM32_BUFHELPER_H
void pyb_buf_get_for_send(mp_obj_t o, mp_buffer_info_t *bufinfo, byte *tmp_data);
mp_obj_t pyb_buf_get_for_recv(mp_obj_t o, vstr_t *vstr);
-#endif // MICROPY_INCLUDED_STMHAL_BUFHELPER_H
+#endif // MICROPY_INCLUDED_STM32_BUFHELPER_H
diff --git a/ports/stm32/can.c b/ports/stm32/can.c
index 25a608ce9..7680b0de4 100644
--- a/ports/stm32/can.c
+++ b/ports/stm32/can.c
@@ -3,7 +3,7 @@
*
* The MIT License (MIT)
*
- * Copyright (c) 2014 Damien P. George
+ * Copyright (c) 2014-2018 Damien P. George
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -29,8 +29,10 @@
#include <stdarg.h>
#include "py/objtuple.h"
+#include "py/objarray.h"
#include "py/runtime.h"
#include "py/gc.h"
+#include "py/binary.h"
#include "py/stream.h"
#include "py/mperrno.h"
#include "py/mphal.h"
@@ -45,6 +47,14 @@
#define MASK32 (2)
#define LIST32 (3)
+enum {
+ CAN_STATE_STOPPED,
+ CAN_STATE_ERROR_ACTIVE,
+ CAN_STATE_ERROR_WARNING,
+ CAN_STATE_ERROR_PASSIVE,
+ CAN_STATE_BUS_OFF,
+};
+
/// \moduleref pyb
/// \class CAN - controller area network communication bus
///
@@ -81,6 +91,9 @@ typedef struct _pyb_can_obj_t {
bool extframe : 1;
byte rx_state0;
byte rx_state1;
+ uint16_t num_error_warning;
+ uint16_t num_error_passive;
+ uint16_t num_bus_off;
CAN_HandleTypeDef can;
} pyb_can_obj_t;
@@ -91,49 +104,57 @@ STATIC uint8_t can2_start_bank = 14;
// assumes Init parameters have been set up correctly
STATIC bool can_init(pyb_can_obj_t *can_obj) {
CAN_TypeDef *CANx = NULL;
-
- uint32_t GPIO_Pin = 0;
- uint8_t GPIO_AF_CANx = 0;
- GPIO_TypeDef* GPIO_Port = NULL;
+ uint32_t sce_irq = 0;
+ const pin_obj_t *pins[2];
switch (can_obj->can_id) {
- // CAN1 is on RX,TX = Y3,Y4 = PB9,PB9
+ #if defined(MICROPY_HW_CAN1_TX)
case PYB_CAN_1:
CANx = CAN1;
- GPIO_AF_CANx = GPIO_AF9_CAN1;
- GPIO_Port = GPIOB;
- GPIO_Pin = GPIO_PIN_8 | GPIO_PIN_9;
+ sce_irq = CAN1_SCE_IRQn;
+ pins[0] = MICROPY_HW_CAN1_TX;
+ pins[1] = MICROPY_HW_CAN1_RX;
__CAN1_CLK_ENABLE();
break;
+ #endif
- // CAN2 is on RX,TX = Y5,Y6 = PB12,PB13
+ #if defined(MICROPY_HW_CAN2_TX)
case PYB_CAN_2:
CANx = CAN2;
- GPIO_AF_CANx = GPIO_AF9_CAN2;
- GPIO_Port = GPIOB;
- GPIO_Pin = GPIO_PIN_12 | GPIO_PIN_13;
+ sce_irq = CAN2_SCE_IRQn;
+ pins[0] = MICROPY_HW_CAN2_TX;
+ pins[1] = MICROPY_HW_CAN2_RX;
__CAN1_CLK_ENABLE(); // CAN2 is a "slave" and needs CAN1 enabled as well
__CAN2_CLK_ENABLE();
break;
+ #endif
default:
return false;
}
// init GPIO
- GPIO_InitTypeDef GPIO_InitStructure;
- GPIO_InitStructure.Pin = GPIO_Pin;
- GPIO_InitStructure.Speed = GPIO_SPEED_HIGH;
- GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;
- GPIO_InitStructure.Pull = GPIO_PULLUP;
- GPIO_InitStructure.Alternate = GPIO_AF_CANx;
- HAL_GPIO_Init(GPIO_Port, &GPIO_InitStructure);
+ uint32_t mode = MP_HAL_PIN_MODE_ALT;
+ uint32_t pull = MP_HAL_PIN_PULL_UP;
+ for (int i = 0; i < 2; i++) {
+ if (!mp_hal_pin_config_alt(pins[i], mode, pull, AF_FN_CAN, can_obj->can_id)) {
+ return false;
+ }
+ }
// init CANx
can_obj->can.Instance = CANx;
HAL_CAN_Init(&can_obj->can);
can_obj->is_enabled = true;
+ can_obj->num_error_warning = 0;
+ can_obj->num_error_passive = 0;
+ can_obj->num_bus_off = 0;
+
+ __HAL_CAN_ENABLE_IT(&can_obj->can, CAN_IT_ERR | CAN_IT_BOF | CAN_IT_EPV | CAN_IT_EWG);
+
+ NVIC_SetPriority(sce_irq, IRQ_PRI_CAN);
+ HAL_NVIC_EnableIRQ(sce_irq);
return true;
}
@@ -170,6 +191,51 @@ STATIC void can_clearfilter(uint32_t f) {
HAL_CAN_ConfigFilter(NULL, &filter);
}
+STATIC int can_receive(CAN_TypeDef *can, int fifo, CanRxMsgTypeDef *msg, uint32_t timeout_ms) {
+ volatile uint32_t *rfr;
+ if (fifo == CAN_FIFO0) {
+ rfr = &can->RF0R;
+ } else {
+ rfr = &can->RF1R;
+ }
+
+ // Wait for a message to become available, with timeout
+ uint32_t start = HAL_GetTick();
+ while ((*rfr & 3) == 0) {
+ MICROPY_EVENT_POLL_HOOK
+ if (HAL_GetTick() - start >= timeout_ms) {
+ return -MP_ETIMEDOUT;
+ }
+ }
+
+ // Read message data
+ CAN_FIFOMailBox_TypeDef *box = &can->sFIFOMailBox[fifo];
+ msg->IDE = box->RIR & 4;
+ if (msg->IDE == CAN_ID_STD) {
+ msg->StdId = box->RIR >> 21;
+ } else {
+ msg->ExtId = box->RIR >> 3;
+ }
+ msg->RTR = box->RIR & 2;
+ msg->DLC = box->RDTR & 0xf;
+ msg->FMI = box->RDTR >> 8 & 0xff;
+ uint32_t rdlr = box->RDLR;
+ msg->Data[0] = rdlr;
+ msg->Data[1] = rdlr >> 8;
+ msg->Data[2] = rdlr >> 16;
+ msg->Data[3] = rdlr >> 24;
+ uint32_t rdhr = box->RDHR;
+ msg->Data[4] = rdhr;
+ msg->Data[5] = rdhr >> 8;
+ msg->Data[6] = rdhr >> 16;
+ msg->Data[7] = rdhr >> 24;
+
+ // Release (free) message from FIFO
+ *rfr |= CAN_RF0R_RFOM0;
+
+ return 0; // success
+}
+
// We have our own version of CAN transmit so we can handle Timeout=0 correctly.
STATIC HAL_StatusTypeDef CAN_Transmit(CAN_HandleTypeDef *hcan, uint32_t Timeout) {
uint32_t transmitmailbox;
@@ -268,7 +334,6 @@ STATIC void pyb_can_print(const mp_print_t *print, mp_obj_t self_in, mp_print_ki
if (!self->is_enabled) {
mp_printf(print, "CAN(%u)", self->can_id);
} else {
- mp_printf(print, "CAN(%u, CAN.", self->can_id);
qstr mode;
switch (self->can.Init.Mode) {
case CAN_MODE_NORMAL: mode = MP_QSTR_NORMAL; break;
@@ -276,18 +341,17 @@ STATIC void pyb_can_print(const mp_print_t *print, mp_obj_t self_in, mp_print_ki
case CAN_MODE_SILENT: mode = MP_QSTR_SILENT; break;
case CAN_MODE_SILENT_LOOPBACK: default: mode = MP_QSTR_SILENT_LOOPBACK; break;
}
- mp_printf(print, "%q, extframe=", mode);
- if (self->extframe) {
- mode = MP_QSTR_True;
- } else {
- mode = MP_QSTR_False;
- }
- mp_printf(print, "%q)", mode);
+ mp_printf(print, "CAN(%u, CAN.%q, extframe=%q, auto_restart=%q)",
+ self->can_id,
+ mode,
+ self->extframe ? MP_QSTR_True : MP_QSTR_False,
+ (self->can.Instance->MCR & CAN_MCR_ABOM) ? MP_QSTR_True : MP_QSTR_False);
}
}
// init(mode, extframe=False, prescaler=100, *, sjw=1, bs1=6, bs2=8)
STATIC mp_obj_t pyb_can_init_helper(pyb_can_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum { ARG_mode, ARG_extframe, ARG_prescaler, ARG_sjw, ARG_bs1, ARG_bs2, ARG_auto_restart };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_mode, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = CAN_MODE_NORMAL} },
{ MP_QSTR_extframe, MP_ARG_BOOL, {.u_bool = false} },
@@ -295,24 +359,25 @@ STATIC mp_obj_t pyb_can_init_helper(pyb_can_obj_t *self, size_t n_args, const mp
{ MP_QSTR_sjw, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1} },
{ MP_QSTR_bs1, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 6} },
{ MP_QSTR_bs2, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 8} },
+ { MP_QSTR_auto_restart, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
};
// parse args
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
- self->extframe = args[1].u_bool;
+ self->extframe = args[ARG_extframe].u_bool;
// set the CAN configuration values
memset(&self->can, 0, sizeof(self->can));
CAN_InitTypeDef *init = &self->can.Init;
- init->Mode = args[0].u_int << 4; // shift-left so modes fit in a small-int
- init->Prescaler = args[2].u_int;
- init->SJW = ((args[3].u_int - 1) & 3) << 24;
- init->BS1 = ((args[4].u_int - 1) & 0xf) << 16;
- init->BS2 = ((args[5].u_int - 1) & 7) << 20;
+ init->Mode = args[ARG_mode].u_int << 4; // shift-left so modes fit in a small-int
+ init->Prescaler = args[ARG_prescaler].u_int;
+ init->SJW = ((args[ARG_sjw].u_int - 1) & 3) << 24;
+ init->BS1 = ((args[ARG_bs1].u_int - 1) & 0xf) << 16;
+ init->BS2 = ((args[ARG_bs2].u_int - 1) & 7) << 20;
init->TTCM = DISABLE;
- init->ABOM = DISABLE;
+ init->ABOM = args[ARG_auto_restart].u_bool ? ENABLE : DISABLE;
init->AWUM = DISABLE;
init->NART = DISABLE;
init->RFLM = DISABLE;
@@ -413,20 +478,91 @@ STATIC mp_obj_t pyb_can_deinit(mp_obj_t self_in) {
if (self->can.Instance == CAN1) {
HAL_NVIC_DisableIRQ(CAN1_RX0_IRQn);
HAL_NVIC_DisableIRQ(CAN1_RX1_IRQn);
+ HAL_NVIC_DisableIRQ(CAN1_SCE_IRQn);
__CAN1_FORCE_RESET();
__CAN1_RELEASE_RESET();
__CAN1_CLK_DISABLE();
+ #if defined(CAN2)
} else if (self->can.Instance == CAN2) {
HAL_NVIC_DisableIRQ(CAN2_RX0_IRQn);
HAL_NVIC_DisableIRQ(CAN2_RX1_IRQn);
+ HAL_NVIC_DisableIRQ(CAN2_SCE_IRQn);
__CAN2_FORCE_RESET();
__CAN2_RELEASE_RESET();
__CAN2_CLK_DISABLE();
+ #endif
}
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_can_deinit_obj, pyb_can_deinit);
+// Force a software restart of the controller, to allow transmission after a bus error
+STATIC mp_obj_t pyb_can_restart(mp_obj_t self_in) {
+ pyb_can_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ if (!self->is_enabled) {
+ mp_raise_ValueError(NULL);
+ }
+ CAN_TypeDef *can = self->can.Instance;
+ can->MCR |= CAN_MCR_INRQ;
+ while ((can->MSR & CAN_MSR_INAK) == 0) {
+ }
+ can->MCR &= ~CAN_MCR_INRQ;
+ while ((can->MSR & CAN_MSR_INAK)) {
+ }
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_can_restart_obj, pyb_can_restart);
+
+// Get the state of the controller
+STATIC mp_obj_t pyb_can_state(mp_obj_t self_in) {
+ pyb_can_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ mp_int_t state = CAN_STATE_STOPPED;
+ if (self->is_enabled) {
+ CAN_TypeDef *can = self->can.Instance;
+ if (can->ESR & CAN_ESR_BOFF) {
+ state = CAN_STATE_BUS_OFF;
+ } else if (can->ESR & CAN_ESR_EPVF) {
+ state = CAN_STATE_ERROR_PASSIVE;
+ } else if (can->ESR & CAN_ESR_EWGF) {
+ state = CAN_STATE_ERROR_WARNING;
+ } else {
+ state = CAN_STATE_ERROR_ACTIVE;
+ }
+ }
+ return MP_OBJ_NEW_SMALL_INT(state);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_can_state_obj, pyb_can_state);
+
+// Get info about error states and TX/RX buffers
+STATIC mp_obj_t pyb_can_info(size_t n_args, const mp_obj_t *args) {
+ pyb_can_obj_t *self = MP_OBJ_TO_PTR(args[0]);
+ mp_obj_list_t *list;
+ if (n_args == 1) {
+ list = MP_OBJ_TO_PTR(mp_obj_new_list(8, NULL));
+ } else {
+ if (!MP_OBJ_IS_TYPE(args[1], &mp_type_list)) {
+ mp_raise_TypeError(NULL);
+ }
+ list = MP_OBJ_TO_PTR(args[1]);
+ if (list->len < 8) {
+ mp_raise_ValueError(NULL);
+ }
+ }
+ CAN_TypeDef *can = self->can.Instance;
+ uint32_t esr = can->ESR;
+ list->items[0] = MP_OBJ_NEW_SMALL_INT(esr >> CAN_ESR_TEC_Pos & 0xff);
+ list->items[1] = MP_OBJ_NEW_SMALL_INT(esr >> CAN_ESR_REC_Pos & 0xff);
+ list->items[2] = MP_OBJ_NEW_SMALL_INT(self->num_error_warning);
+ list->items[3] = MP_OBJ_NEW_SMALL_INT(self->num_error_passive);
+ list->items[4] = MP_OBJ_NEW_SMALL_INT(self->num_bus_off);
+ int n_tx_pending = 0x01121223 >> ((can->TSR >> CAN_TSR_TME_Pos & 7) << 2) & 0xf;
+ list->items[5] = MP_OBJ_NEW_SMALL_INT(n_tx_pending);
+ list->items[6] = MP_OBJ_NEW_SMALL_INT(can->RF0R >> CAN_RF0R_FMP0_Pos & 3);
+ list->items[7] = MP_OBJ_NEW_SMALL_INT(can->RF1R >> CAN_RF1R_FMP1_Pos & 3);
+ return MP_OBJ_FROM_PTR(list);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_can_info_obj, 1, 2, pyb_can_info);
+
/// \method any(fifo)
/// Return `True` if any message waiting on the FIFO, else `False`.
STATIC mp_obj_t pyb_can_any(mp_obj_t self_in, mp_obj_t fifo_in) {
@@ -454,6 +590,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(pyb_can_any_obj, pyb_can_any);
///
/// Return value: `None`.
STATIC mp_obj_t pyb_can_send(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum { ARG_data, ARG_id, ARG_timeout, ARG_rtr };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_data, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
{ MP_QSTR_id, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} },
@@ -469,7 +606,7 @@ STATIC mp_obj_t pyb_can_send(size_t n_args, const mp_obj_t *pos_args, mp_map_t *
// get the buffer to send from
mp_buffer_info_t bufinfo;
uint8_t data[1];
- pyb_buf_get_for_send(args[0].u_obj, &bufinfo, data);
+ pyb_buf_get_for_send(args[ARG_data].u_obj, &bufinfo, data);
if (bufinfo.len > 8) {
mp_raise_ValueError("CAN data field too long");
@@ -478,13 +615,13 @@ STATIC mp_obj_t pyb_can_send(size_t n_args, const mp_obj_t *pos_args, mp_map_t *
// send the data
CanTxMsgTypeDef tx_msg;
if (self->extframe) {
- tx_msg.ExtId = args[1].u_int & 0x1FFFFFFF;
+ tx_msg.ExtId = args[ARG_id].u_int & 0x1FFFFFFF;
tx_msg.IDE = CAN_ID_EXT;
} else {
- tx_msg.StdId = args[1].u_int & 0x7FF;
+ tx_msg.StdId = args[ARG_id].u_int & 0x7FF;
tx_msg.IDE = CAN_ID_STD;
}
- if (args[3].u_bool == false) {
+ if (args[ARG_rtr].u_bool == false) {
tx_msg.RTR = CAN_RTR_DATA;
} else {
tx_msg.RTR = CAN_RTR_REMOTE;
@@ -495,7 +632,7 @@ STATIC mp_obj_t pyb_can_send(size_t n_args, const mp_obj_t *pos_args, mp_map_t *
}
self->can.pTxMsg = &tx_msg;
- HAL_StatusTypeDef status = CAN_Transmit(&self->can, args[2].u_int);
+ HAL_StatusTypeDef status = CAN_Transmit(&self->can, args[ARG_timeout].u_int);
if (status != HAL_OK) {
mp_hal_raise(status);
@@ -505,17 +642,20 @@ STATIC mp_obj_t pyb_can_send(size_t n_args, const mp_obj_t *pos_args, mp_map_t *
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_can_send_obj, 1, pyb_can_send);
-/// \method recv(fifo, *, timeout=5000)
+/// \method recv(fifo, list=None, *, timeout=5000)
///
/// Receive data on the bus:
///
/// - `fifo` is an integer, which is the FIFO to receive on
+/// - `list` if not None is a list with at least 4 elements
/// - `timeout` is the timeout in milliseconds to wait for the receive.
///
/// Return value: buffer of data bytes.
STATIC mp_obj_t pyb_can_recv(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum { ARG_fifo, ARG_list, ARG_timeout };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_fifo, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} },
+ { MP_QSTR_list, MP_ARG_OBJ, {.u_obj = mp_const_none} },
{ MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 5000} },
};
@@ -526,57 +666,82 @@ STATIC mp_obj_t pyb_can_recv(size_t n_args, const mp_obj_t *pos_args, mp_map_t *
// receive the data
CanRxMsgTypeDef rx_msg;
- self->can.pRxMsg = self->can.pRx1Msg = &rx_msg;
- HAL_StatusTypeDef status = HAL_CAN_Receive(&self->can, args[0].u_int, args[1].u_int);
-
- if (status != HAL_OK) {
- mp_hal_raise(status);
+ int ret = can_receive(self->can.Instance, args[ARG_fifo].u_int, &rx_msg, args[ARG_timeout].u_int);
+ if (ret < 0) {
+ mp_raise_OSError(-ret);
}
// Manage the rx state machine
- if ((args[0].u_int == CAN_FIFO0 && self->rxcallback0 != mp_const_none) ||
- (args[0].u_int == CAN_FIFO1 && self->rxcallback1 != mp_const_none)) {
- byte *state = (args[0].u_int == CAN_FIFO0) ? &self->rx_state0 : &self->rx_state1;
+ mp_int_t fifo = args[ARG_fifo].u_int;
+ if ((fifo == CAN_FIFO0 && self->rxcallback0 != mp_const_none) ||
+ (fifo == CAN_FIFO1 && self->rxcallback1 != mp_const_none)) {
+ byte *state = (fifo == CAN_FIFO0) ? &self->rx_state0 : &self->rx_state1;
switch (*state) {
case RX_STATE_FIFO_EMPTY:
break;
case RX_STATE_MESSAGE_PENDING:
- if (__HAL_CAN_MSG_PENDING(&self->can, args[0].u_int) == 0) {
+ if (__HAL_CAN_MSG_PENDING(&self->can, fifo) == 0) {
// Fifo is empty
- __HAL_CAN_ENABLE_IT(&self->can, (args[0].u_int == CAN_FIFO0) ? CAN_IT_FMP0 : CAN_IT_FMP1);
+ __HAL_CAN_ENABLE_IT(&self->can, (fifo == CAN_FIFO0) ? CAN_IT_FMP0 : CAN_IT_FMP1);
*state = RX_STATE_FIFO_EMPTY;
}
break;
case RX_STATE_FIFO_FULL:
- __HAL_CAN_ENABLE_IT(&self->can, (args[0].u_int == CAN_FIFO0) ? CAN_IT_FF0 : CAN_IT_FF1);
+ __HAL_CAN_ENABLE_IT(&self->can, (fifo == CAN_FIFO0) ? CAN_IT_FF0 : CAN_IT_FF1);
*state = RX_STATE_MESSAGE_PENDING;
break;
case RX_STATE_FIFO_OVERFLOW:
- __HAL_CAN_ENABLE_IT(&self->can, (args[0].u_int == CAN_FIFO0) ? CAN_IT_FOV0 : CAN_IT_FOV1);
- __HAL_CAN_ENABLE_IT(&self->can, (args[0].u_int == CAN_FIFO0) ? CAN_IT_FF0 : CAN_IT_FF1);
+ __HAL_CAN_ENABLE_IT(&self->can, (fifo == CAN_FIFO0) ? CAN_IT_FOV0 : CAN_IT_FOV1);
+ __HAL_CAN_ENABLE_IT(&self->can, (fifo == CAN_FIFO0) ? CAN_IT_FF0 : CAN_IT_FF1);
*state = RX_STATE_MESSAGE_PENDING;
break;
}
}
- // return the received data
- // TODO use a namedtuple (when namedtuple types can be stored in ROM)
- mp_obj_tuple_t *tuple = mp_obj_new_tuple(4, NULL);
- if (rx_msg.IDE == CAN_ID_STD) {
- tuple->items[0] = MP_OBJ_NEW_SMALL_INT(rx_msg.StdId);
+ // Create the tuple, or get the list, that will hold the return values
+ // Also populate the fourth element, either a new bytes or reuse existing memoryview
+ mp_obj_t ret_obj = args[ARG_list].u_obj;
+ mp_obj_t *items;
+ if (ret_obj == mp_const_none) {
+ ret_obj = mp_obj_new_tuple(4, NULL);
+ items = ((mp_obj_tuple_t*)MP_OBJ_TO_PTR(ret_obj))->items;
+ items[3] = mp_obj_new_bytes(&rx_msg.Data[0], rx_msg.DLC);
} else {
- tuple->items[0] = MP_OBJ_NEW_SMALL_INT(rx_msg.ExtId);
+ // User should provide a list of length at least 4 to hold the values
+ if (!MP_OBJ_IS_TYPE(ret_obj, &mp_type_list)) {
+ mp_raise_TypeError(NULL);
+ }
+ mp_obj_list_t *list = MP_OBJ_TO_PTR(ret_obj);
+ if (list->len < 4) {
+ mp_raise_ValueError(NULL);
+ }
+ items = list->items;
+ // Fourth element must be a memoryview which we assume points to a
+ // byte-like array which is large enough, and then we resize it inplace
+ if (!MP_OBJ_IS_TYPE(items[3], &mp_type_memoryview)) {
+ mp_raise_TypeError(NULL);
+ }
+ mp_obj_array_t *mv = MP_OBJ_TO_PTR(items[3]);
+ if (!(mv->typecode == (MP_OBJ_ARRAY_TYPECODE_FLAG_RW | BYTEARRAY_TYPECODE)
+ || (mv->typecode | 0x20) == (MP_OBJ_ARRAY_TYPECODE_FLAG_RW | 'b'))) {
+ mp_raise_ValueError(NULL);
+ }
+ mv->len = rx_msg.DLC;
+ memcpy(mv->items, &rx_msg.Data[0], rx_msg.DLC);
}
- tuple->items[1] = rx_msg.RTR == CAN_RTR_REMOTE ? mp_const_true : mp_const_false;
- tuple->items[2] = MP_OBJ_NEW_SMALL_INT(rx_msg.FMI);
- vstr_t vstr;
- vstr_init_len(&vstr, rx_msg.DLC);
- for (mp_uint_t i = 0; i < rx_msg.DLC; i++) {
- vstr.buf[i] = rx_msg.Data[i]; // Data is uint32_t but holds only 1 byte
+
+ // Populate the first 3 values of the tuple/list
+ if (rx_msg.IDE == CAN_ID_STD) {
+ items[0] = MP_OBJ_NEW_SMALL_INT(rx_msg.StdId);
+ } else {
+ items[0] = MP_OBJ_NEW_SMALL_INT(rx_msg.ExtId);
}
- tuple->items[3] = mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
- return tuple;
+ items[1] = rx_msg.RTR == CAN_RTR_REMOTE ? mp_const_true : mp_const_false;
+ items[2] = MP_OBJ_NEW_SMALL_INT(rx_msg.FMI);
+
+ // Return the result
+ return ret_obj;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_can_recv_obj, 1, pyb_can_recv);
@@ -617,6 +782,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(pyb_can_clearfilter_obj, pyb_can_clearfilter);
/// Return value: `None`.
#define EXTENDED_ID_TO_16BIT_FILTER(id) (((id & 0xC00000) >> 13) | ((id & 0x38000) >> 15)) | 8
STATIC mp_obj_t pyb_can_setfilter(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum { ARG_bank, ARG_mode, ARG_fifo, ARG_params, ARG_rtr };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_bank, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} },
{ MP_QSTR_mode, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} },
@@ -635,20 +801,20 @@ STATIC mp_obj_t pyb_can_setfilter(size_t n_args, const mp_obj_t *pos_args, mp_ma
mp_uint_t rtr_masks[4] = {0, 0, 0, 0};
mp_obj_t *rtr_flags;
mp_obj_t *params;
- mp_obj_get_array(args[3].u_obj, &len, &params);
- if (args[4].u_obj != MP_OBJ_NULL){
- mp_obj_get_array(args[4].u_obj, &rtr_len, &rtr_flags);
+ mp_obj_get_array(args[ARG_params].u_obj, &len, &params);
+ if (args[ARG_rtr].u_obj != MP_OBJ_NULL){
+ mp_obj_get_array(args[ARG_rtr].u_obj, &rtr_len, &rtr_flags);
}
CAN_FilterConfTypeDef filter;
- if (args[1].u_int == MASK16 || args[1].u_int == LIST16) {
+ if (args[ARG_mode].u_int == MASK16 || args[ARG_mode].u_int == LIST16) {
if (len != 4) {
goto error;
}
filter.FilterScale = CAN_FILTERSCALE_16BIT;
if (self->extframe) {
- if (args[4].u_obj != MP_OBJ_NULL) {
- if (args[1].u_int == MASK16) {
+ if (args[ARG_rtr].u_obj != MP_OBJ_NULL) {
+ if (args[ARG_mode].u_int == MASK16) {
rtr_masks[0] = mp_obj_get_int(rtr_flags[0]) ? 0x02 : 0;
rtr_masks[1] = 0x02;
rtr_masks[2] = mp_obj_get_int(rtr_flags[1]) ? 0x02 : 0;
@@ -665,8 +831,8 @@ STATIC mp_obj_t pyb_can_setfilter(size_t n_args, const mp_obj_t *pos_args, mp_ma
filter.FilterIdHigh = EXTENDED_ID_TO_16BIT_FILTER(mp_obj_get_int(params[2])) | rtr_masks[2]; // id2
filter.FilterMaskIdHigh = EXTENDED_ID_TO_16BIT_FILTER(mp_obj_get_int(params[3])) | rtr_masks[3]; // mask2
} else { // Basic frames
- if (args[4].u_obj != MP_OBJ_NULL) {
- if (args[1].u_int == MASK16) {
+ if (args[ARG_rtr].u_obj != MP_OBJ_NULL) {
+ if (args[ARG_mode].u_int == MASK16) {
rtr_masks[0] = mp_obj_get_int(rtr_flags[0]) ? 0x10 : 0;
rtr_masks[1] = 0x10;
rtr_masks[2] = mp_obj_get_int(rtr_flags[1]) ? 0x10 : 0;
@@ -683,20 +849,20 @@ STATIC mp_obj_t pyb_can_setfilter(size_t n_args, const mp_obj_t *pos_args, mp_ma
filter.FilterIdHigh = (mp_obj_get_int(params[2]) << 5) | rtr_masks[2]; // id2
filter.FilterMaskIdHigh = (mp_obj_get_int(params[3]) << 5) | rtr_masks[3]; // mask2
}
- if (args[1].u_int == MASK16) {
+ if (args[ARG_mode].u_int == MASK16) {
filter.FilterMode = CAN_FILTERMODE_IDMASK;
}
- if (args[1].u_int == LIST16) {
+ if (args[ARG_mode].u_int == LIST16) {
filter.FilterMode = CAN_FILTERMODE_IDLIST;
}
}
- else if (args[1].u_int == MASK32 || args[1].u_int == LIST32) {
+ else if (args[ARG_mode].u_int == MASK32 || args[ARG_mode].u_int == LIST32) {
if (len != 2) {
goto error;
}
filter.FilterScale = CAN_FILTERSCALE_32BIT;
- if (args[4].u_obj != MP_OBJ_NULL) {
- if (args[1].u_int == MASK32) {
+ if (args[ARG_rtr].u_obj != MP_OBJ_NULL) {
+ if (args[ARG_mode].u_int == MASK32) {
rtr_masks[0] = mp_obj_get_int(rtr_flags[0]) ? 0x02 : 0;
rtr_masks[1] = 0x02;
} else { // LIST32
@@ -708,18 +874,18 @@ STATIC mp_obj_t pyb_can_setfilter(size_t n_args, const mp_obj_t *pos_args, mp_ma
filter.FilterIdLow = (((mp_obj_get_int(params[0]) & 0x00001FFF) << 3) | 4) | rtr_masks[0];
filter.FilterMaskIdHigh = (mp_obj_get_int(params[1]) & 0x1FFFE000 ) >> 13;
filter.FilterMaskIdLow = (((mp_obj_get_int(params[1]) & 0x00001FFF) << 3) | 4) | rtr_masks[1];
- if (args[1].u_int == MASK32) {
+ if (args[ARG_mode].u_int == MASK32) {
filter.FilterMode = CAN_FILTERMODE_IDMASK;
}
- if (args[1].u_int == LIST32) {
+ if (args[ARG_mode].u_int == LIST32) {
filter.FilterMode = CAN_FILTERMODE_IDLIST;
}
} else {
goto error;
}
- filter.FilterFIFOAssignment = args[2].u_int; // fifo
- filter.FilterNumber = args[0].u_int; // bank
+ filter.FilterFIFOAssignment = args[ARG_fifo].u_int;
+ filter.FilterNumber = args[ARG_bank].u_int;
if (self->can_id == 1) {
if (filter.FilterNumber >= can2_start_bank) {
goto error;
@@ -760,13 +926,15 @@ STATIC mp_obj_t pyb_can_rxcallback(mp_obj_t self_in, mp_obj_t fifo_in, mp_obj_t
*callback = callback_in;
} else if (mp_obj_is_callable(callback_in)) {
*callback = callback_in;
- uint32_t irq;
+ uint32_t irq = 0;
if (self->can_id == PYB_CAN_1) {
irq = (fifo == 0) ? CAN1_RX0_IRQn : CAN1_RX1_IRQn;
+ #if defined(CAN2)
} else {
irq = (fifo == 0) ? CAN2_RX0_IRQn : CAN2_RX1_IRQn;
+ #endif
}
- HAL_NVIC_SetPriority(irq, IRQ_PRI_CAN, IRQ_SUBPRI_CAN);
+ NVIC_SetPriority(irq, IRQ_PRI_CAN);
HAL_NVIC_EnableIRQ(irq);
__HAL_CAN_ENABLE_IT(&self->can, (fifo == 0) ? CAN_IT_FMP0 : CAN_IT_FMP1);
__HAL_CAN_ENABLE_IT(&self->can, (fifo == 0) ? CAN_IT_FF0 : CAN_IT_FF1);
@@ -780,6 +948,9 @@ STATIC const mp_rom_map_elem_t pyb_can_locals_dict_table[] = {
// instance methods
{ MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&pyb_can_init_obj) },
{ MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&pyb_can_deinit_obj) },
+ { MP_ROM_QSTR(MP_QSTR_restart), MP_ROM_PTR(&pyb_can_restart_obj) },
+ { MP_ROM_QSTR(MP_QSTR_state), MP_ROM_PTR(&pyb_can_state_obj) },
+ { MP_ROM_QSTR(MP_QSTR_info), MP_ROM_PTR(&pyb_can_info_obj) },
{ MP_ROM_QSTR(MP_QSTR_any), MP_ROM_PTR(&pyb_can_any_obj) },
{ MP_ROM_QSTR(MP_QSTR_send), MP_ROM_PTR(&pyb_can_send_obj) },
{ MP_ROM_QSTR(MP_QSTR_recv), MP_ROM_PTR(&pyb_can_recv_obj) },
@@ -799,6 +970,13 @@ STATIC const mp_rom_map_elem_t pyb_can_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_LIST16), MP_ROM_INT(LIST16) },
{ MP_ROM_QSTR(MP_QSTR_MASK32), MP_ROM_INT(MASK32) },
{ MP_ROM_QSTR(MP_QSTR_LIST32), MP_ROM_INT(LIST32) },
+
+ // values for CAN.state()
+ { MP_ROM_QSTR(MP_QSTR_STOPPED), MP_ROM_INT(CAN_STATE_STOPPED) },
+ { MP_ROM_QSTR(MP_QSTR_ERROR_ACTIVE), MP_ROM_INT(CAN_STATE_ERROR_ACTIVE) },
+ { MP_ROM_QSTR(MP_QSTR_ERROR_WARNING), MP_ROM_INT(CAN_STATE_ERROR_WARNING) },
+ { MP_ROM_QSTR(MP_QSTR_ERROR_PASSIVE), MP_ROM_INT(CAN_STATE_ERROR_PASSIVE) },
+ { MP_ROM_QSTR(MP_QSTR_BUS_OFF), MP_ROM_INT(CAN_STATE_BUS_OFF) },
};
STATIC MP_DEFINE_CONST_DICT(pyb_can_locals_dict, pyb_can_locals_dict_table);
@@ -881,6 +1059,21 @@ void can_rx_irq_handler(uint can_id, uint fifo_id) {
}
}
+void can_sce_irq_handler(uint can_id) {
+ pyb_can_obj_t *self = MP_STATE_PORT(pyb_can_obj_all)[can_id - 1];
+ if (self) {
+ self->can.Instance->MSR = CAN_MSR_ERRI;
+ uint32_t esr = self->can.Instance->ESR;
+ if (esr & CAN_ESR_BOFF) {
+ ++self->num_bus_off;
+ } else if (esr & CAN_ESR_EPVF) {
+ ++self->num_error_passive;
+ } else if (esr & CAN_ESR_EWGF) {
+ ++self->num_error_warning;
+ }
+ }
+}
+
STATIC const mp_stream_p_t can_stream_p = {
//.read = can_read, // is read sensible for CAN?
//.write = can_write, // is write sensible for CAN?
diff --git a/ports/stm32/can.h b/ports/stm32/can.h
index 860012813..54e7deaa5 100644
--- a/ports/stm32/can.h
+++ b/ports/stm32/can.h
@@ -23,8 +23,8 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
-#ifndef MICROPY_INCLUDED_STMHAL_CAN_H
-#define MICROPY_INCLUDED_STMHAL_CAN_H
+#ifndef MICROPY_INCLUDED_STM32_CAN_H
+#define MICROPY_INCLUDED_STM32_CAN_H
#define PYB_CAN_1 (1)
#define PYB_CAN_2 (2)
@@ -34,5 +34,6 @@ extern const mp_obj_type_t pyb_can_type;
void can_init0(void);
void can_deinit(void);
void can_rx_irq_handler(uint can_id, uint fifo_id);
+void can_sce_irq_handler(uint can_id);
-#endif // MICROPY_INCLUDED_STMHAL_CAN_H
+#endif // MICROPY_INCLUDED_STM32_CAN_H
diff --git a/ports/stm32/dac.c b/ports/stm32/dac.c
index 268b1bcfb..559bb0b0d 100644
--- a/ports/stm32/dac.c
+++ b/ports/stm32/dac.c
@@ -29,11 +29,11 @@
#include <string.h>
#include "py/runtime.h"
+#include "py/mphal.h"
#include "timer.h"
#include "dac.h"
#include "dma.h"
#include "pin.h"
-#include "genhdr/pins.h"
/// \moduleref pyb
/// \class DAC - digital to analog conversion
@@ -66,6 +66,10 @@
#if defined(MICROPY_HW_ENABLE_DAC) && MICROPY_HW_ENABLE_DAC
+#if defined(STM32H7)
+#define DAC DAC1
+#endif
+
STATIC DAC_HandleTypeDef DAC_Handle;
void dac_init(void) {
@@ -102,10 +106,14 @@ STATIC uint32_t TIMx_Config(mp_obj_t timer) {
// work out the trigger channel (only certain ones are supported)
if (tim->Instance == TIM2) {
return DAC_TRIGGER_T2_TRGO;
+ #if defined(TIM4)
} else if (tim->Instance == TIM4) {
return DAC_TRIGGER_T4_TRGO;
+ #endif
+ #if defined(TIM5)
} else if (tim->Instance == TIM5) {
return DAC_TRIGGER_T5_TRGO;
+ #endif
#if defined(TIM6)
} else if (tim->Instance == TIM6) {
return DAC_TRIGGER_T6_TRGO;
@@ -137,14 +145,24 @@ typedef struct _pyb_dac_obj_t {
mp_obj_base_t base;
uint32_t dac_channel; // DAC_CHANNEL_1 or DAC_CHANNEL_2
const dma_descr_t *tx_dma_descr;
- uint16_t pin; // GPIO_PIN_4 or GPIO_PIN_5
+ mp_hal_pin_obj_t pin; // pin_A4 or pin_A5
uint8_t bits; // 8 or 12
uint8_t state;
+ uint8_t outbuf_single;
+ uint8_t outbuf_waveform;
} pyb_dac_obj_t;
+STATIC void pyb_dac_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
+ pyb_dac_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ mp_printf(print, "DAC(%u, bits=%u)",
+ self->dac_channel == DAC_CHANNEL_1 ? 1 : 2,
+ self->bits);
+}
+
STATIC mp_obj_t pyb_dac_init_helper(pyb_dac_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_bits, MP_ARG_INT, {.u_int = 8} },
+ { MP_QSTR_buffering, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} },
};
// parse args
@@ -152,23 +170,21 @@ STATIC mp_obj_t pyb_dac_init_helper(pyb_dac_obj_t *self, size_t n_args, const mp
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
// GPIO configuration
- GPIO_InitTypeDef GPIO_InitStructure;
- GPIO_InitStructure.Pin = self->pin;
- GPIO_InitStructure.Mode = GPIO_MODE_ANALOG;
- GPIO_InitStructure.Pull = GPIO_NOPULL;
- HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);
+ mp_hal_pin_config(self->pin, MP_HAL_PIN_MODE_ANALOG, MP_HAL_PIN_PULL_NONE, 0);
// DAC peripheral clock
- #if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7)
+ #if defined(STM32F4) || defined(STM32F7)
__DAC_CLK_ENABLE();
- #elif defined(MCU_SERIES_L4)
+ #elif defined(STM32H7)
+ __HAL_RCC_DAC12_CLK_ENABLE();
+ #elif defined(STM32F0) || defined(STM32L4)
__HAL_RCC_DAC1_CLK_ENABLE();
#else
#error Unsupported Processor
#endif
// stop anything already going on
- __DMA1_CLK_ENABLE();
+ __HAL_RCC_DMA1_CLK_ENABLE();
DMA_HandleTypeDef DMA_Handle;
/* Get currently configured dma */
dma_init_handle(&DMA_Handle, self->tx_dma_descr, (void*)NULL);
@@ -189,6 +205,19 @@ STATIC mp_obj_t pyb_dac_init_helper(pyb_dac_obj_t *self, size_t n_args, const mp
mp_raise_ValueError("unsupported bits");
}
+ // set output buffer config
+ if (args[1].u_obj == mp_const_none) {
+ // due to legacy, default values differ for single and waveform outputs
+ self->outbuf_single = DAC_OUTPUTBUFFER_DISABLE;
+ self->outbuf_waveform = DAC_OUTPUTBUFFER_ENABLE;
+ } else if (mp_obj_is_true(args[1].u_obj)) {
+ self->outbuf_single = DAC_OUTPUTBUFFER_ENABLE;
+ self->outbuf_waveform = DAC_OUTPUTBUFFER_ENABLE;
+ } else {
+ self->outbuf_single = DAC_OUTPUTBUFFER_DISABLE;
+ self->outbuf_waveform = DAC_OUTPUTBUFFER_DISABLE;
+ }
+
// reset state of DAC
self->state = DAC_STATE_RESET;
@@ -213,9 +242,9 @@ STATIC mp_obj_t pyb_dac_make_new(const mp_obj_type_t *type, size_t n_args, size_
dac_id = mp_obj_get_int(args[0]);
} else {
const pin_obj_t *pin = pin_find(args[0]);
- if (pin == &pin_A4) {
+ if (pin == pin_A4) {
dac_id = 1;
- } else if (pin == &pin_A5) {
+ } else if (pin == pin_A5) {
dac_id = 2;
} else {
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "Pin(%q) doesn't have DAC capabilities", pin->name));
@@ -226,11 +255,11 @@ STATIC mp_obj_t pyb_dac_make_new(const mp_obj_type_t *type, size_t n_args, size_
dac->base.type = &pyb_dac_type;
if (dac_id == 1) {
- dac->pin = GPIO_PIN_4;
+ dac->pin = pin_A4;
dac->dac_channel = DAC_CHANNEL_1;
dac->tx_dma_descr = &dma_DAC_1_TX;
} else if (dac_id == 2) {
- dac->pin = GPIO_PIN_5;
+ dac->pin = pin_A5;
dac->dac_channel = DAC_CHANNEL_2;
dac->tx_dma_descr = &dma_DAC_2_TX;
} else {
@@ -257,10 +286,18 @@ STATIC mp_obj_t pyb_dac_deinit(mp_obj_t self_in) {
pyb_dac_obj_t *self = self_in;
if (self->dac_channel == DAC_CHANNEL_1) {
DAC_Handle.Instance->CR &= ~DAC_CR_EN1;
+ #if defined(STM32H7) || defined(STM32L4)
+ DAC->MCR = (DAC->MCR & ~(7 << DAC_MCR_MODE1_Pos)) | 2 << DAC_MCR_MODE1_Pos;
+ #else
DAC_Handle.Instance->CR |= DAC_CR_BOFF1;
+ #endif
} else {
DAC_Handle.Instance->CR &= ~DAC_CR_EN2;
+ #if defined(STM32H7) || defined(STM32L4)
+ DAC->MCR = (DAC->MCR & ~(7 << DAC_MCR_MODE2_Pos)) | 2 << DAC_MCR_MODE2_Pos;
+ #else
DAC_Handle.Instance->CR |= DAC_CR_BOFF2;
+ #endif
}
return mp_const_none;
}
@@ -280,7 +317,7 @@ STATIC mp_obj_t pyb_dac_noise(mp_obj_t self_in, mp_obj_t freq) {
// configure DAC to trigger via TIM6
DAC_ChannelConfTypeDef config;
config.DAC_Trigger = DAC_TRIGGER_T6_TRGO;
- config.DAC_OutputBuffer = DAC_OUTPUTBUFFER_ENABLE;
+ config.DAC_OutputBuffer = self->outbuf_waveform;
HAL_DAC_ConfigChannel(&DAC_Handle, &config, self->dac_channel);
self->state = DAC_STATE_BUILTIN_WAVEFORM;
}
@@ -310,7 +347,7 @@ STATIC mp_obj_t pyb_dac_triangle(mp_obj_t self_in, mp_obj_t freq) {
// configure DAC to trigger via TIM6
DAC_ChannelConfTypeDef config;
config.DAC_Trigger = DAC_TRIGGER_T6_TRGO;
- config.DAC_OutputBuffer = DAC_OUTPUTBUFFER_ENABLE;
+ config.DAC_OutputBuffer = self->outbuf_waveform;
HAL_DAC_ConfigChannel(&DAC_Handle, &config, self->dac_channel);
self->state = DAC_STATE_BUILTIN_WAVEFORM;
}
@@ -333,7 +370,7 @@ STATIC mp_obj_t pyb_dac_write(mp_obj_t self_in, mp_obj_t val) {
if (self->state != DAC_STATE_WRITE_SINGLE) {
DAC_ChannelConfTypeDef config;
config.DAC_Trigger = DAC_TRIGGER_NONE;
- config.DAC_OutputBuffer = DAC_OUTPUTBUFFER_DISABLE;
+ config.DAC_OutputBuffer = self->outbuf_single;
HAL_DAC_ConfigChannel(&DAC_Handle, &config, self->dac_channel);
self->state = DAC_STATE_WRITE_SINGLE;
}
@@ -395,7 +432,7 @@ mp_obj_t pyb_dac_write_timed(size_t n_args, const mp_obj_t *pos_args, mp_map_t *
dac_trigger = TIMx_Config(args[1].u_obj);
}
- __DMA1_CLK_ENABLE();
+ __HAL_RCC_DMA1_CLK_ENABLE();
DMA_HandleTypeDef DMA_Handle;
/* Get currently configured dma */
@@ -445,7 +482,7 @@ mp_obj_t pyb_dac_write_timed(size_t n_args, const mp_obj_t *pos_args, mp_map_t *
if (self->state != DAC_STATE_DMA_WAVEFORM + dac_trigger) {
DAC_ChannelConfTypeDef config;
config.DAC_Trigger = dac_trigger;
- config.DAC_OutputBuffer = DAC_OUTPUTBUFFER_ENABLE;
+ config.DAC_OutputBuffer = self->outbuf_waveform;
HAL_DAC_ConfigChannel(&DAC_Handle, &config, self->dac_channel);
self->state = DAC_STATE_DMA_WAVEFORM + dac_trigger;
}
@@ -499,6 +536,7 @@ STATIC MP_DEFINE_CONST_DICT(pyb_dac_locals_dict, pyb_dac_locals_dict_table);
const mp_obj_type_t pyb_dac_type = {
{ &mp_type_type },
.name = MP_QSTR_DAC,
+ .print = pyb_dac_print,
.make_new = pyb_dac_make_new,
.locals_dict = (mp_obj_dict_t*)&pyb_dac_locals_dict,
};
diff --git a/ports/stm32/dac.h b/ports/stm32/dac.h
index f487f52a9..1d8f0ab61 100644
--- a/ports/stm32/dac.h
+++ b/ports/stm32/dac.h
@@ -23,11 +23,11 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
-#ifndef MICROPY_INCLUDED_STMHAL_DAC_H
-#define MICROPY_INCLUDED_STMHAL_DAC_H
+#ifndef MICROPY_INCLUDED_STM32_DAC_H
+#define MICROPY_INCLUDED_STM32_DAC_H
void dac_init(void);
extern const mp_obj_type_t pyb_dac_type;
-#endif // MICROPY_INCLUDED_STMHAL_DAC_H
+#endif // MICROPY_INCLUDED_STM32_DAC_H
diff --git a/ports/stm32/dma.c b/ports/stm32/dma.c
index df6275d65..dc1ad6c1c 100644
--- a/ports/stm32/dma.c
+++ b/ports/stm32/dma.c
@@ -52,10 +52,10 @@ typedef enum {
dma_id_15,
} dma_id_t;
-typedef struct _dma_descr_t {
- #if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7)
+struct _dma_descr_t {
+ #if defined(STM32F4) || defined(STM32F7) || defined(STM32H7)
DMA_Stream_TypeDef *instance;
- #elif defined(MCU_SERIES_L4)
+ #elif defined(STM32F0) || defined(STM32L4)
DMA_Channel_TypeDef *instance;
#else
#error "Unsupported Processor"
@@ -64,14 +64,14 @@ typedef struct _dma_descr_t {
uint32_t transfer_direction; // periph to memory or vice-versa
dma_id_t id;
const DMA_InitTypeDef *init;
-} dma_descr_t;
+};
// Default parameters to dma_init() shared by spi and i2c; Channel and Direction
// vary depending on the peripheral instance so they get passed separately
static const DMA_InitTypeDef dma_init_struct_spi_i2c = {
- #if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7)
+ #if defined(STM32F4) || defined(STM32F7)
.Channel = 0,
- #elif defined(MCU_SERIES_L4)
+ #elif defined(STM32L4)
.Request = 0,
#endif
.Direction = 0,
@@ -81,7 +81,7 @@ static const DMA_InitTypeDef dma_init_struct_spi_i2c = {
.MemDataAlignment = DMA_MDATAALIGN_BYTE,
.Mode = DMA_NORMAL,
.Priority = DMA_PRIORITY_LOW,
- #if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7)
+ #if defined(STM32F4) || defined(STM32F7)
.FIFOMode = DMA_FIFOMODE_DISABLE,
.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL,
.MemBurst = DMA_MBURST_INC4,
@@ -89,12 +89,12 @@ static const DMA_InitTypeDef dma_init_struct_spi_i2c = {
#endif
};
-#if defined(MICROPY_HW_HAS_SDCARD) && MICROPY_HW_HAS_SDCARD
+#if defined(MICROPY_HW_HAS_SDCARD) && MICROPY_HW_HAS_SDCARD && !defined(STM32H7)
// Parameters to dma_init() for SDIO tx and rx.
static const DMA_InitTypeDef dma_init_struct_sdio = {
- #if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7)
+ #if defined(STM32F4) || defined(STM32F7)
.Channel = 0,
- #elif defined(MCU_SERIES_L4)
+ #elif defined(STM32L4)
.Request = 0,
#endif
.Direction = 0,
@@ -102,13 +102,13 @@ static const DMA_InitTypeDef dma_init_struct_sdio = {
.MemInc = DMA_MINC_ENABLE,
.PeriphDataAlignment = DMA_PDATAALIGN_WORD,
.MemDataAlignment = DMA_MDATAALIGN_WORD,
- #if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7)
+ #if defined(STM32F4) || defined(STM32F7)
.Mode = DMA_PFCTRL,
- #elif defined(MCU_SERIES_L4)
+ #elif defined(STM32L4)
.Mode = DMA_NORMAL,
#endif
.Priority = DMA_PRIORITY_VERY_HIGH,
- #if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7)
+ #if defined(STM32F4) || defined(STM32F7)
.FIFOMode = DMA_FIFOMODE_ENABLE,
.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL,
.MemBurst = DMA_MBURST_INC4,
@@ -120,9 +120,9 @@ static const DMA_InitTypeDef dma_init_struct_sdio = {
#if defined(MICROPY_HW_ENABLE_DAC) && MICROPY_HW_ENABLE_DAC
// Default parameters to dma_init() for DAC tx
static const DMA_InitTypeDef dma_init_struct_dac = {
- #if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7)
+ #if defined(STM32F4) || defined(STM32F7)
.Channel = 0,
- #elif defined(MCU_SERIES_L4)
+ #elif defined(STM32L4)
.Request = 0,
#endif
.Direction = 0,
@@ -132,7 +132,7 @@ static const DMA_InitTypeDef dma_init_struct_dac = {
.MemDataAlignment = DMA_MDATAALIGN_BYTE,
.Mode = DMA_NORMAL,
.Priority = DMA_PRIORITY_HIGH,
- #if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7)
+ #if defined(STM32F4) || defined(STM32F7)
.FIFOMode = DMA_FIFOMODE_DISABLE,
.FIFOThreshold = DMA_FIFO_THRESHOLD_HALFFULL,
.MemBurst = DMA_MBURST_SINGLE,
@@ -141,7 +141,46 @@ static const DMA_InitTypeDef dma_init_struct_dac = {
};
#endif
-#if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7)
+#if defined(STM32F0)
+
+#define NCONTROLLERS (2)
+#define NSTREAMS_PER_CONTROLLER (7)
+#define NSTREAM (NCONTROLLERS * NSTREAMS_PER_CONTROLLER)
+
+#define DMA_SUB_INSTANCE_AS_UINT8(dma_channel) (dma_channel)
+
+#define DMA1_ENABLE_MASK (0x007f) // Bits in dma_enable_mask corresponfing to DMA1 (7 channels)
+#define DMA2_ENABLE_MASK (0x0f80) // Bits in dma_enable_mask corresponding to DMA2 (only 5 channels)
+
+// DMA1 streams
+#if MICROPY_HW_ENABLE_DAC
+const dma_descr_t dma_DAC_1_TX = { DMA1_Channel3, HAL_DMA1_CH3_DAC_CH1, DMA_MEMORY_TO_PERIPH, dma_id_3, &dma_init_struct_dac };
+const dma_descr_t dma_DAC_2_TX = { DMA1_Channel4, HAL_DMA1_CH4_DAC_CH2, DMA_MEMORY_TO_PERIPH, dma_id_4, &dma_init_struct_dac };
+#endif
+const dma_descr_t dma_SPI_2_TX = { DMA1_Channel5, HAL_DMA1_CH5_SPI2_TX, DMA_MEMORY_TO_PERIPH, dma_id_5, &dma_init_struct_spi_i2c};
+const dma_descr_t dma_SPI_2_RX = { DMA1_Channel6, HAL_DMA1_CH6_SPI2_RX, DMA_PERIPH_TO_MEMORY, dma_id_6, &dma_init_struct_spi_i2c};
+const dma_descr_t dma_SPI_1_RX = { DMA2_Channel3, HAL_DMA2_CH3_SPI1_RX, DMA_PERIPH_TO_MEMORY, dma_id_3, &dma_init_struct_spi_i2c};
+const dma_descr_t dma_SPI_1_TX = { DMA2_Channel4, HAL_DMA2_CH4_SPI1_TX, DMA_MEMORY_TO_PERIPH, dma_id_4, &dma_init_struct_spi_i2c};
+
+static const uint8_t dma_irqn[NSTREAM] = {
+ DMA1_Ch1_IRQn,
+ DMA1_Ch2_3_DMA2_Ch1_2_IRQn,
+ DMA1_Ch2_3_DMA2_Ch1_2_IRQn,
+ DMA1_Ch4_7_DMA2_Ch3_5_IRQn,
+ DMA1_Ch4_7_DMA2_Ch3_5_IRQn,
+ DMA1_Ch4_7_DMA2_Ch3_5_IRQn,
+ DMA1_Ch4_7_DMA2_Ch3_5_IRQn,
+
+ DMA1_Ch2_3_DMA2_Ch1_2_IRQn,
+ DMA1_Ch2_3_DMA2_Ch1_2_IRQn,
+ DMA1_Ch4_7_DMA2_Ch3_5_IRQn,
+ DMA1_Ch4_7_DMA2_Ch3_5_IRQn,
+ DMA1_Ch4_7_DMA2_Ch3_5_IRQn,
+ 0,
+ 0,
+};
+
+#elif defined(STM32F4) || defined(STM32F7)
#define NCONTROLLERS (2)
#define NSTREAMS_PER_CONTROLLER (8)
@@ -161,7 +200,7 @@ static const DMA_InitTypeDef dma_init_struct_dac = {
// DMA1 streams
const dma_descr_t dma_I2C_1_RX = { DMA1_Stream0, DMA_CHANNEL_1, DMA_PERIPH_TO_MEMORY, dma_id_0, &dma_init_struct_spi_i2c };
const dma_descr_t dma_SPI_3_RX = { DMA1_Stream2, DMA_CHANNEL_0, DMA_PERIPH_TO_MEMORY, dma_id_2, &dma_init_struct_spi_i2c };
-#if defined(MCU_SERIES_F7)
+#if defined(STM32F7)
const dma_descr_t dma_I2C_4_RX = { DMA1_Stream2, DMA_CHANNEL_2, DMA_PERIPH_TO_MEMORY, dma_id_2, &dma_init_struct_spi_i2c };
#endif
const dma_descr_t dma_I2C_3_RX = { DMA1_Stream2, DMA_CHANNEL_3, DMA_PERIPH_TO_MEMORY, dma_id_2, &dma_init_struct_spi_i2c };
@@ -169,7 +208,7 @@ const dma_descr_t dma_I2C_2_RX = { DMA1_Stream2, DMA_CHANNEL_7, DMA_PERIPH_TO_ME
const dma_descr_t dma_SPI_2_RX = { DMA1_Stream3, DMA_CHANNEL_0, DMA_PERIPH_TO_MEMORY, dma_id_3, &dma_init_struct_spi_i2c };
const dma_descr_t dma_SPI_2_TX = { DMA1_Stream4, DMA_CHANNEL_0, DMA_MEMORY_TO_PERIPH, dma_id_4, &dma_init_struct_spi_i2c };
const dma_descr_t dma_I2C_3_TX = { DMA1_Stream4, DMA_CHANNEL_3, DMA_MEMORY_TO_PERIPH, dma_id_4, &dma_init_struct_spi_i2c };
-#if defined(MCU_SERIES_F7)
+#if defined(STM32F7)
const dma_descr_t dma_I2C_4_TX = { DMA1_Stream5, DMA_CHANNEL_2, DMA_MEMORY_TO_PERIPH, dma_id_5, &dma_init_struct_spi_i2c };
#endif
#if defined(MICROPY_HW_ENABLE_DAC) && MICROPY_HW_ENABLE_DAC
@@ -185,7 +224,7 @@ const dma_descr_t dma_I2C_1_TX = { DMA1_Stream6, DMA_CHANNEL_1, DMA_MEMORY_TO_PE
*/
// DMA2 streams
-#if defined(MCU_SERIES_F7) && defined(SDMMC2) && MICROPY_HW_HAS_SDCARD
+#if defined(STM32F7) && defined(SDMMC2) && MICROPY_HW_HAS_SDCARD
const dma_descr_t dma_SDMMC_2_RX= { DMA2_Stream0, DMA_CHANNEL_11, DMA_PERIPH_TO_MEMORY, dma_id_8, &dma_init_struct_sdio };
#endif
const dma_descr_t dma_SPI_1_RX = { DMA2_Stream2, DMA_CHANNEL_3, DMA_PERIPH_TO_MEMORY, dma_id_10, &dma_init_struct_spi_i2c };
@@ -198,7 +237,7 @@ const dma_descr_t dma_SPI_5_TX = { DMA2_Stream4, DMA_CHANNEL_2, DMA_MEMORY_TO_PE
const dma_descr_t dma_SPI_4_TX = { DMA2_Stream4, DMA_CHANNEL_5, DMA_MEMORY_TO_PERIPH, dma_id_12, &dma_init_struct_spi_i2c };
const dma_descr_t dma_SPI_6_TX = { DMA2_Stream5, DMA_CHANNEL_1, DMA_MEMORY_TO_PERIPH, dma_id_13, &dma_init_struct_spi_i2c };
const dma_descr_t dma_SPI_1_TX = { DMA2_Stream5, DMA_CHANNEL_3, DMA_MEMORY_TO_PERIPH, dma_id_13, &dma_init_struct_spi_i2c };
-#if defined(MCU_SERIES_F7) && defined(SDMMC2) && MICROPY_HW_HAS_SDCARD
+#if defined(STM32F7) && defined(SDMMC2) && MICROPY_HW_HAS_SDCARD
const dma_descr_t dma_SDMMC_2_TX= { DMA2_Stream5, DMA_CHANNEL_11, DMA_MEMORY_TO_PERIPH, dma_id_13, &dma_init_struct_sdio };
#endif
const dma_descr_t dma_SPI_6_RX = { DMA2_Stream6, DMA_CHANNEL_1, DMA_PERIPH_TO_MEMORY, dma_id_14, &dma_init_struct_spi_i2c };
@@ -233,7 +272,7 @@ static const uint8_t dma_irqn[NSTREAM] = {
DMA2_Stream7_IRQn,
};
-#elif defined(MCU_SERIES_L4)
+#elif defined(STM32L4)
#define NCONTROLLERS (2)
#define NSTREAMS_PER_CONTROLLER (7)
@@ -308,6 +347,70 @@ static const uint8_t dma_irqn[NSTREAM] = {
DMA2_Channel7_IRQn,
};
+#elif defined(STM32H7)
+
+#define NCONTROLLERS (2)
+#define NSTREAMS_PER_CONTROLLER (8)
+#define NSTREAM (NCONTROLLERS * NSTREAMS_PER_CONTROLLER)
+
+#define DMA_SUB_INSTANCE_AS_UINT8(dma_channel) (dma_channel)
+
+#define DMA1_ENABLE_MASK (0x00ff) // Bits in dma_enable_mask corresponding to DMA1
+#define DMA2_ENABLE_MASK (0xff00) // Bits in dma_enable_mask corresponding to DMA2
+
+// These descriptors are ordered by DMAx_Stream number, and within a stream by channel
+// number. The duplicate streams are ok as long as they aren't used at the same time.
+//
+// Currently I2C and SPI are synchronous and they call dma_init/dma_deinit
+// around each transfer.
+
+// DMA1 streams
+const dma_descr_t dma_I2C_1_RX = { DMA1_Stream0, DMA_REQUEST_I2C1_RX, DMA_PERIPH_TO_MEMORY, dma_id_0, &dma_init_struct_spi_i2c };
+const dma_descr_t dma_SPI_3_RX = { DMA1_Stream2, DMA_REQUEST_SPI3_RX, DMA_PERIPH_TO_MEMORY, dma_id_2, &dma_init_struct_spi_i2c };
+const dma_descr_t dma_I2C_4_RX = { DMA1_Stream2, BDMA_REQUEST_I2C4_RX, DMA_PERIPH_TO_MEMORY, dma_id_2, &dma_init_struct_spi_i2c };
+const dma_descr_t dma_I2C_3_RX = { DMA1_Stream2, DMA_REQUEST_I2C3_RX, DMA_PERIPH_TO_MEMORY, dma_id_2, &dma_init_struct_spi_i2c };
+const dma_descr_t dma_I2C_2_RX = { DMA1_Stream2, DMA_REQUEST_I2C2_RX, DMA_PERIPH_TO_MEMORY, dma_id_2, &dma_init_struct_spi_i2c };
+const dma_descr_t dma_SPI_2_RX = { DMA1_Stream3, DMA_REQUEST_SPI2_RX, DMA_PERIPH_TO_MEMORY, dma_id_3, &dma_init_struct_spi_i2c };
+const dma_descr_t dma_SPI_2_TX = { DMA1_Stream4, DMA_REQUEST_SPI2_TX, DMA_MEMORY_TO_PERIPH, dma_id_4, &dma_init_struct_spi_i2c };
+const dma_descr_t dma_I2C_3_TX = { DMA1_Stream4, DMA_REQUEST_I2C3_TX, DMA_MEMORY_TO_PERIPH, dma_id_4, &dma_init_struct_spi_i2c };
+const dma_descr_t dma_I2C_4_TX = { DMA1_Stream5, BDMA_REQUEST_I2C4_TX, DMA_MEMORY_TO_PERIPH, dma_id_5, &dma_init_struct_spi_i2c };
+#if defined(MICROPY_HW_ENABLE_DAC) && MICROPY_HW_ENABLE_DAC
+const dma_descr_t dma_DAC_1_TX = { DMA1_Stream5, DMA_REQUEST_DAC1_CH1, DMA_MEMORY_TO_PERIPH, dma_id_5, &dma_init_struct_dac };
+const dma_descr_t dma_DAC_2_TX = { DMA1_Stream6, DMA_REQUEST_DAC1_CH2, DMA_MEMORY_TO_PERIPH, dma_id_6, &dma_init_struct_dac };
+#endif
+const dma_descr_t dma_SPI_3_TX = { DMA1_Stream7, DMA_REQUEST_SPI3_TX, DMA_MEMORY_TO_PERIPH, dma_id_7, &dma_init_struct_spi_i2c };
+const dma_descr_t dma_I2C_1_TX = { DMA1_Stream7, DMA_REQUEST_I2C1_TX, DMA_MEMORY_TO_PERIPH, dma_id_7, &dma_init_struct_spi_i2c };
+const dma_descr_t dma_I2C_2_TX = { DMA1_Stream7, DMA_REQUEST_I2C2_TX, DMA_MEMORY_TO_PERIPH, dma_id_7, &dma_init_struct_spi_i2c };
+
+// DMA2 streams
+const dma_descr_t dma_SPI_1_RX = { DMA2_Stream2, DMA_REQUEST_SPI1_RX, DMA_PERIPH_TO_MEMORY, dma_id_10, &dma_init_struct_spi_i2c };
+const dma_descr_t dma_SPI_5_RX = { DMA2_Stream3, DMA_REQUEST_SPI5_RX, DMA_PERIPH_TO_MEMORY, dma_id_11, &dma_init_struct_spi_i2c };
+const dma_descr_t dma_SPI_4_RX = { DMA2_Stream3, DMA_REQUEST_SPI4_RX, DMA_PERIPH_TO_MEMORY, dma_id_11, &dma_init_struct_spi_i2c };
+const dma_descr_t dma_SPI_5_TX = { DMA2_Stream4, DMA_REQUEST_SPI5_TX, DMA_MEMORY_TO_PERIPH, dma_id_12, &dma_init_struct_spi_i2c };
+const dma_descr_t dma_SPI_4_TX = { DMA2_Stream4, DMA_REQUEST_SPI4_TX, DMA_MEMORY_TO_PERIPH, dma_id_12, &dma_init_struct_spi_i2c };
+const dma_descr_t dma_SPI_6_TX = { DMA2_Stream5, BDMA_REQUEST_SPI6_TX, DMA_MEMORY_TO_PERIPH, dma_id_13, &dma_init_struct_spi_i2c };
+const dma_descr_t dma_SPI_1_TX = { DMA2_Stream5, DMA_REQUEST_SPI1_TX, DMA_MEMORY_TO_PERIPH, dma_id_13, &dma_init_struct_spi_i2c };
+const dma_descr_t dma_SPI_6_RX = { DMA2_Stream6, BDMA_REQUEST_SPI6_RX, DMA_PERIPH_TO_MEMORY, dma_id_14, &dma_init_struct_spi_i2c };
+
+static const uint8_t dma_irqn[NSTREAM] = {
+ DMA1_Stream0_IRQn,
+ DMA1_Stream1_IRQn,
+ DMA1_Stream2_IRQn,
+ DMA1_Stream3_IRQn,
+ DMA1_Stream4_IRQn,
+ DMA1_Stream5_IRQn,
+ DMA1_Stream6_IRQn,
+ DMA1_Stream7_IRQn,
+ DMA2_Stream0_IRQn,
+ DMA2_Stream1_IRQn,
+ DMA2_Stream2_IRQn,
+ DMA2_Stream3_IRQn,
+ DMA2_Stream4_IRQn,
+ DMA2_Stream5_IRQn,
+ DMA2_Stream6_IRQn,
+ DMA2_Stream7_IRQn,
+};
+
#endif
static DMA_HandleTypeDef *dma_handle[NSTREAM] = {NULL};
@@ -317,10 +420,15 @@ volatile dma_idle_count_t dma_idle;
#define DMA_INVALID_CHANNEL 0xff // Value stored in dma_last_channel which means invalid
+#if defined(STM32F0)
+#define DMA1_IS_CLK_ENABLED() ((RCC->AHBENR & RCC_AHBENR_DMA1EN) != 0)
+#define DMA2_IS_CLK_ENABLED() ((RCC->AHBENR & RCC_AHBENR_DMA2EN) != 0)
+#else
#define DMA1_IS_CLK_ENABLED() ((RCC->AHB1ENR & RCC_AHB1ENR_DMA1EN) != 0)
#define DMA2_IS_CLK_ENABLED() ((RCC->AHB1ENR & RCC_AHB1ENR_DMA2EN) != 0)
+#endif
-#if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7)
+#if defined(STM32F4) || defined(STM32F7) || defined(STM32H7)
void DMA1_Stream0_IRQHandler(void) { IRQ_ENTER(DMA1_Stream0_IRQn); if (dma_handle[dma_id_0] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_0]); } IRQ_EXIT(DMA1_Stream0_IRQn); }
void DMA1_Stream1_IRQHandler(void) { IRQ_ENTER(DMA1_Stream1_IRQn); if (dma_handle[dma_id_1] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_1]); } IRQ_EXIT(DMA1_Stream1_IRQn); }
@@ -339,7 +447,7 @@ void DMA2_Stream5_IRQHandler(void) { IRQ_ENTER(DMA2_Stream5_IRQn); if (dma_handl
void DMA2_Stream6_IRQHandler(void) { IRQ_ENTER(DMA2_Stream6_IRQn); if (dma_handle[dma_id_14] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_14]); } IRQ_EXIT(DMA2_Stream6_IRQn); }
void DMA2_Stream7_IRQHandler(void) { IRQ_ENTER(DMA2_Stream7_IRQn); if (dma_handle[dma_id_15] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_15]); } IRQ_EXIT(DMA2_Stream7_IRQn); }
-#elif defined(MCU_SERIES_L4)
+#elif defined(STM32L4)
void DMA1_Channel1_IRQHandler(void) { IRQ_ENTER(DMA1_Channel1_IRQn); if (dma_handle[dma_id_0] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_0]); } IRQ_EXIT(DMA1_Channel1_IRQn); }
void DMA1_Channel2_IRQHandler(void) { IRQ_ENTER(DMA1_Channel2_IRQn); if (dma_handle[dma_id_1] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_1]); } IRQ_EXIT(DMA1_Channel2_IRQn); }
@@ -373,7 +481,7 @@ static void dma_enable_clock(dma_id_t dma_id) {
if (dma_id < NSTREAMS_PER_CONTROLLER) {
if (((old_enable_mask & DMA1_ENABLE_MASK) == 0) && !DMA1_IS_CLK_ENABLED()) {
- __DMA1_CLK_ENABLE();
+ __HAL_RCC_DMA1_CLK_ENABLE();
// We just turned on the clock. This means that anything stored
// in dma_last_channel (for DMA1) needs to be invalidated.
@@ -384,7 +492,7 @@ static void dma_enable_clock(dma_id_t dma_id) {
}
} else {
if (((old_enable_mask & DMA2_ENABLE_MASK) == 0) && !DMA2_IS_CLK_ENABLED()) {
- __DMA2_CLK_ENABLE();
+ __HAL_RCC_DMA2_CLK_ENABLE();
// We just turned on the clock. This means that anything stored
// in dma_last_channel (for DMA1) needs to be invalidated.
@@ -409,11 +517,13 @@ void dma_init_handle(DMA_HandleTypeDef *dma, const dma_descr_t *dma_descr, void
dma->Instance = dma_descr->instance;
dma->Init = *dma_descr->init;
dma->Init.Direction = dma_descr->transfer_direction;
- #if defined(MCU_SERIES_L4)
+ #if defined(STM32L4) || defined(STM32H7)
dma->Init.Request = dma_descr->sub_instance;
#else
+ #if !defined(STM32F0)
dma->Init.Channel = dma_descr->sub_instance;
#endif
+ #endif
// half of __HAL_LINKDMA(data, xxx, *dma)
// caller must implement other half by doing: data->xxx = dma
dma->Parent = data;
@@ -434,6 +544,14 @@ void dma_init(DMA_HandleTypeDef *dma, const dma_descr_t *dma_descr, void *data){
dma_enable_clock(dma_id);
+ #if defined(STM32L4)
+ // Always reset and configure the L4 DMA peripheral
+ // (dma->State is set to HAL_DMA_STATE_RESET by memset above)
+ // TODO: understand how L4 DMA works so this is not needed
+ HAL_DMA_DeInit(dma);
+ HAL_DMA_Init(dma);
+ NVIC_SetPriority(IRQn_NONNEG(dma_irqn[dma_id]), IRQ_PRI_DMA);
+ #else
// if this stream was previously configured for this channel/request then we
// can skip most of the initialisation
uint8_t sub_inst = DMA_SUB_INSTANCE_AS_UINT8(dma_descr->sub_instance);
@@ -444,16 +562,24 @@ void dma_init(DMA_HandleTypeDef *dma, const dma_descr_t *dma_descr, void *data){
// (dma->State is set to HAL_DMA_STATE_RESET by memset above)
HAL_DMA_DeInit(dma);
HAL_DMA_Init(dma);
- HAL_NVIC_SetPriority(dma_irqn[dma_id], IRQ_PRI_DMA, IRQ_SUBPRI_DMA);
+ NVIC_SetPriority(IRQn_NONNEG(dma_irqn[dma_id]), IRQ_PRI_DMA);
+ #if defined(STM32F0)
+ if (dma->Instance < DMA2_Channel1) {
+ __HAL_DMA1_REMAP(dma_descr->sub_instance);
+ } else {
+ __HAL_DMA2_REMAP(dma_descr->sub_instance);
+ }
+ #endif
} else {
// only necessary initialization
dma->State = HAL_DMA_STATE_READY;
-#if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7)
+#if defined(STM32F4) || defined(STM32F7)
// calculate DMA base address and bitshift to be used in IRQ handler
extern uint32_t DMA_CalcBaseAndBitshift(DMA_HandleTypeDef *hdma);
DMA_CalcBaseAndBitshift(dma);
#endif
}
+ #endif
HAL_NVIC_EnableIRQ(dma_irqn[dma_id]);
}
@@ -494,9 +620,9 @@ void dma_idle_handler(int tick) {
// Now we'll really disable the clock.
dma_idle.counter[controller] = 0;
if (controller == 0) {
- __DMA1_CLK_DISABLE();
+ __HAL_RCC_DMA1_CLK_DISABLE();
} else {
- __DMA2_CLK_DISABLE();
+ __HAL_RCC_DMA2_CLK_DISABLE();
}
} else {
// Something is still active, but the counter never got
diff --git a/ports/stm32/dma.h b/ports/stm32/dma.h
index 55fb62175..cacabe925 100644
--- a/ports/stm32/dma.h
+++ b/ports/stm32/dma.h
@@ -23,12 +23,12 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
-#ifndef MICROPY_INCLUDED_STMHAL_DMA_H
-#define MICROPY_INCLUDED_STMHAL_DMA_H
+#ifndef MICROPY_INCLUDED_STM32_DMA_H
+#define MICROPY_INCLUDED_STM32_DMA_H
typedef struct _dma_descr_t dma_descr_t;
-#if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7)
+#if defined(STM32F0) || defined(STM32F4) || defined(STM32F7) || defined(STM32H7)
extern const dma_descr_t dma_I2C_1_RX;
extern const dma_descr_t dma_SPI_3_RX;
@@ -57,7 +57,7 @@ extern const dma_descr_t dma_SDMMC_2_TX;
extern const dma_descr_t dma_SPI_6_RX;
extern const dma_descr_t dma_SDIO_0_TX;
-#elif defined(MCU_SERIES_L4)
+#elif defined(STM32L4)
extern const dma_descr_t dma_ADC_1_RX;
extern const dma_descr_t dma_ADC_2_RX;
@@ -100,4 +100,4 @@ void dma_deinit(const dma_descr_t *dma_descr);
void dma_invalidate_channel(const dma_descr_t *dma_descr);
void dma_idle_handler(int controller);
-#endif // MICROPY_INCLUDED_STMHAL_DMA_H
+#endif // MICROPY_INCLUDED_STM32_DMA_H
diff --git a/ports/stm32/extint.c b/ports/stm32/extint.c
index 41943f1cd..70bf7eae7 100644
--- a/ports/stm32/extint.c
+++ b/ports/stm32/extint.c
@@ -89,7 +89,7 @@
// register in an atomic fashion by using bitband addressing.
#define EXTI_MODE_BB(mode, line) (*(__IO uint32_t *)(PERIPH_BB_BASE + ((EXTI_OFFSET + (mode)) * 32) + ((line) * 4)))
-#if defined(MCU_SERIES_L4)
+#if defined(STM32L4)
// The L4 MCU supports 40 Events/IRQs lines of the type configurable and direct.
// Here we only support configurable line types. Details, see page 330 of RM0351, Rev 1.
// The USB_FS_WAKUP event is a direct type and there is no support for it.
@@ -97,6 +97,11 @@
#define EXTI_Mode_Event offsetof(EXTI_TypeDef, EMR1)
#define EXTI_RTSR EXTI->RTSR1
#define EXTI_FTSR EXTI->FTSR1
+#elif defined(STM32H7)
+#define EXTI_Mode_Interrupt offsetof(EXTI_Core_TypeDef, IMR1)
+#define EXTI_Mode_Event offsetof(EXTI_Core_TypeDef, EMR1)
+#define EXTI_RTSR EXTI->RTSR1
+#define EXTI_FTSR EXTI->FTSR1
#else
#define EXTI_Mode_Interrupt offsetof(EXTI_TypeDef, IMR)
#define EXTI_Mode_Event offsetof(EXTI_TypeDef, EMR)
@@ -128,11 +133,17 @@ STATIC mp_obj_t pyb_extint_callback_arg[EXTI_NUM_VECTORS];
#endif
STATIC const uint8_t nvic_irq_channel[EXTI_NUM_VECTORS] = {
+ #if defined(STM32F0)
+ EXTI0_1_IRQn, EXTI0_1_IRQn, EXTI2_3_IRQn, EXTI2_3_IRQn,
+ EXTI4_15_IRQn, EXTI4_15_IRQn, EXTI4_15_IRQn, EXTI4_15_IRQn,
+ EXTI4_15_IRQn, EXTI4_15_IRQn, EXTI4_15_IRQn, EXTI4_15_IRQn,
+ EXTI4_15_IRQn, EXTI4_15_IRQn, EXTI4_15_IRQn, EXTI4_15_IRQn,
+ #else
EXTI0_IRQn, EXTI1_IRQn, EXTI2_IRQn, EXTI3_IRQn, EXTI4_IRQn,
EXTI9_5_IRQn, EXTI9_5_IRQn, EXTI9_5_IRQn, EXTI9_5_IRQn, EXTI9_5_IRQn,
EXTI15_10_IRQn, EXTI15_10_IRQn, EXTI15_10_IRQn, EXTI15_10_IRQn, EXTI15_10_IRQn,
EXTI15_10_IRQn,
- #if defined(MCU_SERIES_L4)
+ #if defined(STM32L4)
PVD_PVM_IRQn,
#else
PVD_IRQn,
@@ -143,6 +154,7 @@ STATIC const uint8_t nvic_irq_channel[EXTI_NUM_VECTORS] = {
OTG_HS_WKUP_IRQn,
TAMP_STAMP_IRQn,
RTC_WKUP_IRQn,
+ #endif
};
// Set override_callback_obj to true if you want to unconditionally set the
@@ -203,13 +215,13 @@ uint extint_register(mp_obj_t pin_obj, uint32_t mode, uint32_t pull, mp_obj_t ca
exti.Pin = pin->pin_mask;
exti.Mode = mode;
exti.Pull = pull;
- exti.Speed = GPIO_SPEED_FAST;
+ exti.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(pin->gpio, &exti);
// Calling HAL_GPIO_Init does an implicit extint_enable
/* Enable and set NVIC Interrupt to the lowest priority */
- HAL_NVIC_SetPriority(nvic_irq_channel[v_line], IRQ_PRI_EXTINT, IRQ_SUBPRI_EXTINT);
+ NVIC_SetPriority(IRQn_NONNEG(nvic_irq_channel[v_line]), IRQ_PRI_EXTINT);
HAL_NVIC_EnableIRQ(nvic_irq_channel[v_line]);
}
return v_line;
@@ -265,7 +277,7 @@ void extint_register_pin(const pin_obj_t *pin, uint32_t mode, bool hard_irq, mp_
}
// Configure the NVIC
- HAL_NVIC_SetPriority(nvic_irq_channel[line], IRQ_PRI_EXTINT, IRQ_SUBPRI_EXTINT);
+ NVIC_SetPriority(IRQn_NONNEG(nvic_irq_channel[line]), IRQ_PRI_EXTINT);
HAL_NVIC_EnableIRQ(nvic_irq_channel[line]);
// Enable the interrupt
@@ -277,13 +289,21 @@ void extint_enable(uint line) {
if (line >= EXTI_NUM_VECTORS) {
return;
}
- #if defined(MCU_SERIES_F7)
+ #if defined(STM32F0) || defined(STM32F7) || defined(STM32H7)
// The Cortex-M7 doesn't have bitband support.
mp_uint_t irq_state = disable_irq();
if (pyb_extint_mode[line] == EXTI_Mode_Interrupt) {
+ #if defined(STM32H7)
+ EXTI_D1->IMR1 |= (1 << line);
+ #else
EXTI->IMR |= (1 << line);
+ #endif
} else {
+ #if defined(STM32H7)
+ EXTI_D1->EMR1 |= (1 << line);
+ #else
EXTI->EMR |= (1 << line);
+ #endif
}
enable_irq(irq_state);
#else
@@ -299,11 +319,16 @@ void extint_disable(uint line) {
return;
}
- #if defined(MCU_SERIES_F7)
+ #if defined(STM32F0) || defined(STM32F7) || defined(STM32H7)
// The Cortex-M7 doesn't have bitband support.
mp_uint_t irq_state = disable_irq();
+ #if defined(STM32H7)
+ EXTI_D1->IMR1 &= ~(1 << line);
+ EXTI_D1->EMR1 &= ~(1 << line);
+ #else
EXTI->IMR &= ~(1 << line);
EXTI->EMR &= ~(1 << line);
+ #endif
enable_irq(irq_state);
#else
// Since manipulating IMR/EMR is a read-modify-write, and we want this to
@@ -319,7 +344,7 @@ void extint_swint(uint line) {
return;
}
// we need 0 to 1 transition to trigger the interrupt
-#if defined(MCU_SERIES_L4)
+#if defined(STM32L4) || defined(STM32H7)
EXTI->SWIER1 &= ~(1 << line);
EXTI->SWIER1 |= (1 << line);
#else
@@ -368,26 +393,45 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(extint_obj_swint_obj, extint_obj_swint);
/// \classmethod regs()
/// Dump the values of the EXTI registers.
STATIC mp_obj_t extint_regs(void) {
- #if defined(MCU_SERIES_L4)
- printf("EXTI_IMR1 %08lx\n", EXTI->IMR1);
- printf("EXTI_IMR2 %08lx\n", EXTI->IMR2);
- printf("EXTI_EMR1 %08lx\n", EXTI->EMR1);
- printf("EXTI_EMR2 %08lx\n", EXTI->EMR2);
- printf("EXTI_RTSR1 %08lx\n", EXTI->RTSR1);
- printf("EXTI_RTSR2 %08lx\n", EXTI->RTSR2);
- printf("EXTI_FTSR1 %08lx\n", EXTI->FTSR1);
- printf("EXTI_FTSR2 %08lx\n", EXTI->FTSR2);
- printf("EXTI_SWIER1 %08lx\n", EXTI->SWIER1);
- printf("EXTI_SWIER2 %08lx\n", EXTI->SWIER2);
- printf("EXTI_PR1 %08lx\n", EXTI->PR1);
- printf("EXTI_PR2 %08lx\n", EXTI->PR2);
+ #if defined(STM32L4)
+ printf("EXTI_IMR1 %08x\n", (unsigned int)EXTI->IMR1);
+ printf("EXTI_IMR2 %08x\n", (unsigned int)EXTI->IMR2);
+ printf("EXTI_EMR1 %08x\n", (unsigned int)EXTI->EMR1);
+ printf("EXTI_EMR2 %08x\n", (unsigned int)EXTI->EMR2);
+ printf("EXTI_RTSR1 %08x\n", (unsigned int)EXTI->RTSR1);
+ printf("EXTI_RTSR2 %08x\n", (unsigned int)EXTI->RTSR2);
+ printf("EXTI_FTSR1 %08x\n", (unsigned int)EXTI->FTSR1);
+ printf("EXTI_FTSR2 %08x\n", (unsigned int)EXTI->FTSR2);
+ printf("EXTI_SWIER1 %08x\n", (unsigned int)EXTI->SWIER1);
+ printf("EXTI_SWIER2 %08x\n", (unsigned int)EXTI->SWIER2);
+ printf("EXTI_PR1 %08x\n", (unsigned int)EXTI->PR1);
+ printf("EXTI_PR2 %08x\n", (unsigned int)EXTI->PR2);
+ #elif defined(STM32H7)
+ printf("EXTI_IMR1 %08x\n", (unsigned int)EXTI_D1->IMR1);
+ printf("EXTI_IMR2 %08x\n", (unsigned int)EXTI_D1->IMR2);
+ printf("EXTI_IMR3 %08x\n", (unsigned int)EXTI_D1->IMR3);
+ printf("EXTI_EMR1 %08x\n", (unsigned int)EXTI_D1->EMR1);
+ printf("EXTI_EMR2 %08x\n", (unsigned int)EXTI_D1->EMR2);
+ printf("EXTI_EMR3 %08x\n", (unsigned int)EXTI_D1->EMR3);
+ printf("EXTI_RTSR1 %08x\n", (unsigned int)EXTI->RTSR1);
+ printf("EXTI_RTSR2 %08x\n", (unsigned int)EXTI->RTSR2);
+ printf("EXTI_RTSR3 %08x\n", (unsigned int)EXTI->RTSR3);
+ printf("EXTI_FTSR1 %08x\n", (unsigned int)EXTI->FTSR1);
+ printf("EXTI_FTSR2 %08x\n", (unsigned int)EXTI->FTSR2);
+ printf("EXTI_FTSR3 %08x\n", (unsigned int)EXTI->FTSR3);
+ printf("EXTI_SWIER1 %08x\n", (unsigned int)EXTI->SWIER1);
+ printf("EXTI_SWIER2 %08x\n", (unsigned int)EXTI->SWIER2);
+ printf("EXTI_SWIER3 %08x\n", (unsigned int)EXTI->SWIER3);
+ printf("EXTI_PR1 %08x\n", (unsigned int)EXTI_D1->PR1);
+ printf("EXTI_PR2 %08x\n", (unsigned int)EXTI_D1->PR2);
+ printf("EXTI_PR3 %08x\n", (unsigned int)EXTI_D1->PR3);
#else
- printf("EXTI_IMR %08lx\n", EXTI->IMR);
- printf("EXTI_EMR %08lx\n", EXTI->EMR);
- printf("EXTI_RTSR %08lx\n", EXTI->RTSR);
- printf("EXTI_FTSR %08lx\n", EXTI->FTSR);
- printf("EXTI_SWIER %08lx\n", EXTI->SWIER);
- printf("EXTI_PR %08lx\n", EXTI->PR);
+ printf("EXTI_IMR %08x\n", (unsigned int)EXTI->IMR);
+ printf("EXTI_EMR %08x\n", (unsigned int)EXTI->EMR);
+ printf("EXTI_RTSR %08x\n", (unsigned int)EXTI->RTSR);
+ printf("EXTI_FTSR %08x\n", (unsigned int)EXTI->FTSR);
+ printf("EXTI_SWIER %08x\n", (unsigned int)EXTI->SWIER);
+ printf("EXTI_PR %08x\n", (unsigned int)EXTI->PR);
#endif
return mp_const_none;
}
@@ -497,7 +541,7 @@ void Handle_EXTI_Irq(uint32_t line) {
// Uncaught exception; disable the callback so it doesn't run again.
*cb = mp_const_none;
extint_disable(line);
- printf("Uncaught exception in ExtInt interrupt handler line %lu\n", line);
+ printf("Uncaught exception in ExtInt interrupt handler line %u\n", (unsigned int)line);
mp_obj_print_exception(&mp_plat_print, (mp_obj_t)nlr.ret_val);
}
gc_unlock();
diff --git a/ports/stm32/extint.h b/ports/stm32/extint.h
index 846790b9b..c4a4ae6bb 100644
--- a/ports/stm32/extint.h
+++ b/ports/stm32/extint.h
@@ -23,8 +23,8 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
-#ifndef MICROPY_INCLUDED_STMHAL_EXTINT_H
-#define MICROPY_INCLUDED_STMHAL_EXTINT_H
+#ifndef MICROPY_INCLUDED_STM32_EXTINT_H
+#define MICROPY_INCLUDED_STM32_EXTINT_H
// Vectors 0-15 are for regular pins
// Vectors 16-22 are for internal sources.
@@ -38,7 +38,7 @@
#define EXTI_USB_OTG_HS_WAKEUP (20)
#define EXTI_RTC_TIMESTAMP (21)
#define EXTI_RTC_WAKEUP (22)
-#if defined(MCU_SERIES_F7)
+#if defined(STM32F7)
#define EXTI_LPTIM1_ASYNC_EVENT (23)
#endif
@@ -64,4 +64,4 @@ void Handle_EXTI_Irq(uint32_t line);
extern const mp_obj_type_t extint_type;
-#endif // MICROPY_INCLUDED_STMHAL_EXTINT_H
+#endif // MICROPY_INCLUDED_STM32_EXTINT_H
diff --git a/ports/stm32/fatfs_port.c b/ports/stm32/fatfs_port.c
index 17ec3f726..d0e311ed7 100644
--- a/ports/stm32/fatfs_port.c
+++ b/ports/stm32/fatfs_port.c
@@ -32,7 +32,7 @@ DWORD get_fattime(void) {
rtc_init_finalise();
RTC_TimeTypeDef time;
RTC_DateTypeDef date;
- HAL_RTC_GetTime(&RTCHandle, &time, FORMAT_BIN);
- HAL_RTC_GetDate(&RTCHandle, &date, FORMAT_BIN);
+ HAL_RTC_GetTime(&RTCHandle, &time, RTC_FORMAT_BIN);
+ HAL_RTC_GetDate(&RTCHandle, &date, RTC_FORMAT_BIN);
return ((2000 + date.Year - 1980) << 25) | ((date.Month) << 21) | ((date.Date) << 16) | ((time.Hours) << 11) | ((time.Minutes) << 5) | (time.Seconds / 2);
}
diff --git a/ports/stm32/flash.c b/ports/stm32/flash.c
index bebb3a161..26f76a174 100644
--- a/ports/stm32/flash.c
+++ b/ports/stm32/flash.c
@@ -34,7 +34,13 @@ typedef struct {
uint32_t sector_count;
} flash_layout_t;
-#if defined(MCU_SERIES_F4)
+#if defined(STM32F0)
+
+static const flash_layout_t flash_layout[] = {
+ { FLASH_BASE, FLASH_PAGE_SIZE, (FLASH_BANK1_END + 1 - FLASH_BASE) / FLASH_PAGE_SIZE },
+};
+
+#elif defined(STM32F4)
static const flash_layout_t flash_layout[] = {
{ 0x08000000, 0x04000, 4 },
@@ -50,7 +56,7 @@ static const flash_layout_t flash_layout[] = {
#endif
};
-#elif defined(MCU_SERIES_F7)
+#elif defined(STM32F7)
// FLASH_FLAG_PGSERR (Programming Sequence Error) was renamed to
// FLASH_FLAG_ERSERR (Erasing Sequence Error) in STM32F7
@@ -62,21 +68,31 @@ static const flash_layout_t flash_layout[] = {
{ 0x08040000, 0x40000, 3 },
};
-#elif defined(MCU_SERIES_L4)
+#elif defined(STM32L4)
static const flash_layout_t flash_layout[] = {
{ (uint32_t)FLASH_BASE, (uint32_t)FLASH_PAGE_SIZE, 512 },
};
+#elif defined(STM32H7)
+
+static const flash_layout_t flash_layout[] = {
+ { 0x08000000, 0x20000, 16 },
+};
+
#else
#error Unsupported processor
#endif
-#if defined(MCU_SERIES_L4)
+#if defined(STM32L4) || defined(STM32H7)
// get the bank of a given flash address
static uint32_t get_bank(uint32_t addr) {
+ #if defined(STM32H7)
+ if (READ_BIT(FLASH->OPTCR, FLASH_OPTCR_SWAP_BANK) == 0) {
+ #else
if (READ_BIT(SYSCFG->MEMRMP, SYSCFG_MEMRMP_FB_MODE) == 0) {
+ #endif
// no bank swap
if (addr < (FLASH_BASE + FLASH_BANK_SIZE)) {
return FLASH_BANK_1;
@@ -93,6 +109,7 @@ static uint32_t get_bank(uint32_t addr) {
}
}
+#if defined(STM32L4)
// get the page of a given flash address
static uint32_t get_page(uint32_t addr) {
if (addr < (FLASH_BASE + FLASH_BANK_SIZE)) {
@@ -103,6 +120,7 @@ static uint32_t get_page(uint32_t addr) {
return (addr - (FLASH_BASE + FLASH_BANK_SIZE)) / FLASH_PAGE_SIZE;
}
}
+#endif
#endif
@@ -130,7 +148,7 @@ uint32_t flash_get_sector_info(uint32_t addr, uint32_t *start_addr, uint32_t *si
return 0;
}
-void flash_erase(uint32_t flash_dest, const uint32_t *src, uint32_t num_word32) {
+void flash_erase(uint32_t flash_dest, uint32_t num_word32) {
// check there is something to write
if (num_word32 == 0) {
return;
@@ -141,7 +159,12 @@ void flash_erase(uint32_t flash_dest, const uint32_t *src, uint32_t num_word32)
FLASH_EraseInitTypeDef EraseInitStruct;
- #if defined(MCU_SERIES_L4)
+ #if defined(STM32F0)
+ __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_WRPERR | FLASH_FLAG_PGERR);
+ EraseInitStruct.TypeErase = FLASH_TYPEERASE_PAGES;
+ EraseInitStruct.PageAddress = flash_dest;
+ EraseInitStruct.NbPages = (4 * num_word32 + FLASH_PAGE_SIZE - 4) / FLASH_PAGE_SIZE;
+ #elif defined(STM32L4)
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_ALL_ERRORS);
// erase the sector(s)
@@ -153,12 +176,19 @@ void flash_erase(uint32_t flash_dest, const uint32_t *src, uint32_t num_word32)
EraseInitStruct.NbPages = get_page(flash_dest + 4 * num_word32 - 1) - EraseInitStruct.Page + 1;;
#else
// Clear pending flags (if any)
+ #if defined(STM32H7)
+ __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_ALL_ERRORS_BANK1 | FLASH_FLAG_ALL_ERRORS_BANK2);
+ #else
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR |
FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR | FLASH_FLAG_PGSERR);
+ #endif
// erase the sector(s)
EraseInitStruct.TypeErase = TYPEERASE_SECTORS;
EraseInitStruct.VoltageRange = VOLTAGE_RANGE_3; // voltage range needs to be 2.7V to 3.6V
+ #if defined(STM32H7)
+ EraseInitStruct.Banks = get_bank(flash_dest);
+ #endif
EraseInitStruct.Sector = flash_get_sector_info(flash_dest, NULL, NULL);
EraseInitStruct.NbSectors = flash_get_sector_info(flash_dest + 4 * num_word32 - 1, NULL, NULL) - EraseInitStruct.Sector + 1;
#endif
@@ -173,7 +203,7 @@ void flash_erase(uint32_t flash_dest, const uint32_t *src, uint32_t num_word32)
/*
// erase the sector using an interrupt
-void flash_erase_it(uint32_t flash_dest, const uint32_t *src, uint32_t num_word32) {
+void flash_erase_it(uint32_t flash_dest, uint32_t num_word32) {
// check there is something to write
if (num_word32 == 0) {
return;
@@ -201,7 +231,7 @@ void flash_erase_it(uint32_t flash_dest, const uint32_t *src, uint32_t num_word3
*/
void flash_write(uint32_t flash_dest, const uint32_t *src, uint32_t num_word32) {
- #if defined(MCU_SERIES_L4)
+ #if defined(STM32L4)
// program the flash uint64 by uint64
for (int i = 0; i < num_word32 / 2; i++) {
@@ -224,11 +254,24 @@ void flash_write(uint32_t flash_dest, const uint32_t *src, uint32_t num_word32)
}
}
+ #elif defined(STM32H7)
+
+ // program the flash 256 bits at a time
+ for (int i = 0; i < num_word32 / 8; i++) {
+ if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_FLASHWORD, flash_dest, (uint64_t)(uint32_t)src) != HAL_OK) {
+ // error occurred during flash write
+ HAL_FLASH_Lock(); // lock the flash
+ return;
+ }
+ flash_dest += 32;
+ src += 8;
+ }
+
#else
// program the flash word by word
for (int i = 0; i < num_word32; i++) {
- if (HAL_FLASH_Program(TYPEPROGRAM_WORD, flash_dest, *src) != HAL_OK) {
+ if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, flash_dest, *src) != HAL_OK) {
// error occurred during flash write
HAL_FLASH_Lock(); // lock the flash
return;
diff --git a/ports/stm32/flash.h b/ports/stm32/flash.h
index 688e70a3c..b9edf6106 100644
--- a/ports/stm32/flash.h
+++ b/ports/stm32/flash.h
@@ -23,11 +23,11 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
-#ifndef MICROPY_INCLUDED_STMHAL_FLASH_H
-#define MICROPY_INCLUDED_STMHAL_FLASH_H
+#ifndef MICROPY_INCLUDED_STM32_FLASH_H
+#define MICROPY_INCLUDED_STM32_FLASH_H
uint32_t flash_get_sector_info(uint32_t addr, uint32_t *start_addr, uint32_t *size);
-void flash_erase(uint32_t flash_dest, const uint32_t *src, uint32_t num_word32);
+void flash_erase(uint32_t flash_dest, uint32_t num_word32);
void flash_write(uint32_t flash_dest, const uint32_t *src, uint32_t num_word32);
-#endif // MICROPY_INCLUDED_STMHAL_FLASH_H
+#endif // MICROPY_INCLUDED_STM32_FLASH_H
diff --git a/ports/stm32/flashbdev.c b/ports/stm32/flashbdev.c
new file mode 100644
index 000000000..5ae67d1ec
--- /dev/null
+++ b/ports/stm32/flashbdev.c
@@ -0,0 +1,269 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2013-2018 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdint.h>
+#include <string.h>
+
+#include "py/obj.h"
+#include "py/mperrno.h"
+#include "led.h"
+#include "flash.h"
+#include "storage.h"
+
+#if MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE
+
+// Here we try to automatically configure the location and size of the flash
+// pages to use for the internal storage. We also configure the location of the
+// cache used for writing.
+
+#if defined(STM32F405xx) || defined(STM32F415xx) || defined(STM32F407xx)
+
+#define CACHE_MEM_START_ADDR (0x10000000) // CCM data RAM, 64k
+#define FLASH_SECTOR_SIZE_MAX (0x10000) // 64k max, size of CCM
+#define FLASH_MEM_SEG1_START_ADDR (0x08004000) // sector 1
+#define FLASH_MEM_SEG1_NUM_BLOCKS (224) // sectors 1,2,3,4: 16k+16k+16k+64k=112k
+
+// enable this to get an extra 64k of storage (uses the last sector of the flash)
+#if 0
+#define FLASH_MEM_SEG2_START_ADDR (0x080e0000) // sector 11
+#define FLASH_MEM_SEG2_NUM_BLOCKS (128) // sector 11: 128k
+#endif
+
+#elif defined(STM32F401xE) || defined(STM32F411xE) || defined(STM32F446xx)
+
+STATIC byte flash_cache_mem[0x4000] __attribute__((aligned(4))); // 16k
+#define CACHE_MEM_START_ADDR (&flash_cache_mem[0])
+#define FLASH_SECTOR_SIZE_MAX (0x4000) // 16k max due to size of cache buffer
+#define FLASH_MEM_SEG1_START_ADDR (0x08004000) // sector 1
+#define FLASH_MEM_SEG1_NUM_BLOCKS (128) // sectors 1,2,3,4: 16k+16k+16k+16k(of 64k)=64k
+
+#elif defined(STM32F429xx)
+
+#define CACHE_MEM_START_ADDR (0x10000000) // CCM data RAM, 64k
+#define FLASH_SECTOR_SIZE_MAX (0x10000) // 64k max, size of CCM
+#define FLASH_MEM_SEG1_START_ADDR (0x08004000) // sector 1
+#define FLASH_MEM_SEG1_NUM_BLOCKS (224) // sectors 1,2,3,4: 16k+16k+16k+64k=112k
+
+#elif defined(STM32F439xx)
+
+#define CACHE_MEM_START_ADDR (0x10000000) // CCM data RAM, 64k
+#define FLASH_SECTOR_SIZE_MAX (0x10000) // 64k max, size of CCM
+#define FLASH_MEM_SEG1_START_ADDR (0x08100000) // sector 12
+#define FLASH_MEM_SEG1_NUM_BLOCKS (384) // sectors 12,13,14,15,16,17: 16k+16k+16k+16k+64k+64k(of 128k)=192k
+#define FLASH_MEM_SEG2_START_ADDR (0x08140000) // sector 18
+#define FLASH_MEM_SEG2_NUM_BLOCKS (128) // sector 18: 64k(of 128k)
+
+#elif defined(STM32F746xx) || defined(STM32F767xx) || defined(STM32F769xx)
+
+// The STM32F746 doesn't really have CCRAM, so we use the 64K DTCM for this.
+
+#define CACHE_MEM_START_ADDR (0x20000000) // DTCM data RAM, 64k
+#define FLASH_SECTOR_SIZE_MAX (0x08000) // 32k max
+#define FLASH_MEM_SEG1_START_ADDR (0x08008000) // sector 1
+#define FLASH_MEM_SEG1_NUM_BLOCKS (192) // sectors 1,2,3: 32k+32k+32=96k
+
+#elif defined(STM32H743xx)
+
+// The STM32H743 flash sectors are 128K
+#define CACHE_MEM_START_ADDR (0x20000000) // DTCM data RAM, 128k
+#define FLASH_SECTOR_SIZE_MAX (0x20000) // 128k max
+#define FLASH_MEM_SEG1_START_ADDR (0x08020000) // sector 1
+#define FLASH_MEM_SEG1_NUM_BLOCKS (256) // Sector 1: 128k / 512b = 256 blocks
+
+#elif defined(STM32L475xx) || defined(STM32L476xx) || defined(STM32L496xx)
+
+extern uint8_t _flash_fs_start;
+extern uint8_t _flash_fs_end;
+extern uint32_t _ram_fs_cache_start[2048 / 4];
+extern uint32_t _ram_fs_cache_block_size;
+
+// The STM32L475/6 doesn't have CCRAM, so we use the 32K SRAM2 for this.
+#define CACHE_MEM_START_ADDR (&_ram_fs_cache_start) // End of SRAM2 RAM segment-2k
+#define FLASH_SECTOR_SIZE_MAX (_ram_fs_cache_block_size) // 2k max
+#define FLASH_MEM_SEG1_START_ADDR ((long)&_flash_fs_start)
+#define FLASH_MEM_SEG1_NUM_BLOCKS ((&_flash_fs_end - &_flash_fs_start) / 512)
+
+#else
+#error "no internal flash storage support for this MCU"
+#endif
+
+#if !defined(FLASH_MEM_SEG2_START_ADDR)
+#define FLASH_MEM_SEG2_START_ADDR (0) // no second segment
+#define FLASH_MEM_SEG2_NUM_BLOCKS (0) // no second segment
+#endif
+
+#define FLASH_FLAG_DIRTY (1)
+#define FLASH_FLAG_FORCE_WRITE (2)
+#define FLASH_FLAG_ERASED (4)
+static __IO uint8_t flash_flags = 0;
+static uint32_t flash_cache_sector_id;
+static uint32_t flash_cache_sector_start;
+static uint32_t flash_cache_sector_size;
+static uint32_t flash_tick_counter_last_write;
+
+static void flash_bdev_irq_handler(void);
+
+int32_t flash_bdev_ioctl(uint32_t op, uint32_t arg) {
+ (void)arg;
+ switch (op) {
+ case BDEV_IOCTL_INIT:
+ flash_flags = 0;
+ flash_cache_sector_id = 0;
+ flash_tick_counter_last_write = 0;
+ return 0;
+
+ case BDEV_IOCTL_NUM_BLOCKS:
+ return FLASH_MEM_SEG1_NUM_BLOCKS + FLASH_MEM_SEG2_NUM_BLOCKS;
+
+ case BDEV_IOCTL_IRQ_HANDLER:
+ flash_bdev_irq_handler();
+ return 0;
+
+ case BDEV_IOCTL_SYNC:
+ if (flash_flags & FLASH_FLAG_DIRTY) {
+ flash_flags |= FLASH_FLAG_FORCE_WRITE;
+ while (flash_flags & FLASH_FLAG_DIRTY) {
+ NVIC->STIR = FLASH_IRQn;
+ }
+ }
+ return 0;
+ }
+ return -MP_EINVAL;
+}
+
+static uint8_t *flash_cache_get_addr_for_write(uint32_t flash_addr) {
+ uint32_t flash_sector_start;
+ uint32_t flash_sector_size;
+ uint32_t flash_sector_id = flash_get_sector_info(flash_addr, &flash_sector_start, &flash_sector_size);
+ if (flash_sector_size > FLASH_SECTOR_SIZE_MAX) {
+ flash_sector_size = FLASH_SECTOR_SIZE_MAX;
+ }
+ if (flash_cache_sector_id != flash_sector_id) {
+ flash_bdev_ioctl(BDEV_IOCTL_SYNC, 0);
+ memcpy((void*)CACHE_MEM_START_ADDR, (const void*)flash_sector_start, flash_sector_size);
+ flash_cache_sector_id = flash_sector_id;
+ flash_cache_sector_start = flash_sector_start;
+ flash_cache_sector_size = flash_sector_size;
+ }
+ flash_flags |= FLASH_FLAG_DIRTY;
+ led_state(PYB_LED_RED, 1); // indicate a dirty cache with LED on
+ flash_tick_counter_last_write = HAL_GetTick();
+ return (uint8_t*)CACHE_MEM_START_ADDR + flash_addr - flash_sector_start;
+}
+
+static uint8_t *flash_cache_get_addr_for_read(uint32_t flash_addr) {
+ uint32_t flash_sector_start;
+ uint32_t flash_sector_size;
+ uint32_t flash_sector_id = flash_get_sector_info(flash_addr, &flash_sector_start, &flash_sector_size);
+ if (flash_cache_sector_id == flash_sector_id) {
+ // in cache, copy from there
+ return (uint8_t*)CACHE_MEM_START_ADDR + flash_addr - flash_sector_start;
+ }
+ // not in cache, copy straight from flash
+ return (uint8_t*)flash_addr;
+}
+
+static uint32_t convert_block_to_flash_addr(uint32_t block) {
+ if (block < FLASH_MEM_SEG1_NUM_BLOCKS) {
+ return FLASH_MEM_SEG1_START_ADDR + block * FLASH_BLOCK_SIZE;
+ }
+ if (block < FLASH_MEM_SEG1_NUM_BLOCKS + FLASH_MEM_SEG2_NUM_BLOCKS) {
+ return FLASH_MEM_SEG2_START_ADDR + (block - FLASH_MEM_SEG1_NUM_BLOCKS) * FLASH_BLOCK_SIZE;
+ }
+ // can add more flash segments here if needed, following above pattern
+
+ // bad block
+ return -1;
+}
+
+static void flash_bdev_irq_handler(void) {
+ if (!(flash_flags & FLASH_FLAG_DIRTY)) {
+ return;
+ }
+
+ // This code uses interrupts to erase the flash
+ /*
+ if (flash_erase_state == 0) {
+ flash_erase_it(flash_cache_sector_start, flash_cache_sector_size / 4);
+ flash_erase_state = 1;
+ return;
+ }
+
+ if (flash_erase_state == 1) {
+ // wait for erase
+ // TODO add timeout
+ #define flash_erase_done() (__HAL_FLASH_GET_FLAG(FLASH_FLAG_BSY) == RESET)
+ if (!flash_erase_done()) {
+ return;
+ }
+ flash_erase_state = 2;
+ }
+ */
+
+ // This code erases the flash directly, waiting for it to finish
+ if (!(flash_flags & FLASH_FLAG_ERASED)) {
+ flash_erase(flash_cache_sector_start, flash_cache_sector_size / 4);
+ flash_flags |= FLASH_FLAG_ERASED;
+ return;
+ }
+
+ // If not a forced write, wait at least 5 seconds after last write to flush
+ // On file close and flash unmount we get a forced write, so we can afford to wait a while
+ if ((flash_flags & FLASH_FLAG_FORCE_WRITE) || HAL_GetTick() - flash_tick_counter_last_write >= 5000) {
+ // sync the cache RAM buffer by writing it to the flash page
+ flash_write(flash_cache_sector_start, (const uint32_t*)CACHE_MEM_START_ADDR, flash_cache_sector_size / 4);
+ // clear the flash flags now that we have a clean cache
+ flash_flags = 0;
+ // indicate a clean cache with LED off
+ led_state(PYB_LED_RED, 0);
+ }
+}
+
+bool flash_bdev_readblock(uint8_t *dest, uint32_t block) {
+ // non-MBR block, get data from flash memory, possibly via cache
+ uint32_t flash_addr = convert_block_to_flash_addr(block);
+ if (flash_addr == -1) {
+ // bad block number
+ return false;
+ }
+ uint8_t *src = flash_cache_get_addr_for_read(flash_addr);
+ memcpy(dest, src, FLASH_BLOCK_SIZE);
+ return true;
+}
+
+bool flash_bdev_writeblock(const uint8_t *src, uint32_t block) {
+ // non-MBR block, copy to cache
+ uint32_t flash_addr = convert_block_to_flash_addr(block);
+ if (flash_addr == -1) {
+ // bad block number
+ return false;
+ }
+ uint8_t *dest = flash_cache_get_addr_for_write(flash_addr);
+ memcpy(dest, src, FLASH_BLOCK_SIZE);
+ return true;
+}
+
+#endif // MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE
diff --git a/ports/stm32/font_petme128_8x8.h b/ports/stm32/font_petme128_8x8.h
index 8b0cc9cb0..cdc4e73a7 100644
--- a/ports/stm32/font_petme128_8x8.h
+++ b/ports/stm32/font_petme128_8x8.h
@@ -23,8 +23,8 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
-#ifndef MICROPY_INCLUDED_STMHAL_FONT_PETME128_8X8_H
-#define MICROPY_INCLUDED_STMHAL_FONT_PETME128_8X8_H
+#ifndef MICROPY_INCLUDED_STM32_FONT_PETME128_8X8_H
+#define MICROPY_INCLUDED_STM32_FONT_PETME128_8X8_H
static const uint8_t font_petme128_8x8[] = {
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // 32=
@@ -125,4 +125,4 @@ static const uint8_t font_petme128_8x8[] = {
0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55, // 127
};
-#endif // MICROPY_INCLUDED_STMHAL_FONT_PETME128_8X8_H
+#endif // MICROPY_INCLUDED_STM32_FONT_PETME128_8X8_H
diff --git a/ports/stm32/gccollect.h b/ports/stm32/gccollect.h
index 1b64a51a6..25a74a306 100644
--- a/ports/stm32/gccollect.h
+++ b/ports/stm32/gccollect.h
@@ -23,8 +23,8 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
-#ifndef MICROPY_INCLUDED_STMHAL_GCCOLLECT_H
-#define MICROPY_INCLUDED_STMHAL_GCCOLLECT_H
+#ifndef MICROPY_INCLUDED_STM32_GCCOLLECT_H
+#define MICROPY_INCLUDED_STM32_GCCOLLECT_H
// variables defining memory layout
// (these probably belong somewhere else...)
@@ -40,4 +40,4 @@ extern uint32_t _heap_end;
extern uint32_t _estack;
extern uint32_t _ram_end;
-#endif // MICROPY_INCLUDED_STMHAL_GCCOLLECT_H
+#endif // MICROPY_INCLUDED_STM32_GCCOLLECT_H
diff --git a/ports/stm32/gchelper_m0.s b/ports/stm32/gchelper_m0.s
new file mode 100644
index 000000000..db0d9738d
--- /dev/null
+++ b/ports/stm32/gchelper_m0.s
@@ -0,0 +1,61 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+ .syntax unified
+ .cpu cortex-m0
+ .thumb
+
+ .section .text
+ .align 2
+
+ .global gc_helper_get_regs_and_sp
+ .type gc_helper_get_regs_and_sp, %function
+
+@ uint gc_helper_get_regs_and_sp(r0=uint regs[10])
+gc_helper_get_regs_and_sp:
+ @ store registers into given array
+ str r4, [r0, #0]
+ str r5, [r0, #4]
+ str r6, [r0, #8]
+ str r7, [r0, #12]
+ mov r1, r8
+ str r1, [r0, #16]
+ mov r1, r9
+ str r1, [r0, #20]
+ mov r1, r10
+ str r1, [r0, #24]
+ mov r1, r11
+ str r1, [r0, #28]
+ mov r1, r12
+ str r1, [r0, #32]
+ mov r1, r13
+ str r1, [r0, #36]
+
+ @ return the sp
+ mov r0, sp
+ bx lr
+
+ .size gc_helper_get_regs_and_sp, .-gc_helper_get_regs_and_sp
diff --git a/ports/stm32/i2c.c b/ports/stm32/i2c.c
index b22787cab..109b9418f 100644
--- a/ports/stm32/i2c.c
+++ b/ports/stm32/i2c.c
@@ -3,7 +3,7 @@
*
* The MIT License (MIT)
*
- * Copyright (c) 2013, 2014 Damien P. George
+ * Copyright (c) 2018 Damien P. George
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -24,1012 +24,451 @@
* THE SOFTWARE.
*/
-#include <stdio.h>
-#include <string.h>
-
-#include "py/runtime.h"
+#include "py/mperrno.h"
#include "py/mphal.h"
-#include "irq.h"
-#include "pin.h"
-#include "genhdr/pins.h"
-#include "bufhelper.h"
-#include "dma.h"
#include "i2c.h"
-/// \moduleref pyb
-/// \class I2C - a two-wire serial protocol
-///
-/// I2C is a two-wire protocol for communicating between devices. At the physical
-/// level it consists of 2 wires: SCL and SDA, the clock and data lines respectively.
-///
-/// I2C objects are created attached to a specific bus. They can be initialised
-/// when created, or initialised later on:
-///
-/// from pyb import I2C
-///
-/// i2c = I2C(1) # create on bus 1
-/// i2c = I2C(1, I2C.MASTER) # create and init as a master
-/// i2c.init(I2C.MASTER, baudrate=20000) # init as a master
-/// i2c.init(I2C.SLAVE, addr=0x42) # init as a slave with given address
-/// i2c.deinit() # turn off the peripheral
-///
-/// Printing the i2c object gives you information about its configuration.
-///
-/// Basic methods for slave are send and recv:
-///
-/// i2c.send('abc') # send 3 bytes
-/// i2c.send(0x42) # send a single byte, given by the number
-/// data = i2c.recv(3) # receive 3 bytes
-///
-/// To receive inplace, first create a bytearray:
-///
-/// data = bytearray(3) # create a buffer
-/// i2c.recv(data) # receive 3 bytes, writing them into data
-///
-/// You can specify a timeout (in ms):
-///
-/// i2c.send(b'123', timeout=2000) # timout after 2 seconds
-///
-/// A master must specify the recipient's address:
-///
-/// i2c.init(I2C.MASTER)
-/// i2c.send('123', 0x42) # send 3 bytes to slave with address 0x42
-/// i2c.send(b'456', addr=0x42) # keyword for address
-///
-/// Master also has other methods:
-///
-/// i2c.is_ready(0x42) # check if slave 0x42 is ready
-/// i2c.scan() # scan for slaves on the bus, returning
-/// # a list of valid addresses
-/// i2c.mem_read(3, 0x42, 2) # read 3 bytes from memory of slave 0x42,
-/// # starting at address 2 in the slave
-/// i2c.mem_write('abc', 0x42, 2, timeout=1000)
-#define PYB_I2C_MASTER (0)
-#define PYB_I2C_SLAVE (1)
-
-#if defined(MICROPY_HW_I2C1_SCL)
-I2C_HandleTypeDef I2CHandle1 = {.Instance = NULL};
-#endif
-#if defined(MICROPY_HW_I2C2_SCL)
-I2C_HandleTypeDef I2CHandle2 = {.Instance = NULL};
-#endif
-#if defined(MICROPY_HW_I2C3_SCL)
-I2C_HandleTypeDef I2CHandle3 = {.Instance = NULL};
-#endif
-#if defined(MICROPY_HW_I2C4_SCL)
-I2C_HandleTypeDef I2CHandle4 = {.Instance = NULL};
-#endif
+#if MICROPY_HW_ENABLE_HW_I2C
-STATIC bool pyb_i2c_use_dma[4];
+#define I2C_POLL_TIMEOUT_MS (50)
-const pyb_i2c_obj_t pyb_i2c_obj[] = {
- #if defined(MICROPY_HW_I2C1_SCL)
- {{&pyb_i2c_type}, &I2CHandle1, &dma_I2C_1_TX, &dma_I2C_1_RX, &pyb_i2c_use_dma[0]},
- #else
- {{&pyb_i2c_type}, NULL, NULL, NULL, NULL},
- #endif
- #if defined(MICROPY_HW_I2C2_SCL)
- {{&pyb_i2c_type}, &I2CHandle2, &dma_I2C_2_TX, &dma_I2C_2_RX, &pyb_i2c_use_dma[1]},
- #else
- {{&pyb_i2c_type}, NULL, NULL, NULL, NULL},
- #endif
- #if defined(MICROPY_HW_I2C3_SCL)
- {{&pyb_i2c_type}, &I2CHandle3, &dma_I2C_3_TX, &dma_I2C_3_RX, &pyb_i2c_use_dma[2]},
- #else
- {{&pyb_i2c_type}, NULL, NULL, NULL, NULL},
- #endif
- #if defined(MICROPY_HW_I2C4_SCL)
- {{&pyb_i2c_type}, &I2CHandle4, &dma_I2C_4_TX, &dma_I2C_4_RX, &pyb_i2c_use_dma[3]},
- #else
- {{&pyb_i2c_type}, NULL, NULL, NULL, NULL},
- #endif
-};
+#if defined(STM32F4)
-#if defined(MCU_SERIES_F7) || defined(MCU_SERIES_L4)
+int i2c_init(i2c_t *i2c, mp_hal_pin_obj_t scl, mp_hal_pin_obj_t sda, uint32_t freq) {
+ uint32_t i2c_id = ((uint32_t)i2c - I2C1_BASE) / (I2C2_BASE - I2C1_BASE);
-// The STM32F0, F3, F7 and L4 use a TIMINGR register rather than ClockSpeed and
-// DutyCycle.
+ // Init pins
+ if (!mp_hal_pin_config_alt(scl, MP_HAL_PIN_MODE_ALT_OPEN_DRAIN, MP_HAL_PIN_PULL_UP, AF_FN_I2C, i2c_id + 1)) {
+ return -MP_EPERM;
+ }
+ if (!mp_hal_pin_config_alt(sda, MP_HAL_PIN_MODE_ALT_OPEN_DRAIN, MP_HAL_PIN_PULL_UP, AF_FN_I2C, i2c_id + 1)) {
+ return -MP_EPERM;
+ }
-#if defined(STM32F746xx)
+ // Force reset I2C peripheral
+ RCC->APB1RSTR |= RCC_APB1RSTR_I2C1RST << i2c_id;
+ RCC->APB1RSTR &= ~(RCC_APB1RSTR_I2C1RST << i2c_id);
-// The value 0x40912732 was obtained from the DISCOVERY_I2Cx_TIMING constant
-// defined in the STM32F7Cube file Drivers/BSP/STM32F746G-Discovery/stm32f7456g_discovery.h
-#define MICROPY_HW_I2C_BAUDRATE_TIMING {{100000, 0x40912732}}
-#define MICROPY_HW_I2C_BAUDRATE_DEFAULT (100000)
-#define MICROPY_HW_I2C_BAUDRATE_MAX (100000)
+ // Enable I2C peripheral clock
+ RCC->APB1ENR |= RCC_APB1ENR_I2C1EN << i2c_id;
+ volatile uint32_t tmp = RCC->APB1ENR; // delay after RCC clock enable
+ (void)tmp;
-#elif defined(STM32F767xx) || defined(STM32F769xx)
+ uint32_t PCLK1 = HAL_RCC_GetPCLK1Freq();
-// These timing values are for f_I2CCLK=54MHz and are only approximate
-#define MICROPY_HW_I2C_BAUDRATE_TIMING { \
- {100000, 0xb0420f13}, \
- {400000, 0x70330309}, \
- {1000000, 0x50100103}, \
- }
-#define MICROPY_HW_I2C_BAUDRATE_DEFAULT (400000)
-#define MICROPY_HW_I2C_BAUDRATE_MAX (1000000)
+ // Initialise I2C peripheral
+ i2c->CR1 = 0;
+ i2c->CR2 = PCLK1 / 1000000;
+ i2c->OAR1 = 0;
+ i2c->OAR2 = 0;
-#elif defined(MCU_SERIES_L4)
+ freq = MIN(freq, 400000);
-// The value 0x90112626 was obtained from the DISCOVERY_I2C1_TIMING constant
-// defined in the STM32L4Cube file Drivers/BSP/STM32L476G-Discovery/stm32l476g_discovery.h
-#define MICROPY_HW_I2C_BAUDRATE_TIMING {{100000, 0x90112626}}
-#define MICROPY_HW_I2C_BAUDRATE_DEFAULT (100000)
-#define MICROPY_HW_I2C_BAUDRATE_MAX (100000)
+ // SM: MAX(4, PCLK1 / (F * 2))
+ // FM, 16:9 duty: 0xc000 | MAX(1, (PCLK1 / (F * (16 + 9))))
+ if (freq <= 100000) {
+ i2c->CCR = MAX(4, PCLK1 / (freq * 2));
+ } else {
+ i2c->CCR = 0xc000 | MAX(1, PCLK1 / (freq * 25));
+ }
-#else
-#error "no I2C timings for this MCU"
-#endif
+ // SM: 1000ns / (1/PCLK1) + 1 = PCLK1 * 1e-6 + 1
+ // FM: 300ns / (1/PCLK1) + 1 = 300e-3 * PCLK1 * 1e-6 + 1
+ if (freq <= 100000) {
+ i2c->TRISE = PCLK1 / 1000000 + 1; // 1000ns rise time in SM
+ } else {
+ i2c->TRISE = PCLK1 / 1000000 * 3 / 10 + 1; // 300ns rise time in FM
+ }
-STATIC const struct {
- uint32_t baudrate;
- uint32_t timing;
-} pyb_i2c_baudrate_timing[] = MICROPY_HW_I2C_BAUDRATE_TIMING;
+ #if defined(I2C_FLTR_ANOFF)
+ i2c->FLTR = 0; // analog filter on, digital filter off
+ #endif
-#define NUM_BAUDRATE_TIMINGS MP_ARRAY_SIZE(pyb_i2c_baudrate_timing)
+ return 0;
+}
-STATIC void i2c_set_baudrate(I2C_InitTypeDef *init, uint32_t baudrate) {
- for (int i = 0; i < NUM_BAUDRATE_TIMINGS; i++) {
- if (pyb_i2c_baudrate_timing[i].baudrate == baudrate) {
- init->Timing = pyb_i2c_baudrate_timing[i].timing;
- return;
+STATIC int i2c_wait_sr1_set(i2c_t *i2c, uint32_t mask) {
+ uint32_t t0 = HAL_GetTick();
+ while (!(i2c->SR1 & mask)) {
+ if (HAL_GetTick() - t0 >= I2C_POLL_TIMEOUT_MS) {
+ i2c->CR1 &= ~I2C_CR1_PE;
+ return -MP_ETIMEDOUT;
}
}
- nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError,
- "Unsupported I2C baudrate: %lu", baudrate));
+ return 0;
}
-uint32_t i2c_get_baudrate(I2C_InitTypeDef *init) {
- for (int i = 0; i < NUM_BAUDRATE_TIMINGS; i++) {
- if (pyb_i2c_baudrate_timing[i].timing == init->Timing) {
- return pyb_i2c_baudrate_timing[i].baudrate;
+STATIC int i2c_wait_stop(i2c_t *i2c) {
+ uint32_t t0 = HAL_GetTick();
+ while (i2c->CR1 & I2C_CR1_STOP) {
+ if (HAL_GetTick() - t0 >= I2C_POLL_TIMEOUT_MS) {
+ i2c->CR1 &= ~I2C_CR1_PE;
+ return -MP_ETIMEDOUT;
}
}
+ i2c->CR1 &= ~I2C_CR1_PE;
return 0;
}
-#else
+// For write: len = 0, 1 or N
+// For read: len = 1, 2 or N; stop = true
+int i2c_start_addr(i2c_t *i2c, int rd_wrn, uint16_t addr, size_t next_len, bool stop) {
+ if (!(i2c->CR1 & I2C_CR1_PE) && (i2c->SR2 & I2C_SR2_MSL)) {
+ // The F4 I2C peripheral can sometimes get into a bad state where it's disabled
+ // (PE low) but still an active master (MSL high). It seems the best way to get
+ // out of this is a full reset.
+ uint32_t i2c_id = ((uint32_t)i2c - I2C1_BASE) / (I2C2_BASE - I2C1_BASE);
+ RCC->APB1RSTR |= RCC_APB1RSTR_I2C1RST << i2c_id;
+ RCC->APB1RSTR &= ~(RCC_APB1RSTR_I2C1RST << i2c_id);
+ }
+
+ // It looks like it's possible to terminate the reading by sending a
+ // START condition instead of STOP condition but we don't support that.
+ if (rd_wrn) {
+ if (!stop) {
+ return -MP_EINVAL;
+ }
+ }
-#define MICROPY_HW_I2C_BAUDRATE_DEFAULT (400000)
-#define MICROPY_HW_I2C_BAUDRATE_MAX (400000)
+ // Repurpose OAR1 to hold stop flag
+ i2c->OAR1 = stop;
-STATIC void i2c_set_baudrate(I2C_InitTypeDef *init, uint32_t baudrate) {
- init->ClockSpeed = baudrate;
- init->DutyCycle = I2C_DUTYCYCLE_16_9;
-}
+ // Enable peripheral and send START condition
+ i2c->CR1 |= I2C_CR1_PE;
+ i2c->CR1 |= I2C_CR1_START;
-uint32_t i2c_get_baudrate(I2C_InitTypeDef *init) {
- return init->ClockSpeed;
-}
+ // Wait for START to be sent
+ int ret;
+ if ((ret = i2c_wait_sr1_set(i2c, I2C_SR1_SB))) {
+ return ret;
+ }
-#endif
+ // Send the 7-bit address with read/write bit
+ i2c->DR = addr << 1 | rd_wrn;
-void i2c_init0(void) {
- // reset the I2C1 handles
- #if defined(MICROPY_HW_I2C1_SCL)
- memset(&I2CHandle1, 0, sizeof(I2C_HandleTypeDef));
- I2CHandle1.Instance = I2C1;
- #endif
- #if defined(MICROPY_HW_I2C2_SCL)
- memset(&I2CHandle2, 0, sizeof(I2C_HandleTypeDef));
- I2CHandle2.Instance = I2C2;
- #endif
- #if defined(MICROPY_HW_I2C3_SCL)
- memset(&I2CHandle3, 0, sizeof(I2C_HandleTypeDef));
- I2CHandle3.Instance = I2C3;
- #endif
- #if defined(MICROPY_HW_I2C4_SCL)
- memset(&I2CHandle4, 0, sizeof(I2C_HandleTypeDef));
- I2CHandle3.Instance = I2C4;
- #endif
-}
+ // Wait for address to be sent
+ if ((ret = i2c_wait_sr1_set(i2c, I2C_SR1_AF | I2C_SR1_ADDR))) {
+ return ret;
+ }
-void i2c_init(I2C_HandleTypeDef *i2c) {
- int i2c_unit;
- const pin_obj_t *scl_pin;
- const pin_obj_t *sda_pin;
-
- if (0) {
- #if defined(MICROPY_HW_I2C1_SCL)
- } else if (i2c == &I2CHandle1) {
- i2c_unit = 1;
- scl_pin = &MICROPY_HW_I2C1_SCL;
- sda_pin = &MICROPY_HW_I2C1_SDA;
- __I2C1_CLK_ENABLE();
- #endif
- #if defined(MICROPY_HW_I2C2_SCL)
- } else if (i2c == &I2CHandle2) {
- i2c_unit = 2;
- scl_pin = &MICROPY_HW_I2C2_SCL;
- sda_pin = &MICROPY_HW_I2C2_SDA;
- __I2C2_CLK_ENABLE();
- #endif
- #if defined(MICROPY_HW_I2C3_SCL)
- } else if (i2c == &I2CHandle3) {
- i2c_unit = 3;
- scl_pin = &MICROPY_HW_I2C3_SCL;
- sda_pin = &MICROPY_HW_I2C3_SDA;
- __I2C3_CLK_ENABLE();
- #endif
- #if defined(MICROPY_HW_I2C4_SCL)
- } else if (i2c == &I2CHandle4) {
- i2c_unit = 4;
- scl_pin = &MICROPY_HW_I2C4_SCL;
- sda_pin = &MICROPY_HW_I2C4_SDA;
- __I2C3_CLK_ENABLE();
- #endif
- } else {
- // I2C does not exist for this board (shouldn't get here, should be checked by caller)
- return;
+ // Check if the slave responded or not
+ if (i2c->SR1 & I2C_SR1_AF) {
+ // Got a NACK
+ i2c->CR1 |= I2C_CR1_STOP;
+ i2c_wait_stop(i2c); // Don't leak errors from this call
+ return -MP_ENODEV;
}
- // init the GPIO lines
- uint32_t mode = MP_HAL_PIN_MODE_ALT_OPEN_DRAIN;
- uint32_t pull = MP_HAL_PIN_PULL_NONE; // have external pull-up resistors on both lines
- mp_hal_pin_config_alt(scl_pin, mode, pull, AF_FN_I2C, i2c_unit);
- mp_hal_pin_config_alt(sda_pin, mode, pull, AF_FN_I2C, i2c_unit);
-
- // init the I2C device
- if (HAL_I2C_Init(i2c) != HAL_OK) {
- // init error
- // TODO should raise an exception, but this function is not necessarily going to be
- // called via Python, so may not be properly wrapped in an NLR handler
- printf("OSError: HAL_I2C_Init failed\n");
- return;
+ if (rd_wrn) {
+ // For reading, set up ACK/NACK control based on number of bytes to read (at least 1 byte)
+ if (next_len <= 1) {
+ // NACK next received byte
+ i2c->CR1 &= ~I2C_CR1_ACK;
+ } else if (next_len <= 2) {
+ // NACK second received byte
+ i2c->CR1 |= I2C_CR1_POS;
+ i2c->CR1 &= ~I2C_CR1_ACK;
+ } else {
+ // ACK next received byte
+ i2c->CR1 |= I2C_CR1_ACK;
+ }
}
- // invalidate the DMA channels so they are initialised on first use
- const pyb_i2c_obj_t *self = &pyb_i2c_obj[i2c_unit - 1];
- dma_invalidate_channel(self->tx_dma_descr);
- dma_invalidate_channel(self->rx_dma_descr);
+ // Read SR2 to clear SR1_ADDR
+ uint32_t sr2 = i2c->SR2;
+ (void)sr2;
- if (0) {
- #if defined(MICROPY_HW_I2C1_SCL)
- } else if (i2c->Instance == I2C1) {
- HAL_NVIC_EnableIRQ(I2C1_EV_IRQn);
- HAL_NVIC_EnableIRQ(I2C1_ER_IRQn);
- #endif
- #if defined(MICROPY_HW_I2C2_SCL)
- } else if (i2c->Instance == I2C2) {
- HAL_NVIC_EnableIRQ(I2C2_EV_IRQn);
- HAL_NVIC_EnableIRQ(I2C2_ER_IRQn);
- #endif
- #if defined(MICROPY_HW_I2C3_SCL)
- } else if (i2c->Instance == I2C3) {
- HAL_NVIC_EnableIRQ(I2C3_EV_IRQn);
- HAL_NVIC_EnableIRQ(I2C3_ER_IRQn);
- #endif
- #if defined(MICROPY_HW_I2C4_SCL)
- } else if (i2c->Instance == I2C4) {
- HAL_NVIC_EnableIRQ(I2C4_EV_IRQn);
- HAL_NVIC_EnableIRQ(I2C4_ER_IRQn);
- #endif
- }
+ return 0;
}
-void i2c_deinit(I2C_HandleTypeDef *i2c) {
- HAL_I2C_DeInit(i2c);
- if (0) {
- #if defined(MICROPY_HW_I2C1_SCL)
- } else if (i2c->Instance == I2C1) {
- __I2C1_FORCE_RESET();
- __I2C1_RELEASE_RESET();
- __I2C1_CLK_DISABLE();
- HAL_NVIC_DisableIRQ(I2C1_EV_IRQn);
- HAL_NVIC_DisableIRQ(I2C1_ER_IRQn);
- #endif
- #if defined(MICROPY_HW_I2C2_SCL)
- } else if (i2c->Instance == I2C2) {
- __I2C2_FORCE_RESET();
- __I2C2_RELEASE_RESET();
- __I2C2_CLK_DISABLE();
- HAL_NVIC_DisableIRQ(I2C2_EV_IRQn);
- HAL_NVIC_DisableIRQ(I2C2_ER_IRQn);
- #endif
- #if defined(MICROPY_HW_I2C3_SCL)
- } else if (i2c->Instance == I2C3) {
- __I2C3_FORCE_RESET();
- __I2C3_RELEASE_RESET();
- __I2C3_CLK_DISABLE();
- HAL_NVIC_DisableIRQ(I2C3_EV_IRQn);
- HAL_NVIC_DisableIRQ(I2C3_ER_IRQn);
- #endif
- #if defined(MICROPY_HW_I2C4_SCL)
- } else if (i2c->Instance == I2C4) {
- __HAL_RCC_I2C4_FORCE_RESET();
- __HAL_RCC_I2C4_RELEASE_RESET();
- __HAL_RCC_I2C4_CLK_DISABLE();
- HAL_NVIC_DisableIRQ(I2C4_EV_IRQn);
- HAL_NVIC_DisableIRQ(I2C4_ER_IRQn);
- #endif
+// next_len = 0 or N (>=2)
+int i2c_read(i2c_t *i2c, uint8_t *dest, size_t len, size_t next_len) {
+ if (len == 0) {
+ return -MP_EINVAL;
+ }
+ if (next_len == 1) {
+ return -MP_EINVAL;
}
-}
-void i2c_init_freq(const pyb_i2c_obj_t *self, mp_int_t freq) {
- I2C_InitTypeDef *init = &self->i2c->Init;
-
- init->AddressingMode = I2C_ADDRESSINGMODE_7BIT;
- init->DualAddressMode = I2C_DUALADDRESS_DISABLED;
- init->GeneralCallMode = I2C_GENERALCALL_DISABLED;
- init->NoStretchMode = I2C_NOSTRETCH_DISABLE;
- init->OwnAddress1 = PYB_I2C_MASTER_ADDRESS;
- init->OwnAddress2 = 0; // unused
- if (freq != -1) {
- i2c_set_baudrate(init, MIN(freq, MICROPY_HW_I2C_BAUDRATE_MAX));
+ size_t remain = len + next_len;
+ if (remain == 1) {
+ // Special case
+ i2c->CR1 |= I2C_CR1_STOP;
+ int ret;
+ if ((ret = i2c_wait_sr1_set(i2c, I2C_SR1_RXNE))) {
+ return ret;
+ }
+ *dest = i2c->DR;
+ } else {
+ for (; len; --len) {
+ remain = len + next_len;
+ int ret;
+ if ((ret = i2c_wait_sr1_set(i2c, I2C_SR1_BTF))) {
+ return ret;
+ }
+ if (remain == 2) {
+ // In this case next_len == 0 (it's not allowed to be 1)
+ i2c->CR1 |= I2C_CR1_STOP;
+ *dest++ = i2c->DR;
+ *dest = i2c->DR;
+ break;
+ } else if (remain == 3) {
+ // NACK next received byte
+ i2c->CR1 &= ~I2C_CR1_ACK;
+ }
+ *dest++ = i2c->DR;
+ }
}
- *self->use_dma = false;
+ if (!next_len) {
+ // We sent a stop above, just wait for it to be finished
+ return i2c_wait_stop(i2c);
+ }
- // init the I2C bus
- i2c_deinit(self->i2c);
- i2c_init(self->i2c);
+ return 0;
}
-STATIC void i2c_reset_after_error(I2C_HandleTypeDef *i2c) {
- // wait for bus-busy flag to be cleared, with a timeout
- for (int timeout = 50; timeout > 0; --timeout) {
- if (!__HAL_I2C_GET_FLAG(i2c, I2C_FLAG_BUSY)) {
- // stop bit was generated and bus is back to normal
- return;
- }
- mp_hal_delay_ms(1);
+// next_len = 0 or N
+int i2c_write(i2c_t *i2c, const uint8_t *src, size_t len, size_t next_len) {
+ int ret;
+ if ((ret = i2c_wait_sr1_set(i2c, I2C_SR1_AF | I2C_SR1_TXE))) {
+ return ret;
}
- // bus was/is busy, need to reset the peripheral to get it to work again
- i2c_deinit(i2c);
- i2c_init(i2c);
-}
-void i2c_ev_irq_handler(mp_uint_t i2c_id) {
- I2C_HandleTypeDef *hi2c;
-
- switch (i2c_id) {
- #if defined(MICROPY_HW_I2C1_SCL)
- case 1:
- hi2c = &I2CHandle1;
- break;
- #endif
- #if defined(MICROPY_HW_I2C2_SCL)
- case 2:
- hi2c = &I2CHandle2;
- break;
- #endif
- #if defined(MICROPY_HW_I2C3_SCL)
- case 3:
- hi2c = &I2CHandle3;
- break;
- #endif
- #if defined(MICROPY_HW_I2C4_SCL)
- case 4:
- hi2c = &I2CHandle4;
+ // Write out the data
+ int num_acks = 0;
+ while (len--) {
+ i2c->DR = *src++;
+ if ((ret = i2c_wait_sr1_set(i2c, I2C_SR1_AF | I2C_SR1_BTF))) {
+ return ret;
+ }
+ if (i2c->SR1 & I2C_SR1_AF) {
+ // Slave did not respond to byte so stop sending
break;
- #endif
- default:
- return;
+ }
+ ++num_acks;
}
- #if defined(MCU_SERIES_F4)
-
- if (hi2c->Instance->SR1 & I2C_FLAG_BTF && hi2c->State == HAL_I2C_STATE_BUSY_TX) {
- if (hi2c->XferCount != 0U) {
- hi2c->Instance->DR = *hi2c->pBuffPtr++;
- hi2c->XferCount--;
- } else {
- __HAL_I2C_DISABLE_IT(hi2c, I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR);
- if (hi2c->XferOptions != I2C_FIRST_FRAME) {
- hi2c->Instance->CR1 |= I2C_CR1_STOP;
+ if (!next_len) {
+ if (i2c->OAR1) {
+ // Send a STOP and wait for it to finish
+ i2c->CR1 |= I2C_CR1_STOP;
+ if ((ret = i2c_wait_stop(i2c))) {
+ return ret;
}
- hi2c->Mode = HAL_I2C_MODE_NONE;
- hi2c->State = HAL_I2C_STATE_READY;
}
}
- #else
-
- // if not an F4 MCU, use the HAL's IRQ handler
- HAL_I2C_EV_IRQHandler(hi2c);
-
- #endif
+ return num_acks;
}
-void i2c_er_irq_handler(mp_uint_t i2c_id) {
- I2C_HandleTypeDef *hi2c;
+#elif defined(STM32F0) || defined(STM32F7)
- switch (i2c_id) {
- #if defined(MICROPY_HW_I2C1_SCL)
- case 1:
- hi2c = &I2CHandle1;
- break;
- #endif
- #if defined(MICROPY_HW_I2C2_SCL)
- case 2:
- hi2c = &I2CHandle2;
- break;
- #endif
- #if defined(MICROPY_HW_I2C3_SCL)
- case 3:
- hi2c = &I2CHandle3;
- break;
- #endif
- #if defined(MICROPY_HW_I2C4_SCL)
- case 4:
- hi2c = &I2CHandle4;
- break;
- #endif
- default:
- return;
- }
-
- #if defined(MCU_SERIES_F4)
-
- uint32_t sr1 = hi2c->Instance->SR1;
+int i2c_init(i2c_t *i2c, mp_hal_pin_obj_t scl, mp_hal_pin_obj_t sda, uint32_t freq) {
+ uint32_t i2c_id = ((uint32_t)i2c - I2C1_BASE) / (I2C2_BASE - I2C1_BASE);
- // I2C Bus error
- if (sr1 & I2C_FLAG_BERR) {
- hi2c->ErrorCode |= HAL_I2C_ERROR_BERR;
- __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_BERR);
+ // Init pins
+ if (!mp_hal_pin_config_alt(scl, MP_HAL_PIN_MODE_ALT_OPEN_DRAIN, MP_HAL_PIN_PULL_UP, AF_FN_I2C, i2c_id + 1)) {
+ return -MP_EPERM;
}
-
- // I2C Arbitration Loss error
- if (sr1 & I2C_FLAG_ARLO) {
- hi2c->ErrorCode |= HAL_I2C_ERROR_ARLO;
- __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_ARLO);
+ if (!mp_hal_pin_config_alt(sda, MP_HAL_PIN_MODE_ALT_OPEN_DRAIN, MP_HAL_PIN_PULL_UP, AF_FN_I2C, i2c_id + 1)) {
+ return -MP_EPERM;
}
- // I2C Acknowledge failure
- if (sr1 & I2C_FLAG_AF) {
- hi2c->ErrorCode |= HAL_I2C_ERROR_AF;
- SET_BIT(hi2c->Instance->CR1,I2C_CR1_STOP);
- __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_AF);
- }
+ // Enable I2C peripheral clock
+ RCC->APB1ENR |= RCC_APB1ENR_I2C1EN << i2c_id;
+ volatile uint32_t tmp = RCC->APB1ENR; // delay after RCC clock enable
+ (void)tmp;
- // I2C Over-Run/Under-Run
- if (sr1 & I2C_FLAG_OVR) {
- hi2c->ErrorCode |= HAL_I2C_ERROR_OVR;
- __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_OVR);
- }
+ // Initialise I2C peripheral
+ i2c->CR1 = 0;
+ i2c->CR2 = 0;
+ i2c->OAR1 = 0;
+ i2c->OAR2 = 0;
- #else
+ // These timing values are for f_I2CCLK=54MHz and are only approximate
+ if (freq >= 1000000) {
+ i2c->TIMINGR = 0x50100103;
+ } else if (freq >= 400000) {
+ i2c->TIMINGR = 0x70330309;
+ } else if (freq >= 100000) {
+ i2c->TIMINGR = 0xb0420f13;
+ } else {
+ return -MP_EINVAL;
+ }
- // if not an F4 MCU, use the HAL's IRQ handler
- HAL_I2C_ER_IRQHandler(hi2c);
+ i2c->TIMEOUTR = 0;
- #endif
+ return 0;
}
-STATIC HAL_StatusTypeDef i2c_wait_dma_finished(I2C_HandleTypeDef *i2c, uint32_t timeout) {
- // Note: we can't use WFI to idle in this loop because the DMA completion
- // interrupt may occur before the WFI. Hence we miss it and have to wait
- // until the next sys-tick (up to 1ms).
- uint32_t start = HAL_GetTick();
- while (HAL_I2C_GetState(i2c) != HAL_I2C_STATE_READY) {
- if (HAL_GetTick() - start >= timeout) {
- return HAL_TIMEOUT;
+STATIC int i2c_wait_cr2_clear(i2c_t *i2c, uint32_t mask) {
+ uint32_t t0 = HAL_GetTick();
+ while (i2c->CR2 & mask) {
+ if (HAL_GetTick() - t0 >= I2C_POLL_TIMEOUT_MS) {
+ i2c->CR1 &= ~I2C_CR1_PE;
+ return -MP_ETIMEDOUT;
}
}
- return HAL_OK;
+ return 0;
}
-/******************************************************************************/
-/* MicroPython bindings */
-
-static inline bool in_master_mode(pyb_i2c_obj_t *self) { return self->i2c->Init.OwnAddress1 == PYB_I2C_MASTER_ADDRESS; }
-
-STATIC void pyb_i2c_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
- pyb_i2c_obj_t *self = self_in;
-
- uint i2c_num = 0;
- if (0) { }
- #if defined(MICROPY_HW_I2C1_SCL)
- else if (self->i2c->Instance == I2C1) { i2c_num = 1; }
- #endif
- #if defined(MICROPY_HW_I2C2_SCL)
- else if (self->i2c->Instance == I2C2) { i2c_num = 2; }
- #endif
- #if defined(MICROPY_HW_I2C3_SCL)
- else if (self->i2c->Instance == I2C3) { i2c_num = 3; }
- #endif
- #if defined(MICROPY_HW_I2C4_SCL)
- else if (self->i2c->Instance == I2C4) { i2c_num = 4; }
- #endif
-
- if (self->i2c->State == HAL_I2C_STATE_RESET) {
- mp_printf(print, "I2C(%u)", i2c_num);
- } else {
- if (in_master_mode(self)) {
- mp_printf(print, "I2C(%u, I2C.MASTER, baudrate=%u)", i2c_num, i2c_get_baudrate(&self->i2c->Init));
- } else {
- mp_printf(print, "I2C(%u, I2C.SLAVE, addr=0x%02x)", i2c_num, (self->i2c->Instance->OAR1 >> 1) & 0x7f);
+STATIC int i2c_wait_isr_set(i2c_t *i2c, uint32_t mask) {
+ uint32_t t0 = HAL_GetTick();
+ while (!(i2c->ISR & mask)) {
+ if (HAL_GetTick() - t0 >= I2C_POLL_TIMEOUT_MS) {
+ i2c->CR1 &= ~I2C_CR1_PE;
+ return -MP_ETIMEDOUT;
}
}
+ return 0;
}
-/// \method init(mode, *, addr=0x12, baudrate=400000, gencall=False)
-///
-/// Initialise the I2C bus with the given parameters:
-///
-/// - `mode` must be either `I2C.MASTER` or `I2C.SLAVE`
-/// - `addr` is the 7-bit address (only sensible for a slave)
-/// - `baudrate` is the SCL clock rate (only sensible for a master)
-/// - `gencall` is whether to support general call mode
-STATIC mp_obj_t pyb_i2c_init_helper(const pyb_i2c_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
- static const mp_arg_t allowed_args[] = {
- { MP_QSTR_mode, MP_ARG_INT, {.u_int = PYB_I2C_MASTER} },
- { MP_QSTR_addr, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0x12} },
- { MP_QSTR_baudrate, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = MICROPY_HW_I2C_BAUDRATE_DEFAULT} },
- { MP_QSTR_gencall, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
- { MP_QSTR_dma, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
- };
-
- // parse args
- mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
- mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
-
- // set the I2C configuration values
- I2C_InitTypeDef *init = &self->i2c->Init;
-
- if (args[0].u_int == PYB_I2C_MASTER) {
- // use a special address to indicate we are a master
- init->OwnAddress1 = PYB_I2C_MASTER_ADDRESS;
- } else {
- init->OwnAddress1 = (args[1].u_int << 1) & 0xfe;
- }
-
- i2c_set_baudrate(init, MIN(args[2].u_int, MICROPY_HW_I2C_BAUDRATE_MAX));
- init->AddressingMode = I2C_ADDRESSINGMODE_7BIT;
- init->DualAddressMode = I2C_DUALADDRESS_DISABLED;
- init->GeneralCallMode = args[3].u_bool ? I2C_GENERALCALL_ENABLED : I2C_GENERALCALL_DISABLED;
- init->OwnAddress2 = 0; // unused
- init->NoStretchMode = I2C_NOSTRETCH_DISABLE;
-
- *self->use_dma = args[4].u_bool;
-
- // init the I2C bus
- i2c_deinit(self->i2c);
- i2c_init(self->i2c);
-
- return mp_const_none;
-}
+// len = 0, 1 or N
+int i2c_start_addr(i2c_t *i2c, int rd_wrn, uint16_t addr, size_t len, bool stop) {
+ // Enable the peripheral and send the START condition with slave address
+ i2c->CR1 |= I2C_CR1_PE;
+ i2c->CR2 = stop << I2C_CR2_AUTOEND_Pos
+ | (len > 1) << I2C_CR2_RELOAD_Pos
+ | (len > 0) << I2C_CR2_NBYTES_Pos
+ | rd_wrn << I2C_CR2_RD_WRN_Pos
+ | (addr & 0x7f) << 1;
+ i2c->CR2 |= I2C_CR2_START;
-/// \classmethod \constructor(bus, ...)
-///
-/// Construct an I2C object on the given bus. `bus` can be 1 or 2.
-/// With no additional parameters, the I2C object is created but not
-/// initialised (it has the settings from the last initialisation of
-/// the bus, if any). If extra arguments are given, the bus is initialised.
-/// See `init` for parameters of initialisation.
-///
-/// The physical pins of the I2C busses are:
-///
-/// - `I2C(1)` is on the X position: `(SCL, SDA) = (X9, X10) = (PB6, PB7)`
-/// - `I2C(2)` is on the Y position: `(SCL, SDA) = (Y9, Y10) = (PB10, PB11)`
-STATIC mp_obj_t pyb_i2c_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
- // check arguments
- mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true);
-
- // work out i2c bus
- int i2c_id = 0;
- if (MP_OBJ_IS_STR(args[0])) {
- const char *port = mp_obj_str_get_str(args[0]);
- if (0) {
- #ifdef MICROPY_HW_I2C1_NAME
- } else if (strcmp(port, MICROPY_HW_I2C1_NAME) == 0) {
- i2c_id = 1;
- #endif
- #ifdef MICROPY_HW_I2C2_NAME
- } else if (strcmp(port, MICROPY_HW_I2C2_NAME) == 0) {
- i2c_id = 2;
- #endif
- #ifdef MICROPY_HW_I2C3_NAME
- } else if (strcmp(port, MICROPY_HW_I2C3_NAME) == 0) {
- i2c_id = 3;
- #endif
- } else {
- nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError,
- "I2C(%s) doesn't exist", port));
- }
- } else {
- i2c_id = mp_obj_get_int(args[0]);
- if (i2c_id < 1 || i2c_id > MP_ARRAY_SIZE(pyb_i2c_obj)
- || pyb_i2c_obj[i2c_id - 1].i2c == NULL) {
- nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError,
- "I2C(%d) doesn't exist", i2c_id));
- }
+ // Wait for address to be sent
+ int ret;
+ if ((ret = i2c_wait_cr2_clear(i2c, I2C_CR2_START))) {
+ return ret;
}
- // get I2C object
- const pyb_i2c_obj_t *i2c_obj = &pyb_i2c_obj[i2c_id - 1];
-
- if (n_args > 1 || n_kw > 0) {
- // start the peripheral
- mp_map_t kw_args;
- mp_map_init_fixed_table(&kw_args, n_kw, args + n_args);
- pyb_i2c_init_helper(i2c_obj, n_args - 1, args + 1, &kw_args);
+ // Check if the slave responded or not
+ if (i2c->ISR & I2C_ISR_NACKF) {
+ // If we get a NACK then I2C periph unconditionally sends a STOP
+ i2c_wait_isr_set(i2c, I2C_ISR_STOPF); // Don't leak errors from this call
+ i2c->CR1 &= ~I2C_CR1_PE;
+ return -MP_ENODEV;
}
- return (mp_obj_t)i2c_obj;
-}
+ // Repurpose OAR1 to indicate that we loaded CR2
+ i2c->OAR1 = 1;
-STATIC mp_obj_t pyb_i2c_init(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
- return pyb_i2c_init_helper(args[0], n_args - 1, args + 1, kw_args);
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_i2c_init_obj, 1, pyb_i2c_init);
-
-/// \method deinit()
-/// Turn off the I2C bus.
-STATIC mp_obj_t pyb_i2c_deinit(mp_obj_t self_in) {
- pyb_i2c_obj_t *self = self_in;
- i2c_deinit(self->i2c);
- return mp_const_none;
+ return 0;
}
-STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_i2c_deinit_obj, pyb_i2c_deinit);
-
-/// \method is_ready(addr)
-/// Check if an I2C device responds to the given address. Only valid when in master mode.
-STATIC mp_obj_t pyb_i2c_is_ready(mp_obj_t self_in, mp_obj_t i2c_addr_o) {
- pyb_i2c_obj_t *self = self_in;
-
- if (!in_master_mode(self)) {
- mp_raise_TypeError("I2C must be a master");
- }
- mp_uint_t i2c_addr = mp_obj_get_int(i2c_addr_o) << 1;
-
- for (int i = 0; i < 10; i++) {
- HAL_StatusTypeDef status = HAL_I2C_IsDeviceReady(self->i2c, i2c_addr, 10, 200);
- if (status == HAL_OK) {
- return mp_const_true;
+STATIC int i2c_check_stop(i2c_t *i2c) {
+ if (i2c->CR2 & I2C_CR2_AUTOEND) {
+ // Wait for the STOP condition and then disable the peripheral
+ int ret;
+ if ((ret = i2c_wait_isr_set(i2c, I2C_ISR_STOPF))) {
+ return ret;
}
+ i2c->CR1 &= ~I2C_CR1_PE;
}
- return mp_const_false;
+ return 0;
}
-STATIC MP_DEFINE_CONST_FUN_OBJ_2(pyb_i2c_is_ready_obj, pyb_i2c_is_ready);
-
-/// \method scan()
-/// Scan all I2C addresses from 0x08 to 0x77 and return a list of those that respond.
-/// Only valid when in master mode.
-STATIC mp_obj_t pyb_i2c_scan(mp_obj_t self_in) {
- pyb_i2c_obj_t *self = self_in;
-
- if (!in_master_mode(self)) {
- mp_raise_TypeError("I2C must be a master");
- }
- mp_obj_t list = mp_obj_new_list(0, NULL);
-
- for (uint addr = 0x08; addr <= 0x77; addr++) {
- HAL_StatusTypeDef status = HAL_I2C_IsDeviceReady(self->i2c, addr << 1, 1, 200);
- if (status == HAL_OK) {
- mp_obj_list_append(list, MP_OBJ_NEW_SMALL_INT(addr));
- }
- }
-
- return list;
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_i2c_scan_obj, pyb_i2c_scan);
-
-/// \method send(send, addr=0x00, timeout=5000)
-/// Send data on the bus:
-///
-/// - `send` is the data to send (an integer to send, or a buffer object)
-/// - `addr` is the address to send to (only required in master mode)
-/// - `timeout` is the timeout in milliseconds to wait for the send
-///
-/// Return value: `None`.
-STATIC mp_obj_t pyb_i2c_send(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
- static const mp_arg_t allowed_args[] = {
- { MP_QSTR_send, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
- { MP_QSTR_addr, MP_ARG_INT, {.u_int = PYB_I2C_MASTER_ADDRESS} },
- { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 5000} },
- };
-
- // parse args
- pyb_i2c_obj_t *self = pos_args[0];
- mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
- mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
-
- // get the buffer to send from
- mp_buffer_info_t bufinfo;
- uint8_t data[1];
- pyb_buf_get_for_send(args[0].u_obj, &bufinfo, data);
-
- // if option is set and IRQs are enabled then we can use DMA
- bool use_dma = *self->use_dma && query_irq() == IRQ_STATE_ENABLED;
-
- DMA_HandleTypeDef tx_dma;
- if (use_dma) {
- dma_init(&tx_dma, self->tx_dma_descr, self->i2c);
- self->i2c->hdmatx = &tx_dma;
- self->i2c->hdmarx = NULL;
+// next_len = 0 or N
+int i2c_read(i2c_t *i2c, uint8_t *dest, size_t len, size_t next_len) {
+ if (i2c->OAR1) {
+ i2c->OAR1 = 0;
+ } else {
+ goto load_cr2;
}
- // send the data
- HAL_StatusTypeDef status;
- if (in_master_mode(self)) {
- if (args[1].u_int == PYB_I2C_MASTER_ADDRESS) {
- if (use_dma) {
- dma_deinit(self->tx_dma_descr);
- }
- mp_raise_TypeError("addr argument required");
- }
- mp_uint_t i2c_addr = args[1].u_int << 1;
- if (!use_dma) {
- status = HAL_I2C_Master_Transmit(self->i2c, i2c_addr, bufinfo.buf, bufinfo.len, args[2].u_int);
- } else {
- MP_HAL_CLEAN_DCACHE(bufinfo.buf, bufinfo.len);
- status = HAL_I2C_Master_Transmit_DMA(self->i2c, i2c_addr, bufinfo.buf, bufinfo.len);
+ // Read in the data
+ while (len--) {
+ int ret;
+ if ((ret = i2c_wait_isr_set(i2c, I2C_ISR_RXNE))) {
+ return ret;
}
- } else {
- if (!use_dma) {
- status = HAL_I2C_Slave_Transmit(self->i2c, bufinfo.buf, bufinfo.len, args[2].u_int);
- } else {
- MP_HAL_CLEAN_DCACHE(bufinfo.buf, bufinfo.len);
- status = HAL_I2C_Slave_Transmit_DMA(self->i2c, bufinfo.buf, bufinfo.len);
+ *dest++ = i2c->RXDR;
+ load_cr2:
+ if (len) {
+ i2c->CR2 = (i2c->CR2 & I2C_CR2_AUTOEND)
+ | (len + next_len > 1) << I2C_CR2_RELOAD_Pos
+ | 1 << I2C_CR2_NBYTES_Pos;
}
}
- // if we used DMA, wait for it to finish
- if (use_dma) {
- if (status == HAL_OK) {
- status = i2c_wait_dma_finished(self->i2c, args[2].u_int);
+ if (!next_len) {
+ int ret;
+ if ((ret = i2c_check_stop(i2c))) {
+ return ret;
}
- dma_deinit(self->tx_dma_descr);
}
- if (status != HAL_OK) {
- i2c_reset_after_error(self->i2c);
- mp_hal_raise(status);
- }
-
- return mp_const_none;
+ return 0;
}
-STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_i2c_send_obj, 1, pyb_i2c_send);
-
-/// \method recv(recv, addr=0x00, timeout=5000)
-///
-/// Receive data on the bus:
-///
-/// - `recv` can be an integer, which is the number of bytes to receive,
-/// or a mutable buffer, which will be filled with received bytes
-/// - `addr` is the address to receive from (only required in master mode)
-/// - `timeout` is the timeout in milliseconds to wait for the receive
-///
-/// Return value: if `recv` is an integer then a new buffer of the bytes received,
-/// otherwise the same buffer that was passed in to `recv`.
-STATIC mp_obj_t pyb_i2c_recv(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
- static const mp_arg_t allowed_args[] = {
- { MP_QSTR_recv, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
- { MP_QSTR_addr, MP_ARG_INT, {.u_int = PYB_I2C_MASTER_ADDRESS} },
- { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 5000} },
- };
-
- // parse args
- pyb_i2c_obj_t *self = pos_args[0];
- mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
- mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
-
- // get the buffer to receive into
- vstr_t vstr;
- mp_obj_t o_ret = pyb_buf_get_for_recv(args[0].u_obj, &vstr);
-
- // if option is set and IRQs are enabled then we can use DMA
- bool use_dma = *self->use_dma && query_irq() == IRQ_STATE_ENABLED;
-
- DMA_HandleTypeDef rx_dma;
- if (use_dma) {
- dma_init(&rx_dma, self->rx_dma_descr, self->i2c);
- self->i2c->hdmatx = NULL;
- self->i2c->hdmarx = &rx_dma;
+
+// next_len = 0 or N
+int i2c_write(i2c_t *i2c, const uint8_t *src, size_t len, size_t next_len) {
+ int num_acks = 0;
+
+ if (i2c->OAR1) {
+ i2c->OAR1 = 0;
+ } else {
+ goto load_cr2;
}
- // receive the data
- HAL_StatusTypeDef status;
- if (in_master_mode(self)) {
- if (args[1].u_int == PYB_I2C_MASTER_ADDRESS) {
- mp_raise_TypeError("addr argument required");
+ // Write out the data
+ while (len--) {
+ int ret;
+ if ((ret = i2c_wait_isr_set(i2c, I2C_ISR_TXE))) {
+ return ret;
}
- mp_uint_t i2c_addr = args[1].u_int << 1;
- if (!use_dma) {
- status = HAL_I2C_Master_Receive(self->i2c, i2c_addr, (uint8_t*)vstr.buf, vstr.len, args[2].u_int);
- } else {
- MP_HAL_CLEANINVALIDATE_DCACHE(vstr.buf, vstr.len);
- status = HAL_I2C_Master_Receive_DMA(self->i2c, i2c_addr, (uint8_t*)vstr.buf, vstr.len);
+ i2c->TXDR = *src++;
+ if ((ret = i2c_wait_isr_set(i2c, I2C_ISR_TCR | I2C_ISR_TC | I2C_ISR_STOPF))) {
+ return ret;
}
- } else {
- if (!use_dma) {
- status = HAL_I2C_Slave_Receive(self->i2c, (uint8_t*)vstr.buf, vstr.len, args[2].u_int);
- } else {
- MP_HAL_CLEANINVALIDATE_DCACHE(vstr.buf, vstr.len);
- status = HAL_I2C_Slave_Receive_DMA(self->i2c, (uint8_t*)vstr.buf, vstr.len);
+ uint32_t isr = i2c->ISR;
+ if (isr & I2C_ISR_NACKF) {
+ // Slave did not respond to byte so stop sending
+ if (!(isr & I2C_ISR_TXE)) {
+ // The TXDR is still full so the byte previous to that wasn't actually ACK'd
+ --num_acks;
+ }
+ break;
}
- }
-
- // if we used DMA, wait for it to finish
- if (use_dma) {
- if (status == HAL_OK) {
- status = i2c_wait_dma_finished(self->i2c, args[2].u_int);
+ ++num_acks;
+ load_cr2:
+ if (len) {
+ i2c->CR2 = (i2c->CR2 & I2C_CR2_AUTOEND)
+ | (len + next_len > 1) << I2C_CR2_RELOAD_Pos
+ | 1 << I2C_CR2_NBYTES_Pos;
}
- dma_deinit(self->rx_dma_descr);
}
- if (status != HAL_OK) {
- i2c_reset_after_error(self->i2c);
- mp_hal_raise(status);
+ if (!next_len) {
+ int ret;
+ if ((ret = i2c_check_stop(i2c))) {
+ return ret;
+ }
}
- // return the received data
- if (o_ret != MP_OBJ_NULL) {
- return o_ret;
- } else {
- return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
- }
+ return num_acks;
}
-STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_i2c_recv_obj, 1, pyb_i2c_recv);
-
-/// \method mem_read(data, addr, memaddr, timeout=5000, addr_size=8)
-///
-/// Read from the memory of an I2C device:
-///
-/// - `data` can be an integer or a buffer to read into
-/// - `addr` is the I2C device address
-/// - `memaddr` is the memory location within the I2C device
-/// - `timeout` is the timeout in milliseconds to wait for the read
-/// - `addr_size` selects width of memaddr: 8 or 16 bits
-///
-/// Returns the read data.
-/// This is only valid in master mode.
-STATIC const mp_arg_t pyb_i2c_mem_read_allowed_args[] = {
- { MP_QSTR_data, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
- { MP_QSTR_addr, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} },
- { MP_QSTR_memaddr, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} },
- { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 5000} },
- { MP_QSTR_addr_size, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 8} },
-};
-
-STATIC mp_obj_t pyb_i2c_mem_read(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
- // parse args
- pyb_i2c_obj_t *self = pos_args[0];
- mp_arg_val_t args[MP_ARRAY_SIZE(pyb_i2c_mem_read_allowed_args)];
- mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(pyb_i2c_mem_read_allowed_args), pyb_i2c_mem_read_allowed_args, args);
-
- if (!in_master_mode(self)) {
- mp_raise_TypeError("I2C must be a master");
- }
-
- // get the buffer to read into
- vstr_t vstr;
- mp_obj_t o_ret = pyb_buf_get_for_recv(args[0].u_obj, &vstr);
-
- // get the addresses
- mp_uint_t i2c_addr = args[1].u_int << 1;
- mp_uint_t mem_addr = args[2].u_int;
- // determine width of mem_addr; default is 8 bits, entering any other value gives 16 bit width
- mp_uint_t mem_addr_size = I2C_MEMADD_SIZE_8BIT;
- if (args[4].u_int != 8) {
- mem_addr_size = I2C_MEMADD_SIZE_16BIT;
- }
-
- // if option is set and IRQs are enabled then we can use DMA
- bool use_dma = *self->use_dma && query_irq() == IRQ_STATE_ENABLED;
- HAL_StatusTypeDef status;
- if (!use_dma) {
- status = HAL_I2C_Mem_Read(self->i2c, i2c_addr, mem_addr, mem_addr_size, (uint8_t*)vstr.buf, vstr.len, args[3].u_int);
- } else {
- DMA_HandleTypeDef rx_dma;
- dma_init(&rx_dma, self->rx_dma_descr, self->i2c);
- self->i2c->hdmatx = NULL;
- self->i2c->hdmarx = &rx_dma;
- MP_HAL_CLEANINVALIDATE_DCACHE(vstr.buf, vstr.len);
- status = HAL_I2C_Mem_Read_DMA(self->i2c, i2c_addr, mem_addr, mem_addr_size, (uint8_t*)vstr.buf, vstr.len);
- if (status == HAL_OK) {
- status = i2c_wait_dma_finished(self->i2c, args[3].u_int);
- }
- dma_deinit(self->rx_dma_descr);
- }
+#endif
- if (status != HAL_OK) {
- i2c_reset_after_error(self->i2c);
- mp_hal_raise(status);
- }
+#if defined(STM32F0) || defined(STM32F4) || defined(STM32F7)
- // return the read data
- if (o_ret != MP_OBJ_NULL) {
- return o_ret;
- } else {
- return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
+int i2c_readfrom(i2c_t *i2c, uint16_t addr, uint8_t *dest, size_t len, bool stop) {
+ int ret;
+ if ((ret = i2c_start_addr(i2c, 1, addr, len, stop))) {
+ return ret;
}
+ return i2c_read(i2c, dest, len, 0);
}
-STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_i2c_mem_read_obj, 1, pyb_i2c_mem_read);
-
-/// \method mem_write(data, addr, memaddr, timeout=5000, addr_size=8)
-///
-/// Write to the memory of an I2C device:
-///
-/// - `data` can be an integer or a buffer to write from
-/// - `addr` is the I2C device address
-/// - `memaddr` is the memory location within the I2C device
-/// - `timeout` is the timeout in milliseconds to wait for the write
-/// - `addr_size` selects width of memaddr: 8 or 16 bits
-///
-/// Returns `None`.
-/// This is only valid in master mode.
-STATIC mp_obj_t pyb_i2c_mem_write(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
- // parse args (same as mem_read)
- pyb_i2c_obj_t *self = pos_args[0];
- mp_arg_val_t args[MP_ARRAY_SIZE(pyb_i2c_mem_read_allowed_args)];
- mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(pyb_i2c_mem_read_allowed_args), pyb_i2c_mem_read_allowed_args, args);
-
- if (!in_master_mode(self)) {
- mp_raise_TypeError("I2C must be a master");
- }
-
- // get the buffer to write from
- mp_buffer_info_t bufinfo;
- uint8_t data[1];
- pyb_buf_get_for_send(args[0].u_obj, &bufinfo, data);
-
- // get the addresses
- mp_uint_t i2c_addr = args[1].u_int << 1;
- mp_uint_t mem_addr = args[2].u_int;
- // determine width of mem_addr; default is 8 bits, entering any other value gives 16 bit width
- mp_uint_t mem_addr_size = I2C_MEMADD_SIZE_8BIT;
- if (args[4].u_int != 8) {
- mem_addr_size = I2C_MEMADD_SIZE_16BIT;
- }
- // if option is set and IRQs are enabled then we can use DMA
- bool use_dma = *self->use_dma && query_irq() == IRQ_STATE_ENABLED;
-
- HAL_StatusTypeDef status;
- if (!use_dma) {
- status = HAL_I2C_Mem_Write(self->i2c, i2c_addr, mem_addr, mem_addr_size, bufinfo.buf, bufinfo.len, args[3].u_int);
- } else {
- DMA_HandleTypeDef tx_dma;
- dma_init(&tx_dma, self->tx_dma_descr, self->i2c);
- self->i2c->hdmatx = &tx_dma;
- self->i2c->hdmarx = NULL;
- MP_HAL_CLEAN_DCACHE(bufinfo.buf, bufinfo.len);
- status = HAL_I2C_Mem_Write_DMA(self->i2c, i2c_addr, mem_addr, mem_addr_size, bufinfo.buf, bufinfo.len);
- if (status == HAL_OK) {
- status = i2c_wait_dma_finished(self->i2c, args[3].u_int);
- }
- dma_deinit(self->tx_dma_descr);
+int i2c_writeto(i2c_t *i2c, uint16_t addr, const uint8_t *src, size_t len, bool stop) {
+ int ret;
+ if ((ret = i2c_start_addr(i2c, 0, addr, len, stop))) {
+ return ret;
}
+ return i2c_write(i2c, src, len, 0);
+}
- if (status != HAL_OK) {
- i2c_reset_after_error(self->i2c);
- mp_hal_raise(status);
- }
+#endif
- return mp_const_none;
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_i2c_mem_write_obj, 1, pyb_i2c_mem_write);
-
-STATIC const mp_rom_map_elem_t pyb_i2c_locals_dict_table[] = {
- // instance methods
- { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&pyb_i2c_init_obj) },
- { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&pyb_i2c_deinit_obj) },
- { MP_ROM_QSTR(MP_QSTR_is_ready), MP_ROM_PTR(&pyb_i2c_is_ready_obj) },
- { MP_ROM_QSTR(MP_QSTR_scan), MP_ROM_PTR(&pyb_i2c_scan_obj) },
- { MP_ROM_QSTR(MP_QSTR_send), MP_ROM_PTR(&pyb_i2c_send_obj) },
- { MP_ROM_QSTR(MP_QSTR_recv), MP_ROM_PTR(&pyb_i2c_recv_obj) },
- { MP_ROM_QSTR(MP_QSTR_mem_read), MP_ROM_PTR(&pyb_i2c_mem_read_obj) },
- { MP_ROM_QSTR(MP_QSTR_mem_write), MP_ROM_PTR(&pyb_i2c_mem_write_obj) },
-
- // class constants
- /// \constant MASTER - for initialising the bus to master mode
- /// \constant SLAVE - for initialising the bus to slave mode
- { MP_ROM_QSTR(MP_QSTR_MASTER), MP_ROM_INT(PYB_I2C_MASTER) },
- { MP_ROM_QSTR(MP_QSTR_SLAVE), MP_ROM_INT(PYB_I2C_SLAVE) },
-};
-
-STATIC MP_DEFINE_CONST_DICT(pyb_i2c_locals_dict, pyb_i2c_locals_dict_table);
-
-const mp_obj_type_t pyb_i2c_type = {
- { &mp_type_type },
- .name = MP_QSTR_I2C,
- .print = pyb_i2c_print,
- .make_new = pyb_i2c_make_new,
- .locals_dict = (mp_obj_dict_t*)&pyb_i2c_locals_dict,
-};
+#endif // MICROPY_HW_ENABLE_HW_I2C
diff --git a/ports/stm32/i2c.h b/ports/stm32/i2c.h
index 6affe3973..5599f4123 100644
--- a/ports/stm32/i2c.h
+++ b/ports/stm32/i2c.h
@@ -23,8 +23,8 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
-#ifndef MICROPY_INCLUDED_STMHAL_I2C_H
-#define MICROPY_INCLUDED_STMHAL_I2C_H
+#ifndef MICROPY_INCLUDED_STM32_I2C_H
+#define MICROPY_INCLUDED_STM32_I2C_H
#include "dma.h"
@@ -42,14 +42,24 @@ typedef struct _pyb_i2c_obj_t {
extern I2C_HandleTypeDef I2CHandle1;
extern I2C_HandleTypeDef I2CHandle2;
extern I2C_HandleTypeDef I2CHandle3;
+extern I2C_HandleTypeDef I2CHandle4;
extern const mp_obj_type_t pyb_i2c_type;
extern const pyb_i2c_obj_t pyb_i2c_obj[4];
void i2c_init0(void);
-void i2c_init(I2C_HandleTypeDef *i2c);
-void i2c_init_freq(const pyb_i2c_obj_t *self, mp_int_t freq);
-uint32_t i2c_get_baudrate(I2C_InitTypeDef *init);
+void pyb_i2c_init(I2C_HandleTypeDef *i2c);
+void pyb_i2c_init_freq(const pyb_i2c_obj_t *self, mp_int_t freq);
+uint32_t pyb_i2c_get_baudrate(I2C_HandleTypeDef *i2c);
void i2c_ev_irq_handler(mp_uint_t i2c_id);
void i2c_er_irq_handler(mp_uint_t i2c_id);
-#endif // MICROPY_INCLUDED_STMHAL_I2C_H
+typedef I2C_TypeDef i2c_t;
+
+int i2c_init(i2c_t *i2c, mp_hal_pin_obj_t scl, mp_hal_pin_obj_t sda, uint32_t freq);
+int i2c_start_addr(i2c_t *i2c, int rd_wrn, uint16_t addr, size_t len, bool stop);
+int i2c_read(i2c_t *i2c, uint8_t *dest, size_t len, size_t next_len);
+int i2c_write(i2c_t *i2c, const uint8_t *src, size_t len, size_t next_len);
+int i2c_readfrom(i2c_t *i2c, uint16_t addr, uint8_t *dest, size_t len, bool stop);
+int i2c_writeto(i2c_t *i2c, uint16_t addr, const uint8_t *src, size_t len, bool stop);
+
+#endif // MICROPY_INCLUDED_STM32_I2C_H
diff --git a/ports/stm32/i2cslave.c b/ports/stm32/i2cslave.c
new file mode 100644
index 000000000..473f0c8c5
--- /dev/null
+++ b/ports/stm32/i2cslave.c
@@ -0,0 +1,101 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "i2cslave.h"
+
+#if defined(STM32F4)
+
+void i2c_slave_init_helper(i2c_slave_t *i2c, int addr) {
+ i2c->CR2 = I2C_CR2_ITBUFEN | I2C_CR2_ITEVTEN | 4 << I2C_CR2_FREQ_Pos;
+ i2c->OAR1 = 1 << 14 | addr << 1;
+ i2c->OAR2 = 0;
+ i2c->CR1 = I2C_CR1_ACK | I2C_CR1_PE;
+}
+
+void i2c_slave_ev_irq_handler(i2c_slave_t *i2c) {
+ uint32_t sr1 = i2c->SR1;
+ if (sr1 & I2C_SR1_ADDR) {
+ // Address matched
+ // Read of SR1, SR2 needed to clear ADDR bit
+ sr1 = i2c->SR1;
+ uint32_t sr2 = i2c->SR2;
+ i2c_slave_process_addr_match((sr2 >> I2C_SR2_TRA_Pos) & 1);
+ }
+ if (sr1 & I2C_SR1_TXE) {
+ i2c->DR = i2c_slave_process_tx_byte();
+ }
+ if (sr1 & I2C_SR1_RXNE) {
+ i2c_slave_process_rx_byte(i2c->DR);
+ }
+ if (sr1 & I2C_SR1_STOPF) {
+ // STOPF only set at end of RX mode (in TX mode AF is set on NACK)
+ // Read of SR1, write CR1 needed to clear STOPF bit
+ sr1 = i2c->SR1;
+ i2c->CR1 &= ~I2C_CR1_ACK;
+ i2c_slave_process_rx_end();
+ i2c->CR1 |= I2C_CR1_ACK;
+ }
+}
+
+#elif defined(STM32F7)
+
+void i2c_slave_init_helper(i2c_slave_t *i2c, int addr) {
+ i2c->CR1 = I2C_CR1_STOPIE | I2C_CR1_ADDRIE | I2C_CR1_RXIE | I2C_CR1_TXIE;
+ i2c->CR2 = 0;
+ i2c->OAR1 = I2C_OAR1_OA1EN | addr << 1;
+ i2c->OAR2 = 0;
+ i2c->CR1 |= I2C_CR1_PE;
+}
+
+void i2c_slave_ev_irq_handler(i2c_slave_t *i2c) {
+ uint32_t isr = i2c->ISR;
+ if (isr & I2C_ISR_ADDR) {
+ // Address matched
+ // Set TXE so that TXDR is flushed and ready for the first byte
+ i2c->ISR = I2C_ISR_TXE;
+ i2c->ICR = I2C_ICR_ADDRCF;
+ i2c_slave_process_addr_match(0);
+ }
+ if (isr & I2C_ISR_TXIS) {
+ i2c->TXDR = i2c_slave_process_tx_byte();
+ }
+ if (isr & I2C_ISR_RXNE) {
+ i2c_slave_process_rx_byte(i2c->RXDR);
+ }
+ if (isr & I2C_ISR_STOPF) {
+ // STOPF only set for STOP condition, not a repeated START
+ i2c->ICR = I2C_ICR_STOPCF;
+ i2c->OAR1 &= ~I2C_OAR1_OA1EN;
+ if (i2c->ISR & I2C_ISR_DIR) {
+ //i2c_slave_process_tx_end();
+ } else {
+ i2c_slave_process_rx_end();
+ }
+ i2c->OAR1 |= I2C_OAR1_OA1EN;
+ }
+}
+
+#endif
diff --git a/ports/stm32/i2cslave.h b/ports/stm32/i2cslave.h
new file mode 100644
index 000000000..ac35c0cc8
--- /dev/null
+++ b/ports/stm32/i2cslave.h
@@ -0,0 +1,60 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#ifndef MICROPY_INCLUDED_STM32_I2CSLAVE_H
+#define MICROPY_INCLUDED_STM32_I2CSLAVE_H
+
+#include STM32_HAL_H
+
+typedef I2C_TypeDef i2c_slave_t;
+
+void i2c_slave_init_helper(i2c_slave_t *i2c, int addr);
+
+static inline void i2c_slave_init(i2c_slave_t *i2c, int irqn, int irq_pri, int addr) {
+ int en_bit = RCC_APB1ENR_I2C1EN_Pos + ((uintptr_t)i2c - I2C1_BASE) / (I2C2_BASE - I2C1_BASE);
+ RCC->APB1ENR |= 1 << en_bit;
+ volatile uint32_t tmp = RCC->APB1ENR; // Delay after enabling clock
+ (void)tmp;
+
+ i2c_slave_init_helper(i2c, addr);
+
+ NVIC_SetPriority(irqn, irq_pri);
+ NVIC_EnableIRQ(irqn);
+}
+
+static inline void i2c_slave_shutdown(i2c_slave_t *i2c, int irqn) {
+ i2c->CR1 = 0;
+ NVIC_DisableIRQ(irqn);
+}
+
+void i2c_slave_ev_irq_handler(i2c_slave_t *i2c);
+
+// These should be provided externally
+int i2c_slave_process_addr_match(int rw);
+int i2c_slave_process_rx_byte(uint8_t val);
+void i2c_slave_process_rx_end(void);
+uint8_t i2c_slave_process_tx_byte(void);
+
+#endif // MICROPY_INCLUDED_STM32_I2CSLAVE_H
diff --git a/ports/stm32/irq.h b/ports/stm32/irq.h
index 2cf58639e..3fe20867f 100644
--- a/ports/stm32/irq.h
+++ b/ports/stm32/irq.h
@@ -23,8 +23,12 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
-#ifndef MICROPY_INCLUDED_STMHAL_IRQ_H
-#define MICROPY_INCLUDED_STMHAL_IRQ_H
+#ifndef MICROPY_INCLUDED_STM32_IRQ_H
+#define MICROPY_INCLUDED_STM32_IRQ_H
+
+// Use this macro together with NVIC_SetPriority to indicate that an IRQn is non-negative,
+// which helps the compiler optimise the resulting inline function.
+#define IRQn_NONNEG(pri) ((pri) & 0x7f)
// these states correspond to values from query_irq, enable_irq and disable_irq
#define IRQ_STATE_DISABLED (0x00000001)
@@ -98,55 +102,57 @@ MP_DECLARE_CONST_FUN_OBJ_0(pyb_irq_stats_obj);
// The following interrupts are arranged from highest priority to lowest
// priority to make it a bit easier to figure out.
-// Priority Sub-Priority
-// -------- ------------
+#if __CORTEX_M == 0
+
//#def IRQ_PRI_SYSTICK 0
-//#def IRQ_SUBPRI_SYSTICK 0
+#define IRQ_PRI_UART 1
+#define IRQ_PRI_FLASH 1
+#define IRQ_PRI_SDIO 1
+#define IRQ_PRI_DMA 1
+#define IRQ_PRI_OTG_FS 2
+#define IRQ_PRI_OTG_HS 2
+#define IRQ_PRI_TIM5 2
+#define IRQ_PRI_CAN 2
+#define IRQ_PRI_TIMX 2
+#define IRQ_PRI_EXTINT 2
+#define IRQ_PRI_PENDSV 3
+#define IRQ_PRI_RTC_WKUP 3
+
+#else
+
+//#def IRQ_PRI_SYSTICK NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 0, 0)
// The UARTs have no FIFOs, so if they don't get serviced quickly then characters
// get dropped. The handling for each character only consumes about 0.5 usec
-#define IRQ_PRI_UART 1
-#define IRQ_SUBPRI_UART 0
+#define IRQ_PRI_UART NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 1, 0)
// Flash IRQ must be higher priority than interrupts of all those components
// that rely on the flash storage.
-#define IRQ_PRI_FLASH 2
-#define IRQ_SUBPRI_FLASH 0
+#define IRQ_PRI_FLASH NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 2, 0)
// SDIO must be higher priority than DMA for SDIO DMA transfers to work.
-#define IRQ_PRI_SDIO 4
-#define IRQ_SUBPRI_SDIO 0
+#define IRQ_PRI_SDIO NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 4, 0)
// DMA should be higher priority than USB, since USB Mass Storage calls
// into the sdcard driver which waits for the DMA to complete.
-#define IRQ_PRI_DMA 5
-#define IRQ_SUBPRI_DMA 0
-
-#define IRQ_PRI_OTG_FS 6
-#define IRQ_SUBPRI_OTG_FS 0
+#define IRQ_PRI_DMA NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 5, 0)
-#define IRQ_PRI_OTG_HS 6
-#define IRQ_SUBPRI_OTG_HS 0
+#define IRQ_PRI_OTG_FS NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 6, 0)
+#define IRQ_PRI_OTG_HS NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 6, 0)
+#define IRQ_PRI_TIM5 NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 6, 0)
-#define IRQ_PRI_TIM5 6
-#define IRQ_SUBPRI_TIM5 0
-
-#define IRQ_PRI_CAN 7
-#define IRQ_SUBPRI_CAN 0
+#define IRQ_PRI_CAN NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 7, 0)
// Interrupt priority for non-special timers.
-#define IRQ_PRI_TIMX 13
-#define IRQ_SUBPRI_TIMX 0
+#define IRQ_PRI_TIMX NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 13, 0)
-#define IRQ_PRI_EXTINT 14
-#define IRQ_SUBPRI_EXTINT 0
+#define IRQ_PRI_EXTINT NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 14, 0)
// PENDSV should be at the lowst priority so that other interrupts complete
// before exception is raised.
-#define IRQ_PRI_PENDSV 15
-#define IRQ_SUBPRI_PENDSV 0
+#define IRQ_PRI_PENDSV NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 15, 0)
+#define IRQ_PRI_RTC_WKUP NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 15, 0)
-#define IRQ_PRI_RTC_WKUP 15
-#define IRQ_SUBPRI_RTC_WKUP 0
+#endif
-#endif // MICROPY_INCLUDED_STMHAL_IRQ_H
+#endif // MICROPY_INCLUDED_STM32_IRQ_H
diff --git a/ports/stm32/lcd.c b/ports/stm32/lcd.c
index 488df1699..10fb54eb5 100644
--- a/ports/stm32/lcd.c
+++ b/ports/stm32/lcd.c
@@ -33,7 +33,6 @@
#if MICROPY_HW_HAS_LCD
#include "pin.h"
-#include "genhdr/pins.h"
#include "bufhelper.h"
#include "spi.h"
#include "font_petme128_8x8.h"
@@ -89,7 +88,7 @@ typedef struct _pyb_lcd_obj_t {
mp_obj_base_t base;
// hardware control for the LCD
- SPI_HandleTypeDef *spi;
+ const spi_t *spi;
const pin_obj_t *pin_cs1;
const pin_obj_t *pin_rst;
const pin_obj_t *pin_a0;
@@ -119,7 +118,7 @@ STATIC void lcd_out(pyb_lcd_obj_t *lcd, int instr_data, uint8_t i) {
mp_hal_pin_high(lcd->pin_a0); // A0=1; select data reg
}
lcd_delay();
- HAL_SPI_Transmit(lcd->spi, &i, 1, 1000);
+ HAL_SPI_Transmit(lcd->spi->spi, &i, 1, 1000);
lcd_delay();
mp_hal_pin_high(lcd->pin_cs1); // CS=1; disable
}
@@ -207,29 +206,29 @@ STATIC mp_obj_t pyb_lcd_make_new(const mp_obj_type_t *type, size_t n_args, size_
// configure pins
// TODO accept an SPI object and pin objects for full customisation
if ((lcd_id[0] | 0x20) == 'x' && lcd_id[1] == '\0') {
- lcd->spi = &SPIHandle1;
- lcd->pin_cs1 = &pyb_pin_X3;
- lcd->pin_rst = &pyb_pin_X4;
- lcd->pin_a0 = &pyb_pin_X5;
- lcd->pin_bl = &pyb_pin_X12;
+ lcd->spi = &spi_obj[0];
+ lcd->pin_cs1 = pyb_pin_X3;
+ lcd->pin_rst = pyb_pin_X4;
+ lcd->pin_a0 = pyb_pin_X5;
+ lcd->pin_bl = pyb_pin_X12;
} else if ((lcd_id[0] | 0x20) == 'y' && lcd_id[1] == '\0') {
- lcd->spi = &SPIHandle2;
- lcd->pin_cs1 = &pyb_pin_Y3;
- lcd->pin_rst = &pyb_pin_Y4;
- lcd->pin_a0 = &pyb_pin_Y5;
- lcd->pin_bl = &pyb_pin_Y12;
+ lcd->spi = &spi_obj[1];
+ lcd->pin_cs1 = pyb_pin_Y3;
+ lcd->pin_rst = pyb_pin_Y4;
+ lcd->pin_a0 = pyb_pin_Y5;
+ lcd->pin_bl = pyb_pin_Y12;
} else {
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "LCD(%s) doesn't exist", lcd_id));
}
// init the SPI bus
- SPI_InitTypeDef *init = &lcd->spi->Init;
+ SPI_InitTypeDef *init = &lcd->spi->spi->Init;
init->Mode = SPI_MODE_MASTER;
// compute the baudrate prescaler from the desired baudrate
// select a prescaler that yields at most the desired baudrate
uint spi_clock;
- if (lcd->spi->Instance == SPI1) {
+ if (lcd->spi->spi->Instance == SPI1) {
// SPI1 is on APB2
spi_clock = HAL_RCC_GetPCLK2Freq();
} else {
diff --git a/ports/stm32/lcd.h b/ports/stm32/lcd.h
index c0d9bd97d..98f904848 100644
--- a/ports/stm32/lcd.h
+++ b/ports/stm32/lcd.h
@@ -23,9 +23,9 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
-#ifndef MICROPY_INCLUDED_STMHAL_LCD_H
-#define MICROPY_INCLUDED_STMHAL_LCD_H
+#ifndef MICROPY_INCLUDED_STM32_LCD_H
+#define MICROPY_INCLUDED_STM32_LCD_H
extern const mp_obj_type_t pyb_lcd_type;
-#endif // MICROPY_INCLUDED_STMHAL_LCD_H
+#endif // MICROPY_INCLUDED_STM32_LCD_H
diff --git a/ports/stm32/led.c b/ports/stm32/led.c
index 9bbcaa6b3..71c674ab9 100644
--- a/ports/stm32/led.c
+++ b/ports/stm32/led.c
@@ -31,7 +31,6 @@
#include "timer.h"
#include "led.h"
#include "pin.h"
-#include "genhdr/pins.h"
#if defined(MICROPY_HW_LED1)
@@ -52,13 +51,13 @@ typedef struct _pyb_led_obj_t {
} pyb_led_obj_t;
STATIC const pyb_led_obj_t pyb_led_obj[] = {
- {{&pyb_led_type}, 1, &MICROPY_HW_LED1},
+ {{&pyb_led_type}, 1, MICROPY_HW_LED1},
#if defined(MICROPY_HW_LED2)
- {{&pyb_led_type}, 2, &MICROPY_HW_LED2},
+ {{&pyb_led_type}, 2, MICROPY_HW_LED2},
#if defined(MICROPY_HW_LED3)
- {{&pyb_led_type}, 3, &MICROPY_HW_LED3},
+ {{&pyb_led_type}, 3, MICROPY_HW_LED3},
#if defined(MICROPY_HW_LED4)
- {{&pyb_led_type}, 4, &MICROPY_HW_LED4},
+ {{&pyb_led_type}, 4, MICROPY_HW_LED4},
#endif
#endif
#endif
@@ -282,7 +281,7 @@ void led_debug(int n, int delay) {
void led_obj_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
pyb_led_obj_t *self = self_in;
- mp_printf(print, "LED(%lu)", self->led_id);
+ mp_printf(print, "LED(%u)", self->led_id);
}
/// \classmethod \constructor(id)
diff --git a/ports/stm32/led.h b/ports/stm32/led.h
index f1b05d1e2..1cc96b75a 100644
--- a/ports/stm32/led.h
+++ b/ports/stm32/led.h
@@ -23,25 +23,14 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
-#ifndef MICROPY_INCLUDED_STMHAL_LED_H
-#define MICROPY_INCLUDED_STMHAL_LED_H
+#ifndef MICROPY_INCLUDED_STM32_LED_H
+#define MICROPY_INCLUDED_STM32_LED_H
typedef enum {
- // PYBv3
- PYB_LED_R1 = 1,
- PYB_LED_R2 = 2,
- PYB_LED_G1 = 3,
- PYB_LED_G2 = 4,
- // PYBv4
PYB_LED_RED = 1,
PYB_LED_GREEN = 2,
PYB_LED_YELLOW = 3,
PYB_LED_BLUE = 4,
- //STM32F4DISC
- PYB_LED_R = 1,
- PYB_LED_G = 2,
- PYB_LED_B = 3,
- PYB_LED_O = 4,
} pyb_led_t;
void led_init(void);
@@ -51,4 +40,4 @@ void led_debug(int value, int delay);
extern const mp_obj_type_t pyb_led_type;
-#endif // MICROPY_INCLUDED_STMHAL_LED_H
+#endif // MICROPY_INCLUDED_STM32_LED_H
diff --git a/ports/stm32/lwip_inc/arch/cc.h b/ports/stm32/lwip_inc/arch/cc.h
new file mode 100644
index 000000000..635b1c805
--- /dev/null
+++ b/ports/stm32/lwip_inc/arch/cc.h
@@ -0,0 +1,8 @@
+#ifndef MICROPY_INCLUDED_STM32_LWIP_ARCH_CC_H
+#define MICROPY_INCLUDED_STM32_LWIP_ARCH_CC_H
+
+#include <assert.h>
+#define LWIP_PLATFORM_DIAG(x)
+#define LWIP_PLATFORM_ASSERT(x) { assert(1); }
+
+#endif // MICROPY_INCLUDED_STM32_LWIP_ARCH_CC_H
diff --git a/ports/stm32/lwip_inc/arch/sys_arch.h b/ports/stm32/lwip_inc/arch/sys_arch.h
new file mode 100644
index 000000000..8b1a39374
--- /dev/null
+++ b/ports/stm32/lwip_inc/arch/sys_arch.h
@@ -0,0 +1 @@
+// empty
diff --git a/ports/stm32/lwip_inc/lwipopts.h b/ports/stm32/lwip_inc/lwipopts.h
new file mode 100644
index 000000000..b8ab8a2ab
--- /dev/null
+++ b/ports/stm32/lwip_inc/lwipopts.h
@@ -0,0 +1,61 @@
+#ifndef MICROPY_INCLUDED_STM32_LWIP_LWIPOPTS_H
+#define MICROPY_INCLUDED_STM32_LWIP_LWIPOPTS_H
+
+#include <stdint.h>
+
+#define NO_SYS 1
+#define SYS_LIGHTWEIGHT_PROT 1
+#define MEM_ALIGNMENT 4
+
+#define LWIP_CHKSUM_ALGORITHM 3
+
+#define LWIP_ARP 1
+#define LWIP_ETHERNET 1
+#define LWIP_NETCONN 0
+#define LWIP_SOCKET 0
+#define LWIP_STATS 0
+#define LWIP_NETIF_HOSTNAME 1
+
+#define LWIP_IPV6 0
+#define LWIP_DHCP 1
+#define LWIP_DHCP_CHECK_LINK_UP 1
+#define LWIP_DNS 1
+#define LWIP_IGMP 1
+
+#define SO_REUSE 1
+
+extern uint32_t rng_get(void);
+#define LWIP_RAND() rng_get()
+
+// default
+// lwip takes 15800 bytes; TCP d/l: 380k/s local, 7.2k/s remote
+// TCP u/l is very slow
+
+#if 0
+// lwip takes 19159 bytes; TCP d/l and u/l are around 320k/s on local network
+#define MEM_SIZE (5000)
+#define TCP_WND (4 * TCP_MSS)
+#define TCP_SND_BUF (4 * TCP_MSS)
+#endif
+
+#if 1
+// lwip takes 26700 bytes; TCP dl/ul are around 750/600 k/s on local network
+#define MEM_SIZE (8000)
+#define TCP_MSS (800)
+#define TCP_WND (8 * TCP_MSS)
+#define TCP_SND_BUF (8 * TCP_MSS)
+#define MEMP_NUM_TCP_SEG (32)
+#endif
+
+#if 0
+// lwip takes 45600 bytes; TCP dl/ul are around 1200/1000 k/s on local network
+#define MEM_SIZE (16000)
+#define TCP_MSS (1460)
+#define TCP_WND (8 * TCP_MSS)
+#define TCP_SND_BUF (8 * TCP_MSS)
+#define MEMP_NUM_TCP_SEG (32)
+#endif
+
+typedef uint32_t sys_prot_t;
+
+#endif // MICROPY_INCLUDED_STM32_LWIP_LWIPOPTS_H
diff --git a/ports/stm32/machine_i2c.c b/ports/stm32/machine_i2c.c
index 1be2151e3..b7a9ea69b 100644
--- a/ports/stm32/machine_i2c.c
+++ b/ports/stm32/machine_i2c.c
@@ -3,7 +3,7 @@
*
* The MIT License (MIT)
*
- * Copyright (c) 2016 Damien P. George
+ * Copyright (c) 2016-2018 Damien P. George
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -31,388 +31,92 @@
#include "py/mphal.h"
#include "py/mperrno.h"
#include "extmod/machine_i2c.h"
-#include "genhdr/pins.h"
#include "i2c.h"
-STATIC const mp_obj_type_t machine_hard_i2c_type;
+#if MICROPY_HW_ENABLE_HW_I2C
-#if defined(MCU_SERIES_F4)
+STATIC const mp_obj_type_t machine_hard_i2c_type;
-// F4xx specific driver for I2C hardware peripheral
-// The hardware-specific I2C code below is based heavily on the code from
-// V1.5.2 of the STM32 CUBE F4 HAL. Its copyright notice is given here.
-/*
-* COPYRIGHT(c) 2016 STMicroelectronics
-*
-* Redistribution and use in source and binary forms, with or without modification,
-* are permitted provided that the following conditions are met:
-* 1. Redistributions of source code must retain the above copyright notice,
-* this list of conditions and the following disclaimer.
-* 2. Redistributions in binary form must reproduce the above copyright notice,
-* this list of conditions and the following disclaimer in the documentation
-* and/or other materials provided with the distribution.
-* 3. Neither the name of STMicroelectronics nor the names of its contributors
-* may be used to endorse or promote products derived from this software
-* without specific prior written permission.
-*
-* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
-* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
-* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
-* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
-* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-*/
+#if defined(STM32F0) || defined(STM32F4) || defined(STM32F7)
typedef struct _machine_hard_i2c_obj_t {
mp_obj_base_t base;
- const pyb_i2c_obj_t *pyb;
- uint32_t *timeout;
+ i2c_t *i2c;
+ mp_hal_pin_obj_t scl;
+ mp_hal_pin_obj_t sda;
} machine_hard_i2c_obj_t;
-STATIC uint32_t machine_hard_i2c_timeout[4];
-
STATIC const machine_hard_i2c_obj_t machine_hard_i2c_obj[] = {
- {{&machine_hard_i2c_type}, &pyb_i2c_obj[0], &machine_hard_i2c_timeout[0]},
- {{&machine_hard_i2c_type}, &pyb_i2c_obj[1], &machine_hard_i2c_timeout[1]},
- {{&machine_hard_i2c_type}, &pyb_i2c_obj[2], &machine_hard_i2c_timeout[2]},
- {{&machine_hard_i2c_type}, &pyb_i2c_obj[3], &machine_hard_i2c_timeout[3]},
+ #if defined(MICROPY_HW_I2C1_SCL)
+ {{&machine_hard_i2c_type}, I2C1, MICROPY_HW_I2C1_SCL, MICROPY_HW_I2C1_SDA},
+ #else
+ {{NULL}, NULL, NULL, NULL},
+ #endif
+ #if defined(MICROPY_HW_I2C2_SCL)
+ {{&machine_hard_i2c_type}, I2C2, MICROPY_HW_I2C2_SCL, MICROPY_HW_I2C2_SDA},
+ #else
+ {{NULL}, NULL, NULL, NULL},
+ #endif
+ #if defined(MICROPY_HW_I2C3_SCL)
+ {{&machine_hard_i2c_type}, I2C3, MICROPY_HW_I2C3_SCL, MICROPY_HW_I2C3_SDA},
+ #else
+ {{NULL}, NULL, NULL, NULL},
+ #endif
+ #if defined(MICROPY_HW_I2C4_SCL)
+ {{&machine_hard_i2c_type}, I2C4, MICROPY_HW_I2C4_SCL, MICROPY_HW_I2C4_SDA},
+ #else
+ {{NULL}, NULL, NULL, NULL},
+ #endif
};
STATIC void machine_hard_i2c_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
machine_hard_i2c_obj_t *self = MP_OBJ_TO_PTR(self_in);
- mp_printf(print, "I2C(%u, freq=%u, timeout=%u)",
- self - &machine_hard_i2c_obj[0] + 1,
- i2c_get_baudrate(&self->pyb->i2c->Init),
- *self->timeout);
-}
-
-STATIC void machine_hard_i2c_init(const machine_hard_i2c_obj_t *self, uint32_t freq, uint32_t timeout) {
- *self->timeout = timeout;
- i2c_init_freq(self->pyb, freq);
-}
-
-// this function is based on STM code
-STATIC bool I2C_IsAcknowledgeFailed(I2C_HandleTypeDef *hi2c) {
- if (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_AF) == SET) {
- /* Clear NACKF Flag */
- __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_AF);
- return true;
- }
- return false;
-}
-// this function is based on STM code
-STATIC bool I2C_WaitOnFlagUntilTimeout(I2C_HandleTypeDef *hi2c, uint32_t Flag, FlagStatus Status, uint32_t Timeout, uint32_t Tickstart) {
- /* Wait until flag is set */
- while ((__HAL_I2C_GET_FLAG(hi2c, Flag) ? SET : RESET) == Status) {
- if (Timeout != HAL_MAX_DELAY) {
- if ((Timeout == 0U)||((HAL_GetTick() - Tickstart ) > Timeout)) {
- return false;
- }
- }
- }
- return true;
-}
+ #if defined(STM32F4)
-// this function is based on STM code
-STATIC int I2C_WaitOnRXNEFlagUntilTimeout(I2C_HandleTypeDef *hi2c, uint32_t Timeout, uint32_t Tickstart) {
- while (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_RXNE) == RESET) {
- /* Check if a STOPF is detected */
- if (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_STOPF) == SET) {
- /* Clear STOP Flag */
- __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_STOPF);
- return -MP_EBUSY;
- }
-
- /* Check for the Timeout */
- if ((Timeout == 0U) || ((HAL_GetTick()-Tickstart) > Timeout)) {
- return -MP_ETIMEDOUT;
- }
+ uint32_t freq = self->i2c->CR2 & 0x3f;
+ uint32_t ccr = self->i2c->CCR;
+ if (ccr & 0x8000) {
+ // Fast mode, assume duty cycle of 16/9
+ freq = freq * 40000 / (ccr & 0xfff);
+ } else {
+ // Standard mode
+ freq = freq * 500000 / (ccr & 0xfff);
}
- return 0;
-}
-
-// this function is based on STM code
-STATIC int send_addr_byte(I2C_HandleTypeDef *hi2c, uint8_t addr_byte, uint32_t Timeout, uint32_t Tickstart) {
- /* Generate Start */
- hi2c->Instance->CR1 |= I2C_CR1_START;
- /* Wait until SB flag is set */
- if (!I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_SB, RESET, Timeout, Tickstart)) {
- return -MP_ETIMEDOUT;
- }
+ mp_printf(print, "I2C(%u, scl=%q, sda=%q, freq=%u)",
+ self - &machine_hard_i2c_obj[0] + 1,
+ mp_hal_pin_name(self->scl), mp_hal_pin_name(self->sda),
+ freq);
- /* Send slave address */
- hi2c->Instance->DR = addr_byte;
+ #else
- /* Wait until ADDR flag is set */
- while (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_ADDR) == RESET) {
- if (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_AF) == SET) {
- // nack received for addr, release the bus cleanly
- hi2c->Instance->CR1 |= I2C_CR1_STOP;
- __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_AF);
- return -MP_ENODEV;
- }
+ uint32_t timingr = self->i2c->TIMINGR;
+ uint32_t presc = timingr >> 28;
+ uint32_t sclh = timingr >> 8 & 0xff;
+ uint32_t scll = timingr & 0xff;
+ uint32_t freq = HAL_RCC_GetPCLK1Freq() / (presc + 1) / (sclh + scll + 2);
+ mp_printf(print, "I2C(%u, scl=%q, sda=%q, freq=%u, timingr=0x%08x)",
+ self - &machine_hard_i2c_obj[0] + 1,
+ mp_hal_pin_name(self->scl), mp_hal_pin_name(self->sda),
+ freq, timingr);
- /* Check for the Timeout */
- if (Timeout != HAL_MAX_DELAY) {
- if ((Timeout == 0U)||((HAL_GetTick() - Tickstart ) > Timeout)) {
- return -MP_ETIMEDOUT;
- }
- }
- }
+ #endif
+}
- return 0;
+void machine_hard_i2c_init(machine_hard_i2c_obj_t *self, uint32_t freq, uint32_t timeout) {
+ (void)timeout;
+ i2c_init(self->i2c, self->scl, self->sda, freq);
}
-// this function is based on STM code
int machine_hard_i2c_readfrom(mp_obj_base_t *self_in, uint16_t addr, uint8_t *dest, size_t len, bool stop) {
- machine_hard_i2c_obj_t *self = (machine_hard_i2c_obj_t*)self_in;
- I2C_HandleTypeDef *hi2c = self->pyb->i2c;
- uint32_t Timeout = *self->timeout;
-
- /* Init tickstart for timeout management*/
- uint32_t tickstart = HAL_GetTick();
-
-#if 0
- // TODO: for multi-master, here we could wait for the bus to be free
- // we'd need a flag to tell if we were in the middle of a set of transactions
- // (ie didn't send a stop bit in the last call)
- /* Wait until BUSY flag is reset */
- if (!I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_BUSY, SET, I2C_TIMEOUT_BUSY_FLAG, tickstart)) {
- return -MP_EBUSY;
- }
-#endif
-
- /* Check if the I2C is already enabled */
- if ((hi2c->Instance->CR1 & I2C_CR1_PE) != I2C_CR1_PE) {
- /* Enable I2C peripheral */
- __HAL_I2C_ENABLE(hi2c);
- }
-
- /* Disable Pos */
- hi2c->Instance->CR1 &= ~I2C_CR1_POS;
-
- /* Enable Acknowledge */
- hi2c->Instance->CR1 |= I2C_CR1_ACK;
-
- /* Send Slave Address */
- int ret = send_addr_byte(hi2c, I2C_7BIT_ADD_READ(addr << 1), Timeout, tickstart);
- if (ret != 0) {
- return ret;
- }
-
- if (len == 0U) {
- /* Clear ADDR flag */
- __HAL_I2C_CLEAR_ADDRFLAG(hi2c);
-
- /* Generate Stop */
- if (stop) {
- hi2c->Instance->CR1 |= I2C_CR1_STOP;
- }
- } else if (len == 1U) {
- /* Disable Acknowledge */
- hi2c->Instance->CR1 &= ~I2C_CR1_ACK;
-
- /* Clear ADDR flag */
- __HAL_I2C_CLEAR_ADDRFLAG(hi2c);
-
- /* Generate Stop */
- if (stop) {
- hi2c->Instance->CR1 |= I2C_CR1_STOP;
- }
- } else if (len == 2U) {
- /* Disable Acknowledge */
- hi2c->Instance->CR1 &= ~I2C_CR1_ACK;
-
- /* Enable Pos */
- hi2c->Instance->CR1 |= I2C_CR1_POS;
-
- /* Clear ADDR flag */
- __HAL_I2C_CLEAR_ADDRFLAG(hi2c);
- } else {
- /* Enable Acknowledge */
- hi2c->Instance->CR1 |= I2C_CR1_ACK;
-
- /* Clear ADDR flag */
- __HAL_I2C_CLEAR_ADDRFLAG(hi2c);
- }
-
- while (len > 0U) {
- if (len <= 3U) {
- if (len == 1U) {
- /* Wait until RXNE flag is set */
- int ret = I2C_WaitOnRXNEFlagUntilTimeout(hi2c, Timeout, tickstart);
- if (ret != 0) {
- return ret;
- }
-
- /* Read data from DR */
- *dest++ = hi2c->Instance->DR;
- len--;
- } else if (len == 2U) {
- /* Wait until BTF flag is set */
- if (!I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_BTF, RESET, Timeout, tickstart)) {
- return -MP_ETIMEDOUT;
- }
-
- /* Generate Stop */
- if (stop) {
- hi2c->Instance->CR1 |= I2C_CR1_STOP;
- }
-
- /* Read data from DR */
- *dest++ = hi2c->Instance->DR;
- len--;
-
- /* Read data from DR */
- *dest++ = hi2c->Instance->DR;
- len--;
- } else {
- /* Wait until BTF flag is set */
- if (!I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_BTF, RESET, Timeout, tickstart)) {
- return -MP_ETIMEDOUT;
- }
-
- /* Disable Acknowledge */
- hi2c->Instance->CR1 &= ~I2C_CR1_ACK;
-
- /* Read data from DR */
- *dest++ = hi2c->Instance->DR;
- len--;
-
- /* Wait until BTF flag is set */
- if (!I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_BTF, RESET, Timeout, tickstart)) {
- return -MP_ETIMEDOUT;
- }
-
- /* Generate Stop */
- if (stop) {
- hi2c->Instance->CR1 |= I2C_CR1_STOP;
- }
-
- /* Read data from DR */
- *dest++ = hi2c->Instance->DR;
- len--;
-
- /* Read data from DR */
- *dest++ = hi2c->Instance->DR;
- len--;
- }
- } else {
- /* Wait until RXNE flag is set */
- int ret = I2C_WaitOnRXNEFlagUntilTimeout(hi2c, Timeout, tickstart);
- if (ret != 0) {
- return ret;
- }
-
- /* Read data from DR */
- *dest++ = hi2c->Instance->DR;
- len--;
-
- if (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BTF) == SET) {
- /* Read data from DR */
- *dest++ = hi2c->Instance->DR;
- len--;
- }
- }
- }
-
- return 0;
+ machine_hard_i2c_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ return i2c_readfrom(self->i2c, addr, dest, len, stop);
}
-// this function is based on STM code
int machine_hard_i2c_writeto(mp_obj_base_t *self_in, uint16_t addr, const uint8_t *src, size_t len, bool stop) {
- machine_hard_i2c_obj_t *self = (machine_hard_i2c_obj_t*)self_in;
- I2C_HandleTypeDef *hi2c = self->pyb->i2c;
- uint32_t Timeout = *self->timeout;
-
- /* Init tickstart for timeout management*/
- uint32_t tickstart = HAL_GetTick();
-
-#if 0
- // TODO: for multi-master, here we could wait for the bus to be free
- // we'd need a flag to tell if we were in the middle of a set of transactions
- // (ie didn't send a stop bit in the last call)
- /* Wait until BUSY flag is reset */
- if (!I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_BUSY, SET, I2C_TIMEOUT_BUSY_FLAG, tickstart)) {
- return -MP_EBUSY;
- }
-#endif
-
- /* Check if the I2C is already enabled */
- if ((hi2c->Instance->CR1 & I2C_CR1_PE) != I2C_CR1_PE) {
- /* Enable I2C peripheral */
- __HAL_I2C_ENABLE(hi2c);
- }
-
- /* Disable Pos */
- hi2c->Instance->CR1 &= ~I2C_CR1_POS;
-
- /* Send Slave Address */
- int ret = send_addr_byte(hi2c, I2C_7BIT_ADD_WRITE(addr << 1), Timeout, tickstart);
- if (ret != 0) {
- return ret;
- }
-
- /* Clear ADDR flag */
- __HAL_I2C_CLEAR_ADDRFLAG(hi2c);
-
- int num_acks = 0;
-
- while (len > 0U) {
- /* Wait until TXE flag is set */
- while (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_TXE) == RESET) {
- /* Check if a NACK is detected */
- if (I2C_IsAcknowledgeFailed(hi2c)) {
- goto nack;
- }
-
- /* Check for the Timeout */
- if (Timeout != HAL_MAX_DELAY) {
- if ((Timeout == 0U) || ((HAL_GetTick()-tickstart) > Timeout)) {
- goto timeout;
- }
- }
- }
-
- /* Write data to DR */
- hi2c->Instance->DR = *src++;
- len--;
-
- /* Wait until BTF flag is set */
- while (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BTF) == RESET) {
- /* Check if a NACK is detected */
- if (I2C_IsAcknowledgeFailed(hi2c)) {
- goto nack;
- }
-
- /* Check for the Timeout */
- if (Timeout != HAL_MAX_DELAY) {
- if ((Timeout == 0U) || ((HAL_GetTick()-tickstart) > Timeout)) {
- goto timeout;
- }
- }
- }
- ++num_acks;
- }
-nack:
-
- /* Generate Stop */
- if (stop) {
- hi2c->Instance->CR1 |= I2C_CR1_STOP;
- }
-
- return num_acks;
-
-timeout:
- // timeout, release the bus cleanly
- hi2c->Instance->CR1 |= I2C_CR1_STOP;
- return -MP_ETIMEDOUT;
+ machine_hard_i2c_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ return i2c_writeto(self->i2c, addr, src, len, stop);
}
#else
@@ -423,22 +127,22 @@ typedef mp_machine_soft_i2c_obj_t machine_hard_i2c_obj_t;
STATIC machine_hard_i2c_obj_t machine_hard_i2c_obj[] = {
#if defined(MICROPY_HW_I2C1_SCL)
- {{&machine_hard_i2c_type}, 1, 500, &MICROPY_HW_I2C1_SCL, &MICROPY_HW_I2C1_SDA},
+ {{&machine_hard_i2c_type}, 1, 500, MICROPY_HW_I2C1_SCL, MICROPY_HW_I2C1_SDA},
#else
{{NULL}, 0, 0, NULL, NULL},
#endif
#if defined(MICROPY_HW_I2C2_SCL)
- {{&machine_hard_i2c_type}, 1, 500, &MICROPY_HW_I2C2_SCL, &MICROPY_HW_I2C2_SDA},
+ {{&machine_hard_i2c_type}, 1, 500, MICROPY_HW_I2C2_SCL, MICROPY_HW_I2C2_SDA},
#else
{{NULL}, 0, 0, NULL, NULL},
#endif
#if defined(MICROPY_HW_I2C3_SCL)
- {{&machine_hard_i2c_type}, 1, 500, &MICROPY_HW_I2C3_SCL, &MICROPY_HW_I2C3_SDA},
+ {{&machine_hard_i2c_type}, 1, 500, MICROPY_HW_I2C3_SCL, MICROPY_HW_I2C3_SDA},
#else
{{NULL}, 0, 0, NULL, NULL},
#endif
#if defined(MICROPY_HW_I2C4_SCL)
- {{&machine_hard_i2c_type}, 1, 500, &MICROPY_HW_I2C4_SCL, &MICROPY_HW_I2C4_SDA},
+ {{&machine_hard_i2c_type}, 1, 500, MICROPY_HW_I2C4_SCL, MICROPY_HW_I2C4_SDA},
#else
{{NULL}, 0, 0, NULL, NULL},
#endif
@@ -548,3 +252,5 @@ STATIC const mp_obj_type_t machine_hard_i2c_type = {
.protocol = &machine_hard_i2c_p,
.locals_dict = (mp_obj_dict_t*)&mp_machine_soft_i2c_locals_dict,
};
+
+#endif // MICROPY_HW_ENABLE_HW_I2C
diff --git a/ports/stm32/main.c b/ports/stm32/main.c
index 16279d073..c018d2de2 100644
--- a/ports/stm32/main.c
+++ b/ports/stm32/main.c
@@ -3,7 +3,7 @@
*
* The MIT License (MIT)
*
- * Copyright (c) 2013, 2014 Damien P. George
+ * Copyright (c) 2013-2018 Damien P. George
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -34,6 +34,7 @@
#include "lib/mp-readline/readline.h"
#include "lib/utils/pyexec.h"
#include "lib/oofatfs/ff.h"
+#include "lwip/init.h"
#include "extmod/vfs.h"
#include "extmod/vfs_fat.h"
@@ -129,6 +130,7 @@ STATIC mp_obj_t pyb_main(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_a
}
MP_DEFINE_CONST_FUN_OBJ_KW(pyb_main_obj, 1, pyb_main);
+#if MICROPY_HW_ENABLE_STORAGE
static const char fresh_boot_py[] =
"# boot.py -- run on boot-up\r\n"
"# can run arbitrary Python, but best to keep it minimal\r\n"
@@ -136,8 +138,10 @@ static const char fresh_boot_py[] =
"import machine\r\n"
"import pyb\r\n"
"#pyb.main('main.py') # main script to run after this one\r\n"
+#if MICROPY_HW_ENABLE_USB
"#pyb.usb_mode('VCP+MSC') # act as a serial and a storage device\r\n"
"#pyb.usb_mode('VCP+HID') # act as a serial device and a mouse\r\n"
+#endif
;
static const char fresh_main_py[] =
@@ -190,7 +194,7 @@ MP_NOINLINE STATIC bool init_flash_fs(uint reset_mode) {
}
// set label
- f_setlabel(&vfs_fat->fatfs, "pybflash");
+ f_setlabel(&vfs_fat->fatfs, MICROPY_HW_FLASH_FS_LABEL);
// create empty main.py
FIL fp;
@@ -261,9 +265,10 @@ MP_NOINLINE STATIC bool init_flash_fs(uint reset_mode) {
return true;
}
+#endif
#if MICROPY_HW_HAS_SDCARD
-STATIC bool init_sdcard_fs(bool first_soft_reset) {
+STATIC bool init_sdcard_fs(void) {
bool first_part = true;
for (int part_num = 1; part_num <= 4; ++part_num) {
// create vfs object
@@ -308,14 +313,14 @@ STATIC bool init_sdcard_fs(bool first_soft_reset) {
}
}
- if (first_soft_reset) {
- // use SD card as medium for the USB MSD
- #if defined(USE_DEVICE_MODE)
+ #if MICROPY_HW_ENABLE_USB
+ if (pyb_usb_storage_medium == PYB_USB_STORAGE_MEDIUM_NONE) {
+ // if no USB MSC medium is selected then use the SD card
pyb_usb_storage_medium = PYB_USB_STORAGE_MEDIUM_SDCARD;
- #endif
}
+ #endif
- #if defined(USE_DEVICE_MODE)
+ #if MICROPY_HW_ENABLE_USB
// only use SD card as current directory if that's what the USB medium is
if (pyb_usb_storage_medium == PYB_USB_STORAGE_MEDIUM_SDCARD)
#endif
@@ -338,13 +343,14 @@ STATIC bool init_sdcard_fs(bool first_soft_reset) {
}
#endif
+#if !MICROPY_HW_USES_BOOTLOADER
STATIC uint update_reset_mode(uint reset_mode) {
-#if MICROPY_HW_HAS_SWITCH
+ #if MICROPY_HW_HAS_SWITCH
if (switch_get()) {
// The original method used on the pyboard is appropriate if you have 2
// or more LEDs.
-#if defined(MICROPY_HW_LED2)
+ #if defined(MICROPY_HW_LED2)
for (uint i = 0; i < 3000; i++) {
if (!switch_get()) {
break;
@@ -372,7 +378,7 @@ STATIC uint update_reset_mode(uint reset_mode) {
}
mp_hal_delay_ms(400);
-#elif defined(MICROPY_HW_LED1)
+ #elif defined(MICROPY_HW_LED1)
// For boards with only a single LED, we'll flash that LED the
// appropriate number of times, with a pause between each one
@@ -405,35 +411,71 @@ STATIC uint update_reset_mode(uint reset_mode) {
}
mp_hal_delay_ms(400);
}
-#else
-#error Need a reset mode update method
-#endif
+ #else
+ #error Need a reset mode update method
+ #endif
}
-#endif
+ #endif
return reset_mode;
}
+#endif
+
+void stm32_main(uint32_t reset_mode) {
+ // Enable caches and prefetch buffers
-int main(void) {
- // TODO disable JTAG
+ #if defined(STM32F4)
- /* STM32F4xx HAL library initialization:
- - Configure the Flash prefetch, instruction and Data caches
- - Configure the Systick to generate an interrupt each 1 msec
- - Set NVIC Group Priority to 4
- - Global MSP (MCU Support Package) initialization
- */
- HAL_Init();
+ #if INSTRUCTION_CACHE_ENABLE
+ __HAL_FLASH_INSTRUCTION_CACHE_ENABLE();
+ #endif
+ #if DATA_CACHE_ENABLE
+ __HAL_FLASH_DATA_CACHE_ENABLE();
+ #endif
+ #if PREFETCH_ENABLE
+ __HAL_FLASH_PREFETCH_BUFFER_ENABLE();
+ #endif
+
+ #elif defined(STM32F7) || defined(STM32H7)
+
+ #if ART_ACCLERATOR_ENABLE
+ __HAL_FLASH_ART_ENABLE();
+ #endif
+
+ SCB_EnableICache();
+ SCB_EnableDCache();
+
+ #elif defined(STM32L4)
+
+ #if !INSTRUCTION_CACHE_ENABLE
+ __HAL_FLASH_INSTRUCTION_CACHE_DISABLE();
+ #endif
+ #if !DATA_CACHE_ENABLE
+ __HAL_FLASH_DATA_CACHE_DISABLE();
+ #endif
+ #if PREFETCH_ENABLE
+ __HAL_FLASH_PREFETCH_BUFFER_ENABLE();
+ #endif
+
+ #endif
+
+ #if __CORTEX_M >= 0x03
+ // Set the priority grouping
+ NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4);
+ #endif
+
+ // SysTick is needed by HAL_RCC_ClockConfig (called in SystemClock_Config)
+ HAL_InitTick(TICK_INT_PRIORITY);
// set the system clock to be HSE
SystemClock_Config();
// enable GPIO clocks
- __GPIOA_CLK_ENABLE();
- __GPIOB_CLK_ENABLE();
- __GPIOC_CLK_ENABLE();
- __GPIOD_CLK_ENABLE();
+ __HAL_RCC_GPIOA_CLK_ENABLE();
+ __HAL_RCC_GPIOB_CLK_ENABLE();
+ __HAL_RCC_GPIOC_CLK_ENABLE();
+ __HAL_RCC_GPIOD_CLK_ENABLE();
- #if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7)
+ #if defined(STM32F4) || defined(STM32F7)
#if defined(__HAL_RCC_DTCMRAMEN_CLK_ENABLE)
// The STM32F746 doesn't really have CCM memory, but it does have DTCM,
// which behaves more or less like normal SRAM.
@@ -442,8 +484,14 @@ int main(void) {
// enable the CCM RAM
__HAL_RCC_CCMDATARAMEN_CLK_ENABLE();
#endif
+ #elif defined(STM32H7)
+ // Enable D2 SRAM1/2/3 clocks.
+ __HAL_RCC_D2SRAM1_CLK_ENABLE();
+ __HAL_RCC_D2SRAM2_CLK_ENABLE();
+ __HAL_RCC_D2SRAM3_CLK_ENABLE();
#endif
+
#if defined(MICROPY_BOARD_EARLY_INIT)
MICROPY_BOARD_EARLY_INIT();
#endif
@@ -454,48 +502,46 @@ int main(void) {
#endif
pendsv_init();
led_init();
-#if MICROPY_HW_HAS_SWITCH
+ #if MICROPY_HW_HAS_SWITCH
switch_init0();
-#endif
-
-#if defined(USE_DEVICE_MODE)
- // default to internal flash being the usb medium
- pyb_usb_storage_medium = PYB_USB_STORAGE_MEDIUM_FLASH;
-#endif
-
- int first_soft_reset = true;
+ #endif
+ machine_init();
+ #if MICROPY_HW_ENABLE_RTC
+ rtc_init_start(false);
+ #endif
+ spi_init0();
+ #if MICROPY_PY_PYB_LEGACY && MICROPY_HW_ENABLE_HW_I2C
+ i2c_init0();
+ #endif
+ #if MICROPY_HW_HAS_SDCARD
+ sdcard_init();
+ #endif
+ #if MICROPY_HW_ENABLE_STORAGE
+ storage_init();
+ #endif
+ #if MICROPY_PY_LWIP
+ // lwIP doesn't allow to reinitialise itself by subsequent calls to this function
+ // because the system timeout list (next_timeout) is only ever reset by BSS clearing.
+ // So for now we only init the lwIP stack once on power-up.
+ lwip_init();
+ #endif
soft_reset:
- // check if user switch held to select the reset mode
-#if defined(MICROPY_HW_LED2)
+ #if defined(MICROPY_HW_LED2)
led_state(1, 0);
led_state(2, 1);
-#else
+ #else
led_state(1, 1);
led_state(2, 0);
-#endif
+ #endif
led_state(3, 0);
led_state(4, 0);
- uint reset_mode = update_reset_mode(1);
-
- machine_init();
-#if MICROPY_HW_ENABLE_RTC
- if (first_soft_reset) {
- rtc_init_start(false);
- }
-#endif
-
- // more sub-system init
-#if MICROPY_HW_HAS_SDCARD
- if (first_soft_reset) {
- sdcard_init();
- }
-#endif
- if (first_soft_reset) {
- storage_init();
- }
+ #if !MICROPY_HW_USES_BOOTLOADER
+ // check if user switch held to select the reset mode
+ reset_mode = update_reset_mode(1);
+ #endif
// Python threading init
#if MICROPY_PY_THREAD
@@ -511,6 +557,11 @@ soft_reset:
// GC init
gc_init(&_heap_start, &_heap_end);
+ #if MICROPY_ENABLE_PYSTACK
+ static mp_obj_t pystack[384];
+ mp_pystack_init(pystack, &pystack[384]);
+ #endif
+
// MicroPython init
mp_init();
mp_obj_list_init(mp_sys_path, 0);
@@ -531,44 +582,51 @@ soft_reset:
// Define MICROPY_HW_UART_REPL to be PYB_UART_6 and define
// MICROPY_HW_UART_REPL_BAUD in your mpconfigboard.h file if you want a
// REPL on a hardware UART as well as on USB VCP
-#if defined(MICROPY_HW_UART_REPL)
+ #if defined(MICROPY_HW_UART_REPL)
{
mp_obj_t args[2] = {
MP_OBJ_NEW_SMALL_INT(MICROPY_HW_UART_REPL),
MP_OBJ_NEW_SMALL_INT(MICROPY_HW_UART_REPL_BAUD),
};
MP_STATE_PORT(pyb_stdio_uart) = pyb_uart_type.make_new((mp_obj_t)&pyb_uart_type, MP_ARRAY_SIZE(args), 0, args);
+ uart_attach_to_repl(MP_STATE_PORT(pyb_stdio_uart), true);
}
-#else
+ #else
MP_STATE_PORT(pyb_stdio_uart) = NULL;
-#endif
+ #endif
-#if MICROPY_HW_ENABLE_CAN
+ #if MICROPY_HW_ENABLE_CAN
can_init0();
-#endif
-
-#if MICROPY_HW_ENABLE_RNG
- rng_init0();
-#endif
+ #endif
- i2c_init0();
- spi_init0();
+ #if MICROPY_HW_ENABLE_USB
pyb_usb_init0();
+ #endif
// Initialise the local flash filesystem.
// Create it if needed, mount in on /flash, and set it as current dir.
- bool mounted_flash = init_flash_fs(reset_mode);
+ bool mounted_flash = false;
+ #if MICROPY_HW_ENABLE_STORAGE
+ mounted_flash = init_flash_fs(reset_mode);
+ #endif
bool mounted_sdcard = false;
-#if MICROPY_HW_HAS_SDCARD
+ #if MICROPY_HW_HAS_SDCARD
// if an SD card is present then mount it on /sd/
if (sdcard_is_present()) {
// if there is a file in the flash called "SKIPSD", then we don't mount the SD card
if (!mounted_flash || f_stat(&fs_user_mount_flash.fatfs, "/SKIPSD", NULL) != FR_OK) {
- mounted_sdcard = init_sdcard_fs(first_soft_reset);
+ mounted_sdcard = init_sdcard_fs();
}
}
-#endif
+ #endif
+
+ #if MICROPY_HW_ENABLE_USB
+ // if the SD card isn't used as the USB MSC medium then use the internal flash
+ if (pyb_usb_storage_medium == PYB_USB_STORAGE_MEDIUM_NONE) {
+ pyb_usb_storage_medium = PYB_USB_STORAGE_MEDIUM_FLASH;
+ }
+ #endif
// set sys.path based on mounted filesystems (/sd is first so it can override /flash)
if (mounted_sdcard) {
@@ -600,12 +658,12 @@ soft_reset:
}
// turn boot-up LEDs off
-#if !defined(MICROPY_HW_LED2)
+ #if !defined(MICROPY_HW_LED2)
// If there is only one LED on the board then it's used to signal boot-up
// and so we turn it off here. Otherwise LED(1) is used to indicate dirty
// flash cache and so we shouldn't change its state.
led_state(1, 0);
-#endif
+ #endif
led_state(2, 0);
led_state(3, 0);
led_state(4, 0);
@@ -614,31 +672,29 @@ soft_reset:
// or whose initialisation can be safely deferred until after running
// boot.py.
-#if defined(USE_DEVICE_MODE)
+ #if MICROPY_HW_ENABLE_USB
// init USB device to default setting if it was not already configured
if (!(pyb_usb_flags & PYB_USB_FLAG_USB_MODE_CALLED)) {
pyb_usb_dev_init(USBD_VID, USBD_PID_CDC_MSC, USBD_MODE_CDC_MSC, NULL);
}
-#endif
+ #endif
-#if MICROPY_HW_HAS_MMA7660
+ #if MICROPY_HW_HAS_MMA7660
// MMA accel: init and reset
accel_init();
-#endif
+ #endif
-#if MICROPY_HW_ENABLE_SERVO
- // servo
+ #if MICROPY_HW_ENABLE_SERVO
servo_init();
-#endif
+ #endif
-#if MICROPY_HW_ENABLE_DAC
- // DAC
+ #if MICROPY_HW_ENABLE_DAC
dac_init();
-#endif
+ #endif
-#if MICROPY_PY_NETWORK
+ #if MICROPY_PY_NETWORK
mod_network_init();
-#endif
+ #endif
// At this point everything is fully configured and initialised.
@@ -680,20 +736,27 @@ soft_reset_exit:
// soft reset
+ #if MICROPY_HW_ENABLE_STORAGE
printf("PYB: sync filesystems\n");
storage_flush();
+ #endif
printf("PYB: soft reboot\n");
+ #if MICROPY_PY_NETWORK
+ mod_network_deinit();
+ #endif
timer_deinit();
uart_deinit();
-#if MICROPY_HW_ENABLE_CAN
+ #if MICROPY_HW_ENABLE_CAN
can_deinit();
-#endif
+ #endif
+ machine_deinit();
#if MICROPY_PY_THREAD
pyb_thread_deinit();
#endif
- first_soft_reset = false;
+ gc_sweep_all();
+
goto soft_reset;
}
diff --git a/ports/stm32/make-stmconst.py b/ports/stm32/make-stmconst.py
index 3a8e22b38..d509d00c1 100644
--- a/ports/stm32/make-stmconst.py
+++ b/ports/stm32/make-stmconst.py
@@ -244,8 +244,10 @@ def main():
print("")
with open(args.qstr_filename, 'wt') as qstr_file:
+ print('#if MICROPY_PY_STM', file=qstr_file)
for qstr in sorted(needed_qstrs):
print('Q({})'.format(qstr), file=qstr_file)
+ print('#endif // MICROPY_PY_STM', file=qstr_file)
with open(args.mpz_filename, 'wt') as mpz_file:
for mpz in sorted(needed_mpzs):
diff --git a/ports/stm32/mboot/Makefile b/ports/stm32/mboot/Makefile
new file mode 100644
index 000000000..b9f439482
--- /dev/null
+++ b/ports/stm32/mboot/Makefile
@@ -0,0 +1,189 @@
+# Select the board to build for: if not given on the command line,
+# then default to PYBV10.
+BOARD ?= PYBV10
+ifeq ($(wildcard ../boards/$(BOARD)/.),)
+$(error Invalid BOARD specified)
+endif
+
+# If the build directory is not given, make it reflect the board name.
+BUILD ?= build-$(BOARD)
+
+include ../../../py/mkenv.mk
+include ../boards/$(BOARD)/mpconfigboard.mk
+
+CMSIS_DIR=$(TOP)/lib/stm32lib/CMSIS/STM32$(MCU_SERIES_UPPER)xx/Include
+MCU_SERIES_UPPER = $(shell echo $(MCU_SERIES) | tr '[:lower:]' '[:upper:]')
+HAL_DIR=lib/stm32lib/STM32$(MCU_SERIES_UPPER)xx_HAL_Driver
+USBDEV_DIR=usbdev
+DFU=$(TOP)/tools/dfu.py
+PYDFU ?= $(TOP)/tools/pydfu.py
+DEVICE=0483:df11
+STFLASH ?= st-flash
+OPENOCD ?= openocd
+OPENOCD_CONFIG ?= boards/openocd_stm32f4.cfg
+
+CROSS_COMPILE = arm-none-eabi-
+
+INC += -I.
+INC += -I..
+INC += -I$(TOP)
+INC += -I$(BUILD)
+INC += -I$(TOP)/lib/cmsis/inc
+INC += -I$(CMSIS_DIR)/
+INC += -I$(TOP)/$(HAL_DIR)/Inc
+INC += -I../$(USBDEV_DIR)/core/inc -I../$(USBDEV_DIR)/class/inc
+
+# Basic Cortex-M flags
+CFLAGS_CORTEX_M = -mthumb
+
+# Options for particular MCU series
+CFLAGS_MCU_f4 = $(CFLAGS_CORTEX_M) -mtune=cortex-m4 -mcpu=cortex-m4
+CFLAGS_MCU_f7 = $(CFLAGS_CORTEX_M) -mtune=cortex-m7 -mcpu=cortex-m7
+CFLAGS_MCU_l4 = $(CFLAGS_CORTEX_M) -mtune=cortex-m4 -mcpu=cortex-m4
+
+CFLAGS = $(INC) -Wall -Wpointer-arith -Werror -std=gnu99 -nostdlib $(CFLAGS_MOD) $(CFLAGS_EXTRA)
+CFLAGS += -D$(CMSIS_MCU)
+CFLAGS += $(CFLAGS_MCU_$(MCU_SERIES))
+CFLAGS += $(COPT)
+CFLAGS += -I../boards/$(BOARD)
+CFLAGS += -DSTM32_HAL_H='<stm32$(MCU_SERIES)xx_hal.h>'
+CFLAGS += -DBOARD_$(BOARD)
+CFLAGS += -DAPPLICATION_ADDR=$(TEXT0_ADDR)
+
+LDFLAGS = -nostdlib -L . -T stm32_generic.ld -Map=$(@:.elf=.map) --cref
+LIBS = $(shell $(CC) $(CFLAGS) -print-libgcc-file-name)
+
+# Remove uncalled code from the final image.
+CFLAGS += -fdata-sections -ffunction-sections
+LDFLAGS += --gc-sections
+
+# Debugging/Optimization
+ifeq ($(DEBUG), 1)
+CFLAGS += -g -DPENDSV_DEBUG
+COPT = -O0
+else
+COPT += -Os -DNDEBUG
+endif
+
+SRC_LIB = $(addprefix lib/,\
+ libc/string0.c \
+ )
+
+SRC_C = \
+ main.c \
+ drivers/bus/softspi.c \
+ drivers/bus/softqspi.c \
+ drivers/memory/spiflash.c \
+ ports/stm32/i2cslave.c \
+ ports/stm32/qspi.c \
+ ports/stm32/flashbdev.c \
+ ports/stm32/spibdev.c \
+ ports/stm32/usbd_conf.c \
+ $(patsubst $(TOP)/%,%,$(wildcard $(TOP)/ports/stm32/boards/$(BOARD)/*.c))
+
+SRC_O = \
+ ports/stm32/boards/startup_stm32$(MCU_SERIES).o \
+ ports/stm32/resethandler.o \
+
+SRC_HAL = $(addprefix $(HAL_DIR)/Src/stm32$(MCU_SERIES)xx_,\
+ hal_cortex.c \
+ hal_flash.c \
+ hal_flash_ex.c \
+ hal_pcd.c \
+ hal_pcd_ex.c \
+ ll_usb.c \
+ )
+
+SRC_USBDEV = $(addprefix ports/stm32/$(USBDEV_DIR)/,\
+ core/src/usbd_core.c \
+ core/src/usbd_ctlreq.c \
+ core/src/usbd_ioreq.c \
+ )
+
+OBJ =
+OBJ += $(addprefix $(BUILD)/, $(SRC_LIB:.c=.o))
+OBJ += $(addprefix $(BUILD)/, $(SRC_C:.c=.o))
+OBJ += $(addprefix $(BUILD)/, $(SRC_O))
+OBJ += $(addprefix $(BUILD)/, $(SRC_HAL:.c=.o))
+OBJ += $(addprefix $(BUILD)/, $(SRC_USBDEV:.c=.o))
+
+all: $(TOP)/lib/stm32lib/README.md $(BUILD)/firmware.dfu $(BUILD)/firmware.hex
+
+# For convenience, automatically fetch required submodules if they don't exist
+$(TOP)/lib/stm32lib/README.md:
+ $(ECHO) "stm32lib submodule not found, fetching it now..."
+ (cd $(TOP) && git submodule update --init lib/stm32lib)
+
+.PHONY: deploy
+
+deploy: $(BUILD)/firmware.dfu
+ $(ECHO) "Writing $< to the board"
+ $(Q)$(PYTHON) $(PYDFU) -u $<
+
+FLASH_ADDR = 0x08000000
+
+$(BUILD)/firmware.dfu: $(BUILD)/firmware.elf
+ $(ECHO) "Create $@"
+ $(Q)$(OBJCOPY) -O binary -j .isr_vector -j .text -j .data $^ $(BUILD)/firmware.bin
+ $(Q)$(PYTHON) $(DFU) -b $(FLASH_ADDR):$(BUILD)/firmware.bin $@
+
+$(BUILD)/firmware.hex: $(BUILD)/firmware.elf
+ $(ECHO) "Create $@"
+ $(Q)$(OBJCOPY) -O ihex $< $@
+
+$(BUILD)/firmware.elf: $(OBJ)
+ $(ECHO) "LINK $@"
+ $(Q)$(LD) $(LDFLAGS) -o $@ $^ $(LIBS)
+ $(Q)$(SIZE) $@
+
+#########################################
+
+vpath %.S . $(TOP)
+$(BUILD)/%.o: %.S
+ $(ECHO) "CC $<"
+ $(Q)$(CC) $(CFLAGS) -c -o $@ $<
+
+vpath %.s . $(TOP)
+$(BUILD)/%.o: %.s
+ $(ECHO) "AS $<"
+ $(Q)$(AS) -o $@ $<
+
+define compile_c
+$(ECHO) "CC $<"
+$(Q)$(CC) $(CFLAGS) -c -MD -o $@ $<
+@# The following fixes the dependency file.
+@# See http://make.paulandlesley.org/autodep.html for details.
+@# Regex adjusted from the above to play better with Windows paths, etc.
+@$(CP) $(@:.o=.d) $(@:.o=.P); \
+ $(SED) -e 's/#.*//' -e 's/^.*: *//' -e 's/ *\\$$//' \
+ -e '/^$$/ d' -e 's/$$/ :/' < $(@:.o=.d) >> $(@:.o=.P); \
+ $(RM) -f $(@:.o=.d)
+endef
+
+vpath %.c . $(TOP)
+$(BUILD)/%.o: %.c
+ $(call compile_c)
+
+# $(sort $(var)) removes duplicates
+#
+# The net effect of this, is it causes the objects to depend on the
+# object directories (but only for existence), and the object directories
+# will be created if they don't exist.
+OBJ_DIRS = $(sort $(dir $(OBJ)))
+$(OBJ): | $(OBJ_DIRS)
+$(OBJ_DIRS):
+ $(MKDIR) -p $@
+
+clean:
+ $(RM) -rf $(BUILD) $(CLEAN_EXTRA)
+.PHONY: clean
+
+###########################################
+
+$(BUILD)/main.o: $(BUILD)/genhdr/qstrdefs.generated.h
+
+$(BUILD)/genhdr/qstrdefs.generated.h:
+ $(MKDIR) -p $(BUILD)/genhdr
+ $(Q)echo "// empty" > $@
+
+-include $(OBJ:.o=.P)
diff --git a/ports/stm32/mboot/README.md b/ports/stm32/mboot/README.md
new file mode 100644
index 000000000..2ff6101b4
--- /dev/null
+++ b/ports/stm32/mboot/README.md
@@ -0,0 +1,78 @@
+Mboot - MicroPython boot loader
+===============================
+
+Mboot is a custom bootloader for STM32 MCUs, and currently supports the
+STM32F4xx and STM32F7xx families. It can provide a standard USB DFU interface
+on either the FS or HS peripherals, as well as a sophisticated, custom I2C
+interface. It fits in 16k of flash space.
+
+How to use
+----------
+
+1. Configure your board to use a boot loader by editing the mpconfigboard.mk
+ and mpconfigboard.h files. For example, for an F767 be sure to have these
+ lines in mpconfigboard.mk:
+
+ LD_FILES = boards/stm32f767.ld boards/common_bl.ld
+ TEXT0_ADDR = 0x08008000
+
+ And this in mpconfigboard.h (recommended to put at the end of the file):
+
+ // Bootloader configuration
+ #define MBOOT_I2C_PERIPH_ID 1
+ #define MBOOT_I2C_SCL (pin_B8)
+ #define MBOOT_I2C_SDA (pin_B9)
+ #define MBOOT_I2C_ALTFUNC (4)
+
+ To configure a pin to force entry into the boot loader the following
+ options can be used (with example configuration):
+
+ #define MBOOT_BOOTPIN_PIN (pin_A0)
+ #define MBOOT_BOOTPIN_PULL (MP_HAL_PIN_PULL_UP)
+ #define MBOOT_BOOTPIN_ACTIVE (0)
+
+ Mboot supports programming external SPI flash via the DFU and I2C
+ interfaces. SPI flash will be mapped to an address range. To
+ configure it use the following options (edit as needed):
+
+ #define MBOOT_SPIFLASH_ADDR (0x80000000)
+ #define MBOOT_SPIFLASH_BYTE_SIZE (2 * 1024 * 1024)
+ #define MBOOT_SPIFLASH_LAYOUT "/0x80000000/64*32Kg"
+ #define MBOOT_SPIFLASH_ERASE_BLOCKS_PER_PAGE (32 / 4)
+ #define MBOOT_SPIFLASH_SPIFLASH (&spi_bdev.spiflash)
+ #define MBOOT_SPIFLASH_CONFIG (&spiflash_config)
+
+ This assumes that the board declares and defines the relevant SPI flash
+ configuration structs, eg in the board-specific bdev.c file. The
+ `MBOOT_SPIFLASH2_LAYOUT` string will be seen by the USB DFU utility and
+ must describe the SPI flash layout. Note that the number of pages in
+ this layout description (the `64` above) cannot be larger than 99 (it
+ must fit in two digits) so the reported page size (the `32Kg` above)
+ must be made large enough so the number of pages fits in two digits.
+ Alternatively the layout can specify multiple sections like
+ `32*16Kg,32*16Kg`, in which case `MBOOT_SPIFLASH_ERASE_BLOCKS_PER_PAGE`
+ must be changed to `16 / 4` to match tho `16Kg` value.
+
+ Mboot supports up to two external SPI flash devices. To configure the
+ second one use the same configuration names as above but with
+ `SPIFLASH2`, ie `MBOOT_SPIFLASH2_ADDR` etc.
+
+2. Build the board's main application firmware as usual.
+
+3. Build mboot via:
+
+ $ cd mboot
+ $ make BOARD=<board-id>
+
+ That should produce a DFU file for mboot. It can be deployed using
+ USB DFU programming via (it will be placed at location 0x08000000):
+
+ $ make BOARD=<board-id> deploy
+
+4. Reset the board while holding USR until all 3 LEDs are lit (the 4th option in
+ the cycle) and then release USR. LED0 will then blink once per second to
+ indicate that it's in mboot
+
+5. Use either USB DFU or I2C to download firmware. The script mboot.py shows how
+ to communicate with the I2C boot loader interface. It should be run on a
+ pyboard connected via I2C to the target board.
diff --git a/ports/stm32/mboot/main.c b/ports/stm32/mboot/main.c
new file mode 100644
index 000000000..11053971b
--- /dev/null
+++ b/ports/stm32/mboot/main.c
@@ -0,0 +1,1341 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017-2018 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include "py/mphal.h"
+#include "extmod/crypto-algorithms/sha256.c"
+#include "usbd_core.h"
+#include "storage.h"
+#include "i2cslave.h"
+
+// Using polling is about 10% faster than not using it (and using IRQ instead)
+// This DFU code with polling runs in about 70% of the time of the ST bootloader
+#define USE_USB_POLLING (1)
+
+// Using cache probably won't make it faster because we run at 48MHz, and best
+// to keep the MCU config as minimal as possible.
+#define USE_CACHE (0)
+
+// IRQ priorities (encoded values suitable for NVIC_SetPriority)
+#define IRQ_PRI_SYSTICK (NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 0, 0))
+#define IRQ_PRI_I2C (NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 1, 0))
+
+// Configure PLL to give a 48MHz CPU freq
+#define CORE_PLL_FREQ (48000000)
+#undef MICROPY_HW_CLK_PLLM
+#undef MICROPY_HW_CLK_PLLN
+#undef MICROPY_HW_CLK_PLLP
+#undef MICROPY_HW_CLK_PLLQ
+#define MICROPY_HW_CLK_PLLM (HSE_VALUE / 1000000)
+#define MICROPY_HW_CLK_PLLN (192)
+#define MICROPY_HW_CLK_PLLP (RCC_PLLP_DIV4)
+#define MICROPY_HW_CLK_PLLQ (4)
+
+// Work out which USB device to use for the USB DFU interface
+#if !defined(MICROPY_HW_USB_MAIN_DEV)
+#if defined(MICROPY_HW_USB_FS)
+#define MICROPY_HW_USB_MAIN_DEV (USB_PHY_FS_ID)
+#elif defined(MICROPY_HW_USB_HS) && defined(MICROPY_HW_USB_HS_IN_FS)
+#define MICROPY_HW_USB_MAIN_DEV (USB_PHY_HS_ID)
+#else
+#error Unable to determine proper MICROPY_HW_USB_MAIN_DEV to use
+#endif
+#endif
+
+// These bits are used to detect valid application firmware at APPLICATION_ADDR
+#define APP_VALIDITY_BITS (0x00000003)
+
+#define MP_ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+
+static void do_reset(void);
+
+static uint32_t get_le32(const uint8_t *b) {
+ return b[0] | b[1] << 8 | b[2] << 16 | b[3] << 24;
+}
+
+void mp_hal_delay_us(mp_uint_t usec) {
+ // use a busy loop for the delay
+ // sys freq is always a multiple of 2MHz, so division here won't lose precision
+ const uint32_t ucount = CORE_PLL_FREQ / 2000000 * usec / 2;
+ for (uint32_t count = 0; ++count <= ucount;) {
+ }
+}
+
+static volatile uint32_t systick_ms;
+
+void mp_hal_delay_ms(mp_uint_t ms) {
+ if (__get_PRIMASK() == 0) {
+ // IRQs enabled, use systick
+ if (ms != 0 && ms != (mp_uint_t)-1) {
+ ++ms; // account for the fact that systick_ms may roll over immediately
+ }
+ uint32_t start = systick_ms;
+ while (systick_ms - start < ms) {
+ __WFI();
+ }
+ } else {
+ // IRQs disabled, so need to use a busy loop for the delay.
+ // To prevent possible overflow of the counter we use a double loop.
+ const uint32_t count_1ms = 16000000 / 8000;
+ for (uint32_t i = 0; i < ms; i++) {
+ for (volatile uint32_t count = 0; ++count <= count_1ms;) {
+ }
+ }
+ }
+}
+
+// Needed by parts of the HAL
+uint32_t HAL_GetTick(void) {
+ return systick_ms;
+}
+
+// Needed by parts of the HAL
+void HAL_Delay(uint32_t ms) {
+ mp_hal_delay_ms(ms);
+}
+
+static void __fatal_error(const char *msg) {
+ NVIC_SystemReset();
+ for (;;) {
+ }
+}
+
+/******************************************************************************/
+// CLOCK
+
+#if defined(STM32F4) || defined(STM32F7)
+
+#define CONFIG_RCC_CR_1ST (RCC_CR_HSION)
+#define CONFIG_RCC_CR_2ND (RCC_CR_HSEON || RCC_CR_CSSON || RCC_CR_PLLON)
+#define CONFIG_RCC_PLLCFGR (0x24003010)
+
+#else
+#error Unknown processor
+#endif
+
+void SystemInit(void) {
+ // Set HSION bit
+ RCC->CR |= CONFIG_RCC_CR_1ST;
+
+ // Reset CFGR register
+ RCC->CFGR = 0x00000000;
+
+ // Reset HSEON, CSSON and PLLON bits
+ RCC->CR &= ~CONFIG_RCC_CR_2ND;
+
+ // Reset PLLCFGR register
+ RCC->PLLCFGR = CONFIG_RCC_PLLCFGR;
+
+ // Reset HSEBYP bit
+ RCC->CR &= (uint32_t)0xFFFBFFFF;
+
+ // Disable all interrupts
+ RCC->CIR = 0x00000000;
+
+ // Set location of vector table
+ SCB->VTOR = FLASH_BASE;
+
+ // Enable 8-byte stack alignment for IRQ handlers, in accord with EABI
+ SCB->CCR |= SCB_CCR_STKALIGN_Msk;
+}
+
+void systick_init(void) {
+ // Configure SysTick as 1ms ticker
+ SysTick_Config(SystemCoreClock / 1000);
+ NVIC_SetPriority(SysTick_IRQn, IRQ_PRI_SYSTICK);
+}
+
+void SystemClock_Config(void) {
+ // This function assumes that HSI is used as the system clock (see RCC->CFGR, SWS bits)
+
+ // Enable Power Control clock
+ __HAL_RCC_PWR_CLK_ENABLE();
+
+ // Reduce power consumption
+ __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
+
+ // Turn HSE on
+ __HAL_RCC_HSE_CONFIG(RCC_HSE_ON);
+ while (__HAL_RCC_GET_FLAG(RCC_FLAG_HSERDY) == RESET) {
+ }
+
+ // Disable PLL
+ __HAL_RCC_PLL_DISABLE();
+ while (__HAL_RCC_GET_FLAG(RCC_FLAG_PLLRDY) != RESET) {
+ }
+
+ // Configure PLL factors and source
+ RCC->PLLCFGR =
+ 1 << RCC_PLLCFGR_PLLSRC_Pos // HSE selected as PLL source
+ | MICROPY_HW_CLK_PLLM << RCC_PLLCFGR_PLLM_Pos
+ | MICROPY_HW_CLK_PLLN << RCC_PLLCFGR_PLLN_Pos
+ | ((MICROPY_HW_CLK_PLLP >> 1) - 1) << RCC_PLLCFGR_PLLP_Pos
+ | MICROPY_HW_CLK_PLLQ << RCC_PLLCFGR_PLLQ_Pos
+ #ifdef RCC_PLLCFGR_PLLR
+ | 2 << RCC_PLLCFGR_PLLR_Pos // default PLLR value of 2
+ #endif
+ ;
+
+ // Enable PLL
+ __HAL_RCC_PLL_ENABLE();
+ while(__HAL_RCC_GET_FLAG(RCC_FLAG_PLLRDY) == RESET) {
+ }
+
+ #if !defined(MICROPY_HW_FLASH_LATENCY)
+ #define MICROPY_HW_FLASH_LATENCY FLASH_LATENCY_1
+ #endif
+
+ // Increase latency before changing clock
+ if (MICROPY_HW_FLASH_LATENCY > (FLASH->ACR & FLASH_ACR_LATENCY)) {
+ __HAL_FLASH_SET_LATENCY(MICROPY_HW_FLASH_LATENCY);
+ }
+
+ // Configure AHB divider
+ MODIFY_REG(RCC->CFGR, RCC_CFGR_HPRE, RCC_SYSCLK_DIV1);
+
+ // Configure SYSCLK source from PLL
+ __HAL_RCC_SYSCLK_CONFIG(RCC_SYSCLKSOURCE_PLLCLK);
+ while (__HAL_RCC_GET_SYSCLK_SOURCE() != RCC_SYSCLKSOURCE_STATUS_PLLCLK) {
+ }
+
+ // Decrease latency after changing clock
+ if (MICROPY_HW_FLASH_LATENCY < (FLASH->ACR & FLASH_ACR_LATENCY)) {
+ __HAL_FLASH_SET_LATENCY(MICROPY_HW_FLASH_LATENCY);
+ }
+
+ // Set APB clock dividers
+ MODIFY_REG(RCC->CFGR, RCC_CFGR_PPRE1, RCC_HCLK_DIV4);
+ MODIFY_REG(RCC->CFGR, RCC_CFGR_PPRE2, RCC_HCLK_DIV2 << 3);
+
+ // Update clock value and reconfigure systick now that the frequency changed
+ SystemCoreClock = CORE_PLL_FREQ;
+ systick_init();
+
+ #if defined(STM32F7)
+ // The DFU bootloader changes the clocksource register from its default power
+ // on reset value, so we set it back here, so the clocksources are the same
+ // whether we were started from DFU or from a power on reset.
+ RCC->DCKCFGR2 = 0;
+ #endif
+}
+
+// Needed by HAL_PCD_IRQHandler
+uint32_t HAL_RCC_GetHCLKFreq(void) {
+ return SystemCoreClock;
+}
+
+/******************************************************************************/
+// GPIO
+
+void mp_hal_pin_config(mp_hal_pin_obj_t port_pin, uint32_t mode, uint32_t pull, uint32_t alt) {
+ GPIO_TypeDef *gpio = (GPIO_TypeDef*)(port_pin & ~0xf);
+
+ // Enable the GPIO peripheral clock
+ uint32_t en_bit = RCC_AHB1ENR_GPIOAEN_Pos + ((uintptr_t)gpio - GPIOA_BASE) / (GPIOB_BASE - GPIOA_BASE);
+ RCC->AHB1ENR |= 1 << en_bit;
+ volatile uint32_t tmp = RCC->AHB1ENR; // Delay after enabling clock
+ (void)tmp;
+
+ // Configure the pin
+ uint32_t pin = port_pin & 0xf;
+ gpio->MODER = (gpio->MODER & ~(3 << (2 * pin))) | ((mode & 3) << (2 * pin));
+ gpio->OTYPER = (gpio->OTYPER & ~(1 << pin)) | ((mode >> 2) << pin);
+ gpio->OSPEEDR = (gpio->OSPEEDR & ~(3 << (2 * pin))) | (2 << (2 * pin)); // full speed
+ gpio->PUPDR = (gpio->PUPDR & ~(3 << (2 * pin))) | (pull << (2 * pin));
+ gpio->AFR[pin >> 3] = (gpio->AFR[pin >> 3] & ~(15 << (4 * (pin & 7)))) | (alt << (4 * (pin & 7)));
+}
+
+void mp_hal_pin_config_speed(uint32_t port_pin, uint32_t speed) {
+ GPIO_TypeDef *gpio = (GPIO_TypeDef*)(port_pin & ~0xf);
+ uint32_t pin = port_pin & 0xf;
+ gpio->OSPEEDR = (gpio->OSPEEDR & ~(3 << (2 * pin))) | (speed << (2 * pin));
+}
+
+/******************************************************************************/
+// LED
+
+#define LED0 MICROPY_HW_LED1
+#define LED1 MICROPY_HW_LED2
+#define LED2 MICROPY_HW_LED3
+
+void led_init(void) {
+ mp_hal_pin_output(LED0);
+ mp_hal_pin_output(LED1);
+ mp_hal_pin_output(LED2);
+}
+
+void led_state(int led, int val) {
+ if (led == 1) {
+ led = LED0;
+ }
+ if (val) {
+ MICROPY_HW_LED_ON(led);
+ } else {
+ MICROPY_HW_LED_OFF(led);
+ }
+}
+
+/******************************************************************************/
+// USR BUTTON
+
+static void usrbtn_init(void) {
+ mp_hal_pin_config(MICROPY_HW_USRSW_PIN, MP_HAL_PIN_MODE_INPUT, MICROPY_HW_USRSW_PULL, 0);
+}
+
+static int usrbtn_state(void) {
+ return mp_hal_pin_read(MICROPY_HW_USRSW_PIN) == MICROPY_HW_USRSW_PRESSED;
+}
+
+/******************************************************************************/
+// FLASH
+
+#ifndef MBOOT_SPIFLASH_LAYOUT
+#define MBOOT_SPIFLASH_LAYOUT ""
+#endif
+
+#ifndef MBOOT_SPIFLASH2_LAYOUT
+#define MBOOT_SPIFLASH2_LAYOUT ""
+#endif
+
+typedef struct {
+ uint32_t base_address;
+ uint32_t sector_size;
+ uint32_t sector_count;
+} flash_layout_t;
+
+#if defined(STM32F7)
+// FLASH_FLAG_PGSERR (Programming Sequence Error) was renamed to
+// FLASH_FLAG_ERSERR (Erasing Sequence Error) in STM32F7
+#define FLASH_FLAG_PGSERR FLASH_FLAG_ERSERR
+#endif
+
+#if defined(STM32F4) \
+ || defined(STM32F722xx) \
+ || defined(STM32F723xx) \
+ || defined(STM32F732xx) \
+ || defined(STM32F733xx)
+
+#define FLASH_LAYOUT_STR "@Internal Flash /0x08000000/04*016Kg,01*064Kg,07*128Kg" MBOOT_SPIFLASH_LAYOUT MBOOT_SPIFLASH2_LAYOUT
+
+static const flash_layout_t flash_layout[] = {
+ { 0x08000000, 0x04000, 4 },
+ { 0x08010000, 0x10000, 1 },
+ { 0x08020000, 0x20000, 3 },
+ #if defined(FLASH_SECTOR_8)
+ { 0x08080000, 0x20000, 4 },
+ #endif
+ #if defined(FLASH_SECTOR_12)
+ { 0x08100000, 0x04000, 4 },
+ { 0x08110000, 0x10000, 1 },
+ { 0x08120000, 0x20000, 7 },
+ #endif
+};
+
+#elif defined(STM32F767xx)
+
+#define FLASH_LAYOUT_STR "@Internal Flash /0x08000000/04*032Kg,01*128Kg,07*256Kg" MBOOT_SPIFLASH_LAYOUT MBOOT_SPIFLASH2_LAYOUT
+
+// This is for dual-bank mode disabled
+static const flash_layout_t flash_layout[] = {
+ { 0x08000000, 0x08000, 4 },
+ { 0x08020000, 0x20000, 1 },
+ { 0x08040000, 0x40000, 7 },
+};
+
+#endif
+
+static uint32_t flash_get_sector_index(uint32_t addr) {
+ if (addr >= flash_layout[0].base_address) {
+ uint32_t sector_index = 0;
+ for (int i = 0; i < MP_ARRAY_SIZE(flash_layout); ++i) {
+ for (int j = 0; j < flash_layout[i].sector_count; ++j) {
+ uint32_t sector_start_next = flash_layout[i].base_address
+ + (j + 1) * flash_layout[i].sector_size;
+ if (addr < sector_start_next) {
+ return sector_index;
+ }
+ ++sector_index;
+ }
+ }
+ }
+ return 0;
+}
+
+static int flash_mass_erase(void) {
+ // TODO
+ return -1;
+}
+
+static int flash_page_erase(uint32_t addr) {
+ uint32_t sector = flash_get_sector_index(addr);
+ if (sector == 0) {
+ // Don't allow to erase the sector with this bootloader in it
+ return -1;
+ }
+
+ HAL_FLASH_Unlock();
+
+ // Clear pending flags (if any)
+ __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR |
+ FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR | FLASH_FLAG_PGSERR);
+
+ // erase the sector(s)
+ FLASH_EraseInitTypeDef EraseInitStruct;
+ EraseInitStruct.TypeErase = TYPEERASE_SECTORS;
+ EraseInitStruct.VoltageRange = VOLTAGE_RANGE_3; // voltage range needs to be 2.7V to 3.6V
+ EraseInitStruct.Sector = sector;
+ EraseInitStruct.NbSectors = 1;
+
+ uint32_t SectorError = 0;
+ if (HAL_FLASHEx_Erase(&EraseInitStruct, &SectorError) != HAL_OK) {
+ // error occurred during sector erase
+ return -1;
+ }
+
+ // Check the erase set bits to 1, at least for the first 256 bytes
+ for (int i = 0; i < 64; ++i) {
+ if (((volatile uint32_t*)addr)[i] != 0xffffffff) {
+ return -2;
+ }
+ }
+
+ return 0;
+}
+
+static int flash_write(uint32_t addr, const uint8_t *src8, size_t len) {
+ if (addr >= flash_layout[0].base_address && addr < flash_layout[0].base_address + flash_layout[0].sector_size) {
+ // Don't allow to write the sector with this bootloader in it
+ return -1;
+ }
+
+ const uint32_t *src = (const uint32_t*)src8;
+ size_t num_word32 = (len + 3) / 4;
+ HAL_FLASH_Unlock();
+ // program the flash word by word
+ for (size_t i = 0; i < num_word32; i++) {
+ if (HAL_FLASH_Program(TYPEPROGRAM_WORD, addr, *src) != HAL_OK) {
+ return -1;
+ }
+ addr += 4;
+ src += 1;
+ }
+
+ // TODO verify data
+
+ return 0;
+}
+
+/******************************************************************************/
+// Writable address space interface
+
+static int do_mass_erase(void) {
+ // TODO
+ return flash_mass_erase();
+}
+
+#if defined(MBOOT_SPIFLASH_ADDR) || defined(MBOOT_SPIFLASH2_ADDR)
+static int spiflash_page_erase(mp_spiflash_t *spif, uint32_t addr, uint32_t n_blocks) {
+ for (int i = 0; i < n_blocks; ++i) {
+ int ret = mp_spiflash_erase_block(spif, addr);
+ if (ret != 0) {
+ return ret;
+ }
+ addr += MP_SPIFLASH_ERASE_BLOCK_SIZE;
+ }
+ return 0;
+}
+#endif
+
+static int do_page_erase(uint32_t addr) {
+ led_state(LED0, 1);
+
+ #if defined(MBOOT_SPIFLASH_ADDR)
+ if (MBOOT_SPIFLASH_ADDR <= addr && addr < MBOOT_SPIFLASH_ADDR + MBOOT_SPIFLASH_BYTE_SIZE) {
+ return spiflash_page_erase(MBOOT_SPIFLASH_SPIFLASH,
+ addr - MBOOT_SPIFLASH_ADDR, MBOOT_SPIFLASH_ERASE_BLOCKS_PER_PAGE);
+ }
+ #endif
+
+ #if defined(MBOOT_SPIFLASH2_ADDR)
+ if (MBOOT_SPIFLASH2_ADDR <= addr && addr < MBOOT_SPIFLASH2_ADDR + MBOOT_SPIFLASH2_BYTE_SIZE) {
+ return spiflash_page_erase(MBOOT_SPIFLASH2_SPIFLASH,
+ addr - MBOOT_SPIFLASH2_ADDR, MBOOT_SPIFLASH2_ERASE_BLOCKS_PER_PAGE);
+ }
+ #endif
+
+ return flash_page_erase(addr);
+}
+
+static void do_read(uint32_t addr, int len, uint8_t *buf) {
+ #if defined(MBOOT_SPIFLASH_ADDR)
+ if (MBOOT_SPIFLASH_ADDR <= addr && addr < MBOOT_SPIFLASH_ADDR + MBOOT_SPIFLASH_BYTE_SIZE) {
+ mp_spiflash_read(MBOOT_SPIFLASH_SPIFLASH, addr - MBOOT_SPIFLASH_ADDR, len, buf);
+ return;
+ }
+ #endif
+ #if defined(MBOOT_SPIFLASH2_ADDR)
+ if (MBOOT_SPIFLASH2_ADDR <= addr && addr < MBOOT_SPIFLASH2_ADDR + MBOOT_SPIFLASH2_BYTE_SIZE) {
+ mp_spiflash_read(MBOOT_SPIFLASH2_SPIFLASH, addr - MBOOT_SPIFLASH2_ADDR, len, buf);
+ return;
+ }
+ #endif
+
+ // Other addresses, just read directly from memory
+ memcpy(buf, (void*)addr, len);
+}
+
+static int do_write(uint32_t addr, const uint8_t *src8, size_t len) {
+ static uint32_t led_tog = 0;
+ led_state(LED0, (led_tog++) & 4);
+
+ #if defined(MBOOT_SPIFLASH_ADDR)
+ if (MBOOT_SPIFLASH_ADDR <= addr && addr < MBOOT_SPIFLASH_ADDR + MBOOT_SPIFLASH_BYTE_SIZE) {
+ return mp_spiflash_write(MBOOT_SPIFLASH_SPIFLASH, addr - MBOOT_SPIFLASH_ADDR, len, src8);
+ }
+ #endif
+
+ #if defined(MBOOT_SPIFLASH2_ADDR)
+ if (MBOOT_SPIFLASH2_ADDR <= addr && addr < MBOOT_SPIFLASH2_ADDR + MBOOT_SPIFLASH2_BYTE_SIZE) {
+ return mp_spiflash_write(MBOOT_SPIFLASH2_SPIFLASH, addr - MBOOT_SPIFLASH2_ADDR, len, src8);
+ }
+ #endif
+
+ return flash_write(addr, src8, len);
+}
+
+/******************************************************************************/
+// I2C slave interface
+
+#if defined(MBOOT_I2C_SCL)
+
+#define PASTE2(a, b) a ## b
+#define PASTE3(a, b, c) a ## b ## c
+#define EVAL_PASTE2(a, b) PASTE2(a, b)
+#define EVAL_PASTE3(a, b, c) PASTE3(a, b, c)
+
+#define MBOOT_I2Cx EVAL_PASTE2(I2C, MBOOT_I2C_PERIPH_ID)
+#define I2Cx_EV_IRQn EVAL_PASTE3(I2C, MBOOT_I2C_PERIPH_ID, _EV_IRQn)
+#define I2Cx_EV_IRQHandler EVAL_PASTE3(I2C, MBOOT_I2C_PERIPH_ID, _EV_IRQHandler)
+
+#define I2C_CMD_BUF_LEN (129)
+
+enum {
+ I2C_CMD_ECHO = 1,
+ I2C_CMD_GETID, // () -> u8*12 unique id, ASCIIZ mcu name, ASCIIZ board name
+ I2C_CMD_GETCAPS, // not implemented
+ I2C_CMD_RESET, // () -> ()
+ I2C_CMD_CONFIG, // not implemented
+ I2C_CMD_GETLAYOUT, // () -> ASCII string
+ I2C_CMD_MASSERASE, // () -> ()
+ I2C_CMD_PAGEERASE, // le32 -> ()
+ I2C_CMD_SETRDADDR, // le32 -> ()
+ I2C_CMD_SETWRADDR, // le32 -> ()
+ I2C_CMD_READ, // u8 -> bytes
+ I2C_CMD_WRITE, // bytes -> ()
+ I2C_CMD_COPY, // not implemented
+ I2C_CMD_CALCHASH, // le32 -> u8*32
+ I2C_CMD_MARKVALID, // () -> ()
+};
+
+typedef struct _i2c_obj_t {
+ volatile bool cmd_send_arg;
+ volatile bool cmd_arg_sent;
+ volatile int cmd_arg;
+ volatile uint32_t cmd_rdaddr;
+ volatile uint32_t cmd_wraddr;
+ volatile uint16_t cmd_buf_pos;
+ uint8_t cmd_buf[I2C_CMD_BUF_LEN];
+} i2c_obj_t;
+
+static i2c_obj_t i2c_obj;
+
+void i2c_init(int addr) {
+ i2c_obj.cmd_send_arg = false;
+
+ mp_hal_pin_config(MBOOT_I2C_SCL, MP_HAL_PIN_MODE_ALT_OPEN_DRAIN, MP_HAL_PIN_PULL_NONE, MBOOT_I2C_ALTFUNC);
+ mp_hal_pin_config(MBOOT_I2C_SDA, MP_HAL_PIN_MODE_ALT_OPEN_DRAIN, MP_HAL_PIN_PULL_NONE, MBOOT_I2C_ALTFUNC);
+
+ i2c_slave_init(MBOOT_I2Cx, I2Cx_EV_IRQn, IRQ_PRI_I2C, addr);
+}
+
+int i2c_slave_process_addr_match(int rw) {
+ if (i2c_obj.cmd_arg_sent) {
+ i2c_obj.cmd_send_arg = false;
+ }
+ i2c_obj.cmd_buf_pos = 0;
+ return 0; // ACK
+}
+
+int i2c_slave_process_rx_byte(uint8_t val) {
+ if (i2c_obj.cmd_buf_pos < sizeof(i2c_obj.cmd_buf)) {
+ i2c_obj.cmd_buf[i2c_obj.cmd_buf_pos++] = val;
+ }
+ return 0; // ACK
+}
+
+void i2c_slave_process_rx_end(void) {
+ if (i2c_obj.cmd_buf_pos == 0) {
+ return;
+ }
+
+ int len = i2c_obj.cmd_buf_pos - 1;
+ uint8_t *buf = i2c_obj.cmd_buf;
+
+ if (buf[0] == I2C_CMD_ECHO) {
+ ++len;
+ } else if (buf[0] == I2C_CMD_GETID && len == 0) {
+ memcpy(buf, (uint8_t*)MP_HAL_UNIQUE_ID_ADDRESS, 12);
+ memcpy(buf + 12, MICROPY_HW_MCU_NAME, sizeof(MICROPY_HW_MCU_NAME));
+ memcpy(buf + 12 + sizeof(MICROPY_HW_MCU_NAME), MICROPY_HW_BOARD_NAME, sizeof(MICROPY_HW_BOARD_NAME) - 1);
+ len = 12 + sizeof(MICROPY_HW_MCU_NAME) + sizeof(MICROPY_HW_BOARD_NAME) - 1;
+ } else if (buf[0] == I2C_CMD_RESET && len == 0) {
+ do_reset();
+ } else if (buf[0] == I2C_CMD_GETLAYOUT && len == 0) {
+ len = strlen(FLASH_LAYOUT_STR);
+ memcpy(buf, FLASH_LAYOUT_STR, len);
+ } else if (buf[0] == I2C_CMD_MASSERASE && len == 0) {
+ len = do_mass_erase();
+ } else if (buf[0] == I2C_CMD_PAGEERASE && len == 4) {
+ len = do_page_erase(get_le32(buf + 1));
+ } else if (buf[0] == I2C_CMD_SETRDADDR && len == 4) {
+ i2c_obj.cmd_rdaddr = get_le32(buf + 1);
+ len = 0;
+ } else if (buf[0] == I2C_CMD_SETWRADDR && len == 4) {
+ i2c_obj.cmd_wraddr = get_le32(buf + 1);
+ len = 0;
+ } else if (buf[0] == I2C_CMD_READ && len == 1) {
+ len = buf[1];
+ if (len > I2C_CMD_BUF_LEN) {
+ len = I2C_CMD_BUF_LEN;
+ }
+ do_read(i2c_obj.cmd_rdaddr, len, buf);
+ i2c_obj.cmd_rdaddr += len;
+ } else if (buf[0] == I2C_CMD_WRITE) {
+ if (i2c_obj.cmd_wraddr == APPLICATION_ADDR) {
+ // Mark the 2 lower bits to indicate invalid app firmware
+ buf[1] |= APP_VALIDITY_BITS;
+ }
+ int ret = do_write(i2c_obj.cmd_wraddr, buf + 1, len);
+ if (ret < 0) {
+ len = ret;
+ } else {
+ i2c_obj.cmd_wraddr += len;
+ len = 0;
+ }
+ } else if (buf[0] == I2C_CMD_CALCHASH && len == 4) {
+ uint32_t hashlen = get_le32(buf + 1);
+ static CRYAL_SHA256_CTX ctx;
+ sha256_init(&ctx);
+ sha256_update(&ctx, (const void*)i2c_obj.cmd_rdaddr, hashlen);
+ i2c_obj.cmd_rdaddr += hashlen;
+ sha256_final(&ctx, buf);
+ len = 32;
+ } else if (buf[0] == I2C_CMD_MARKVALID && len == 0) {
+ uint32_t buf;
+ buf = *(volatile uint32_t*)APPLICATION_ADDR;
+ if ((buf & APP_VALIDITY_BITS) != APP_VALIDITY_BITS) {
+ len = -1;
+ } else {
+ buf &= ~APP_VALIDITY_BITS;
+ int ret = do_write(APPLICATION_ADDR, (void*)&buf, 4);
+ if (ret < 0) {
+ len = ret;
+ } else {
+ buf = *(volatile uint32_t*)APPLICATION_ADDR;
+ if ((buf & APP_VALIDITY_BITS) != 0) {
+ len = -2;
+ } else {
+ len = 0;
+ }
+ }
+ }
+ } else {
+ len = -127;
+ }
+ i2c_obj.cmd_arg = len;
+ i2c_obj.cmd_send_arg = true;
+ i2c_obj.cmd_arg_sent = false;
+}
+
+uint8_t i2c_slave_process_tx_byte(void) {
+ if (i2c_obj.cmd_send_arg) {
+ i2c_obj.cmd_arg_sent = true;
+ return i2c_obj.cmd_arg;
+ } else if (i2c_obj.cmd_buf_pos < sizeof(i2c_obj.cmd_buf)) {
+ return i2c_obj.cmd_buf[i2c_obj.cmd_buf_pos++];
+ } else {
+ return 0;
+ }
+}
+
+#endif // defined(MBOOT_I2C_SCL)
+
+/******************************************************************************/
+// DFU
+
+#define DFU_XFER_SIZE (2048)
+
+enum {
+ DFU_DNLOAD = 1,
+ DFU_UPLOAD = 2,
+ DFU_GETSTATUS = 3,
+ DFU_CLRSTATUS = 4,
+ DFU_ABORT = 6,
+};
+
+enum {
+ DFU_STATUS_IDLE = 2,
+ DFU_STATUS_BUSY = 4,
+ DFU_STATUS_DNLOAD_IDLE = 5,
+ DFU_STATUS_MANIFEST = 7,
+ DFU_STATUS_UPLOAD_IDLE = 9,
+ DFU_STATUS_ERROR = 0xa,
+};
+
+enum {
+ DFU_CMD_NONE = 0,
+ DFU_CMD_EXIT = 1,
+ DFU_CMD_UPLOAD = 7,
+ DFU_CMD_DNLOAD = 8,
+};
+
+typedef struct _dfu_state_t {
+ int status;
+ int cmd;
+ uint16_t wBlockNum;
+ uint16_t wLength;
+ uint32_t addr;
+ uint8_t buf[DFU_XFER_SIZE] __attribute__((aligned(4)));
+} dfu_state_t;
+
+static dfu_state_t dfu_state;
+
+static void dfu_init(void) {
+ dfu_state.status = DFU_STATUS_IDLE;
+ dfu_state.cmd = DFU_CMD_NONE;
+ dfu_state.addr = 0x08000000;
+}
+
+static int dfu_process_dnload(void) {
+ int ret = -1;
+ if (dfu_state.wBlockNum == 0) {
+ // download control commands
+ if (dfu_state.wLength >= 1 && dfu_state.buf[0] == 0x41) {
+ if (dfu_state.wLength == 1) {
+ // mass erase
+ ret = do_mass_erase();
+ } else if (dfu_state.wLength == 5) {
+ // erase page
+ ret = do_page_erase(get_le32(&dfu_state.buf[1]));
+ }
+ } else if (dfu_state.wLength >= 1 && dfu_state.buf[0] == 0x21) {
+ if (dfu_state.wLength == 5) {
+ // set address
+ dfu_state.addr = get_le32(&dfu_state.buf[1]);
+ ret = 0;
+ }
+ }
+ } else if (dfu_state.wBlockNum > 1) {
+ // write data to memory
+ ret = do_write(dfu_state.addr, dfu_state.buf, dfu_state.wLength);
+ }
+ if (ret == 0) {
+ return DFU_STATUS_DNLOAD_IDLE;
+ } else {
+ return DFU_STATUS_ERROR;
+ }
+}
+
+static void dfu_handle_rx(int cmd, int arg, int len, const void *buf) {
+ if (cmd == DFU_CLRSTATUS) {
+ // clear status
+ dfu_state.status = DFU_STATUS_IDLE;
+ dfu_state.cmd = DFU_CMD_NONE;
+ } else if (cmd == DFU_ABORT) {
+ // clear status
+ dfu_state.status = DFU_STATUS_IDLE;
+ dfu_state.cmd = DFU_CMD_NONE;
+ } else if (cmd == DFU_DNLOAD) {
+ if (len == 0) {
+ // exit DFU
+ dfu_state.cmd = DFU_CMD_EXIT;
+ } else {
+ // download
+ dfu_state.cmd = DFU_CMD_DNLOAD;
+ dfu_state.wBlockNum = arg;
+ dfu_state.wLength = len;
+ memcpy(dfu_state.buf, buf, len);
+ }
+ }
+}
+
+static void dfu_process(void) {
+ if (dfu_state.status == DFU_STATUS_MANIFEST) {
+ do_reset();
+ }
+
+ if (dfu_state.status == DFU_STATUS_BUSY) {
+ if (dfu_state.cmd == DFU_CMD_DNLOAD) {
+ dfu_state.cmd = DFU_CMD_NONE;
+ dfu_state.status = dfu_process_dnload();
+ }
+ }
+}
+
+static int dfu_handle_tx(int cmd, int arg, int len, uint8_t *buf, int max_len) {
+ if (cmd == DFU_UPLOAD) {
+ if (arg >= 2) {
+ dfu_state.cmd = DFU_CMD_UPLOAD;
+ uint32_t addr = (arg - 2) * max_len + dfu_state.addr;
+ do_read(addr, len, buf);
+ return len;
+ }
+ } else if (cmd == DFU_GETSTATUS && len == 6) {
+ // execute command and get status
+ switch (dfu_state.cmd) {
+ case DFU_CMD_NONE:
+ break;
+ case DFU_CMD_EXIT:
+ dfu_state.status = DFU_STATUS_MANIFEST;
+ break;
+ case DFU_CMD_UPLOAD:
+ dfu_state.status = DFU_STATUS_UPLOAD_IDLE;
+ break;
+ case DFU_CMD_DNLOAD:
+ dfu_state.status = DFU_STATUS_BUSY;
+ break;
+ }
+ buf[0] = 0;
+ buf[1] = dfu_state.cmd; // TODO is this correct?
+ buf[2] = 0;
+ buf[3] = 0;
+ buf[4] = dfu_state.status;
+ buf[5] = 0;
+ return 6;
+ }
+ return -1;
+}
+
+/******************************************************************************/
+// USB
+
+#define USB_XFER_SIZE (DFU_XFER_SIZE)
+
+enum {
+ USB_PHY_FS_ID = 0,
+ USB_PHY_HS_ID = 1,
+};
+
+typedef struct _pyb_usbdd_obj_t {
+ bool started;
+ bool tx_pending;
+ USBD_HandleTypeDef hUSBDDevice;
+
+ uint8_t bRequest;
+ uint16_t wValue;
+ uint16_t wLength;
+ __ALIGN_BEGIN uint8_t rx_buf[USB_XFER_SIZE] __ALIGN_END;
+ __ALIGN_BEGIN uint8_t tx_buf[USB_XFER_SIZE] __ALIGN_END;
+
+ // RAM to hold the current descriptors, which we configure on the fly
+ __ALIGN_BEGIN uint8_t usbd_device_desc[USB_LEN_DEV_DESC] __ALIGN_END;
+ __ALIGN_BEGIN uint8_t usbd_str_desc[USBD_MAX_STR_DESC_SIZ] __ALIGN_END;
+} pyb_usbdd_obj_t;
+
+#define USBD_LANGID_STRING (0x409)
+
+__ALIGN_BEGIN static const uint8_t USBD_LangIDDesc[USB_LEN_LANGID_STR_DESC] __ALIGN_END = {
+ USB_LEN_LANGID_STR_DESC,
+ USB_DESC_TYPE_STRING,
+ LOBYTE(USBD_LANGID_STRING),
+ HIBYTE(USBD_LANGID_STRING),
+};
+
+static const uint8_t dev_descr[0x12] = "\x12\x01\x00\x01\x00\x00\x00\x40\x83\x04\x11\xdf\x00\x22\x01\x02\x03\x01";
+
+// This may be modified by USBD_GetDescriptor
+static uint8_t cfg_descr[9 + 9 + 9] =
+ "\x09\x02\x1b\x00\x01\x01\x00\xc0\x32"
+ "\x09\x04\x00\x00\x00\xfe\x01\x02\x04"
+ "\x09\x21\x0b\xff\x00\x00\x08\x1a\x01" // \x00\x08 goes with USB_XFER_SIZE
+;
+
+static uint8_t *pyb_usbdd_DeviceDescriptor(USBD_HandleTypeDef *pdev, uint16_t *length) {
+ *length = USB_LEN_DEV_DESC;
+ return (uint8_t*)dev_descr;
+}
+
+static char get_hex_char(int val) {
+ val &= 0xf;
+ if (val <= 9) {
+ return '0' + val;
+ } else {
+ return 'A' + val - 10;
+ }
+}
+
+static void format_hex(char *buf, int val) {
+ buf[0] = get_hex_char(val >> 4);
+ buf[1] = get_hex_char(val);
+}
+
+static uint8_t *pyb_usbdd_StrDescriptor(USBD_HandleTypeDef *pdev, uint8_t idx, uint16_t *length) {
+ pyb_usbdd_obj_t *self = (pyb_usbdd_obj_t*)pdev->pClassData;
+ uint8_t *str_desc = self->usbd_str_desc;
+ switch (idx) {
+ case USBD_IDX_LANGID_STR:
+ *length = sizeof(USBD_LangIDDesc);
+ return (uint8_t*)USBD_LangIDDesc; // the data should only be read from this buf
+
+ case USBD_IDX_MFC_STR:
+ USBD_GetString((uint8_t*)"USBDevice Manuf", str_desc, length);
+ return str_desc;
+
+ case USBD_IDX_PRODUCT_STR:
+ USBD_GetString((uint8_t*)"USBDevice Product", str_desc, length);
+ return str_desc;
+
+ case USBD_IDX_SERIAL_STR: {
+ // This document: http://www.usb.org/developers/docs/devclass_docs/usbmassbulk_10.pdf
+ // says that the serial number has to be at least 12 digits long and that
+ // the last 12 digits need to be unique. It also stipulates that the valid
+ // character set is that of upper-case hexadecimal digits.
+ //
+ // The onboard DFU bootloader produces a 12-digit serial number based on
+ // the 96-bit unique ID, so for consistency we go with this algorithm.
+ // You can see the serial number if you do:
+ //
+ // dfu-util -l
+ //
+ // See: https://my.st.com/52d187b7 for the algorithim used.
+ uint8_t *id = (uint8_t*)MP_HAL_UNIQUE_ID_ADDRESS;
+ char serial_buf[16];
+ format_hex(&serial_buf[0], id[11]);
+ format_hex(&serial_buf[2], id[10] + id[2]);
+ format_hex(&serial_buf[4], id[9]);
+ format_hex(&serial_buf[6], id[8] + id[0]);
+ format_hex(&serial_buf[8], id[7]);
+ format_hex(&serial_buf[10], id[6]);
+ serial_buf[12] = '\0';
+
+ USBD_GetString((uint8_t*)serial_buf, str_desc, length);
+ return str_desc;
+ }
+
+ case USBD_IDX_CONFIG_STR:
+ USBD_GetString((uint8_t*)FLASH_LAYOUT_STR, str_desc, length);
+ return str_desc;
+
+ default:
+ return NULL;
+ }
+}
+
+static const USBD_DescriptorsTypeDef pyb_usbdd_descriptors = {
+ pyb_usbdd_DeviceDescriptor,
+ pyb_usbdd_StrDescriptor,
+};
+
+static uint8_t pyb_usbdd_Init(USBD_HandleTypeDef *pdev, uint8_t cfgidx) {
+ pyb_usbdd_obj_t *self = (pyb_usbdd_obj_t*)pdev->pClassData;
+ (void)self;
+ return USBD_OK;
+}
+
+static uint8_t pyb_usbdd_DeInit(USBD_HandleTypeDef *pdev, uint8_t cfgidx) {
+ pyb_usbdd_obj_t *self = (pyb_usbdd_obj_t*)pdev->pClassData;
+ (void)self;
+ return USBD_OK;
+}
+
+static uint8_t pyb_usbdd_Setup(USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req) {
+ pyb_usbdd_obj_t *self = (pyb_usbdd_obj_t*)pdev->pClassData;
+ (void)self;
+ self->bRequest = req->bRequest;
+ self->wValue = req->wValue;
+ self->wLength = req->wLength;
+ if (req->bmRequest == 0x21) {
+ // host-to-device request
+ if (req->wLength == 0) {
+ // no data, process command straightaway
+ dfu_handle_rx(self->bRequest, self->wValue, 0, NULL);
+ } else {
+ // have data, prepare to receive it
+ USBD_CtlPrepareRx(pdev, self->rx_buf, req->wLength);
+ }
+ } else if (req->bmRequest == 0xa1) {
+ // device-to-host request
+ int len = dfu_handle_tx(self->bRequest, self->wValue, self->wLength, self->tx_buf, USB_XFER_SIZE);
+ if (len >= 0) {
+ self->tx_pending = true;
+ USBD_CtlSendData(&self->hUSBDDevice, self->tx_buf, len);
+ }
+ }
+ return USBD_OK;
+}
+
+static uint8_t pyb_usbdd_EP0_TxSent(USBD_HandleTypeDef *pdev) {
+ pyb_usbdd_obj_t *self = (pyb_usbdd_obj_t*)pdev->pClassData;
+ self->tx_pending = false;
+ #if !USE_USB_POLLING
+ // Process now that we have sent a response
+ dfu_process();
+ #endif
+ return USBD_OK;
+}
+
+static uint8_t pyb_usbdd_EP0_RxReady(USBD_HandleTypeDef *pdev) {
+ pyb_usbdd_obj_t *self = (pyb_usbdd_obj_t*)pdev->pClassData;
+ dfu_handle_rx(self->bRequest, self->wValue, self->wLength, self->rx_buf);
+ return USBD_OK;
+}
+
+static uint8_t *pyb_usbdd_GetCfgDesc(USBD_HandleTypeDef *pdev, uint16_t *length) {
+ *length = sizeof(cfg_descr);
+ return (uint8_t*)cfg_descr;
+}
+
+// this is used only in high-speed mode, which we don't support
+static uint8_t *pyb_usbdd_GetDeviceQualifierDescriptor(USBD_HandleTypeDef *pdev, uint16_t *length) {
+ pyb_usbdd_obj_t *self = (pyb_usbdd_obj_t*)pdev->pClassData;
+ (void)self;
+ /*
+ *length = sizeof(USBD_CDC_MSC_HID_DeviceQualifierDesc);
+ return USBD_CDC_MSC_HID_DeviceQualifierDesc;
+ */
+ *length = 0;
+ return NULL;
+}
+
+static const USBD_ClassTypeDef pyb_usbdd_class = {
+ pyb_usbdd_Init,
+ pyb_usbdd_DeInit,
+ pyb_usbdd_Setup,
+ pyb_usbdd_EP0_TxSent,
+ pyb_usbdd_EP0_RxReady,
+ NULL, // pyb_usbdd_DataIn,
+ NULL, // pyb_usbdd_DataOut,
+ NULL, // SOF
+ NULL, // IsoINIncomplete
+ NULL, // IsoOUTIncomplete
+ pyb_usbdd_GetCfgDesc,
+ pyb_usbdd_GetCfgDesc,
+ pyb_usbdd_GetCfgDesc,
+ pyb_usbdd_GetDeviceQualifierDescriptor,
+};
+
+static pyb_usbdd_obj_t pyb_usbdd;
+
+static void pyb_usbdd_init(pyb_usbdd_obj_t *self, int phy_id) {
+ self->started = false;
+ USBD_HandleTypeDef *usbd = &self->hUSBDDevice;
+ usbd->id = phy_id;
+ usbd->dev_state = USBD_STATE_DEFAULT;
+ usbd->pDesc = (USBD_DescriptorsTypeDef*)&pyb_usbdd_descriptors;
+ usbd->pClass = &pyb_usbdd_class;
+ usbd->pClassData = self;
+}
+
+static void pyb_usbdd_start(pyb_usbdd_obj_t *self) {
+ if (!self->started) {
+ USBD_LL_Init(&self->hUSBDDevice, 0);
+ USBD_LL_Start(&self->hUSBDDevice);
+ self->started = true;
+ }
+}
+
+static void pyb_usbdd_stop(pyb_usbdd_obj_t *self) {
+ if (self->started) {
+ USBD_Stop(&self->hUSBDDevice);
+ self->started = false;
+ }
+}
+
+static int pyb_usbdd_shutdown(void) {
+ pyb_usbdd_stop(&pyb_usbdd);
+ return 0;
+}
+
+/******************************************************************************/
+// main
+
+#define RESET_MODE_NUM_STATES (4)
+#define RESET_MODE_TIMEOUT_CYCLES (8)
+#define RESET_MODE_LED_STATES 0x7421
+
+static int get_reset_mode(void) {
+ usrbtn_init();
+ int reset_mode = 1;
+ if (usrbtn_state()) {
+ // Cycle through reset modes while USR is held
+ // Timeout is roughly 20s, where reset_mode=1
+ systick_init();
+ led_init();
+ reset_mode = 0;
+ for (int i = 0; i < (RESET_MODE_NUM_STATES * RESET_MODE_TIMEOUT_CYCLES + 1) * 32; i++) {
+ if (i % 32 == 0) {
+ if (++reset_mode > RESET_MODE_NUM_STATES) {
+ reset_mode = 1;
+ }
+ uint8_t l = RESET_MODE_LED_STATES >> ((reset_mode - 1) * 4);
+ led_state(LED0, l & 1);
+ led_state(LED1, l & 2);
+ led_state(LED2, l & 4);
+ }
+ if (!usrbtn_state()) {
+ break;
+ }
+ mp_hal_delay_ms(19);
+ }
+ // Flash the selected reset mode
+ for (int i = 0; i < 6; i++) {
+ led_state(LED0, 0);
+ led_state(LED1, 0);
+ led_state(LED2, 0);
+ mp_hal_delay_ms(50);
+ uint8_t l = RESET_MODE_LED_STATES >> ((reset_mode - 1) * 4);
+ led_state(LED0, l & 1);
+ led_state(LED1, l & 2);
+ led_state(LED2, l & 4);
+ mp_hal_delay_ms(50);
+ }
+ mp_hal_delay_ms(300);
+ }
+ return reset_mode;
+}
+
+static void do_reset(void) {
+ led_state(LED0, 0);
+ led_state(LED1, 0);
+ led_state(LED2, 0);
+ mp_hal_delay_ms(50);
+ pyb_usbdd_shutdown();
+ #if defined(MBOOT_I2C_SCL)
+ i2c_slave_shutdown(MBOOT_I2Cx, I2Cx_EV_IRQn);
+ #endif
+ mp_hal_delay_ms(50);
+ NVIC_SystemReset();
+}
+
+uint32_t SystemCoreClock;
+
+extern PCD_HandleTypeDef pcd_fs_handle;
+extern PCD_HandleTypeDef pcd_hs_handle;
+
+void stm32_main(int initial_r0) {
+ #if defined(STM32F4)
+ #if INSTRUCTION_CACHE_ENABLE
+ __HAL_FLASH_INSTRUCTION_CACHE_ENABLE();
+ #endif
+ #if DATA_CACHE_ENABLE
+ __HAL_FLASH_DATA_CACHE_ENABLE();
+ #endif
+ #if PREFETCH_ENABLE
+ __HAL_FLASH_PREFETCH_BUFFER_ENABLE();
+ #endif
+ #elif defined(STM32F7)
+ #if ART_ACCLERATOR_ENABLE
+ __HAL_FLASH_ART_ENABLE();
+ #endif
+ #endif
+
+ NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4);
+
+ #if USE_CACHE && defined(STM32F7)
+ SCB_EnableICache();
+ SCB_EnableDCache();
+ #endif
+
+ #ifdef MBOOT_BOOTPIN_PIN
+ mp_hal_pin_config(MBOOT_BOOTPIN_PIN, MP_HAL_PIN_MODE_INPUT, MBOOT_BOOTPIN_PULL, 0);
+ if (mp_hal_pin_read(MBOOT_BOOTPIN_PIN) == MBOOT_BOOTPIN_ACTIVE) {
+ goto enter_bootloader;
+ }
+ #endif
+
+ if ((initial_r0 & 0xffffff00) == 0x70ad0000) {
+ goto enter_bootloader;
+ }
+
+ // MCU starts up with 16MHz HSI
+ SystemCoreClock = 16000000;
+
+ int reset_mode = get_reset_mode();
+ uint32_t msp = *(volatile uint32_t*)APPLICATION_ADDR;
+ if (reset_mode != 4 && (msp & APP_VALIDITY_BITS) == 0) {
+ // not DFU mode so jump to application, passing through reset_mode
+ // undo our DFU settings
+ // TODO probably should disable all IRQ sources first
+ #if USE_CACHE && defined(STM32F7)
+ SCB_DisableICache();
+ SCB_DisableDCache();
+ #endif
+ __set_MSP(msp);
+ ((void (*)(uint32_t)) *((volatile uint32_t*)(APPLICATION_ADDR + 4)))(reset_mode);
+ }
+
+enter_bootloader:
+
+ // Init subsystems (get_reset_mode() may call these, calling them again is ok)
+ led_init();
+
+ // set the system clock to be HSE
+ SystemClock_Config();
+
+ #if USE_USB_POLLING
+ // irqs with a priority value greater or equal to "pri" will be disabled
+ // "pri" should be between 1 and 15 inclusive
+ uint32_t pri = 2;
+ pri <<= (8 - __NVIC_PRIO_BITS);
+ __ASM volatile ("msr basepri_max, %0" : : "r" (pri) : "memory");
+ #endif
+
+ #if defined(MBOOT_SPIFLASH_ADDR)
+ MBOOT_SPIFLASH_SPIFLASH->config = MBOOT_SPIFLASH_CONFIG;
+ mp_spiflash_init(MBOOT_SPIFLASH_SPIFLASH);
+ #endif
+
+ #if defined(MBOOT_SPIFLASH2_ADDR)
+ MBOOT_SPIFLASH2_SPIFLASH->config = MBOOT_SPIFLASH2_CONFIG;
+ mp_spiflash_init(MBOOT_SPIFLASH2_SPIFLASH);
+ #endif
+
+ dfu_init();
+
+ pyb_usbdd_init(&pyb_usbdd, MICROPY_HW_USB_MAIN_DEV);
+ pyb_usbdd_start(&pyb_usbdd);
+
+ #if defined(MBOOT_I2C_SCL)
+ initial_r0 &= 0x7f;
+ if (initial_r0 == 0) {
+ initial_r0 = 0x23; // Default I2C address
+ }
+ i2c_init(initial_r0);
+ #endif
+
+ led_state(LED0, 0);
+ led_state(LED1, 0);
+ led_state(LED2, 0);
+
+ #if USE_USB_POLLING
+ uint32_t ss = systick_ms;
+ int ss2 = -1;
+ #endif
+ for (;;) {
+ #if USE_USB_POLLING
+ #if defined(MICROPY_HW_USB_FS)
+ if (pcd_fs_handle.Instance->GINTSTS & pcd_fs_handle.Instance->GINTMSK) {
+ HAL_PCD_IRQHandler(&pcd_fs_handle);
+ }
+ #endif
+ #if defined(MICROPY_HW_USB_HS)
+ if (pcd_hs_handle.Instance->GINTSTS & pcd_hs_handle.Instance->GINTMSK) {
+ HAL_PCD_IRQHandler(&pcd_hs_handle);
+ }
+ #endif
+ if (!pyb_usbdd.tx_pending) {
+ dfu_process();
+ }
+ #endif
+
+ #if USE_USB_POLLING
+ //__WFI(); // slows it down way too much; might work with 10x faster systick
+ if (systick_ms - ss > 50) {
+ ss += 50;
+ ss2 = (ss2 + 1) % 20;
+ switch (ss2) {
+ case 0: led_state(LED0, 1); break;
+ case 1: led_state(LED0, 0); break;
+ }
+ }
+ #else
+ led_state(LED0, 1);
+ mp_hal_delay_ms(50);
+ led_state(LED0, 0);
+ mp_hal_delay_ms(950);
+ #endif
+ }
+}
+
+void NMI_Handler(void) {
+}
+
+void MemManage_Handler(void) {
+ while (1) {
+ __fatal_error("MemManage");
+ }
+}
+
+void BusFault_Handler(void) {
+ while (1) {
+ __fatal_error("BusFault");
+ }
+}
+
+void UsageFault_Handler(void) {
+ while (1) {
+ __fatal_error("UsageFault");
+ }
+}
+
+void SVC_Handler(void) {
+}
+
+void DebugMon_Handler(void) {
+}
+
+void PendSV_Handler(void) {
+}
+
+void SysTick_Handler(void) {
+ systick_ms += 1;
+
+ // Read the systick control regster. This has the side effect of clearing
+ // the COUNTFLAG bit, which makes the logic in mp_hal_ticks_us
+ // work properly.
+ SysTick->CTRL;
+}
+
+#if defined(MBOOT_I2C_SCL)
+void I2Cx_EV_IRQHandler(void) {
+ i2c_slave_ev_irq_handler(MBOOT_I2Cx);
+}
+#endif
+
+#if !USE_USB_POLLING
+#if defined(MICROPY_HW_USB_FS)
+void OTG_FS_IRQHandler(void) {
+ HAL_PCD_IRQHandler(&pcd_fs_handle);
+}
+#endif
+#if defined(MICROPY_HW_USB_HS)
+void OTG_HS_IRQHandler(void) {
+ HAL_PCD_IRQHandler(&pcd_hs_handle);
+}
+#endif
+#endif
diff --git a/ports/stm32/mboot/mboot.py b/ports/stm32/mboot/mboot.py
new file mode 100644
index 000000000..39ae0f6f2
--- /dev/null
+++ b/ports/stm32/mboot/mboot.py
@@ -0,0 +1,177 @@
+# Driver for Mboot, the MicroPython boot loader
+# MIT license; Copyright (c) 2018 Damien P. George
+
+import struct, time, os, hashlib
+
+
+I2C_CMD_ECHO = 1
+I2C_CMD_GETID = 2
+I2C_CMD_GETCAPS = 3
+I2C_CMD_RESET = 4
+I2C_CMD_CONFIG = 5
+I2C_CMD_GETLAYOUT = 6
+I2C_CMD_MASSERASE = 7
+I2C_CMD_PAGEERASE = 8
+I2C_CMD_SETRDADDR = 9
+I2C_CMD_SETWRADDR = 10
+I2C_CMD_READ = 11
+I2C_CMD_WRITE = 12
+I2C_CMD_COPY = 13
+I2C_CMD_CALCHASH = 14
+I2C_CMD_MARKVALID = 15
+
+
+class Bootloader:
+ def __init__(self, i2c, addr):
+ self.i2c = i2c
+ self.addr = addr
+ self.buf1 = bytearray(1)
+ try:
+ self.i2c.writeto(addr, b'')
+ except OSError:
+ raise Exception('no I2C mboot device found')
+
+ def wait_response(self):
+ start = time.ticks_ms()
+ while 1:
+ try:
+ self.i2c.readfrom_into(self.addr, self.buf1)
+ n = self.buf1[0]
+ break
+ except OSError as er:
+ time.sleep_us(500)
+ if time.ticks_diff(time.ticks_ms(), start) > 5000:
+ raise Exception('timeout')
+ if n >= 129:
+ raise Exception(n)
+ if n == 0:
+ return b''
+ else:
+ return self.i2c.readfrom(self.addr, n)
+
+ def wait_empty_response(self):
+ ret = self.wait_response()
+ if ret:
+ raise Exception('expected empty response got %r' % ret)
+ else:
+ return None
+
+ def echo(self, data):
+ self.i2c.writeto(self.addr, struct.pack('<B', I2C_CMD_ECHO) + data)
+ return self.wait_response()
+
+ def getid(self):
+ self.i2c.writeto(self.addr, struct.pack('<B', I2C_CMD_GETID))
+ ret = self.wait_response()
+ unique_id = ret[:12]
+ mcu_name, board_name = ret[12:].split(b'\x00')
+ return unique_id, str(mcu_name, 'ascii'), str(board_name, 'ascii')
+
+ def reset(self):
+ self.i2c.writeto(self.addr, struct.pack('<B', I2C_CMD_RESET))
+ # we don't expect any response
+
+ def getlayout(self):
+ self.i2c.writeto(self.addr, struct.pack('<B', I2C_CMD_GETLAYOUT))
+ layout = self.wait_response()
+ id, flash_addr, layout = layout.split(b'/')
+ assert id == b'@Internal Flash '
+ flash_addr = int(flash_addr, 16)
+ pages = []
+ for chunk in layout.split(b','):
+ n, sz = chunk.split(b'*')
+ n = int(n)
+ assert sz.endswith(b'Kg')
+ sz = int(sz[:-2]) * 1024
+ for i in range(n):
+ pages.append((flash_addr, sz))
+ flash_addr += sz
+ return pages
+
+ def pageerase(self, addr):
+ self.i2c.writeto(self.addr, struct.pack('<BI', I2C_CMD_PAGEERASE, addr))
+ self.wait_empty_response()
+
+ def setrdaddr(self, addr):
+ self.i2c.writeto(self.addr, struct.pack('<BI', I2C_CMD_SETRDADDR, addr))
+ self.wait_empty_response()
+
+ def setwraddr(self, addr):
+ self.i2c.writeto(self.addr, struct.pack('<BI', I2C_CMD_SETWRADDR, addr))
+ self.wait_empty_response()
+
+ def read(self, n):
+ self.i2c.writeto(self.addr, struct.pack('<BB', I2C_CMD_READ, n))
+ return self.wait_response()
+
+ def write(self, buf):
+ self.i2c.writeto(self.addr, struct.pack('<B', I2C_CMD_WRITE) + buf)
+ self.wait_empty_response()
+
+ def calchash(self, n):
+ self.i2c.writeto(self.addr, struct.pack('<BI', I2C_CMD_CALCHASH, n))
+ return self.wait_response()
+
+ def markvalid(self):
+ self.i2c.writeto(self.addr, struct.pack('<B', I2C_CMD_MARKVALID))
+ self.wait_empty_response()
+
+ def deployfile(self, filename, addr):
+ pages = self.getlayout()
+ page_erased = [False] * len(pages)
+ buf = bytearray(128) # maximum payload supported by I2C protocol
+ start_addr = addr
+ self.setwraddr(addr)
+ fsize = os.stat(filename)[6]
+ local_sha = hashlib.sha256()
+ print('Deploying %s to location 0x%08x' % (filename, addr))
+ with open(filename, 'rb') as f:
+ t0 = time.ticks_ms()
+ while True:
+ n = f.readinto(buf)
+ if n == 0:
+ break
+
+ # check if we need to erase the page
+ for i, p in enumerate(pages):
+ if p[0] <= addr < p[0] + p[1]:
+ # found page
+ if not page_erased[i]:
+ print('\r% 3u%% erase 0x%08x' % (100 * (addr - start_addr) // fsize, addr), end='')
+ self.pageerase(addr)
+ page_erased[i] = True
+ break
+ else:
+ raise Exception('address 0x%08x not valid' % addr)
+
+ # write the data
+ self.write(buf)
+
+ # update local SHA256, with validity bits set
+ if addr == start_addr:
+ buf[0] |= 3
+ if n == len(buf):
+ local_sha.update(buf)
+ else:
+ local_sha.update(buf[:n])
+
+ addr += n
+ ntotal = addr - start_addr
+ if ntotal % 2048 == 0 or ntotal == fsize:
+ print('\r% 3u%% % 7u bytes ' % (100 * ntotal // fsize, ntotal), end='')
+ t1 = time.ticks_ms()
+ print()
+ print('rate: %.2f KiB/sec' % (1024 * ntotal / (t1 - t0) / 1000))
+
+ local_sha = local_sha.digest()
+ print('Local SHA256: ', ''.join('%02x' % x for x in local_sha))
+
+ self.setrdaddr(start_addr)
+ remote_sha = self.calchash(ntotal)
+ print('Remote SHA256:', ''.join('%02x' % x for x in remote_sha))
+
+ if local_sha == remote_sha:
+ print('Marking app firmware as valid')
+ self.markvalid()
+
+ self.reset()
diff --git a/ports/stm32/mboot/mphalport.h b/ports/stm32/mboot/mphalport.h
new file mode 100644
index 000000000..2cf7c243e
--- /dev/null
+++ b/ports/stm32/mboot/mphalport.h
@@ -0,0 +1,155 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017-2018 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdbool.h>
+
+#define mp_hal_delay_us_fast(us) mp_hal_delay_us(us)
+
+#define MP_HAL_PIN_MODE_INPUT (0)
+#define MP_HAL_PIN_MODE_OUTPUT (1)
+#define MP_HAL_PIN_MODE_ALT (2)
+#define MP_HAL_PIN_MODE_ANALOG (3)
+#define MP_HAL_PIN_MODE_OPEN_DRAIN (5)
+#define MP_HAL_PIN_MODE_ALT_OPEN_DRAIN (6)
+#define MP_HAL_PIN_PULL_NONE (GPIO_NOPULL)
+#define MP_HAL_PIN_PULL_UP (GPIO_PULLUP)
+#define MP_HAL_PIN_PULL_DOWN (GPIO_PULLDOWN)
+
+#define mp_hal_pin_obj_t uint32_t
+#define mp_hal_pin_input(p) mp_hal_pin_config((p), MP_HAL_PIN_MODE_INPUT, MP_HAL_PIN_PULL_NONE, 0)
+#define mp_hal_pin_output(p) mp_hal_pin_config((p), MP_HAL_PIN_MODE_OUTPUT, MP_HAL_PIN_PULL_NONE, 0)
+#define mp_hal_pin_open_drain(p) mp_hal_pin_config((p), MP_HAL_PIN_MODE_OPEN_DRAIN, MP_HAL_PIN_PULL_NONE, 0)
+#define mp_hal_pin_low(p) (((GPIO_TypeDef*)((p) & ~0xf))->BSRR = 0x10000 << ((p) & 0xf))
+#define mp_hal_pin_high(p) (((GPIO_TypeDef*)((p) & ~0xf))->BSRR = 1 << ((p) & 0xf))
+#define mp_hal_pin_od_low(p) mp_hal_pin_low(p)
+#define mp_hal_pin_od_high(p) mp_hal_pin_high(p)
+#define mp_hal_pin_read(p) ((((GPIO_TypeDef*)((p) & ~0xf))->IDR >> ((p) & 0xf)) & 1)
+#define mp_hal_pin_write(p, v) do { if (v) { mp_hal_pin_high(p); } else { mp_hal_pin_low(p); } } while (0)
+
+void mp_hal_pin_config(uint32_t port_pin, uint32_t mode, uint32_t pull, uint32_t alt);
+void mp_hal_pin_config_speed(uint32_t port_pin, uint32_t speed);
+
+#define pin_A0 (GPIOA_BASE | 0)
+#define pin_A1 (GPIOA_BASE | 1)
+#define pin_A2 (GPIOA_BASE | 2)
+#define pin_A3 (GPIOA_BASE | 3)
+#define pin_A4 (GPIOA_BASE | 4)
+#define pin_A5 (GPIOA_BASE | 5)
+#define pin_A6 (GPIOA_BASE | 6)
+#define pin_A7 (GPIOA_BASE | 7)
+#define pin_A8 (GPIOA_BASE | 8)
+#define pin_A9 (GPIOA_BASE | 9)
+#define pin_A10 (GPIOA_BASE | 10)
+#define pin_A11 (GPIOA_BASE | 11)
+#define pin_A12 (GPIOA_BASE | 12)
+#define pin_A13 (GPIOA_BASE | 13)
+#define pin_A14 (GPIOA_BASE | 14)
+#define pin_A15 (GPIOA_BASE | 15)
+
+#define pin_B0 (GPIOB_BASE | 0)
+#define pin_B1 (GPIOB_BASE | 1)
+#define pin_B2 (GPIOB_BASE | 2)
+#define pin_B3 (GPIOB_BASE | 3)
+#define pin_B4 (GPIOB_BASE | 4)
+#define pin_B5 (GPIOB_BASE | 5)
+#define pin_B6 (GPIOB_BASE | 6)
+#define pin_B7 (GPIOB_BASE | 7)
+#define pin_B8 (GPIOB_BASE | 8)
+#define pin_B9 (GPIOB_BASE | 9)
+#define pin_B10 (GPIOB_BASE | 10)
+#define pin_B11 (GPIOB_BASE | 11)
+#define pin_B12 (GPIOB_BASE | 12)
+#define pin_B13 (GPIOB_BASE | 13)
+#define pin_B14 (GPIOB_BASE | 14)
+#define pin_B15 (GPIOB_BASE | 15)
+
+#define pin_C0 (GPIOC_BASE | 0)
+#define pin_C1 (GPIOC_BASE | 1)
+#define pin_C2 (GPIOC_BASE | 2)
+#define pin_C3 (GPIOC_BASE | 3)
+#define pin_C4 (GPIOC_BASE | 4)
+#define pin_C5 (GPIOC_BASE | 5)
+#define pin_C6 (GPIOC_BASE | 6)
+#define pin_C7 (GPIOC_BASE | 7)
+#define pin_C8 (GPIOC_BASE | 8)
+#define pin_C9 (GPIOC_BASE | 9)
+#define pin_C10 (GPIOC_BASE | 10)
+#define pin_C11 (GPIOC_BASE | 11)
+#define pin_C12 (GPIOC_BASE | 12)
+#define pin_C13 (GPIOC_BASE | 13)
+#define pin_C14 (GPIOC_BASE | 14)
+#define pin_C15 (GPIOC_BASE | 15)
+
+#define pin_D0 (GPIOD_BASE | 0)
+#define pin_D1 (GPIOD_BASE | 1)
+#define pin_D2 (GPIOD_BASE | 2)
+#define pin_D3 (GPIOD_BASE | 3)
+#define pin_D4 (GPIOD_BASE | 4)
+#define pin_D5 (GPIOD_BASE | 5)
+#define pin_D6 (GPIOD_BASE | 6)
+#define pin_D7 (GPIOD_BASE | 7)
+#define pin_D8 (GPIOD_BASE | 8)
+#define pin_D9 (GPIOD_BASE | 9)
+#define pin_D10 (GPIOD_BASE | 10)
+#define pin_D11 (GPIOD_BASE | 11)
+#define pin_D12 (GPIOD_BASE | 12)
+#define pin_D13 (GPIOD_BASE | 13)
+#define pin_D14 (GPIOD_BASE | 14)
+#define pin_D15 (GPIOD_BASE | 15)
+
+#define pin_E0 (GPIOE_BASE | 0)
+#define pin_E1 (GPIOE_BASE | 1)
+#define pin_E2 (GPIOE_BASE | 2)
+#define pin_E3 (GPIOE_BASE | 3)
+#define pin_E4 (GPIOE_BASE | 4)
+#define pin_E5 (GPIOE_BASE | 5)
+#define pin_E6 (GPIOE_BASE | 6)
+#define pin_E7 (GPIOE_BASE | 7)
+#define pin_E8 (GPIOE_BASE | 8)
+#define pin_E9 (GPIOE_BASE | 9)
+#define pin_E10 (GPIOE_BASE | 10)
+#define pin_E11 (GPIOE_BASE | 11)
+#define pin_E12 (GPIOE_BASE | 12)
+#define pin_E13 (GPIOE_BASE | 13)
+#define pin_E14 (GPIOE_BASE | 14)
+#define pin_E15 (GPIOE_BASE | 15)
+
+#define pin_F0 (GPIOF_BASE | 0)
+#define pin_F1 (GPIOF_BASE | 1)
+#define pin_F2 (GPIOF_BASE | 2)
+#define pin_F3 (GPIOF_BASE | 3)
+#define pin_F4 (GPIOF_BASE | 4)
+#define pin_F5 (GPIOF_BASE | 5)
+#define pin_F6 (GPIOF_BASE | 6)
+#define pin_F7 (GPIOF_BASE | 7)
+#define pin_F8 (GPIOF_BASE | 8)
+#define pin_F9 (GPIOF_BASE | 9)
+#define pin_F10 (GPIOF_BASE | 10)
+#define pin_F11 (GPIOF_BASE | 11)
+#define pin_F12 (GPIOF_BASE | 12)
+#define pin_F13 (GPIOF_BASE | 13)
+#define pin_F14 (GPIOF_BASE | 14)
+#define pin_F15 (GPIOF_BASE | 15)
diff --git a/ports/stm32/mboot/stm32_generic.ld b/ports/stm32/mboot/stm32_generic.ld
new file mode 100644
index 000000000..8585c6873
--- /dev/null
+++ b/ports/stm32/mboot/stm32_generic.ld
@@ -0,0 +1,77 @@
+/*
+ GNU linker script for generic STM32xxx MCU
+*/
+
+/* Specify the memory areas */
+MEMORY
+{
+ FLASH_BL (rx) : ORIGIN = 0x08000000, LENGTH = 16K /* sector 0 (can be 32K) */
+ RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 32K
+}
+
+/* produce a link error if there is not this amount of RAM for these sections */
+_minimum_stack_size = 2K;
+
+/* Define tho top end of the stack. The stack is full descending so begins just
+ above last byte of RAM. Note that EABI requires the stack to be 8-byte
+ aligned for a call. */
+_estack = ORIGIN(RAM) + LENGTH(RAM);
+
+ENTRY(Reset_Handler)
+
+SECTIONS
+{
+ /* The startup code goes first into FLASH */
+ .isr_vector :
+ {
+ . = ALIGN(4);
+ KEEP(*(.isr_vector)) /* Startup code */
+ . = ALIGN(4);
+ } >FLASH_BL
+
+ /* The program code and other data goes into FLASH */
+ .text :
+ {
+ . = ALIGN(4);
+ *(.text*)
+ *(.rodata*)
+ . = ALIGN(4);
+ _etext = .;
+ } >FLASH_BL
+
+ /* used by the startup to initialize data */
+ _sidata = LOADADDR(.data);
+
+ /* Initialized data section */
+ .data :
+ {
+ . = ALIGN(4);
+ _sdata = .;
+ *(.data*)
+
+ . = ALIGN(4);
+ _edata = .;
+ } >RAM AT> FLASH_BL
+
+ /* Uninitialized data section */
+ .bss :
+ {
+ . = ALIGN(4);
+ _sbss = .;
+ *(.bss*)
+ *(COMMON)
+
+ . = ALIGN(4);
+ _ebss = .;
+ } >RAM
+
+ /* this just checks there is enough RAM for the stack */
+ .stack :
+ {
+ . = ALIGN(4);
+ . = . + _minimum_stack_size;
+ . = ALIGN(4);
+ } >RAM
+
+ .ARM.attributes 0 : { *(.ARM.attributes) }
+}
diff --git a/ports/stm32/modmachine.c b/ports/stm32/modmachine.c
index 8c59758fa..158f5f2b3 100644
--- a/ports/stm32/modmachine.c
+++ b/ports/stm32/modmachine.c
@@ -54,11 +54,29 @@
#include "wdt.h"
#include "genhdr/pllfreqtable.h"
-#if defined(MCU_SERIES_L4)
+#if defined(STM32L4)
// L4 does not have a POR, so use BOR instead
#define RCC_CSR_PORRSTF RCC_CSR_BORRSTF
#endif
+#if defined(STM32H7)
+#define RCC_SR RSR
+#define RCC_SR_IWDGRSTF RCC_RSR_IWDG1RSTF
+#define RCC_SR_WWDGRSTF RCC_RSR_WWDG1RSTF
+#define RCC_SR_PORRSTF RCC_RSR_PORRSTF
+#define RCC_SR_BORRSTF RCC_RSR_BORRSTF
+#define RCC_SR_PINRSTF RCC_RSR_PINRSTF
+#define RCC_SR_RMVF RCC_RSR_RMVF
+#else
+#define RCC_SR CSR
+#define RCC_SR_IWDGRSTF RCC_CSR_IWDGRSTF
+#define RCC_SR_WWDGRSTF RCC_CSR_WWDGRSTF
+#define RCC_SR_PORRSTF RCC_CSR_PORRSTF
+#define RCC_SR_BORRSTF RCC_CSR_BORRSTF
+#define RCC_SR_PINRSTF RCC_CSR_PINRSTF
+#define RCC_SR_RMVF RCC_CSR_RMVF
+#endif
+
#define PYB_RESET_SOFT (0)
#define PYB_RESET_POWER_ON (1)
#define PYB_RESET_HARD (2)
@@ -68,27 +86,37 @@
STATIC uint32_t reset_cause;
void machine_init(void) {
- #if defined(MCU_SERIES_F4)
+ #if defined(STM32F4)
if (PWR->CSR & PWR_CSR_SBF) {
// came out of standby
reset_cause = PYB_RESET_DEEPSLEEP;
PWR->CR |= PWR_CR_CSBF;
} else
- #elif defined(MCU_SERIES_F7)
+ #elif defined(STM32F7)
if (PWR->CSR1 & PWR_CSR1_SBF) {
// came out of standby
reset_cause = PYB_RESET_DEEPSLEEP;
PWR->CR1 |= PWR_CR1_CSBF;
} else
+ #elif defined(STM32H7)
+ if (PWR->CPUCR & PWR_CPUCR_SBF || PWR->CPUCR & PWR_CPUCR_STOPF) {
+ // came out of standby or stop mode
+ reset_cause = PYB_RESET_DEEPSLEEP;
+ PWR->CPUCR |= PWR_CPUCR_CSSF;
+ } else
#endif
{
// get reset cause from RCC flags
- uint32_t state = RCC->CSR;
- if (state & RCC_CSR_IWDGRSTF || state & RCC_CSR_WWDGRSTF) {
+ uint32_t state = RCC->RCC_SR;
+ if (state & RCC_SR_IWDGRSTF || state & RCC_SR_WWDGRSTF) {
reset_cause = PYB_RESET_WDT;
- } else if (state & RCC_CSR_PORRSTF || state & RCC_CSR_BORRSTF) {
+ } else if (state & RCC_SR_PORRSTF
+ #if !defined(STM32F0)
+ || state & RCC_SR_BORRSTF
+ #endif
+ ) {
reset_cause = PYB_RESET_POWER_ON;
- } else if (state & RCC_CSR_PINRSTF) {
+ } else if (state & RCC_SR_PINRSTF) {
reset_cause = PYB_RESET_HARD;
} else {
// default is soft reset
@@ -96,7 +124,12 @@ void machine_init(void) {
}
}
// clear RCC reset flags
- RCC->CSR |= RCC_CSR_RMVF;
+ RCC->RCC_SR |= RCC_SR_RMVF;
+}
+
+void machine_deinit(void) {
+ // we are doing a soft-reset so change the reset_cause
+ reset_cause = PYB_RESET_SOFT;
}
// machine.info([dump_alloc_table])
@@ -111,11 +144,18 @@ STATIC mp_obj_t machine_info(size_t n_args, const mp_obj_t *args) {
// get and print clock speeds
// SYSCLK=168MHz, HCLK=168MHz, PCLK1=42MHz, PCLK2=84MHz
{
- printf("S=%lu\nH=%lu\nP1=%lu\nP2=%lu\n",
- HAL_RCC_GetSysClockFreq(),
- HAL_RCC_GetHCLKFreq(),
- HAL_RCC_GetPCLK1Freq(),
- HAL_RCC_GetPCLK2Freq());
+ #if defined(STM32F0)
+ printf("S=%u\nH=%u\nP1=%u\n",
+ (unsigned int)HAL_RCC_GetSysClockFreq(),
+ (unsigned int)HAL_RCC_GetHCLKFreq(),
+ (unsigned int)HAL_RCC_GetPCLK1Freq());
+ #else
+ printf("S=%u\nH=%u\nP1=%u\nP2=%u\n",
+ (unsigned int)HAL_RCC_GetSysClockFreq(),
+ (unsigned int)HAL_RCC_GetHCLKFreq(),
+ (unsigned int)HAL_RCC_GetPCLK1Freq(),
+ (unsigned int)HAL_RCC_GetPCLK2Freq());
+ #endif
}
// to print info about memory
@@ -152,6 +192,7 @@ STATIC mp_obj_t machine_info(size_t n_args, const mp_obj_t *args) {
// free space on flash
{
+ #if MICROPY_VFS_FAT
for (mp_vfs_mount_t *vfs = MP_STATE_VM(vfs_mount_table); vfs != NULL; vfs = vfs->next) {
if (strncmp("/flash", vfs->str, vfs->len) == 0) {
// assumes that it's a FatFs filesystem
@@ -162,6 +203,7 @@ STATIC mp_obj_t machine_info(size_t n_args, const mp_obj_t *args) {
break;
}
}
+ #endif
}
#if MICROPY_PY_THREAD
@@ -199,8 +241,12 @@ MP_DEFINE_CONST_FUN_OBJ_0(machine_soft_reset_obj, machine_soft_reset);
// Activate the bootloader without BOOT* pins.
STATIC NORETURN mp_obj_t machine_bootloader(void) {
+ #if MICROPY_HW_ENABLE_USB
pyb_usb_dev_deinit();
+ #endif
+ #if MICROPY_HW_ENABLE_STORAGE
storage_flush();
+ #endif
HAL_RCC_DeInit();
HAL_DeInit();
@@ -210,7 +256,7 @@ STATIC NORETURN mp_obj_t machine_bootloader(void) {
HAL_MPU_Disable();
#endif
-#if defined(MCU_SERIES_F7)
+#if defined(STM32F7) || defined(STM32H7)
// arm-none-eabi-gcc 4.9.0 does not correctly inline this
// MSP function, so we write it out explicitly here.
//__set_MSP(*((uint32_t*) 0x1FF00000));
@@ -218,7 +264,7 @@ STATIC NORETURN mp_obj_t machine_bootloader(void) {
((void (*)(void)) *((uint32_t*) 0x1FF00004))();
#else
- __HAL_REMAPMEMORY_SYSTEMFLASH();
+ __HAL_SYSCFG_REMAPMEMORY_SYSTEMFLASH();
// arm-none-eabi-gcc 4.9.0 does not correctly inline this
// MSP function, so we write it out explicitly here.
@@ -232,6 +278,7 @@ STATIC NORETURN mp_obj_t machine_bootloader(void) {
}
MP_DEFINE_CONST_FUN_OBJ_0(machine_bootloader_obj, machine_bootloader);
+#if !(defined(STM32F0) || defined(STM32L4))
// get or set the MCU frequencies
STATIC mp_uint_t machine_freq_calc_ahb_div(mp_uint_t wanted_div) {
if (wanted_div <= 1) { return RCC_SYSCLK_DIV1; }
@@ -251,23 +298,28 @@ STATIC mp_uint_t machine_freq_calc_apb_div(mp_uint_t wanted_div) {
else if (wanted_div <= 8) { return RCC_HCLK_DIV8; }
else { return RCC_SYSCLK_DIV16; }
}
+#endif
+
STATIC mp_obj_t machine_freq(size_t n_args, const mp_obj_t *args) {
if (n_args == 0) {
// get
- mp_obj_t tuple[4] = {
+ mp_obj_t tuple[] = {
mp_obj_new_int(HAL_RCC_GetSysClockFreq()),
mp_obj_new_int(HAL_RCC_GetHCLKFreq()),
mp_obj_new_int(HAL_RCC_GetPCLK1Freq()),
+ #if !defined(STM32F0)
mp_obj_new_int(HAL_RCC_GetPCLK2Freq()),
+ #endif
};
- return mp_obj_new_tuple(4, tuple);
+ return mp_obj_new_tuple(MP_ARRAY_SIZE(tuple), tuple);
} else {
// set
- mp_int_t wanted_sysclk = mp_obj_get_int(args[0]) / 1000000;
- #if defined(MCU_SERIES_L4)
+ #if defined(STM32F0) || defined(STM32L4)
mp_raise_NotImplementedError("machine.freq set not supported yet");
- #endif
+ #else
+
+ mp_int_t wanted_sysclk = mp_obj_get_int(args[0]) / 1000000;
// default PLL parameters that give 48MHz on PLL48CK
uint32_t m = HSE_VALUE / 1000000, n = 336, p = 2, q = 7;
@@ -346,7 +398,7 @@ STATIC mp_obj_t machine_freq(size_t n_args, const mp_obj_t *args) {
// even if we don't use the PLL for the system clock, we still need it for USB, RNG and SDIO
RCC_OscInitTypeDef RCC_OscInitStruct;
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
- RCC_OscInitStruct.HSEState = RCC_HSE_ON;
+ RCC_OscInitStruct.HSEState = MICROPY_HW_CLK_HSE_STATE;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = m;
@@ -359,33 +411,50 @@ STATIC mp_obj_t machine_freq(size_t n_args, const mp_obj_t *args) {
// set PLL as system clock source if wanted
if (sysclk_source == RCC_SYSCLKSOURCE_PLLCLK) {
- #if defined(MCU_SERIES_F7)
+ uint32_t flash_latency;
+ #if defined(STM32F7)
// if possible, scale down the internal voltage regulator to save power
+ // the flash_latency values assume a supply voltage between 2.7V and 3.6V
uint32_t volt_scale;
- if (wanted_sysclk <= 151000000) {
+ if (wanted_sysclk <= 90000000) {
volt_scale = PWR_REGULATOR_VOLTAGE_SCALE3;
+ flash_latency = FLASH_LATENCY_2;
+ } else if (wanted_sysclk <= 120000000) {
+ volt_scale = PWR_REGULATOR_VOLTAGE_SCALE3;
+ flash_latency = FLASH_LATENCY_3;
+ } else if (wanted_sysclk <= 144000000) {
+ volt_scale = PWR_REGULATOR_VOLTAGE_SCALE3;
+ flash_latency = FLASH_LATENCY_4;
} else if (wanted_sysclk <= 180000000) {
volt_scale = PWR_REGULATOR_VOLTAGE_SCALE2;
+ flash_latency = FLASH_LATENCY_5;
+ } else if (wanted_sysclk <= 210000000) {
+ volt_scale = PWR_REGULATOR_VOLTAGE_SCALE1;
+ flash_latency = FLASH_LATENCY_6;
} else {
volt_scale = PWR_REGULATOR_VOLTAGE_SCALE1;
+ flash_latency = FLASH_LATENCY_7;
}
if (HAL_PWREx_ControlVoltageScaling(volt_scale) != HAL_OK) {
goto fail;
}
#endif
+ #if !defined(STM32F7)
#if !defined(MICROPY_HW_FLASH_LATENCY)
#define MICROPY_HW_FLASH_LATENCY FLASH_LATENCY_5
#endif
+ flash_latency = MICROPY_HW_FLASH_LATENCY;
+ #endif
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
- if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, MICROPY_HW_FLASH_LATENCY) != HAL_OK) {
+ if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, flash_latency) != HAL_OK) {
goto fail;
}
}
#if defined(MICROPY_HW_CLK_LAST_FREQ) && MICROPY_HW_CLK_LAST_FREQ
- #if defined(MCU_SERIES_F7)
+ #if defined(STM32F7)
#define FREQ_BKP BKP31R
#else
#define FREQ_BKP BKP19R
@@ -406,12 +475,14 @@ STATIC mp_obj_t machine_freq(size_t n_args, const mp_obj_t *args) {
fail:;
void NORETURN __fatal_error(const char *msg);
__fatal_error("can't change freq");
+
+ #endif
}
}
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_freq_obj, 0, 4, machine_freq);
STATIC mp_obj_t machine_sleep(void) {
- #if defined(MCU_SERIES_L4)
+ #if defined(STM32L4)
// Enter Stop 1 mode
__HAL_RCC_WAKEUPSTOP_CLK_CONFIG(RCC_STOP_WAKEUPCLOCK_MSI);
@@ -440,10 +511,12 @@ STATIC mp_obj_t machine_sleep(void) {
#else
+ #if !defined(STM32F0)
// takes longer to wake but reduces stop current
HAL_PWREx_EnableFlashPowerDown();
+ #endif
- # if defined(MCU_SERIES_F7)
+ # if defined(STM32F7)
HAL_PWR_EnterSTOPMode((PWR_CR1_LPDS | PWR_CR1_LPUDS | PWR_CR1_FPDS | PWR_CR1_UDEN), PWR_STOPENTRY_WFI);
# else
HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI);
@@ -452,7 +525,7 @@ STATIC mp_obj_t machine_sleep(void) {
// reconfigure the system clock after waking up
// enable HSE
- __HAL_RCC_HSE_CONFIG(RCC_HSE_ON);
+ __HAL_RCC_HSE_CONFIG(MICROPY_HW_CLK_HSE_STATE);
while (!__HAL_RCC_GET_FLAG(RCC_FLAG_HSERDY)) {
}
@@ -463,7 +536,11 @@ STATIC mp_obj_t machine_sleep(void) {
// select PLL as system clock source
MODIFY_REG(RCC->CFGR, RCC_CFGR_SW, RCC_SYSCLKSOURCE_PLLCLK);
+ #if defined(STM32H7)
+ while (__HAL_RCC_GET_SYSCLK_SOURCE() != RCC_CFGR_SWS_PLL1) {
+ #else
while (__HAL_RCC_GET_SYSCLK_SOURCE() != RCC_CFGR_SWS_PLL) {
+ #endif
}
#endif
@@ -475,7 +552,7 @@ MP_DEFINE_CONST_FUN_OBJ_0(machine_sleep_obj, machine_sleep);
STATIC mp_obj_t machine_deepsleep(void) {
rtc_init_finalise();
-#if defined(MCU_SERIES_L4)
+#if defined(STM32L4)
printf("machine.deepsleep not supported yet\n");
#else
// We need to clear the PWR wake-up-flag before entering standby, since
@@ -486,22 +563,30 @@ STATIC mp_obj_t machine_deepsleep(void) {
// Note: we only support RTC ALRA, ALRB, WUT and TS.
// TODO support TAMP and WKUP (PA0 external pin).
- uint32_t irq_bits = RTC_CR_ALRAIE | RTC_CR_ALRBIE | RTC_CR_WUTIE | RTC_CR_TSIE;
+ #if defined(STM32F0)
+ #define CR_BITS (RTC_CR_ALRAIE | RTC_CR_WUTIE | RTC_CR_TSIE)
+ #define ISR_BITS (RTC_ISR_ALRAF | RTC_ISR_WUTF | RTC_ISR_TSF)
+ #else
+ #define CR_BITS (RTC_CR_ALRAIE | RTC_CR_ALRBIE | RTC_CR_WUTIE | RTC_CR_TSIE)
+ #define ISR_BITS (RTC_ISR_ALRAF | RTC_ISR_ALRBF | RTC_ISR_WUTF | RTC_ISR_TSF)
+ #endif
// save RTC interrupts
- uint32_t save_irq_bits = RTC->CR & irq_bits;
+ uint32_t save_irq_bits = RTC->CR & CR_BITS;
// disable RTC interrupts
- RTC->CR &= ~irq_bits;
+ RTC->CR &= ~CR_BITS;
// clear RTC wake-up flags
- RTC->ISR &= ~(RTC_ISR_ALRAF | RTC_ISR_ALRBF | RTC_ISR_WUTF | RTC_ISR_TSF);
+ RTC->ISR &= ~ISR_BITS;
- #if defined(MCU_SERIES_F7)
+ #if defined(STM32F7)
// disable wake-up flags
PWR->CSR2 &= ~(PWR_CSR2_EWUP6 | PWR_CSR2_EWUP5 | PWR_CSR2_EWUP4 | PWR_CSR2_EWUP3 | PWR_CSR2_EWUP2 | PWR_CSR2_EWUP1);
// clear global wake-up flag
PWR->CR2 |= PWR_CR2_CWUPF6 | PWR_CR2_CWUPF5 | PWR_CR2_CWUPF4 | PWR_CR2_CWUPF3 | PWR_CR2_CWUPF2 | PWR_CR2_CWUPF1;
+ #elif defined(STM32H7)
+ // TODO
#else
// clear global wake-up flag
PWR->CR |= PWR_CR_CWUF;
@@ -558,7 +643,9 @@ STATIC const mp_rom_map_elem_t machine_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR_RTC), MP_ROM_PTR(&pyb_rtc_type) },
{ MP_ROM_QSTR(MP_QSTR_ADC), MP_ROM_PTR(&pyb_adc_type) },
#endif
+#if MICROPY_PY_MACHINE_I2C
{ MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&machine_i2c_type) },
+#endif
{ MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&machine_hard_spi_type) },
{ MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&pyb_uart_type) },
{ MP_ROM_QSTR(MP_QSTR_WDT), MP_ROM_PTR(&pyb_wdt_type) },
diff --git a/ports/stm32/modmachine.h b/ports/stm32/modmachine.h
index 77668695f..88fe23692 100644
--- a/ports/stm32/modmachine.h
+++ b/ports/stm32/modmachine.h
@@ -23,12 +23,13 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
-#ifndef MICROPY_INCLUDED_STMHAL_MODMACHINE_H
-#define MICROPY_INCLUDED_STMHAL_MODMACHINE_H
+#ifndef MICROPY_INCLUDED_STM32_MODMACHINE_H
+#define MICROPY_INCLUDED_STM32_MODMACHINE_H
#include "py/obj.h"
void machine_init(void);
+void machine_deinit(void);
MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(machine_info_obj);
MP_DECLARE_CONST_FUN_OBJ_0(machine_unique_id_obj);
@@ -38,4 +39,4 @@ MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(machine_freq_obj);
MP_DECLARE_CONST_FUN_OBJ_0(machine_sleep_obj);
MP_DECLARE_CONST_FUN_OBJ_0(machine_deepsleep_obj);
-#endif // MICROPY_INCLUDED_STMHAL_MODMACHINE_H
+#endif // MICROPY_INCLUDED_STM32_MODMACHINE_H
diff --git a/ports/stm32/modnetwork.c b/ports/stm32/modnetwork.c
index 642174532..cf7ecbf3c 100644
--- a/ports/stm32/modnetwork.c
+++ b/ports/stm32/modnetwork.c
@@ -30,10 +30,37 @@
#include "py/objlist.h"
#include "py/runtime.h"
+#include "py/mphal.h"
+#include "lib/netutils/netutils.h"
#include "modnetwork.h"
#if MICROPY_PY_NETWORK
+#if MICROPY_PY_LWIP
+
+#include "lwip/netif.h"
+#include "lwip/timeouts.h"
+#include "lwip/dns.h"
+#include "lwip/dhcp.h"
+
+u32_t sys_now(void) {
+ return mp_hal_ticks_ms();
+}
+
+void pyb_lwip_poll(void) {
+ // Poll all the NICs for incoming data
+ for (struct netif *netif = netif_list; netif != NULL; netif = netif->next) {
+ if (netif->flags & NETIF_FLAG_LINK_UP) {
+ mod_network_nic_type_t *nic = netif->state;
+ nic->poll_callback(nic, netif);
+ }
+ }
+ // Run the lwIP internal updates
+ sys_check_timeouts();
+}
+
+#endif
+
/// \module network - network configuration
///
/// This module provides network drivers and routing configuration.
@@ -42,6 +69,9 @@ void mod_network_init(void) {
mp_obj_list_init(&MP_STATE_PORT(mod_network_nic_list), 0);
}
+void mod_network_deinit(void) {
+}
+
void mod_network_register_nic(mp_obj_t nic) {
for (mp_uint_t i = 0; i < MP_STATE_PORT(mod_network_nic_list).len; i++) {
if (MP_STATE_PORT(mod_network_nic_list).items[i] == nic) {
@@ -90,4 +120,58 @@ const mp_obj_module_t mp_module_network = {
.globals = (mp_obj_dict_t*)&mp_module_network_globals,
};
+/*******************************************************************************/
+// Implementations of network methods that can be used by any interface
+
+#if MICROPY_PY_LWIP
+
+mp_obj_t mod_network_nic_ifconfig(struct netif *netif, size_t n_args, const mp_obj_t *args) {
+ if (n_args == 0) {
+ // Get IP addresses
+ const ip_addr_t *dns = dns_getserver(0);
+ mp_obj_t tuple[4] = {
+ netutils_format_ipv4_addr((uint8_t*)&netif->ip_addr, NETUTILS_BIG),
+ netutils_format_ipv4_addr((uint8_t*)&netif->netmask, NETUTILS_BIG),
+ netutils_format_ipv4_addr((uint8_t*)&netif->gw, NETUTILS_BIG),
+ netutils_format_ipv4_addr((uint8_t*)&dns, NETUTILS_BIG),
+ };
+ return mp_obj_new_tuple(4, tuple);
+ } else if (args[0] == MP_OBJ_NEW_QSTR(MP_QSTR_dhcp)) {
+ // Start the DHCP client
+ if (dhcp_supplied_address(netif)) {
+ dhcp_renew(netif);
+ } else {
+ dhcp_stop(netif);
+ dhcp_start(netif);
+ }
+
+ // Wait for DHCP to get IP address
+ uint32_t start = mp_hal_ticks_ms();
+ while (!dhcp_supplied_address(netif)) {
+ if (mp_hal_ticks_ms() - start > 10000) {
+ mp_raise_msg(&mp_type_OSError, "timeout waiting for DHCP to get IP address");
+ }
+ mp_hal_delay_ms(100);
+ }
+
+ return mp_const_none;
+ } else {
+ // Release and stop any existing DHCP
+ dhcp_release(netif);
+ dhcp_stop(netif);
+ // Set static IP addresses
+ mp_obj_t *items;
+ mp_obj_get_array_fixed_n(args[0], 4, &items);
+ netutils_parse_ipv4_addr(items[0], (uint8_t*)&netif->ip_addr, NETUTILS_BIG);
+ netutils_parse_ipv4_addr(items[1], (uint8_t*)&netif->netmask, NETUTILS_BIG);
+ netutils_parse_ipv4_addr(items[2], (uint8_t*)&netif->gw, NETUTILS_BIG);
+ ip_addr_t dns;
+ netutils_parse_ipv4_addr(items[3], (uint8_t*)&dns, NETUTILS_BIG);
+ dns_setserver(0, &dns);
+ return mp_const_none;
+ }
+}
+
+#endif
+
#endif // MICROPY_PY_NETWORK
diff --git a/ports/stm32/modnetwork.h b/ports/stm32/modnetwork.h
index ecda94da4..f45e00fbc 100644
--- a/ports/stm32/modnetwork.h
+++ b/ports/stm32/modnetwork.h
@@ -23,8 +23,8 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
-#ifndef MICROPY_INCLUDED_STMHAL_MODNETWORK_H
-#define MICROPY_INCLUDED_STMHAL_MODNETWORK_H
+#ifndef MICROPY_INCLUDED_STM32_MODNETWORK_H
+#define MICROPY_INCLUDED_STM32_MODNETWORK_H
#define MOD_NETWORK_IPADDR_BUF_SIZE (4)
@@ -35,6 +35,21 @@
#define MOD_NETWORK_SOCK_DGRAM (2)
#define MOD_NETWORK_SOCK_RAW (3)
+#if MICROPY_PY_LWIP
+
+struct netif;
+
+typedef struct _mod_network_nic_type_t {
+ mp_obj_base_t base;
+ void (*poll_callback)(void *data, struct netif *netif);
+} mod_network_nic_type_t;
+
+extern const mp_obj_type_t mod_network_nic_type_wiznet5k;
+
+mp_obj_t mod_network_nic_ifconfig(struct netif *netif, size_t n_args, const mp_obj_t *args);
+
+#else
+
struct _mod_network_socket_obj_t;
typedef struct _mod_network_nic_type_t {
@@ -76,8 +91,11 @@ typedef struct _mod_network_socket_obj_t {
extern const mod_network_nic_type_t mod_network_nic_type_wiznet5k;
extern const mod_network_nic_type_t mod_network_nic_type_cc3k;
+#endif
+
void mod_network_init(void);
+void mod_network_deinit(void);
void mod_network_register_nic(mp_obj_t nic);
mp_obj_t mod_network_find_nic(const uint8_t *ip);
-#endif // MICROPY_INCLUDED_STMHAL_MODNETWORK_H
+#endif // MICROPY_INCLUDED_STM32_MODNETWORK_H
diff --git a/ports/stm32/modnwcc3k.c b/ports/stm32/modnwcc3k.c
index 8cc0a613d..8723994f4 100644
--- a/ports/stm32/modnwcc3k.c
+++ b/ports/stm32/modnwcc3k.c
@@ -39,7 +39,6 @@
#include "lib/netutils/netutils.h"
#include "modnetwork.h"
#include "pin.h"
-#include "genhdr/pins.h"
#include "spi.h"
#include "hci.h"
@@ -433,7 +432,7 @@ STATIC mp_obj_t cc3k_make_new(const mp_obj_type_t *type, size_t n_args, size_t n
// set the pins to use
SpiInit(
- spi_get_handle(args[0]),
+ spi_from_mp_obj(args[0])->spi,
pin_find(args[1]),
pin_find(args[2]),
pin_find(args[3])
@@ -531,8 +530,8 @@ STATIC mp_obj_t cc3k_ifconfig(mp_obj_t self_in) {
netutils_format_ipv4_addr(ipconfig.aucDefaultGateway, NETUTILS_LITTLE),
netutils_format_ipv4_addr(ipconfig.aucDNSServer, NETUTILS_LITTLE),
netutils_format_ipv4_addr(ipconfig.aucDHCPServer, NETUTILS_LITTLE),
- mp_obj_new_str(mac_vstr.buf, mac_vstr.len, false),
- mp_obj_new_str((const char*)ipconfig.uaSSID, strlen((const char*)ipconfig.uaSSID), false),
+ mp_obj_new_str(mac_vstr.buf, mac_vstr.len),
+ mp_obj_new_str((const char*)ipconfig.uaSSID, strlen((const char*)ipconfig.uaSSID)),
};
return mp_obj_new_tuple(MP_ARRAY_SIZE(tuple), tuple);
}
diff --git a/ports/stm32/modnwwiznet5k.c b/ports/stm32/modnwwiznet5k.c
index 763137c70..bf4b72ff2 100644
--- a/ports/stm32/modnwwiznet5k.c
+++ b/ports/stm32/modnwwiznet5k.c
@@ -36,9 +36,10 @@
#include "lib/netutils/netutils.h"
#include "modnetwork.h"
#include "pin.h"
-#include "genhdr/pins.h"
#include "spi.h"
+#if MICROPY_PY_WIZNET5K && !MICROPY_PY_LWIP
+
#include "ethernet/wizchip_conf.h"
#include "ethernet/socket.h"
#include "internet/dns/dns.h"
@@ -48,7 +49,7 @@
typedef struct _wiznet5k_obj_t {
mp_obj_base_t base;
mp_uint_t cris_state;
- SPI_HandleTypeDef *spi;
+ const spi_t *spi;
const pin_obj_t *cs;
const pin_obj_t *rst;
uint8_t socket_used;
@@ -73,12 +74,12 @@ STATIC void wiz_cs_deselect(void) {
}
STATIC void wiz_spi_read(uint8_t *buf, uint32_t len) {
- HAL_StatusTypeDef status = HAL_SPI_Receive(wiznet5k_obj.spi, buf, len, 5000);
+ HAL_StatusTypeDef status = HAL_SPI_Receive(wiznet5k_obj.spi->spi, buf, len, 5000);
(void)status;
}
STATIC void wiz_spi_write(const uint8_t *buf, uint32_t len) {
- HAL_StatusTypeDef status = HAL_SPI_Transmit(wiznet5k_obj.spi, (uint8_t*)buf, len, 5000);
+ HAL_StatusTypeDef status = HAL_SPI_Transmit(wiznet5k_obj.spi->spi, (uint8_t*)buf, len, 5000);
(void)status;
}
@@ -345,23 +346,24 @@ STATIC mp_obj_t wiznet5k_make_new(const mp_obj_type_t *type, size_t n_args, size
// init the wiznet5k object
wiznet5k_obj.base.type = (mp_obj_type_t*)&mod_network_nic_type_wiznet5k;
wiznet5k_obj.cris_state = 0;
- wiznet5k_obj.spi = spi_get_handle(args[0]);
+ wiznet5k_obj.spi = spi_from_mp_obj(args[0]);
wiznet5k_obj.cs = pin_find(args[1]);
wiznet5k_obj.rst = pin_find(args[2]);
wiznet5k_obj.socket_used = 0;
/*!< SPI configuration */
- wiznet5k_obj.spi->Init.Mode = SPI_MODE_MASTER;
- wiznet5k_obj.spi->Init.Direction = SPI_DIRECTION_2LINES;
- wiznet5k_obj.spi->Init.DataSize = SPI_DATASIZE_8BIT;
- wiznet5k_obj.spi->Init.CLKPolarity = SPI_POLARITY_LOW; // clock is low when idle
- wiznet5k_obj.spi->Init.CLKPhase = SPI_PHASE_1EDGE; // data latched on first edge, which is rising edge for low-idle
- wiznet5k_obj.spi->Init.NSS = SPI_NSS_SOFT;
- wiznet5k_obj.spi->Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2; // clock freq = f_PCLK / this_prescale_value; Wiz820i can do up to 80MHz
- wiznet5k_obj.spi->Init.FirstBit = SPI_FIRSTBIT_MSB;
- wiznet5k_obj.spi->Init.TIMode = SPI_TIMODE_DISABLED;
- wiznet5k_obj.spi->Init.CRCCalculation = SPI_CRCCALCULATION_DISABLED;
- wiznet5k_obj.spi->Init.CRCPolynomial = 7; // unused
+ SPI_InitTypeDef *init = &wiznet5k_obj.spi->spi->Init;
+ init->Mode = SPI_MODE_MASTER;
+ init->Direction = SPI_DIRECTION_2LINES;
+ init->DataSize = SPI_DATASIZE_8BIT;
+ init->CLKPolarity = SPI_POLARITY_LOW; // clock is low when idle
+ init->CLKPhase = SPI_PHASE_1EDGE; // data latched on first edge, which is rising edge for low-idle
+ init->NSS = SPI_NSS_SOFT;
+ init->BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2; // clock freq = f_PCLK / this_prescale_value; Wiz820i can do up to 80MHz
+ init->FirstBit = SPI_FIRSTBIT_MSB;
+ init->TIMode = SPI_TIMODE_DISABLED;
+ init->CRCCalculation = SPI_CRCCALCULATION_DISABLED;
+ init->CRCPolynomial = 7; // unused
spi_init(wiznet5k_obj.spi, false);
mp_hal_pin_output(wiznet5k_obj.cs);
@@ -499,3 +501,5 @@ const mod_network_nic_type_t mod_network_nic_type_wiznet5k = {
.settimeout = wiznet5k_socket_settimeout,
.ioctl = wiznet5k_socket_ioctl,
};
+
+#endif // MICROPY_PY_WIZNET5K && !MICROPY_PY_LWIP
diff --git a/ports/stm32/modpyb.c b/ports/stm32/modpyb.c
index 81cbdcc19..5afbbc484 100644
--- a/ports/stm32/modpyb.c
+++ b/ports/stm32/modpyb.c
@@ -28,18 +28,12 @@
#include <stdio.h>
#include "py/runtime.h"
-#include "py/gc.h"
-#include "py/builtin.h"
#include "py/mphal.h"
#include "lib/utils/pyexec.h"
-#include "lib/oofatfs/ff.h"
-#include "lib/oofatfs/diskio.h"
-#include "gccollect.h"
+#include "drivers/dht/dht.h"
#include "stm32_it.h"
#include "irq.h"
-#include "systick.h"
#include "led.h"
-#include "pin.h"
#include "timer.h"
#include "extint.h"
#include "usrsw.h"
@@ -68,16 +62,10 @@ STATIC mp_obj_t pyb_fault_debug(mp_obj_t value) {
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_fault_debug_obj, pyb_fault_debug);
-/// \function elapsed_millis(start)
-/// Returns the number of milliseconds which have elapsed since `start`.
-///
-/// This function takes care of counter wrap, and always returns a positive
-/// number. This means it can be used to measure periods upto about 12.4 days.
-///
-/// Example:
-/// start = pyb.millis()
-/// while pyb.elapsed_millis(start) < 1000:
-/// # Perform some operation
+#if MICROPY_PY_PYB_LEGACY
+
+// Returns the number of milliseconds which have elapsed since `start`.
+// This function takes care of counter wrap and always returns a positive number.
STATIC mp_obj_t pyb_elapsed_millis(mp_obj_t start) {
uint32_t startMillis = mp_obj_get_int(start);
uint32_t currMillis = mp_hal_ticks_ms();
@@ -85,16 +73,8 @@ STATIC mp_obj_t pyb_elapsed_millis(mp_obj_t start) {
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_elapsed_millis_obj, pyb_elapsed_millis);
-/// \function elapsed_micros(start)
-/// Returns the number of microseconds which have elapsed since `start`.
-///
-/// This function takes care of counter wrap, and always returns a positive
-/// number. This means it can be used to measure periods upto about 17.8 minutes.
-///
-/// Example:
-/// start = pyb.micros()
-/// while pyb.elapsed_micros(start) < 1000:
-/// # Perform some operation
+// Returns the number of microseconds which have elapsed since `start`.
+// This function takes care of counter wrap and always returns a positive number.
STATIC mp_obj_t pyb_elapsed_micros(mp_obj_t start) {
uint32_t startMicros = mp_obj_get_int(start);
uint32_t currMicros = mp_hal_ticks_us();
@@ -102,6 +82,8 @@ STATIC mp_obj_t pyb_elapsed_micros(mp_obj_t start) {
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_elapsed_micros_obj, pyb_elapsed_micros);
+#endif
+
MP_DECLARE_CONST_FUN_OBJ_KW(pyb_main_obj); // defined in main.c
// Get or set the UART object that the REPL is repeated on.
@@ -115,9 +97,13 @@ STATIC mp_obj_t pyb_repl_uart(size_t n_args, const mp_obj_t *args) {
}
} else {
if (args[0] == mp_const_none) {
- MP_STATE_PORT(pyb_stdio_uart) = NULL;
+ if (MP_STATE_PORT(pyb_stdio_uart) != NULL) {
+ uart_attach_to_repl(MP_STATE_PORT(pyb_stdio_uart), false);
+ MP_STATE_PORT(pyb_stdio_uart) = NULL;
+ }
} else if (mp_obj_get_type(args[0]) == &pyb_uart_type) {
MP_STATE_PORT(pyb_stdio_uart) = args[0];
+ uart_attach_to_repl(MP_STATE_PORT(pyb_stdio_uart), true);
} else {
mp_raise_ValueError("need a UART object");
}
@@ -131,11 +117,13 @@ STATIC const mp_rom_map_elem_t pyb_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR_fault_debug), MP_ROM_PTR(&pyb_fault_debug_obj) },
+ #if MICROPY_PY_PYB_LEGACY
{ MP_ROM_QSTR(MP_QSTR_bootloader), MP_ROM_PTR(&machine_bootloader_obj) },
{ MP_ROM_QSTR(MP_QSTR_hard_reset), MP_ROM_PTR(&machine_reset_obj) },
{ MP_ROM_QSTR(MP_QSTR_info), MP_ROM_PTR(&machine_info_obj) },
{ MP_ROM_QSTR(MP_QSTR_unique_id), MP_ROM_PTR(&machine_unique_id_obj) },
{ MP_ROM_QSTR(MP_QSTR_freq), MP_ROM_PTR(&machine_freq_obj) },
+ #endif
{ MP_ROM_QSTR(MP_QSTR_repl_info), MP_ROM_PTR(&pyb_set_repl_info_obj) },
{ MP_ROM_QSTR(MP_QSTR_wfi), MP_ROM_PTR(&pyb_wfi_obj) },
@@ -145,20 +133,27 @@ STATIC const mp_rom_map_elem_t pyb_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR_irq_stats), MP_ROM_PTR(&pyb_irq_stats_obj) },
#endif
+ #if MICROPY_PY_PYB_LEGACY
{ MP_ROM_QSTR(MP_QSTR_stop), MP_ROM_PTR(&machine_sleep_obj) },
{ MP_ROM_QSTR(MP_QSTR_standby), MP_ROM_PTR(&machine_deepsleep_obj) },
+ #endif
{ MP_ROM_QSTR(MP_QSTR_main), MP_ROM_PTR(&pyb_main_obj) },
{ MP_ROM_QSTR(MP_QSTR_repl_uart), MP_ROM_PTR(&pyb_repl_uart_obj) },
+ #if MICROPY_HW_ENABLE_USB
{ MP_ROM_QSTR(MP_QSTR_usb_mode), MP_ROM_PTR(&pyb_usb_mode_obj) },
{ MP_ROM_QSTR(MP_QSTR_hid_mouse), MP_ROM_PTR(&pyb_usb_hid_mouse_obj) },
{ MP_ROM_QSTR(MP_QSTR_hid_keyboard), MP_ROM_PTR(&pyb_usb_hid_keyboard_obj) },
{ MP_ROM_QSTR(MP_QSTR_USB_VCP), MP_ROM_PTR(&pyb_usb_vcp_type) },
{ MP_ROM_QSTR(MP_QSTR_USB_HID), MP_ROM_PTR(&pyb_usb_hid_type) },
+ #if MICROPY_PY_PYB_LEGACY
// these 2 are deprecated; use USB_VCP.isconnected and USB_HID.send instead
{ MP_ROM_QSTR(MP_QSTR_have_cdc), MP_ROM_PTR(&pyb_have_cdc_obj) },
{ MP_ROM_QSTR(MP_QSTR_hid), MP_ROM_PTR(&pyb_hid_send_report_obj) },
+ #endif
+ #endif
+ #if MICROPY_PY_PYB_LEGACY
{ MP_ROM_QSTR(MP_QSTR_millis), MP_ROM_PTR(&mp_utime_ticks_ms_obj) },
{ MP_ROM_QSTR(MP_QSTR_elapsed_millis), MP_ROM_PTR(&pyb_elapsed_millis_obj) },
{ MP_ROM_QSTR(MP_QSTR_micros), MP_ROM_PTR(&mp_utime_ticks_us_obj) },
@@ -167,6 +162,10 @@ STATIC const mp_rom_map_elem_t pyb_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR_udelay), MP_ROM_PTR(&mp_utime_sleep_us_obj) },
{ MP_ROM_QSTR(MP_QSTR_sync), MP_ROM_PTR(&mod_os_sync_obj) },
{ MP_ROM_QSTR(MP_QSTR_mount), MP_ROM_PTR(&mp_vfs_mount_obj) },
+ #endif
+
+ // This function is not intended to be public and may be moved elsewhere
+ { MP_ROM_QSTR(MP_QSTR_dht_readinto), MP_ROM_PTR(&dht_readinto_obj) },
{ MP_ROM_QSTR(MP_QSTR_Timer), MP_ROM_PTR(&pyb_timer_type) },
@@ -196,22 +195,28 @@ STATIC const mp_rom_map_elem_t pyb_module_globals_table[] = {
#endif
#if MICROPY_HW_HAS_SDCARD
+ #if MICROPY_PY_PYB_LEGACY
{ MP_ROM_QSTR(MP_QSTR_SD), MP_ROM_PTR(&pyb_sdcard_obj) }, // now obsolete
+ #endif
{ MP_ROM_QSTR(MP_QSTR_SDCard), MP_ROM_PTR(&pyb_sdcard_type) },
#endif
#if defined(MICROPY_HW_LED1)
{ MP_ROM_QSTR(MP_QSTR_LED), MP_ROM_PTR(&pyb_led_type) },
#endif
+ #if MICROPY_PY_PYB_LEGACY && MICROPY_HW_ENABLE_HW_I2C
{ MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&pyb_i2c_type) },
+ #endif
{ MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&pyb_spi_type) },
{ MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&pyb_uart_type) },
#if MICROPY_HW_ENABLE_CAN
{ MP_ROM_QSTR(MP_QSTR_CAN), MP_ROM_PTR(&pyb_can_type) },
#endif
+ #if MICROPY_HW_ENABLE_ADC
{ MP_ROM_QSTR(MP_QSTR_ADC), MP_ROM_PTR(&pyb_adc_type) },
{ MP_ROM_QSTR(MP_QSTR_ADCAll), MP_ROM_PTR(&pyb_adc_all_type) },
+ #endif
#if MICROPY_HW_ENABLE_DAC
{ MP_ROM_QSTR(MP_QSTR_DAC), MP_ROM_PTR(&pyb_dac_type) },
diff --git a/ports/stm32/modstm.c b/ports/stm32/modstm.c
index 2084c0aa0..3fae3a57c 100644
--- a/ports/stm32/modstm.c
+++ b/ports/stm32/modstm.c
@@ -30,9 +30,12 @@
#include "py/obj.h"
#include "py/objint.h"
#include "extmod/machine_mem.h"
-#include "genhdr/modstm_mpz.h"
#include "portmodules.h"
+#if MICROPY_PY_STM
+
+#include "genhdr/modstm_mpz.h"
+
STATIC const mp_rom_map_elem_t stm_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_stm) },
@@ -49,3 +52,5 @@ const mp_obj_module_t stm_module = {
.base = { &mp_type_module },
.globals = (mp_obj_dict_t*)&stm_module_globals,
};
+
+#endif // MICROPY_PY_STM
diff --git a/ports/stm32/modules/dht.py b/ports/stm32/modules/dht.py
new file mode 120000
index 000000000..2aa2f5cbf
--- /dev/null
+++ b/ports/stm32/modules/dht.py
@@ -0,0 +1 @@
+../../../drivers/dht/dht.py \ No newline at end of file
diff --git a/ports/stm32/moduos.c b/ports/stm32/moduos.c
index f6e1483d3..0dde844f3 100644
--- a/ports/stm32/moduos.c
+++ b/ports/stm32/moduos.c
@@ -82,10 +82,12 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_0(os_uname_obj, os_uname);
/// \function sync()
/// Sync all filesystems.
STATIC mp_obj_t os_sync(void) {
+ #if MICROPY_VFS_FAT
for (mp_vfs_mount_t *vfs = MP_STATE_VM(vfs_mount_table); vfs != NULL; vfs = vfs->next) {
// this assumes that vfs->obj is fs_user_mount_t with block device functions
disk_ioctl(MP_OBJ_TO_PTR(vfs->obj), CTRL_SYNC, NULL);
}
+ #endif
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_0(mod_os_sync_obj, os_sync);
@@ -106,6 +108,18 @@ STATIC mp_obj_t os_urandom(mp_obj_t num) {
STATIC MP_DEFINE_CONST_FUN_OBJ_1(os_urandom_obj, os_urandom);
#endif
+STATIC mp_obj_t uos_dupterm(size_t n_args, const mp_obj_t *args) {
+ mp_obj_t prev_obj = mp_uos_dupterm_obj.fun.var(n_args, args);
+ if (mp_obj_get_type(prev_obj) == &pyb_uart_type) {
+ uart_attach_to_repl(MP_OBJ_TO_PTR(prev_obj), false);
+ }
+ if (mp_obj_get_type(args[0]) == &pyb_uart_type) {
+ uart_attach_to_repl(MP_OBJ_TO_PTR(args[0]), true);
+ }
+ return prev_obj;
+}
+MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(uos_dupterm_obj, 1, 2, uos_dupterm);
+
STATIC const mp_rom_map_elem_t os_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_uos) },
@@ -133,10 +147,12 @@ STATIC const mp_rom_map_elem_t os_module_globals_table[] = {
#endif
// these are MicroPython extensions
- { MP_ROM_QSTR(MP_QSTR_dupterm), MP_ROM_PTR(&mp_uos_dupterm_obj) },
+ { MP_ROM_QSTR(MP_QSTR_dupterm), MP_ROM_PTR(&uos_dupterm_obj) },
{ MP_ROM_QSTR(MP_QSTR_mount), MP_ROM_PTR(&mp_vfs_mount_obj) },
{ MP_ROM_QSTR(MP_QSTR_umount), MP_ROM_PTR(&mp_vfs_umount_obj) },
+ #if MICROPY_VFS_FAT
{ MP_ROM_QSTR(MP_QSTR_VfsFat), MP_ROM_PTR(&mp_fat_vfs_type) },
+ #endif
};
STATIC MP_DEFINE_CONST_DICT(os_module_globals, os_module_globals_table);
diff --git a/ports/stm32/modusocket.c b/ports/stm32/modusocket.c
index 71a237b0d..715faa3c4 100644
--- a/ports/stm32/modusocket.c
+++ b/ports/stm32/modusocket.c
@@ -30,11 +30,12 @@
#include "py/objtuple.h"
#include "py/objlist.h"
#include "py/runtime.h"
+#include "py/stream.h"
#include "py/mperrno.h"
#include "lib/netutils/netutils.h"
#include "modnetwork.h"
-#if MICROPY_PY_USOCKET
+#if MICROPY_PY_USOCKET && !MICROPY_PY_LWIP
/******************************************************************************/
// socket class
@@ -79,16 +80,6 @@ STATIC void socket_select_nic(mod_network_socket_obj_t *self, const byte *ip) {
}
}
}
-// method socket.close()
-STATIC mp_obj_t socket_close(mp_obj_t self_in) {
- mod_network_socket_obj_t *self = self_in;
- if (self->nic != MP_OBJ_NULL) {
- self->nic_type->close(self);
- self->nic = MP_OBJ_NULL;
- }
- return mp_const_none;
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_1(socket_close_obj, socket_close);
// method socket.bind(address)
STATIC mp_obj_t socket_bind(mp_obj_t self_in, mp_obj_t addr_in) {
@@ -347,8 +338,8 @@ STATIC mp_obj_t socket_setblocking(mp_obj_t self_in, mp_obj_t blocking) {
STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_setblocking_obj, socket_setblocking);
STATIC const mp_rom_map_elem_t socket_locals_dict_table[] = {
- { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&socket_close_obj) },
- { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&socket_close_obj) },
+ { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mp_stream_close_obj) },
+ { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) },
{ MP_ROM_QSTR(MP_QSTR_bind), MP_ROM_PTR(&socket_bind_obj) },
{ MP_ROM_QSTR(MP_QSTR_listen), MP_ROM_PTR(&socket_listen_obj) },
{ MP_ROM_QSTR(MP_QSTR_accept), MP_ROM_PTR(&socket_accept_obj) },
@@ -366,6 +357,13 @@ STATIC MP_DEFINE_CONST_DICT(socket_locals_dict, socket_locals_dict_table);
mp_uint_t socket_ioctl(mp_obj_t self_in, mp_uint_t request, mp_uint_t arg, int *errcode) {
mod_network_socket_obj_t *self = self_in;
+ if (request == MP_STREAM_CLOSE) {
+ if (self->nic != MP_OBJ_NULL) {
+ self->nic_type->close(self);
+ self->nic = MP_OBJ_NULL;
+ }
+ return 0;
+ }
return self->nic_type->ioctl(self, request, arg, errcode);
}
@@ -467,4 +465,4 @@ const mp_obj_module_t mp_module_usocket = {
.globals = (mp_obj_dict_t*)&mp_module_usocket_globals,
};
-#endif // MICROPY_PY_USOCKET
+#endif // MICROPY_PY_USOCKET && !MICROPY_PY_LWIP
diff --git a/ports/stm32/modutime.c b/ports/stm32/modutime.c
index 54045f4c5..6b5c84115 100644
--- a/ports/stm32/modutime.c
+++ b/ports/stm32/modutime.c
@@ -60,8 +60,8 @@ STATIC mp_obj_t time_localtime(size_t n_args, const mp_obj_t *args) {
rtc_init_finalise();
RTC_DateTypeDef date;
RTC_TimeTypeDef time;
- HAL_RTC_GetTime(&RTCHandle, &time, FORMAT_BIN);
- HAL_RTC_GetDate(&RTCHandle, &date, FORMAT_BIN);
+ HAL_RTC_GetTime(&RTCHandle, &time, RTC_FORMAT_BIN);
+ HAL_RTC_GetDate(&RTCHandle, &date, RTC_FORMAT_BIN);
mp_obj_t tuple[8] = {
mp_obj_new_int(2000 + date.Year),
mp_obj_new_int(date.Month),
@@ -123,8 +123,8 @@ STATIC mp_obj_t time_time(void) {
rtc_init_finalise();
RTC_DateTypeDef date;
RTC_TimeTypeDef time;
- HAL_RTC_GetTime(&RTCHandle, &time, FORMAT_BIN);
- HAL_RTC_GetDate(&RTCHandle, &date, FORMAT_BIN);
+ HAL_RTC_GetTime(&RTCHandle, &time, RTC_FORMAT_BIN);
+ HAL_RTC_GetDate(&RTCHandle, &date, RTC_FORMAT_BIN);
return mp_obj_new_int(timeutils_seconds_since_2000(2000 + date.Year, date.Month, date.Date, time.Hours, time.Minutes, time.Seconds));
}
MP_DEFINE_CONST_FUN_OBJ_0(time_time_obj, time_time);
diff --git a/ports/stm32/mpconfigboard_common.h b/ports/stm32/mpconfigboard_common.h
new file mode 100644
index 000000000..2cc02b77c
--- /dev/null
+++ b/ports/stm32/mpconfigboard_common.h
@@ -0,0 +1,218 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+// Common settings and defaults for board configuration.
+// The defaults here should be overridden in mpconfigboard.h.
+
+#include STM32_HAL_H
+
+/*****************************************************************************/
+// Feature settings with defaults
+
+// Whether to include the stm module, with peripheral register constants
+#ifndef MICROPY_PY_STM
+#define MICROPY_PY_STM (1)
+#endif
+
+// Whether to include legacy functions and classes in the pyb module
+#ifndef MICROPY_PY_PYB_LEGACY
+#define MICROPY_PY_PYB_LEGACY (1)
+#endif
+
+// Whether to enable storage on the internal flash of the MCU
+#ifndef MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE
+#define MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE (1)
+#endif
+
+// Whether to enable the RTC, exposed as pyb.RTC
+#ifndef MICROPY_HW_ENABLE_RTC
+#define MICROPY_HW_ENABLE_RTC (0)
+#endif
+
+// Whether to enable the hardware RNG peripheral, exposed as pyb.rng()
+#ifndef MICROPY_HW_ENABLE_RNG
+#define MICROPY_HW_ENABLE_RNG (0)
+#endif
+
+// Whether to enable the ADC peripheral, exposed as pyb.ADC and pyb.ADCAll
+#ifndef MICROPY_HW_ENABLE_ADC
+#define MICROPY_HW_ENABLE_ADC (1)
+#endif
+
+// Whether to enable the DAC peripheral, exposed as pyb.DAC
+#ifndef MICROPY_HW_ENABLE_DAC
+#define MICROPY_HW_ENABLE_DAC (0)
+#endif
+
+// Whether to enable USB support
+#ifndef MICROPY_HW_ENABLE_USB
+#define MICROPY_HW_ENABLE_USB (0)
+#endif
+
+// Whether to enable the PA0-PA3 servo driver, exposed as pyb.Servo
+#ifndef MICROPY_HW_ENABLE_SERVO
+#define MICROPY_HW_ENABLE_SERVO (0)
+#endif
+
+// Whether to enable a USR switch, exposed as pyb.Switch
+#ifndef MICROPY_HW_HAS_SWITCH
+#define MICROPY_HW_HAS_SWITCH (0)
+#endif
+
+// Whether to expose internal flash storage as pyb.Flash
+#ifndef MICROPY_HW_HAS_FLASH
+#define MICROPY_HW_HAS_FLASH (0)
+#endif
+
+// Whether to enable the SD card interface, exposed as pyb.SDCard
+#ifndef MICROPY_HW_HAS_SDCARD
+#define MICROPY_HW_HAS_SDCARD (0)
+#endif
+
+// Whether to enable the MMA7660 driver, exposed as pyb.Accel
+#ifndef MICROPY_HW_HAS_MMA7660
+#define MICROPY_HW_HAS_MMA7660 (0)
+#endif
+
+// Whether to enable the LCD32MK driver, exposed as pyb.LCD
+#ifndef MICROPY_HW_HAS_LCD
+#define MICROPY_HW_HAS_LCD (0)
+#endif
+
+// The volume label used when creating the flash filesystem
+#ifndef MICROPY_HW_FLASH_FS_LABEL
+#define MICROPY_HW_FLASH_FS_LABEL "pybflash"
+#endif
+
+/*****************************************************************************/
+// General configuration
+
+// Configuration for STM32F0 series
+#if defined(STM32F0)
+
+#define MP_HAL_UNIQUE_ID_ADDRESS (0x1ffff7ac)
+#define PYB_EXTI_NUM_VECTORS (23)
+#define MICROPY_HW_MAX_TIMER (17)
+#define MICROPY_HW_MAX_UART (8)
+
+// Configuration for STM32F4 series
+#elif defined(STM32F4)
+
+#define MP_HAL_UNIQUE_ID_ADDRESS (0x1fff7a10)
+#define PYB_EXTI_NUM_VECTORS (23)
+#define MICROPY_HW_MAX_TIMER (14)
+#ifdef UART8
+#define MICROPY_HW_MAX_UART (8)
+#else
+#define MICROPY_HW_MAX_UART (6)
+#endif
+
+// Configuration for STM32F7 series
+#elif defined(STM32F7)
+
+#if defined(STM32F722xx) || defined(STM32F723xx) || defined(STM32F732xx) || defined(STM32F733xx)
+#define MP_HAL_UNIQUE_ID_ADDRESS (0x1ff07a10)
+#else
+#define MP_HAL_UNIQUE_ID_ADDRESS (0x1ff0f420)
+#endif
+
+#define PYB_EXTI_NUM_VECTORS (24)
+#define MICROPY_HW_MAX_TIMER (17)
+#define MICROPY_HW_MAX_UART (8)
+
+// Configuration for STM32H7 series
+#elif defined(STM32H7)
+
+#define MP_HAL_UNIQUE_ID_ADDRESS (0x1ff1e800)
+#define PYB_EXTI_NUM_VECTORS (24)
+#define MICROPY_HW_MAX_TIMER (17)
+#define MICROPY_HW_MAX_UART (8)
+
+// Configuration for STM32L4 series
+#elif defined(STM32L4)
+
+#define MP_HAL_UNIQUE_ID_ADDRESS (0x1fff7590)
+#define PYB_EXTI_NUM_VECTORS (23)
+#define MICROPY_HW_MAX_TIMER (17)
+#define MICROPY_HW_MAX_UART (6)
+
+#else
+#error Unsupported MCU series
+#endif
+
+// Configure HSE for bypass or oscillator
+#if MICROPY_HW_CLK_USE_BYPASS
+#define MICROPY_HW_CLK_HSE_STATE (RCC_HSE_BYPASS)
+#else
+#define MICROPY_HW_CLK_HSE_STATE (RCC_HSE_ON)
+#endif
+
+#if MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE
+// Provide block device macros if internal flash storage is enabled
+#define MICROPY_HW_BDEV_IOCTL flash_bdev_ioctl
+#define MICROPY_HW_BDEV_READBLOCK flash_bdev_readblock
+#define MICROPY_HW_BDEV_WRITEBLOCK flash_bdev_writeblock
+#endif
+
+// Enable the storage sub-system if a block device is defined
+#if defined(MICROPY_HW_BDEV_IOCTL)
+#define MICROPY_HW_ENABLE_STORAGE (1)
+#else
+#define MICROPY_HW_ENABLE_STORAGE (0)
+#endif
+
+// Enable hardware I2C if there are any peripherals defined
+#if defined(MICROPY_HW_I2C1_SCL) || defined(MICROPY_HW_I2C2_SCL) \
+ || defined(MICROPY_HW_I2C3_SCL) || defined(MICROPY_HW_I2C4_SCL)
+#define MICROPY_HW_ENABLE_HW_I2C (1)
+#else
+#define MICROPY_HW_ENABLE_HW_I2C (0)
+#endif
+
+// Enable CAN if there are any peripherals defined
+#if defined(MICROPY_HW_CAN1_TX) || defined(MICROPY_HW_CAN2_TX)
+#define MICROPY_HW_ENABLE_CAN (1)
+#else
+#define MICROPY_HW_ENABLE_CAN (0)
+#endif
+
+// Pin definition header file
+#define MICROPY_PIN_DEFS_PORT_H "pin_defs_stm32.h"
+
+// D-cache clean/invalidate helpers
+#if __DCACHE_PRESENT == 1
+#define MP_HAL_CLEANINVALIDATE_DCACHE(addr, size) \
+ (SCB_CleanInvalidateDCache_by_Addr((uint32_t*)((uint32_t)addr & ~0x1f), \
+ ((uint32_t)((uint8_t*)addr + size + 0x1f) & ~0x1f) - ((uint32_t)addr & ~0x1f)))
+#define MP_HAL_CLEAN_DCACHE(addr, size) \
+ (SCB_CleanDCache_by_Addr((uint32_t*)((uint32_t)addr & ~0x1f), \
+ ((uint32_t)((uint8_t*)addr + size + 0x1f) & ~0x1f) - ((uint32_t)addr & ~0x1f)))
+#else
+#define MP_HAL_CLEANINVALIDATE_DCACHE(addr, size)
+#define MP_HAL_CLEAN_DCACHE(addr, size)
+#endif
+
+#define MICROPY_HW_USES_BOOTLOADER (MICROPY_HW_VTOR != 0x08000000)
diff --git a/ports/stm32/mpconfigport.h b/ports/stm32/mpconfigport.h
index 51d442561..a038664e8 100644
--- a/ports/stm32/mpconfigport.h
+++ b/ports/stm32/mpconfigport.h
@@ -29,6 +29,7 @@
// board specific definitions
#include "mpconfigboard.h"
+#include "mpconfigboard_common.h"
// memory allocation policies
#define MICROPY_ALLOC_PATH_MAX (128)
@@ -75,10 +76,14 @@
#define MICROPY_ENABLE_SCHEDULER (1)
#define MICROPY_SCHEDULER_DEPTH (8)
#define MICROPY_VFS (1)
+#ifndef MICROPY_VFS_FAT
#define MICROPY_VFS_FAT (1)
+#endif
// control over Python builtins
#define MICROPY_PY_FUNCTION_ATTRS (1)
+#define MICROPY_PY_DESCRIPTORS (1)
+#define MICROPY_PY_DELATTR_SETATTR (1)
#define MICROPY_PY_BUILTINS_STR_UNICODE (1)
#define MICROPY_PY_BUILTINS_STR_CENTER (1)
#define MICROPY_PY_BUILTINS_STR_PARTITION (1)
@@ -86,9 +91,11 @@
#define MICROPY_PY_BUILTINS_MEMORYVIEW (1)
#define MICROPY_PY_BUILTINS_FROZENSET (1)
#define MICROPY_PY_BUILTINS_SLICE_ATTRS (1)
+#define MICROPY_PY_BUILTINS_ROUND_INT (1)
#define MICROPY_PY_ALL_SPECIAL_METHODS (1)
#define MICROPY_PY_BUILTINS_COMPILE (1)
#define MICROPY_PY_BUILTINS_EXECFILE (1)
+#define MICROPY_PY_BUILTINS_NOTIMPLEMENTED (1)
#define MICROPY_PY_BUILTINS_INPUT (1)
#define MICROPY_PY_BUILTINS_POW3 (1)
#define MICROPY_PY_BUILTINS_HELP (1)
@@ -96,11 +103,13 @@
#define MICROPY_PY_BUILTINS_HELP_MODULES (1)
#define MICROPY_PY_MICROPYTHON_MEM_INFO (1)
#define MICROPY_PY_ARRAY_SLICE_ASSIGN (1)
+#define MICROPY_PY_COLLECTIONS_DEQUE (1)
#define MICROPY_PY_COLLECTIONS_ORDEREDDICT (1)
#define MICROPY_PY_MATH_SPECIAL_FUNCTIONS (1)
#define MICROPY_PY_CMATH (1)
#define MICROPY_PY_IO (1)
-#define MICROPY_PY_IO_FILEIO (1)
+#define MICROPY_PY_IO_IOBASE (1)
+#define MICROPY_PY_IO_FILEIO (MICROPY_VFS_FAT) // because mp_type_fileio/textio point to fatfs impl
#define MICROPY_PY_SYS_MAXSIZE (1)
#define MICROPY_PY_SYS_EXIT (1)
#define MICROPY_PY_SYS_STDFILES (1)
@@ -131,13 +140,15 @@
#define MICROPY_PY_MACHINE_PULSE (1)
#define MICROPY_PY_MACHINE_PIN_MAKE_NEW mp_pin_make_new
#define MICROPY_PY_MACHINE_I2C (1)
+#if MICROPY_HW_ENABLE_HW_I2C
#define MICROPY_PY_MACHINE_I2C_MAKE_NEW machine_hard_i2c_make_new
+#endif
#define MICROPY_PY_MACHINE_SPI (1)
#define MICROPY_PY_MACHINE_SPI_MSB (SPI_FIRSTBIT_MSB)
#define MICROPY_PY_MACHINE_SPI_LSB (SPI_FIRSTBIT_LSB)
#define MICROPY_PY_MACHINE_SPI_MAKE_NEW machine_hard_spi_make_new
-#define MICROPY_PY_MACHINE_SPI_MIN_DELAY (0)
-#define MICROPY_PY_MACHINE_SPI_MAX_BAUDRATE (HAL_RCC_GetSysClockFreq() / 48)
+#define MICROPY_HW_SOFTSPI_MIN_DELAY (0)
+#define MICROPY_HW_SOFTSPI_MAX_BAUDRATE (HAL_RCC_GetSysClockFreq() / 48)
#define MICROPY_PY_FRAMEBUF (1)
#ifndef MICROPY_PY_USOCKET
#define MICROPY_PY_USOCKET (1)
@@ -154,8 +165,8 @@
#define MICROPY_FATFS_MULTI_PARTITION (1)
// TODO these should be generic, not bound to fatfs
-#define mp_type_fileio fatfs_type_fileio
-#define mp_type_textio fatfs_type_textio
+#define mp_type_fileio mp_type_vfs_fat_fileio
+#define mp_type_textio mp_type_vfs_fat_textio
// use vfs's functions for import stat and builtin open
#define mp_import_stat mp_vfs_import_stat
@@ -182,12 +193,27 @@ extern const struct _mp_obj_module_t mp_module_usocket;
extern const struct _mp_obj_module_t mp_module_network;
extern const struct _mp_obj_module_t mp_module_onewire;
-#if MICROPY_PY_USOCKET
+#if MICROPY_PY_STM
+#define STM_BUILTIN_MODULE { MP_ROM_QSTR(MP_QSTR_stm), MP_ROM_PTR(&stm_module) },
+#else
+#define STM_BUILTIN_MODULE
+#endif
+
+#if MICROPY_PY_USOCKET && MICROPY_PY_LWIP
+// usocket implementation provided by lwIP
+#define SOCKET_BUILTIN_MODULE { MP_ROM_QSTR(MP_QSTR_usocket), MP_ROM_PTR(&mp_module_lwip) },
+#define SOCKET_BUILTIN_MODULE_WEAK_LINKS { MP_ROM_QSTR(MP_QSTR_socket), MP_ROM_PTR(&mp_module_lwip) },
+#define SOCKET_POLL extern void pyb_lwip_poll(void); pyb_lwip_poll();
+#elif MICROPY_PY_USOCKET
+// usocket implementation provided by skeleton wrapper
#define SOCKET_BUILTIN_MODULE { MP_ROM_QSTR(MP_QSTR_usocket), MP_ROM_PTR(&mp_module_usocket) },
#define SOCKET_BUILTIN_MODULE_WEAK_LINKS { MP_ROM_QSTR(MP_QSTR_socket), MP_ROM_PTR(&mp_module_usocket) },
+#define SOCKET_POLL
#else
+// no usocket module
#define SOCKET_BUILTIN_MODULE
#define SOCKET_BUILTIN_MODULE_WEAK_LINKS
+#define SOCKET_POLL
#endif
#if MICROPY_PY_NETWORK
@@ -199,7 +225,7 @@ extern const struct _mp_obj_module_t mp_module_onewire;
#define MICROPY_PORT_BUILTIN_MODULES \
{ MP_ROM_QSTR(MP_QSTR_umachine), MP_ROM_PTR(&machine_module) }, \
{ MP_ROM_QSTR(MP_QSTR_pyb), MP_ROM_PTR(&pyb_module) }, \
- { MP_ROM_QSTR(MP_QSTR_stm), MP_ROM_PTR(&stm_module) }, \
+ STM_BUILTIN_MODULE \
{ MP_ROM_QSTR(MP_QSTR_uos), MP_ROM_PTR(&mp_module_uos) }, \
{ MP_ROM_QSTR(MP_QSTR_utime), MP_ROM_PTR(&mp_module_utime) }, \
SOCKET_BUILTIN_MODULE \
@@ -229,21 +255,7 @@ extern const struct _mp_obj_module_t mp_module_onewire;
{ MP_ROM_QSTR(MP_QSTR_umachine), MP_ROM_PTR(&machine_module) }, \
{ MP_ROM_QSTR(MP_QSTR_machine), MP_ROM_PTR(&machine_module) }, \
{ MP_ROM_QSTR(MP_QSTR_pyb), MP_ROM_PTR(&pyb_module) }, \
- { MP_ROM_QSTR(MP_QSTR_stm), MP_ROM_PTR(&stm_module) }, \
-
-#if defined(MCU_SERIES_F7)
-#define PYB_EXTI_NUM_VECTORS (24)
-#define MICROPY_HW_MAX_TIMER (17)
-#define MICROPY_HW_MAX_UART (8)
-#elif defined(MCU_SERIES_L4)
-#define PYB_EXTI_NUM_VECTORS (23)
-#define MICROPY_HW_MAX_TIMER (17)
-#define MICROPY_HW_MAX_UART (6)
-#else
-#define PYB_EXTI_NUM_VECTORS (23)
-#define MICROPY_HW_MAX_TIMER (14)
-#define MICROPY_HW_MAX_UART (6)
-#endif
+ STM_BUILTIN_MODULE \
#define MP_STATE_PORT MP_STATE_VM
@@ -299,8 +311,6 @@ typedef long mp_off_t;
// value from disable_irq back to enable_irq. If you really need
// to know the machine-specific values, see irq.h.
-#include STM32_HAL_H
-
static inline void enable_irq(mp_uint_t state) {
__set_PRIMASK(state);
}
@@ -319,6 +329,7 @@ static inline mp_uint_t disable_irq(void) {
do { \
extern void mp_handle_pending(void); \
mp_handle_pending(); \
+ SOCKET_POLL \
if (pyb_thread_enabled) { \
MP_THREAD_GIL_EXIT(); \
pyb_thread_yield(); \
@@ -334,6 +345,7 @@ static inline mp_uint_t disable_irq(void) {
do { \
extern void mp_handle_pending(void); \
mp_handle_pending(); \
+ SOCKET_POLL \
__WFI(); \
} while (0);
@@ -351,12 +363,5 @@ static inline mp_uint_t disable_irq(void) {
#define free(p) m_free(p)
#define realloc(p, n) m_realloc(p, n)
-// see stm32f4XX_hal_conf.h USE_USB_FS & USE_USB_HS
-// at the moment only USB_FS is supported
-#define USE_DEVICE_MODE
-//#define USE_HOST_MODE
-
// We need to provide a declaration/definition of alloca()
#include <alloca.h>
-
-#define MICROPY_PIN_DEFS_PORT_H "pin_defs_stm32.h"
diff --git a/ports/stm32/mphalport.c b/ports/stm32/mphalport.c
index e9c4f28f7..a2f8e412e 100644
--- a/ports/stm32/mphalport.c
+++ b/ports/stm32/mphalport.c
@@ -7,8 +7,6 @@
#include "usb.h"
#include "uart.h"
-bool mp_hal_ticks_cpu_enabled = false;
-
// this table converts from HAL_StatusTypeDef to POSIX errno
const byte mp_hal_status_to_errno_table[4] = {
[HAL_OK] = 0,
@@ -33,10 +31,13 @@ int mp_hal_stdin_rx_chr(void) {
#endif
#endif
+ #if MICROPY_HW_ENABLE_USB
byte c;
if (usb_vcp_recv_byte(&c) != 0) {
return c;
- } else if (MP_STATE_PORT(pyb_stdio_uart) != NULL && uart_rx_any(MP_STATE_PORT(pyb_stdio_uart))) {
+ }
+ #endif
+ if (MP_STATE_PORT(pyb_stdio_uart) != NULL && uart_rx_any(MP_STATE_PORT(pyb_stdio_uart))) {
return uart_rx_char(MP_STATE_PORT(pyb_stdio_uart));
}
int dupterm_c = mp_uos_dupterm_rx_chr();
@@ -58,9 +59,11 @@ void mp_hal_stdout_tx_strn(const char *str, size_t len) {
#if 0 && defined(USE_HOST_MODE) && MICROPY_HW_HAS_LCD
lcd_print_strn(str, len);
#endif
+ #if MICROPY_HW_ENABLE_USB
if (usb_vcp_is_enabled()) {
usb_vcp_send_strn(str, len);
}
+ #endif
mp_uos_dupterm_tx_strn(str, len);
}
@@ -84,8 +87,9 @@ void mp_hal_stdout_tx_strn_cooked(const char *str, size_t len) {
}
}
+#if __CORTEX_M >= 0x03
void mp_hal_ticks_cpu_enable(void) {
- if (!mp_hal_ticks_cpu_enabled) {
+ if (!(DWT->CTRL & DWT_CTRL_CYCCNTENA_Msk)) {
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
#if defined(__CORTEX_M) && __CORTEX_M == 7
// on Cortex-M7 we must unlock the DWT before writing to its registers
@@ -93,61 +97,38 @@ void mp_hal_ticks_cpu_enable(void) {
#endif
DWT->CYCCNT = 0;
DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
- mp_hal_ticks_cpu_enabled = true;
}
}
+#endif
void mp_hal_gpio_clock_enable(GPIO_TypeDef *gpio) {
- if (0) {
- #ifdef __GPIOA_CLK_ENABLE
- } else if (gpio == GPIOA) {
- __GPIOA_CLK_ENABLE();
- #endif
- #ifdef __GPIOB_CLK_ENABLE
- } else if (gpio == GPIOB) {
- __GPIOB_CLK_ENABLE();
- #endif
- #ifdef __GPIOC_CLK_ENABLE
- } else if (gpio == GPIOC) {
- __GPIOC_CLK_ENABLE();
- #endif
- #ifdef __GPIOD_CLK_ENABLE
- } else if (gpio == GPIOD) {
- __GPIOD_CLK_ENABLE();
- #endif
- #ifdef __GPIOE_CLK_ENABLE
- } else if (gpio == GPIOE) {
- __GPIOE_CLK_ENABLE();
- #endif
- #if defined(GPIOF) && defined(__GPIOF_CLK_ENABLE)
- } else if (gpio == GPIOF) {
- __GPIOF_CLK_ENABLE();
- #endif
- #if defined(GPIOG) && defined(__GPIOG_CLK_ENABLE)
- } else if (gpio == GPIOG) {
- #if defined(STM32L476xx) || defined(STM32L486xx)
+ #if defined(STM32L476xx) || defined(STM32L496xx)
+ if (gpio == GPIOG) {
// Port G pins 2 thru 15 are powered using VddIO2 on these MCUs.
HAL_PWREx_EnableVddIO2();
- #endif
- __GPIOG_CLK_ENABLE();
- #endif
- #ifdef __GPIOH_CLK_ENABLE
- } else if (gpio == GPIOH) {
- __GPIOH_CLK_ENABLE();
- #endif
- #if defined(GPIOI) && defined(__GPIOI_CLK_ENABLE)
- } else if (gpio == GPIOI) {
- __GPIOI_CLK_ENABLE();
- #endif
- #if defined(GPIOJ) && defined(__GPIOJ_CLK_ENABLE)
- } else if (gpio == GPIOJ) {
- __GPIOJ_CLK_ENABLE();
+ }
#endif
- #if defined(GPIOK) && defined(__GPIOK_CLK_ENABLE)
- } else if (gpio == GPIOK) {
- __GPIOK_CLK_ENABLE();
+
+ // This logic assumes that all the GPIOx_EN bits are adjacent and ordered in one register
+
+ #if defined(STM32F0)
+ #define AHBxENR AHBENR
+ #define AHBxENR_GPIOAEN_Pos RCC_AHBENR_GPIOAEN_Pos
+ #elif defined(STM32F4) || defined(STM32F7)
+ #define AHBxENR AHB1ENR
+ #define AHBxENR_GPIOAEN_Pos RCC_AHB1ENR_GPIOAEN_Pos
+ #elif defined(STM32H7)
+ #define AHBxENR AHB4ENR
+ #define AHBxENR_GPIOAEN_Pos RCC_AHB4ENR_GPIOAEN_Pos
+ #elif defined(STM32L4)
+ #define AHBxENR AHB2ENR
+ #define AHBxENR_GPIOAEN_Pos RCC_AHB2ENR_GPIOAEN_Pos
#endif
- }
+
+ uint32_t gpio_idx = ((uint32_t)gpio - GPIOA_BASE) / (GPIOB_BASE - GPIOA_BASE);
+ RCC->AHBxENR |= 1 << (AHBxENR_GPIOAEN_Pos + gpio_idx);
+ volatile uint32_t tmp = RCC->AHBxENR; // Delay after enabling clock
+ (void)tmp;
}
void mp_hal_pin_config(mp_hal_pin_obj_t pin_obj, uint32_t mode, uint32_t pull, uint32_t alt) {
@@ -155,7 +136,13 @@ void mp_hal_pin_config(mp_hal_pin_obj_t pin_obj, uint32_t mode, uint32_t pull, u
uint32_t pin = pin_obj->pin;
mp_hal_gpio_clock_enable(gpio);
gpio->MODER = (gpio->MODER & ~(3 << (2 * pin))) | ((mode & 3) << (2 * pin));
+ #if defined(GPIO_ASCR_ASC0)
+ // The L4 has a special analog switch to connect the GPIO to the ADC
+ gpio->OTYPER = (gpio->OTYPER & ~(1 << pin)) | (((mode >> 2) & 1) << pin);
+ gpio->ASCR = (gpio->ASCR & ~(1 << pin)) | ((mode >> 3) & 1) << pin;
+ #else
gpio->OTYPER = (gpio->OTYPER & ~(1 << pin)) | ((mode >> 2) << pin);
+ #endif
gpio->OSPEEDR = (gpio->OSPEEDR & ~(3 << (2 * pin))) | (2 << (2 * pin)); // full speed
gpio->PUPDR = (gpio->PUPDR & ~(3 << (2 * pin))) | (pull << (2 * pin));
gpio->AFR[pin >> 3] = (gpio->AFR[pin >> 3] & ~(15 << (4 * (pin & 7)))) | (alt << (4 * (pin & 7)));
@@ -169,3 +156,9 @@ bool mp_hal_pin_config_alt(mp_hal_pin_obj_t pin, uint32_t mode, uint32_t pull, u
mp_hal_pin_config(pin, mode, pull, af->idx);
return true;
}
+
+void mp_hal_pin_config_speed(mp_hal_pin_obj_t pin_obj, uint32_t speed) {
+ GPIO_TypeDef *gpio = pin_obj->gpio;
+ uint32_t pin = pin_obj->pin;
+ gpio->OSPEEDR = (gpio->OSPEEDR & ~(3 << (2 * pin))) | (speed << (2 * pin));
+}
diff --git a/ports/stm32/mphalport.h b/ports/stm32/mphalport.h
index 939df0b3d..72413c04c 100644
--- a/ports/stm32/mphalport.h
+++ b/ports/stm32/mphalport.h
@@ -2,24 +2,6 @@
#include STM32_HAL_H
#include "pin.h"
-// The unique id address differs per MCU. Ideally this define should
-// go in some MCU-specific header, but for now it lives here.
-#if defined(MCU_SERIES_F4)
-#define MP_HAL_UNIQUE_ID_ADDRESS (0x1fff7a10)
-#define MP_HAL_CLEANINVALIDATE_DCACHE(addr, size)
-#define MP_HAL_CLEAN_DCACHE(addr, size)
-#elif defined(MCU_SERIES_F7)
-#define MP_HAL_UNIQUE_ID_ADDRESS (0x1ff0f420)
-#define MP_HAL_CLEANINVALIDATE_DCACHE(addr, size) (SCB_CleanInvalidateDCache_by_Addr((uint32_t*)((uint32_t)addr & ~0x1f), ((uint32_t)((uint8_t*)addr + size + 0x1f) & ~0x1f) - ((uint32_t)addr & ~0x1f)))
-#define MP_HAL_CLEAN_DCACHE(addr, size) (SCB_CleanDCache_by_Addr((uint32_t*)((uint32_t)addr & ~0x1f), ((uint32_t)((uint8_t*)addr + size + 0x1f) & ~0x1f) - ((uint32_t)addr & ~0x1f)))
-#elif defined(MCU_SERIES_L4)
-#define MP_HAL_UNIQUE_ID_ADDRESS (0x1fff7590)
-#define MP_HAL_CLEANINVALIDATE_DCACHE(addr, size)
-#define MP_HAL_CLEAN_DCACHE(addr, size)
-#else
-#error mphalport.h: Unrecognized MCU_SERIES
-#endif
-
extern const unsigned char mp_hal_status_to_errno_table[4];
NORETURN void mp_hal_raise(HAL_StatusTypeDef status);
@@ -29,17 +11,26 @@ void mp_hal_set_interrupt_char(int c); // -1 to disable
#include "irq.h"
+#if __CORTEX_M == 0
+// Don't have raise_irq_pri on Cortex-M0 so keep IRQs enabled to have SysTick timing
+#define mp_hal_quiet_timing_enter() (1)
+#define mp_hal_quiet_timing_exit(irq_state) (void)(irq_state)
+#else
#define mp_hal_quiet_timing_enter() raise_irq_pri(1)
#define mp_hal_quiet_timing_exit(irq_state) restore_irq_pri(irq_state)
+#endif
#define mp_hal_delay_us_fast(us) mp_hal_delay_us(us)
-extern bool mp_hal_ticks_cpu_enabled;
void mp_hal_ticks_cpu_enable(void);
static inline mp_uint_t mp_hal_ticks_cpu(void) {
- if (!mp_hal_ticks_cpu_enabled) {
+ #if __CORTEX_M == 0
+ return 0;
+ #else
+ if (!(DWT->CTRL & DWT_CTRL_CYCCNTENA_Msk)) {
mp_hal_ticks_cpu_enable();
}
return DWT->CYCCNT;
+ #endif
}
// C-level pin HAL
@@ -51,6 +42,11 @@ static inline mp_uint_t mp_hal_ticks_cpu(void) {
#define MP_HAL_PIN_MODE_OUTPUT (1)
#define MP_HAL_PIN_MODE_ALT (2)
#define MP_HAL_PIN_MODE_ANALOG (3)
+#if defined(GPIO_ASCR_ASC0)
+#define MP_HAL_PIN_MODE_ADC (11)
+#else
+#define MP_HAL_PIN_MODE_ADC (3)
+#endif
#define MP_HAL_PIN_MODE_OPEN_DRAIN (5)
#define MP_HAL_PIN_MODE_ALT_OPEN_DRAIN (6)
#define MP_HAL_PIN_PULL_NONE (GPIO_NOPULL)
@@ -63,8 +59,13 @@ static inline mp_uint_t mp_hal_ticks_cpu(void) {
#define mp_hal_pin_input(p) mp_hal_pin_config((p), MP_HAL_PIN_MODE_INPUT, MP_HAL_PIN_PULL_NONE, 0)
#define mp_hal_pin_output(p) mp_hal_pin_config((p), MP_HAL_PIN_MODE_OUTPUT, MP_HAL_PIN_PULL_NONE, 0)
#define mp_hal_pin_open_drain(p) mp_hal_pin_config((p), MP_HAL_PIN_MODE_OPEN_DRAIN, MP_HAL_PIN_PULL_NONE, 0)
+#if defined(STM32H7)
+#define mp_hal_pin_high(p) (((p)->gpio->BSRRL) = (p)->pin_mask)
+#define mp_hal_pin_low(p) (((p)->gpio->BSRRH) = (p)->pin_mask)
+#else
#define mp_hal_pin_high(p) (((p)->gpio->BSRR) = (p)->pin_mask)
#define mp_hal_pin_low(p) (((p)->gpio->BSRR) = ((p)->pin_mask << 16))
+#endif
#define mp_hal_pin_od_low(p) mp_hal_pin_low(p)
#define mp_hal_pin_od_high(p) mp_hal_pin_high(p)
#define mp_hal_pin_read(p) (((p)->gpio->IDR >> (p)->pin) & 1)
@@ -73,3 +74,4 @@ static inline mp_uint_t mp_hal_ticks_cpu(void) {
void mp_hal_gpio_clock_enable(GPIO_TypeDef *gpio);
void mp_hal_pin_config(mp_hal_pin_obj_t pin, uint32_t mode, uint32_t pull, uint32_t alt);
bool mp_hal_pin_config_alt(mp_hal_pin_obj_t pin, uint32_t mode, uint32_t pull, uint8_t fn, uint8_t unit);
+void mp_hal_pin_config_speed(mp_hal_pin_obj_t pin_obj, uint32_t speed);
diff --git a/ports/stm32/network_wiznet5k.c b/ports/stm32/network_wiznet5k.c
new file mode 100644
index 000000000..9db42b787
--- /dev/null
+++ b/ports/stm32/network_wiznet5k.c
@@ -0,0 +1,417 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2014-2018 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdio.h>
+#include "py/runtime.h"
+#include "py/mphal.h"
+#include "spi.h"
+#include "modnetwork.h"
+
+#if MICROPY_PY_WIZNET5K && MICROPY_PY_LWIP
+
+#include "drivers/wiznet5k/ethernet/socket.h"
+#include "lwip/err.h"
+#include "lwip/dns.h"
+#include "lwip/dhcp.h"
+#include "netif/etharp.h"
+
+/*******************************************************************************/
+// Wiznet5k Ethernet driver in MACRAW mode
+
+typedef struct _wiznet5k_obj_t {
+ mod_network_nic_type_t base;
+ mp_uint_t cris_state;
+ const spi_t *spi;
+ mp_hal_pin_obj_t cs;
+ mp_hal_pin_obj_t rst;
+ uint8_t eth_frame[1514];
+ struct netif netif;
+ struct dhcp dhcp_struct;
+} wiznet5k_obj_t;
+
+// Global object holding the Wiznet5k state
+STATIC wiznet5k_obj_t wiznet5k_obj;
+
+STATIC void wiznet5k_lwip_init(wiznet5k_obj_t *self);
+STATIC void wiznet5k_lwip_poll(void *self_in, struct netif *netif);
+
+STATIC void wiz_cris_enter(void) {
+ wiznet5k_obj.cris_state = MICROPY_BEGIN_ATOMIC_SECTION();
+}
+
+STATIC void wiz_cris_exit(void) {
+ MICROPY_END_ATOMIC_SECTION(wiznet5k_obj.cris_state);
+}
+
+STATIC void wiz_cs_select(void) {
+ mp_hal_pin_low(wiznet5k_obj.cs);
+}
+
+STATIC void wiz_cs_deselect(void) {
+ mp_hal_pin_high(wiznet5k_obj.cs);
+}
+
+STATIC void wiz_spi_read(uint8_t *buf, uint32_t len) {
+ HAL_StatusTypeDef status = HAL_SPI_Receive(wiznet5k_obj.spi->spi, buf, len, 5000);
+ (void)status;
+}
+
+STATIC void wiz_spi_write(const uint8_t *buf, uint32_t len) {
+ HAL_StatusTypeDef status = HAL_SPI_Transmit(wiznet5k_obj.spi->spi, (uint8_t*)buf, len, 5000);
+ (void)status;
+}
+
+STATIC void wiznet5k_init(void) {
+ // SPI configuration
+ SPI_InitTypeDef *init = &wiznet5k_obj.spi->spi->Init;
+ init->Mode = SPI_MODE_MASTER;
+ init->Direction = SPI_DIRECTION_2LINES;
+ init->DataSize = SPI_DATASIZE_8BIT;
+ init->CLKPolarity = SPI_POLARITY_LOW; // clock is low when idle
+ init->CLKPhase = SPI_PHASE_1EDGE; // data latched on first edge, which is rising edge for low-idle
+ init->NSS = SPI_NSS_SOFT;
+ init->BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2; // clock freq = f_PCLK / this_prescale_value; Wiz820i can do up to 80MHz
+ init->FirstBit = SPI_FIRSTBIT_MSB;
+ init->TIMode = SPI_TIMODE_DISABLED;
+ init->CRCCalculation = SPI_CRCCALCULATION_DISABLED;
+ init->CRCPolynomial = 7; // unused
+ spi_init(wiznet5k_obj.spi, false);
+
+ mp_hal_pin_output(wiznet5k_obj.cs);
+ mp_hal_pin_output(wiznet5k_obj.rst);
+
+ // Reset the chip
+ mp_hal_pin_low(wiznet5k_obj.rst);
+ mp_hal_delay_ms(1); // datasheet says 2us
+ mp_hal_pin_high(wiznet5k_obj.rst);
+ mp_hal_delay_ms(150); // datasheet says 150ms
+
+ // Set physical interface callbacks
+ reg_wizchip_cris_cbfunc(wiz_cris_enter, wiz_cris_exit);
+ reg_wizchip_cs_cbfunc(wiz_cs_select, wiz_cs_deselect);
+ reg_wizchip_spi_cbfunc(wiz_spi_read, wiz_spi_write);
+
+ // Configure 16k buffers for fast MACRAW
+ uint8_t sn_size[16] = {16, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0};
+ ctlwizchip(CW_INIT_WIZCHIP, sn_size);
+
+ // Seems we need a small delay after init
+ mp_hal_delay_ms(250);
+
+ // Hook the Wiznet into lwIP
+ wiznet5k_lwip_init(&wiznet5k_obj);
+}
+
+STATIC void wiznet5k_deinit(void) {
+ for (struct netif *netif = netif_list; netif != NULL; netif = netif->next) {
+ if (netif == &wiznet5k_obj.netif) {
+ netif_remove(netif);
+ netif->flags = 0;
+ break;
+ }
+ }
+}
+
+STATIC void wiznet5k_get_mac_address(wiznet5k_obj_t *self, uint8_t mac[6]) {
+ (void)self;
+ getSHAR(mac);
+}
+
+STATIC void wiznet5k_send_ethernet(wiznet5k_obj_t *self, size_t len, const uint8_t *buf) {
+ uint8_t ip[4] = {1, 1, 1, 1}; // dummy
+ int ret = WIZCHIP_EXPORT(sendto)(0, (byte*)buf, len, ip, 11); // dummy port
+ if (ret != len) {
+ printf("wiznet5k_send_ethernet: fatal error %d\n", ret);
+ netif_set_link_down(&self->netif);
+ netif_set_down(&self->netif);
+ }
+}
+
+// Stores the frame in self->eth_frame and returns number of bytes in the frame, 0 for no frame
+STATIC uint16_t wiznet5k_recv_ethernet(wiznet5k_obj_t *self) {
+ uint16_t len = getSn_RX_RSR(0);
+ if (len == 0) {
+ return 0;
+ }
+
+ byte ip[4];
+ uint16_t port;
+ int ret = WIZCHIP_EXPORT(recvfrom)(0, self->eth_frame, 1514, ip, &port);
+ if (ret <= 0) {
+ printf("wiznet5k_lwip_poll: fatal error len=%u ret=%d\n", len, ret);
+ netif_set_link_down(&self->netif);
+ netif_set_down(&self->netif);
+ return 0;
+ }
+
+ return ret;
+}
+
+/*******************************************************************************/
+// Wiznet5k lwIP interface
+
+STATIC err_t wiznet5k_netif_output(struct netif *netif, struct pbuf *p) {
+ wiznet5k_obj_t *self = netif->state;
+ pbuf_copy_partial(p, self->eth_frame, p->tot_len, 0);
+ wiznet5k_send_ethernet(self, p->tot_len, self->eth_frame);
+ return ERR_OK;
+}
+
+STATIC err_t wiznet5k_netif_init(struct netif *netif) {
+ netif->linkoutput = wiznet5k_netif_output;
+ netif->output = etharp_output;
+ netif->mtu = 1500;
+ netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET | NETIF_FLAG_IGMP;
+ wiznet5k_get_mac_address(netif->state, netif->hwaddr);
+ netif->hwaddr_len = sizeof(netif->hwaddr);
+ int ret = WIZCHIP_EXPORT(socket)(0, Sn_MR_MACRAW, 0, 0);
+ if (ret != 0) {
+ printf("WIZNET fatal error in netifinit: %d\n", ret);
+ return ERR_IF;
+ }
+
+ // Enable MAC filtering so we only get frames destined for us, to reduce load on lwIP
+ setSn_MR(0, getSn_MR(0) | Sn_MR_MFEN);
+
+ return ERR_OK;
+}
+
+STATIC void wiznet5k_lwip_init(wiznet5k_obj_t *self) {
+ ip_addr_t ipconfig[4];
+ ipconfig[0].addr = 0;
+ ipconfig[1].addr = 0;
+ ipconfig[2].addr = 0;
+ ipconfig[3].addr = 0;
+ netif_add(&self->netif, &ipconfig[0], &ipconfig[1], &ipconfig[2], self, wiznet5k_netif_init, ethernet_input);
+ self->netif.name[0] = 'e';
+ self->netif.name[1] = '0';
+ netif_set_default(&self->netif);
+ dns_setserver(0, &ipconfig[3]);
+ dhcp_set_struct(&self->netif, &self->dhcp_struct);
+ // Setting NETIF_FLAG_UP then clearing it is a workaround for dhcp_start and the
+ // LWIP_DHCP_CHECK_LINK_UP option, so that the DHCP client schedules itself to
+ // automatically start when the interface later goes up.
+ self->netif.flags |= NETIF_FLAG_UP;
+ dhcp_start(&self->netif);
+ self->netif.flags &= ~NETIF_FLAG_UP;
+}
+
+STATIC void wiznet5k_lwip_poll(void *self_in, struct netif *netif) {
+ wiznet5k_obj_t *self = self_in;
+ uint16_t len;
+ while ((len = wiznet5k_recv_ethernet(self)) > 0) {
+ struct pbuf *p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL);
+ if (p != NULL) {
+ pbuf_take(p, self->eth_frame, len);
+ if (self->netif.input(p, &self->netif) != ERR_OK) {
+ pbuf_free(p);
+ }
+ }
+ }
+}
+
+/*******************************************************************************/
+// MicroPython bindings
+
+// WIZNET5K([spi, pin_cs, pin_rst])
+STATIC mp_obj_t wiznet5k_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
+ // check arguments
+ mp_arg_check_num(n_args, n_kw, 3, 3, false);
+
+ const spi_t *spi = spi_from_mp_obj(args[0]);
+ mp_hal_pin_obj_t cs = pin_find(args[1]);
+ mp_hal_pin_obj_t rst = pin_find(args[2]);
+
+ // Access the existing object, if it has been constructed with the same hardware interface
+ if (wiznet5k_obj.base.base.type == &mod_network_nic_type_wiznet5k) {
+ if (!(wiznet5k_obj.spi == spi && wiznet5k_obj.cs == cs && wiznet5k_obj.rst == rst
+ && wiznet5k_obj.netif.flags != 0)) {
+ wiznet5k_deinit();
+ }
+ }
+
+ // Init the wiznet5k object
+ wiznet5k_obj.base.base.type = &mod_network_nic_type_wiznet5k;
+ wiznet5k_obj.base.poll_callback = wiznet5k_lwip_poll;
+ wiznet5k_obj.cris_state = 0;
+ wiznet5k_obj.spi = spi;
+ wiznet5k_obj.cs = cs;
+ wiznet5k_obj.rst = rst;
+
+ // Return wiznet5k object
+ return MP_OBJ_FROM_PTR(&wiznet5k_obj);
+}
+
+STATIC mp_obj_t wiznet5k_regs(mp_obj_t self_in) {
+ (void)self_in;
+ printf("Wiz CREG:");
+ for (int i = 0; i < 0x50; ++i) {
+ if (i % 16 == 0) {
+ printf("\n %04x:", i);
+ }
+ #if MICROPY_PY_WIZNET5K == 5200
+ uint32_t reg = i;
+ #else
+ uint32_t reg = _W5500_IO_BASE_ | i << 8;
+ #endif
+ printf(" %02x", WIZCHIP_READ(reg));
+ }
+ for (int sn = 0; sn < 4; ++sn) {
+ printf("\nWiz SREG[%d]:", sn);
+ for (int i = 0; i < 0x30; ++i) {
+ if (i % 16 == 0) {
+ printf("\n %04x:", i);
+ }
+ #if MICROPY_PY_WIZNET5K == 5200
+ uint32_t reg = WIZCHIP_SREG_ADDR(sn, i);
+ #else
+ uint32_t reg = _W5500_IO_BASE_ | i << 8 | WIZCHIP_SREG_BLOCK(sn) << 3;
+ #endif
+ printf(" %02x", WIZCHIP_READ(reg));
+ }
+ }
+ printf("\n");
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(wiznet5k_regs_obj, wiznet5k_regs);
+
+STATIC mp_obj_t wiznet5k_isconnected(mp_obj_t self_in) {
+ wiznet5k_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ return mp_obj_new_bool(
+ wizphy_getphylink() == PHY_LINK_ON
+ && (self->netif.flags & NETIF_FLAG_UP)
+ && self->netif.ip_addr.addr != 0
+ );
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(wiznet5k_isconnected_obj, wiznet5k_isconnected);
+
+STATIC mp_obj_t wiznet5k_active(size_t n_args, const mp_obj_t *args) {
+ wiznet5k_obj_t *self = MP_OBJ_TO_PTR(args[0]);
+ if (n_args == 1) {
+ return mp_obj_new_bool(self->netif.flags & NETIF_FLAG_UP);
+ } else {
+ if (mp_obj_is_true(args[1])) {
+ if (!(self->netif.flags & NETIF_FLAG_UP)) {
+ wiznet5k_init();
+ netif_set_link_up(&self->netif);
+ netif_set_up(&self->netif);
+ }
+ } else {
+ if (self->netif.flags & NETIF_FLAG_UP) {
+ netif_set_down(&self->netif);
+ netif_set_link_down(&self->netif);
+ wiznet5k_deinit();
+ }
+ }
+ return mp_const_none;
+ }
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(wiznet5k_active_obj, 1, 2, wiznet5k_active);
+
+STATIC mp_obj_t wiznet5k_ifconfig(size_t n_args, const mp_obj_t *args) {
+ wiznet5k_obj_t *self = MP_OBJ_TO_PTR(args[0]);
+ return mod_network_nic_ifconfig(&self->netif, n_args - 1, args + 1);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(wiznet5k_ifconfig_obj, 1, 2, wiznet5k_ifconfig);
+
+STATIC mp_obj_t wiznet5k_status(size_t n_args, const mp_obj_t *args) {
+ wiznet5k_obj_t *self = MP_OBJ_TO_PTR(args[0]);
+ (void)self;
+
+ if (n_args == 1) {
+ // No arguments: return link status
+ if (self->netif.flags && wizphy_getphylink() == PHY_LINK_ON) {
+ if ((self->netif.flags & NETIF_FLAG_UP) && self->netif.ip_addr.addr != 0) {
+ return MP_OBJ_NEW_SMALL_INT(2);
+ } else {
+ return MP_OBJ_NEW_SMALL_INT(1);
+ }
+ } else {
+ return MP_OBJ_NEW_SMALL_INT(0);
+ }
+ }
+
+ mp_raise_ValueError("unknown config param");
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(wiznet5k_status_obj, 1, 2, wiznet5k_status);
+
+STATIC mp_obj_t wiznet5k_config(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) {
+ wiznet5k_obj_t *self = MP_OBJ_TO_PTR(args[0]);
+
+ if (kwargs->used == 0) {
+ // Get config value
+ if (n_args != 2) {
+ mp_raise_TypeError("must query one param");
+ }
+
+ switch (mp_obj_str_get_qstr(args[1])) {
+ case MP_QSTR_mac: {
+ uint8_t buf[6];
+ wiznet5k_get_mac_address(self, buf);
+ return mp_obj_new_bytes(buf, 6);
+ }
+ default:
+ mp_raise_ValueError("unknown config param");
+ }
+ } else {
+ // Set config value(s)
+ if (n_args != 1) {
+ mp_raise_TypeError("can't specify pos and kw args");
+ }
+ mp_raise_ValueError("unknown config param");
+ }
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(wiznet5k_config_obj, 1, wiznet5k_config);
+
+STATIC mp_obj_t send_ethernet_wrapper(mp_obj_t self_in, mp_obj_t buf_in) {
+ wiznet5k_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ mp_buffer_info_t buf;
+ mp_get_buffer_raise(buf_in, &buf, MP_BUFFER_READ);
+ wiznet5k_send_ethernet(self, buf.len, buf.buf);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(send_ethernet_obj, send_ethernet_wrapper);
+
+STATIC const mp_rom_map_elem_t wiznet5k_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_regs), MP_ROM_PTR(&wiznet5k_regs_obj) },
+ { MP_ROM_QSTR(MP_QSTR_isconnected), MP_ROM_PTR(&wiznet5k_isconnected_obj) },
+ { MP_ROM_QSTR(MP_QSTR_active), MP_ROM_PTR(&wiznet5k_active_obj) },
+ { MP_ROM_QSTR(MP_QSTR_ifconfig), MP_ROM_PTR(&wiznet5k_ifconfig_obj) },
+ { MP_ROM_QSTR(MP_QSTR_status), MP_ROM_PTR(&wiznet5k_status_obj) },
+ { MP_ROM_QSTR(MP_QSTR_config), MP_ROM_PTR(&wiznet5k_config_obj) },
+
+ { MP_ROM_QSTR(MP_QSTR_send_ethernet), MP_ROM_PTR(&send_ethernet_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(wiznet5k_locals_dict, wiznet5k_locals_dict_table);
+
+const mp_obj_type_t mod_network_nic_type_wiznet5k = {
+ { &mp_type_type },
+ .name = MP_QSTR_WIZNET5K,
+ .make_new = wiznet5k_make_new,
+ .locals_dict = (mp_obj_dict_t*)&wiznet5k_locals_dict,
+};
+
+#endif // MICROPY_PY_WIZNET5K && MICROPY_PY_LWIP
diff --git a/ports/stm32/pendsv.c b/ports/stm32/pendsv.c
index 0aeb1a6dc..b5fe42f70 100644
--- a/ports/stm32/pendsv.c
+++ b/ports/stm32/pendsv.c
@@ -40,7 +40,7 @@ void *pendsv_object;
void pendsv_init(void) {
// set PendSV interrupt at lowest priority
- HAL_NVIC_SetPriority(PendSV_IRQn, IRQ_PRI_PENDSV, IRQ_SUBPRI_PENDSV);
+ NVIC_SetPriority(PendSV_IRQn, IRQ_PRI_PENDSV);
}
// Call this function to raise a pending exception during an interrupt.
diff --git a/ports/stm32/pendsv.h b/ports/stm32/pendsv.h
index 6a9eb0d79..0d9fde687 100644
--- a/ports/stm32/pendsv.h
+++ b/ports/stm32/pendsv.h
@@ -23,8 +23,8 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
-#ifndef MICROPY_INCLUDED_STMHAL_PENDSV_H
-#define MICROPY_INCLUDED_STMHAL_PENDSV_H
+#ifndef MICROPY_INCLUDED_STM32_PENDSV_H
+#define MICROPY_INCLUDED_STM32_PENDSV_H
void pendsv_init(void);
void pendsv_kbd_intr(void);
@@ -33,4 +33,4 @@ void pendsv_kbd_intr(void);
// prelude for this function
void pendsv_isr_handler(void) __attribute__((naked));
-#endif // MICROPY_INCLUDED_STMHAL_PENDSV_H
+#endif // MICROPY_INCLUDED_STM32_PENDSV_H
diff --git a/ports/stm32/pin.c b/ports/stm32/pin.c
index ee2d84646..fbd3f00c1 100644
--- a/ports/stm32/pin.c
+++ b/ports/stm32/pin.c
@@ -376,7 +376,7 @@ STATIC mp_obj_t pin_obj_init_helper(const pin_obj_t *self, size_t n_args, const
GPIO_InitStructure.Pin = self->pin_mask;
GPIO_InitStructure.Mode = mode;
GPIO_InitStructure.Pull = pull;
- GPIO_InitStructure.Speed = GPIO_SPEED_FAST;
+ GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_HIGH;
GPIO_InitStructure.Alternate = af;
HAL_GPIO_Init(self->gpio, &GPIO_InitStructure);
diff --git a/ports/stm32/pin.h b/ports/stm32/pin.h
index 90de79e5c..ea57b0a27 100644
--- a/ports/stm32/pin.h
+++ b/ports/stm32/pin.h
@@ -23,8 +23,8 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
-#ifndef MICROPY_INCLUDED_STMHAL_PIN_H
-#define MICROPY_INCLUDED_STMHAL_PIN_H
+#ifndef MICROPY_INCLUDED_STM32_PIN_H
+#define MICROPY_INCLUDED_STM32_PIN_H
// This file requires pin_defs_xxx.h (which has port specific enums and
// defines, so we include it here. It should never be included directly
@@ -39,12 +39,7 @@ typedef struct {
uint8_t fn;
uint8_t unit;
uint8_t type;
-
- union {
- void *reg;
-
- PIN_DEFS_PORT_AF_UNION
- };
+ void *reg; // The peripheral associated with this AF
} pin_af_obj_t;
typedef struct {
@@ -63,6 +58,9 @@ typedef struct {
extern const mp_obj_type_t pin_type;
extern const mp_obj_type_t pin_af_type;
+// Include all of the individual pin objects
+#include "genhdr/pins.h"
+
typedef struct {
const char *name;
const pin_obj_t *pin;
@@ -97,4 +95,4 @@ const pin_af_obj_t *pin_find_af(const pin_obj_t *pin, uint8_t fn, uint8_t unit);
const pin_af_obj_t *pin_find_af_by_index(const pin_obj_t *pin, mp_uint_t af_idx);
const pin_af_obj_t *pin_find_af_by_name(const pin_obj_t *pin, const char *name);
-#endif // MICROPY_INCLUDED_STMHAL_PIN_H
+#endif // MICROPY_INCLUDED_STM32_PIN_H
diff --git a/ports/stm32/pin_defs_stm32.h b/ports/stm32/pin_defs_stm32.h
index c5b286283..5c5c6be69 100644
--- a/ports/stm32/pin_defs_stm32.h
+++ b/ports/stm32/pin_defs_stm32.h
@@ -49,6 +49,7 @@ enum {
AF_FN_SPI,
AF_FN_I2S,
AF_FN_SDMMC,
+ AF_FN_CAN,
};
enum {
@@ -93,6 +94,9 @@ enum {
AF_PIN_TYPE_SDMMC_D1,
AF_PIN_TYPE_SDMMC_D2,
AF_PIN_TYPE_SDMMC_D3,
+
+ AF_PIN_TYPE_CAN_TX = 0,
+ AF_PIN_TYPE_CAN_RX,
};
// The HAL uses a slightly different naming than we chose, so we provide
@@ -115,17 +119,5 @@ enum {
PIN_ADC3 = (1 << 2),
};
-// Note that SPI and I2S are really the same peripheral as far as the HAL
-// is concerned, so there is no I2S_TypeDef.
-// We use void* for SDMMC because not all MCUs have the SDMMC_TypeDef type.
-#define PIN_DEFS_PORT_AF_UNION \
- TIM_TypeDef *TIM; \
- I2C_TypeDef *I2C; \
- USART_TypeDef *USART; \
- USART_TypeDef *UART; \
- SPI_TypeDef *SPI;\
- SPI_TypeDef *I2S; \
- void *SDMMC; \
-
typedef GPIO_TypeDef pin_gpio_t;
diff --git a/ports/stm32/portmodules.h b/ports/stm32/portmodules.h
index b575109b8..81cb7fd04 100644
--- a/ports/stm32/portmodules.h
+++ b/ports/stm32/portmodules.h
@@ -23,8 +23,8 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
-#ifndef MICROPY_INCLUDED_STMHAL_PORTMODULES_H
-#define MICROPY_INCLUDED_STMHAL_PORTMODULES_H
+#ifndef MICROPY_INCLUDED_STM32_PORTMODULES_H
+#define MICROPY_INCLUDED_STM32_PORTMODULES_H
extern const mp_obj_module_t pyb_module;
extern const mp_obj_module_t stm_module;
@@ -40,4 +40,4 @@ MP_DECLARE_CONST_FUN_OBJ_1(time_sleep_us_obj);
MP_DECLARE_CONST_FUN_OBJ_0(mod_os_sync_obj);
MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mod_os_dupterm_obj);
-#endif // MICROPY_INCLUDED_STMHAL_PORTMODULES_H
+#endif // MICROPY_INCLUDED_STM32_PORTMODULES_H
diff --git a/ports/stm32/pyb_i2c.c b/ports/stm32/pyb_i2c.c
new file mode 100644
index 000000000..33aaa48cb
--- /dev/null
+++ b/ports/stm32/pyb_i2c.c
@@ -0,0 +1,1068 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2013, 2014 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include "py/runtime.h"
+#include "py/mphal.h"
+#include "irq.h"
+#include "pin.h"
+#include "bufhelper.h"
+#include "dma.h"
+#include "i2c.h"
+
+#if MICROPY_PY_PYB_LEGACY && MICROPY_HW_ENABLE_HW_I2C
+
+/// \moduleref pyb
+/// \class I2C - a two-wire serial protocol
+///
+/// I2C is a two-wire protocol for communicating between devices. At the physical
+/// level it consists of 2 wires: SCL and SDA, the clock and data lines respectively.
+///
+/// I2C objects are created attached to a specific bus. They can be initialised
+/// when created, or initialised later on:
+///
+/// from pyb import I2C
+///
+/// i2c = I2C(1) # create on bus 1
+/// i2c = I2C(1, I2C.MASTER) # create and init as a master
+/// i2c.init(I2C.MASTER, baudrate=20000) # init as a master
+/// i2c.init(I2C.SLAVE, addr=0x42) # init as a slave with given address
+/// i2c.deinit() # turn off the peripheral
+///
+/// Printing the i2c object gives you information about its configuration.
+///
+/// Basic methods for slave are send and recv:
+///
+/// i2c.send('abc') # send 3 bytes
+/// i2c.send(0x42) # send a single byte, given by the number
+/// data = i2c.recv(3) # receive 3 bytes
+///
+/// To receive inplace, first create a bytearray:
+///
+/// data = bytearray(3) # create a buffer
+/// i2c.recv(data) # receive 3 bytes, writing them into data
+///
+/// You can specify a timeout (in ms):
+///
+/// i2c.send(b'123', timeout=2000) # timout after 2 seconds
+///
+/// A master must specify the recipient's address:
+///
+/// i2c.init(I2C.MASTER)
+/// i2c.send('123', 0x42) # send 3 bytes to slave with address 0x42
+/// i2c.send(b'456', addr=0x42) # keyword for address
+///
+/// Master also has other methods:
+///
+/// i2c.is_ready(0x42) # check if slave 0x42 is ready
+/// i2c.scan() # scan for slaves on the bus, returning
+/// # a list of valid addresses
+/// i2c.mem_read(3, 0x42, 2) # read 3 bytes from memory of slave 0x42,
+/// # starting at address 2 in the slave
+/// i2c.mem_write('abc', 0x42, 2, timeout=1000)
+#define PYB_I2C_MASTER (0)
+#define PYB_I2C_SLAVE (1)
+
+#define PYB_I2C_SPEED_STANDARD (100000L)
+#define PYB_I2C_SPEED_FULL (400000L)
+#define PYB_I2C_SPEED_FAST (1000000L)
+
+#if defined(MICROPY_HW_I2C1_SCL)
+I2C_HandleTypeDef I2CHandle1 = {.Instance = NULL};
+#endif
+#if defined(MICROPY_HW_I2C2_SCL)
+I2C_HandleTypeDef I2CHandle2 = {.Instance = NULL};
+#endif
+#if defined(MICROPY_HW_I2C3_SCL)
+I2C_HandleTypeDef I2CHandle3 = {.Instance = NULL};
+#endif
+#if defined(MICROPY_HW_I2C4_SCL)
+I2C_HandleTypeDef I2CHandle4 = {.Instance = NULL};
+#endif
+
+STATIC bool pyb_i2c_use_dma[4];
+
+const pyb_i2c_obj_t pyb_i2c_obj[] = {
+ #if defined(MICROPY_HW_I2C1_SCL)
+ {{&pyb_i2c_type}, &I2CHandle1, &dma_I2C_1_TX, &dma_I2C_1_RX, &pyb_i2c_use_dma[0]},
+ #else
+ {{&pyb_i2c_type}, NULL, NULL, NULL, NULL},
+ #endif
+ #if defined(MICROPY_HW_I2C2_SCL)
+ {{&pyb_i2c_type}, &I2CHandle2, &dma_I2C_2_TX, &dma_I2C_2_RX, &pyb_i2c_use_dma[1]},
+ #else
+ {{&pyb_i2c_type}, NULL, NULL, NULL, NULL},
+ #endif
+ #if defined(MICROPY_HW_I2C3_SCL)
+ {{&pyb_i2c_type}, &I2CHandle3, &dma_I2C_3_TX, &dma_I2C_3_RX, &pyb_i2c_use_dma[2]},
+ #else
+ {{&pyb_i2c_type}, NULL, NULL, NULL, NULL},
+ #endif
+ #if defined(MICROPY_HW_I2C4_SCL)
+ {{&pyb_i2c_type}, &I2CHandle4, &dma_I2C_4_TX, &dma_I2C_4_RX, &pyb_i2c_use_dma[3]},
+ #else
+ {{&pyb_i2c_type}, NULL, NULL, NULL, NULL},
+ #endif
+};
+
+#if defined(STM32F7) || defined(STM32L4) || defined(STM32H7)
+
+// The STM32F0, F3, F7, H7 and L4 use a TIMINGR register rather than ClockSpeed and
+// DutyCycle.
+
+#if defined(STM32F746xx)
+
+// The value 0x40912732 was obtained from the DISCOVERY_I2Cx_TIMING constant
+// defined in the STM32F7Cube file Drivers/BSP/STM32F746G-Discovery/stm32f7456g_discovery.h
+#define MICROPY_HW_I2C_BAUDRATE_TIMING { \
+ {PYB_I2C_SPEED_STANDARD, 0x40912732}, \
+ {PYB_I2C_SPEED_FULL, 0x10911823}, \
+ {PYB_I2C_SPEED_FAST, 0x00611116}, \
+ }
+#define MICROPY_HW_I2C_BAUDRATE_DEFAULT (PYB_I2C_SPEED_FULL)
+#define MICROPY_HW_I2C_BAUDRATE_MAX (PYB_I2C_SPEED_FAST)
+
+#elif defined(STM32F722xx) || defined(STM32F723xx) \
+ || defined(STM32F732xx) || defined(STM32F733xx) \
+ || defined(STM32F767xx) || defined(STM32F769xx)
+
+// These timing values are for f_I2CCLK=54MHz and are only approximate
+#define MICROPY_HW_I2C_BAUDRATE_TIMING { \
+ {PYB_I2C_SPEED_STANDARD, 0xb0420f13}, \
+ {PYB_I2C_SPEED_FULL, 0x70330309}, \
+ {PYB_I2C_SPEED_FAST, 0x50100103}, \
+ }
+#define MICROPY_HW_I2C_BAUDRATE_DEFAULT (PYB_I2C_SPEED_FULL)
+#define MICROPY_HW_I2C_BAUDRATE_MAX (PYB_I2C_SPEED_FAST)
+
+#elif defined(STM32H7)
+
+// I2C TIMINGs obtained from the STHAL examples.
+#define MICROPY_HW_I2C_BAUDRATE_TIMING { \
+ {PYB_I2C_SPEED_STANDARD, 0x40604E73}, \
+ {PYB_I2C_SPEED_FULL, 0x00901954}, \
+ {PYB_I2C_SPEED_FAST, 0x10810915}, \
+ }
+#define MICROPY_HW_I2C_BAUDRATE_DEFAULT (PYB_I2C_SPEED_FULL)
+#define MICROPY_HW_I2C_BAUDRATE_MAX (PYB_I2C_SPEED_FAST)
+
+#elif defined(STM32L4)
+
+// The value 0x90112626 was obtained from the DISCOVERY_I2C1_TIMING constant
+// defined in the STM32L4Cube file Drivers/BSP/STM32L476G-Discovery/stm32l476g_discovery.h
+#define MICROPY_HW_I2C_BAUDRATE_TIMING {{PYB_I2C_SPEED_STANDARD, 0x90112626}}
+#define MICROPY_HW_I2C_BAUDRATE_DEFAULT (PYB_I2C_SPEED_STANDARD)
+#define MICROPY_HW_I2C_BAUDRATE_MAX (PYB_I2C_SPEED_STANDARD)
+
+#else
+#error "no I2C timings for this MCU"
+#endif
+
+STATIC const struct {
+ uint32_t baudrate;
+ uint32_t timing;
+} pyb_i2c_baudrate_timing[] = MICROPY_HW_I2C_BAUDRATE_TIMING;
+
+#define NUM_BAUDRATE_TIMINGS MP_ARRAY_SIZE(pyb_i2c_baudrate_timing)
+
+STATIC void i2c_set_baudrate(I2C_InitTypeDef *init, uint32_t baudrate) {
+ for (int i = 0; i < NUM_BAUDRATE_TIMINGS; i++) {
+ if (pyb_i2c_baudrate_timing[i].baudrate == baudrate) {
+ init->Timing = pyb_i2c_baudrate_timing[i].timing;
+ return;
+ }
+ }
+ nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError,
+ "Unsupported I2C baudrate: %u", baudrate));
+}
+
+uint32_t pyb_i2c_get_baudrate(I2C_HandleTypeDef *i2c) {
+ for (int i = 0; i < NUM_BAUDRATE_TIMINGS; i++) {
+ if (pyb_i2c_baudrate_timing[i].timing == i2c->Init.Timing) {
+ return pyb_i2c_baudrate_timing[i].baudrate;
+ }
+ }
+ return 0;
+}
+
+#else
+
+#define MICROPY_HW_I2C_BAUDRATE_DEFAULT (PYB_I2C_SPEED_FULL)
+#define MICROPY_HW_I2C_BAUDRATE_MAX (PYB_I2C_SPEED_FULL)
+
+STATIC void i2c_set_baudrate(I2C_InitTypeDef *init, uint32_t baudrate) {
+ init->ClockSpeed = baudrate;
+ init->DutyCycle = I2C_DUTYCYCLE_16_9;
+}
+
+uint32_t pyb_i2c_get_baudrate(I2C_HandleTypeDef *i2c) {
+ uint32_t pfreq = i2c->Instance->CR2 & 0x3f;
+ uint32_t ccr = i2c->Instance->CCR & 0xfff;
+ if (i2c->Instance->CCR & 0x8000) {
+ // Fast mode, assume duty cycle of 16/9
+ return pfreq * 40000 / ccr;
+ } else {
+ // Standard mode
+ return pfreq * 500000 / ccr;
+ }
+}
+
+#endif
+
+void i2c_init0(void) {
+ // Initialise the I2C handles.
+ // The structs live on the BSS so all other fields will be zero after a reset.
+ #if defined(MICROPY_HW_I2C1_SCL)
+ I2CHandle1.Instance = I2C1;
+ #endif
+ #if defined(MICROPY_HW_I2C2_SCL)
+ I2CHandle2.Instance = I2C2;
+ #endif
+ #if defined(MICROPY_HW_I2C3_SCL)
+ I2CHandle3.Instance = I2C3;
+ #endif
+ #if defined(MICROPY_HW_I2C4_SCL)
+ I2CHandle4.Instance = I2C4;
+ #endif
+}
+
+void pyb_i2c_init(I2C_HandleTypeDef *i2c) {
+ int i2c_unit;
+ const pin_obj_t *scl_pin;
+ const pin_obj_t *sda_pin;
+
+ if (0) {
+ #if defined(MICROPY_HW_I2C1_SCL)
+ } else if (i2c == &I2CHandle1) {
+ i2c_unit = 1;
+ scl_pin = MICROPY_HW_I2C1_SCL;
+ sda_pin = MICROPY_HW_I2C1_SDA;
+ __HAL_RCC_I2C1_CLK_ENABLE();
+ #endif
+ #if defined(MICROPY_HW_I2C2_SCL)
+ } else if (i2c == &I2CHandle2) {
+ i2c_unit = 2;
+ scl_pin = MICROPY_HW_I2C2_SCL;
+ sda_pin = MICROPY_HW_I2C2_SDA;
+ __HAL_RCC_I2C2_CLK_ENABLE();
+ #endif
+ #if defined(MICROPY_HW_I2C3_SCL)
+ } else if (i2c == &I2CHandle3) {
+ i2c_unit = 3;
+ scl_pin = MICROPY_HW_I2C3_SCL;
+ sda_pin = MICROPY_HW_I2C3_SDA;
+ __HAL_RCC_I2C3_CLK_ENABLE();
+ #endif
+ #if defined(MICROPY_HW_I2C4_SCL)
+ } else if (i2c == &I2CHandle4) {
+ i2c_unit = 4;
+ scl_pin = MICROPY_HW_I2C4_SCL;
+ sda_pin = MICROPY_HW_I2C4_SDA;
+ __HAL_RCC_I2C4_CLK_ENABLE();
+ #endif
+ } else {
+ // I2C does not exist for this board (shouldn't get here, should be checked by caller)
+ return;
+ }
+
+ // init the GPIO lines
+ uint32_t mode = MP_HAL_PIN_MODE_ALT_OPEN_DRAIN;
+ uint32_t pull = MP_HAL_PIN_PULL_NONE; // have external pull-up resistors on both lines
+ mp_hal_pin_config_alt(scl_pin, mode, pull, AF_FN_I2C, i2c_unit);
+ mp_hal_pin_config_alt(sda_pin, mode, pull, AF_FN_I2C, i2c_unit);
+
+ // init the I2C device
+ if (HAL_I2C_Init(i2c) != HAL_OK) {
+ // init error
+ // TODO should raise an exception, but this function is not necessarily going to be
+ // called via Python, so may not be properly wrapped in an NLR handler
+ printf("OSError: HAL_I2C_Init failed\n");
+ return;
+ }
+
+ // invalidate the DMA channels so they are initialised on first use
+ const pyb_i2c_obj_t *self = &pyb_i2c_obj[i2c_unit - 1];
+ dma_invalidate_channel(self->tx_dma_descr);
+ dma_invalidate_channel(self->rx_dma_descr);
+
+ if (0) {
+ #if defined(MICROPY_HW_I2C1_SCL)
+ } else if (i2c->Instance == I2C1) {
+ HAL_NVIC_EnableIRQ(I2C1_EV_IRQn);
+ HAL_NVIC_EnableIRQ(I2C1_ER_IRQn);
+ #endif
+ #if defined(MICROPY_HW_I2C2_SCL)
+ } else if (i2c->Instance == I2C2) {
+ HAL_NVIC_EnableIRQ(I2C2_EV_IRQn);
+ HAL_NVIC_EnableIRQ(I2C2_ER_IRQn);
+ #endif
+ #if defined(MICROPY_HW_I2C3_SCL)
+ } else if (i2c->Instance == I2C3) {
+ HAL_NVIC_EnableIRQ(I2C3_EV_IRQn);
+ HAL_NVIC_EnableIRQ(I2C3_ER_IRQn);
+ #endif
+ #if defined(MICROPY_HW_I2C4_SCL)
+ } else if (i2c->Instance == I2C4) {
+ HAL_NVIC_EnableIRQ(I2C4_EV_IRQn);
+ HAL_NVIC_EnableIRQ(I2C4_ER_IRQn);
+ #endif
+ }
+}
+
+void i2c_deinit(I2C_HandleTypeDef *i2c) {
+ HAL_I2C_DeInit(i2c);
+ if (0) {
+ #if defined(MICROPY_HW_I2C1_SCL)
+ } else if (i2c->Instance == I2C1) {
+ __HAL_RCC_I2C1_FORCE_RESET();
+ __HAL_RCC_I2C1_RELEASE_RESET();
+ __HAL_RCC_I2C1_CLK_DISABLE();
+ HAL_NVIC_DisableIRQ(I2C1_EV_IRQn);
+ HAL_NVIC_DisableIRQ(I2C1_ER_IRQn);
+ #endif
+ #if defined(MICROPY_HW_I2C2_SCL)
+ } else if (i2c->Instance == I2C2) {
+ __HAL_RCC_I2C2_FORCE_RESET();
+ __HAL_RCC_I2C2_RELEASE_RESET();
+ __HAL_RCC_I2C2_CLK_DISABLE();
+ HAL_NVIC_DisableIRQ(I2C2_EV_IRQn);
+ HAL_NVIC_DisableIRQ(I2C2_ER_IRQn);
+ #endif
+ #if defined(MICROPY_HW_I2C3_SCL)
+ } else if (i2c->Instance == I2C3) {
+ __HAL_RCC_I2C3_FORCE_RESET();
+ __HAL_RCC_I2C3_RELEASE_RESET();
+ __HAL_RCC_I2C3_CLK_DISABLE();
+ HAL_NVIC_DisableIRQ(I2C3_EV_IRQn);
+ HAL_NVIC_DisableIRQ(I2C3_ER_IRQn);
+ #endif
+ #if defined(MICROPY_HW_I2C4_SCL)
+ } else if (i2c->Instance == I2C4) {
+ __HAL_RCC_I2C4_FORCE_RESET();
+ __HAL_RCC_I2C4_RELEASE_RESET();
+ __HAL_RCC_I2C4_CLK_DISABLE();
+ HAL_NVIC_DisableIRQ(I2C4_EV_IRQn);
+ HAL_NVIC_DisableIRQ(I2C4_ER_IRQn);
+ #endif
+ }
+}
+
+void pyb_i2c_init_freq(const pyb_i2c_obj_t *self, mp_int_t freq) {
+ I2C_InitTypeDef *init = &self->i2c->Init;
+
+ init->AddressingMode = I2C_ADDRESSINGMODE_7BIT;
+ init->DualAddressMode = I2C_DUALADDRESS_DISABLED;
+ init->GeneralCallMode = I2C_GENERALCALL_DISABLED;
+ init->NoStretchMode = I2C_NOSTRETCH_DISABLE;
+ init->OwnAddress1 = PYB_I2C_MASTER_ADDRESS;
+ init->OwnAddress2 = 0; // unused
+ if (freq != -1) {
+ i2c_set_baudrate(init, MIN(freq, MICROPY_HW_I2C_BAUDRATE_MAX));
+ }
+
+ *self->use_dma = false;
+
+ // init the I2C bus
+ i2c_deinit(self->i2c);
+ pyb_i2c_init(self->i2c);
+}
+
+STATIC void i2c_reset_after_error(I2C_HandleTypeDef *i2c) {
+ // wait for bus-busy flag to be cleared, with a timeout
+ for (int timeout = 50; timeout > 0; --timeout) {
+ if (!__HAL_I2C_GET_FLAG(i2c, I2C_FLAG_BUSY)) {
+ // stop bit was generated and bus is back to normal
+ return;
+ }
+ mp_hal_delay_ms(1);
+ }
+ // bus was/is busy, need to reset the peripheral to get it to work again
+ i2c_deinit(i2c);
+ pyb_i2c_init(i2c);
+}
+
+void i2c_ev_irq_handler(mp_uint_t i2c_id) {
+ I2C_HandleTypeDef *hi2c;
+
+ switch (i2c_id) {
+ #if defined(MICROPY_HW_I2C1_SCL)
+ case 1:
+ hi2c = &I2CHandle1;
+ break;
+ #endif
+ #if defined(MICROPY_HW_I2C2_SCL)
+ case 2:
+ hi2c = &I2CHandle2;
+ break;
+ #endif
+ #if defined(MICROPY_HW_I2C3_SCL)
+ case 3:
+ hi2c = &I2CHandle3;
+ break;
+ #endif
+ #if defined(MICROPY_HW_I2C4_SCL)
+ case 4:
+ hi2c = &I2CHandle4;
+ break;
+ #endif
+ default:
+ return;
+ }
+
+ #if defined(STM32F4)
+
+ if (hi2c->Instance->SR1 & I2C_FLAG_BTF && hi2c->State == HAL_I2C_STATE_BUSY_TX) {
+ if (hi2c->XferCount != 0U) {
+ hi2c->Instance->DR = *hi2c->pBuffPtr++;
+ hi2c->XferCount--;
+ } else {
+ __HAL_I2C_DISABLE_IT(hi2c, I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR);
+ if (hi2c->XferOptions != I2C_FIRST_FRAME) {
+ hi2c->Instance->CR1 |= I2C_CR1_STOP;
+ }
+ hi2c->Mode = HAL_I2C_MODE_NONE;
+ hi2c->State = HAL_I2C_STATE_READY;
+ }
+ }
+
+ #else
+
+ // if not an F4 MCU, use the HAL's IRQ handler
+ HAL_I2C_EV_IRQHandler(hi2c);
+
+ #endif
+}
+
+void i2c_er_irq_handler(mp_uint_t i2c_id) {
+ I2C_HandleTypeDef *hi2c;
+
+ switch (i2c_id) {
+ #if defined(MICROPY_HW_I2C1_SCL)
+ case 1:
+ hi2c = &I2CHandle1;
+ break;
+ #endif
+ #if defined(MICROPY_HW_I2C2_SCL)
+ case 2:
+ hi2c = &I2CHandle2;
+ break;
+ #endif
+ #if defined(MICROPY_HW_I2C3_SCL)
+ case 3:
+ hi2c = &I2CHandle3;
+ break;
+ #endif
+ #if defined(MICROPY_HW_I2C4_SCL)
+ case 4:
+ hi2c = &I2CHandle4;
+ break;
+ #endif
+ default:
+ return;
+ }
+
+ #if defined(STM32F4)
+
+ uint32_t sr1 = hi2c->Instance->SR1;
+
+ // I2C Bus error
+ if (sr1 & I2C_FLAG_BERR) {
+ hi2c->ErrorCode |= HAL_I2C_ERROR_BERR;
+ __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_BERR);
+ }
+
+ // I2C Arbitration Loss error
+ if (sr1 & I2C_FLAG_ARLO) {
+ hi2c->ErrorCode |= HAL_I2C_ERROR_ARLO;
+ __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_ARLO);
+ }
+
+ // I2C Acknowledge failure
+ if (sr1 & I2C_FLAG_AF) {
+ hi2c->ErrorCode |= HAL_I2C_ERROR_AF;
+ SET_BIT(hi2c->Instance->CR1,I2C_CR1_STOP);
+ __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_AF);
+ }
+
+ // I2C Over-Run/Under-Run
+ if (sr1 & I2C_FLAG_OVR) {
+ hi2c->ErrorCode |= HAL_I2C_ERROR_OVR;
+ __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_OVR);
+ }
+
+ #else
+
+ // if not an F4 MCU, use the HAL's IRQ handler
+ HAL_I2C_ER_IRQHandler(hi2c);
+
+ #endif
+}
+
+STATIC HAL_StatusTypeDef i2c_wait_dma_finished(I2C_HandleTypeDef *i2c, uint32_t timeout) {
+ // Note: we can't use WFI to idle in this loop because the DMA completion
+ // interrupt may occur before the WFI. Hence we miss it and have to wait
+ // until the next sys-tick (up to 1ms).
+ uint32_t start = HAL_GetTick();
+ while (HAL_I2C_GetState(i2c) != HAL_I2C_STATE_READY) {
+ if (HAL_GetTick() - start >= timeout) {
+ return HAL_TIMEOUT;
+ }
+ }
+ return HAL_OK;
+}
+
+/******************************************************************************/
+/* MicroPython bindings */
+
+static inline bool in_master_mode(pyb_i2c_obj_t *self) { return self->i2c->Init.OwnAddress1 == PYB_I2C_MASTER_ADDRESS; }
+
+STATIC void pyb_i2c_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
+ pyb_i2c_obj_t *self = self_in;
+
+ uint i2c_num = 0;
+ if (0) { }
+ #if defined(MICROPY_HW_I2C1_SCL)
+ else if (self->i2c->Instance == I2C1) { i2c_num = 1; }
+ #endif
+ #if defined(MICROPY_HW_I2C2_SCL)
+ else if (self->i2c->Instance == I2C2) { i2c_num = 2; }
+ #endif
+ #if defined(MICROPY_HW_I2C3_SCL)
+ else if (self->i2c->Instance == I2C3) { i2c_num = 3; }
+ #endif
+ #if defined(MICROPY_HW_I2C4_SCL)
+ else if (self->i2c->Instance == I2C4) { i2c_num = 4; }
+ #endif
+
+ if (self->i2c->State == HAL_I2C_STATE_RESET) {
+ mp_printf(print, "I2C(%u)", i2c_num);
+ } else {
+ if (in_master_mode(self)) {
+ mp_printf(print, "I2C(%u, I2C.MASTER, baudrate=%u)", i2c_num, pyb_i2c_get_baudrate(self->i2c));
+ } else {
+ mp_printf(print, "I2C(%u, I2C.SLAVE, addr=0x%02x)", i2c_num, (self->i2c->Instance->OAR1 >> 1) & 0x7f);
+ }
+ }
+}
+
+/// \method init(mode, *, addr=0x12, baudrate=400000, gencall=False)
+///
+/// Initialise the I2C bus with the given parameters:
+///
+/// - `mode` must be either `I2C.MASTER` or `I2C.SLAVE`
+/// - `addr` is the 7-bit address (only sensible for a slave)
+/// - `baudrate` is the SCL clock rate (only sensible for a master)
+/// - `gencall` is whether to support general call mode
+STATIC mp_obj_t pyb_i2c_init_helper(const pyb_i2c_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_mode, MP_ARG_INT, {.u_int = PYB_I2C_MASTER} },
+ { MP_QSTR_addr, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0x12} },
+ { MP_QSTR_baudrate, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = MICROPY_HW_I2C_BAUDRATE_DEFAULT} },
+ { MP_QSTR_gencall, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
+ { MP_QSTR_dma, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
+ };
+
+ // parse args
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ // set the I2C configuration values
+ I2C_InitTypeDef *init = &self->i2c->Init;
+
+ if (args[0].u_int == PYB_I2C_MASTER) {
+ // use a special address to indicate we are a master
+ init->OwnAddress1 = PYB_I2C_MASTER_ADDRESS;
+ } else {
+ init->OwnAddress1 = (args[1].u_int << 1) & 0xfe;
+ }
+
+ i2c_set_baudrate(init, MIN(args[2].u_int, MICROPY_HW_I2C_BAUDRATE_MAX));
+ init->AddressingMode = I2C_ADDRESSINGMODE_7BIT;
+ init->DualAddressMode = I2C_DUALADDRESS_DISABLED;
+ init->GeneralCallMode = args[3].u_bool ? I2C_GENERALCALL_ENABLED : I2C_GENERALCALL_DISABLED;
+ init->OwnAddress2 = 0; // unused
+ init->NoStretchMode = I2C_NOSTRETCH_DISABLE;
+
+ *self->use_dma = args[4].u_bool;
+
+ // init the I2C bus
+ i2c_deinit(self->i2c);
+ pyb_i2c_init(self->i2c);
+
+ return mp_const_none;
+}
+
+/// \classmethod \constructor(bus, ...)
+///
+/// Construct an I2C object on the given bus. `bus` can be 1 or 2.
+/// With no additional parameters, the I2C object is created but not
+/// initialised (it has the settings from the last initialisation of
+/// the bus, if any). If extra arguments are given, the bus is initialised.
+/// See `init` for parameters of initialisation.
+///
+/// The physical pins of the I2C busses are:
+///
+/// - `I2C(1)` is on the X position: `(SCL, SDA) = (X9, X10) = (PB6, PB7)`
+/// - `I2C(2)` is on the Y position: `(SCL, SDA) = (Y9, Y10) = (PB10, PB11)`
+STATIC mp_obj_t pyb_i2c_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
+ // check arguments
+ mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true);
+
+ // work out i2c bus
+ int i2c_id = 0;
+ if (MP_OBJ_IS_STR(args[0])) {
+ const char *port = mp_obj_str_get_str(args[0]);
+ if (0) {
+ #ifdef MICROPY_HW_I2C1_NAME
+ } else if (strcmp(port, MICROPY_HW_I2C1_NAME) == 0) {
+ i2c_id = 1;
+ #endif
+ #ifdef MICROPY_HW_I2C2_NAME
+ } else if (strcmp(port, MICROPY_HW_I2C2_NAME) == 0) {
+ i2c_id = 2;
+ #endif
+ #ifdef MICROPY_HW_I2C3_NAME
+ } else if (strcmp(port, MICROPY_HW_I2C3_NAME) == 0) {
+ i2c_id = 3;
+ #endif
+ #ifdef MICROPY_HW_I2C4_NAME
+ } else if (strcmp(port, MICROPY_HW_I2C4_NAME) == 0) {
+ i2c_id = 4;
+ #endif
+ } else {
+ nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError,
+ "I2C(%s) doesn't exist", port));
+ }
+ } else {
+ i2c_id = mp_obj_get_int(args[0]);
+ if (i2c_id < 1 || i2c_id > MP_ARRAY_SIZE(pyb_i2c_obj)
+ || pyb_i2c_obj[i2c_id - 1].i2c == NULL) {
+ nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError,
+ "I2C(%d) doesn't exist", i2c_id));
+ }
+ }
+
+ // get I2C object
+ const pyb_i2c_obj_t *i2c_obj = &pyb_i2c_obj[i2c_id - 1];
+
+ if (n_args > 1 || n_kw > 0) {
+ // start the peripheral
+ mp_map_t kw_args;
+ mp_map_init_fixed_table(&kw_args, n_kw, args + n_args);
+ pyb_i2c_init_helper(i2c_obj, n_args - 1, args + 1, &kw_args);
+ }
+
+ return (mp_obj_t)i2c_obj;
+}
+
+STATIC mp_obj_t pyb_i2c_init_(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
+ return pyb_i2c_init_helper(args[0], n_args - 1, args + 1, kw_args);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_i2c_init_obj, 1, pyb_i2c_init_);
+
+/// \method deinit()
+/// Turn off the I2C bus.
+STATIC mp_obj_t pyb_i2c_deinit(mp_obj_t self_in) {
+ pyb_i2c_obj_t *self = self_in;
+ i2c_deinit(self->i2c);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_i2c_deinit_obj, pyb_i2c_deinit);
+
+/// \method is_ready(addr)
+/// Check if an I2C device responds to the given address. Only valid when in master mode.
+STATIC mp_obj_t pyb_i2c_is_ready(mp_obj_t self_in, mp_obj_t i2c_addr_o) {
+ pyb_i2c_obj_t *self = self_in;
+
+ if (!in_master_mode(self)) {
+ mp_raise_TypeError("I2C must be a master");
+ }
+
+ mp_uint_t i2c_addr = mp_obj_get_int(i2c_addr_o) << 1;
+
+ for (int i = 0; i < 10; i++) {
+ HAL_StatusTypeDef status = HAL_I2C_IsDeviceReady(self->i2c, i2c_addr, 10, 200);
+ if (status == HAL_OK) {
+ return mp_const_true;
+ }
+ }
+
+ return mp_const_false;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(pyb_i2c_is_ready_obj, pyb_i2c_is_ready);
+
+/// \method scan()
+/// Scan all I2C addresses from 0x08 to 0x77 and return a list of those that respond.
+/// Only valid when in master mode.
+STATIC mp_obj_t pyb_i2c_scan(mp_obj_t self_in) {
+ pyb_i2c_obj_t *self = self_in;
+
+ if (!in_master_mode(self)) {
+ mp_raise_TypeError("I2C must be a master");
+ }
+
+ mp_obj_t list = mp_obj_new_list(0, NULL);
+
+ for (uint addr = 0x08; addr <= 0x77; addr++) {
+ HAL_StatusTypeDef status = HAL_I2C_IsDeviceReady(self->i2c, addr << 1, 1, 200);
+ if (status == HAL_OK) {
+ mp_obj_list_append(list, MP_OBJ_NEW_SMALL_INT(addr));
+ }
+ }
+
+ return list;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_i2c_scan_obj, pyb_i2c_scan);
+
+/// \method send(send, addr=0x00, timeout=5000)
+/// Send data on the bus:
+///
+/// - `send` is the data to send (an integer to send, or a buffer object)
+/// - `addr` is the address to send to (only required in master mode)
+/// - `timeout` is the timeout in milliseconds to wait for the send
+///
+/// Return value: `None`.
+STATIC mp_obj_t pyb_i2c_send(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_send, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+ { MP_QSTR_addr, MP_ARG_INT, {.u_int = PYB_I2C_MASTER_ADDRESS} },
+ { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 5000} },
+ };
+
+ // parse args
+ pyb_i2c_obj_t *self = pos_args[0];
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ // get the buffer to send from
+ mp_buffer_info_t bufinfo;
+ uint8_t data[1];
+ pyb_buf_get_for_send(args[0].u_obj, &bufinfo, data);
+
+ // if option is set and IRQs are enabled then we can use DMA
+ bool use_dma = *self->use_dma && query_irq() == IRQ_STATE_ENABLED;
+
+ DMA_HandleTypeDef tx_dma;
+ if (use_dma) {
+ dma_init(&tx_dma, self->tx_dma_descr, self->i2c);
+ self->i2c->hdmatx = &tx_dma;
+ self->i2c->hdmarx = NULL;
+ }
+
+ // send the data
+ HAL_StatusTypeDef status;
+ if (in_master_mode(self)) {
+ if (args[1].u_int == PYB_I2C_MASTER_ADDRESS) {
+ if (use_dma) {
+ dma_deinit(self->tx_dma_descr);
+ }
+ mp_raise_TypeError("addr argument required");
+ }
+ mp_uint_t i2c_addr = args[1].u_int << 1;
+ if (!use_dma) {
+ status = HAL_I2C_Master_Transmit(self->i2c, i2c_addr, bufinfo.buf, bufinfo.len, args[2].u_int);
+ } else {
+ MP_HAL_CLEAN_DCACHE(bufinfo.buf, bufinfo.len);
+ status = HAL_I2C_Master_Transmit_DMA(self->i2c, i2c_addr, bufinfo.buf, bufinfo.len);
+ }
+ } else {
+ if (!use_dma) {
+ status = HAL_I2C_Slave_Transmit(self->i2c, bufinfo.buf, bufinfo.len, args[2].u_int);
+ } else {
+ MP_HAL_CLEAN_DCACHE(bufinfo.buf, bufinfo.len);
+ status = HAL_I2C_Slave_Transmit_DMA(self->i2c, bufinfo.buf, bufinfo.len);
+ }
+ }
+
+ // if we used DMA, wait for it to finish
+ if (use_dma) {
+ if (status == HAL_OK) {
+ status = i2c_wait_dma_finished(self->i2c, args[2].u_int);
+ }
+ dma_deinit(self->tx_dma_descr);
+ }
+
+ if (status != HAL_OK) {
+ i2c_reset_after_error(self->i2c);
+ mp_hal_raise(status);
+ }
+
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_i2c_send_obj, 1, pyb_i2c_send);
+
+/// \method recv(recv, addr=0x00, timeout=5000)
+///
+/// Receive data on the bus:
+///
+/// - `recv` can be an integer, which is the number of bytes to receive,
+/// or a mutable buffer, which will be filled with received bytes
+/// - `addr` is the address to receive from (only required in master mode)
+/// - `timeout` is the timeout in milliseconds to wait for the receive
+///
+/// Return value: if `recv` is an integer then a new buffer of the bytes received,
+/// otherwise the same buffer that was passed in to `recv`.
+STATIC mp_obj_t pyb_i2c_recv(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_recv, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+ { MP_QSTR_addr, MP_ARG_INT, {.u_int = PYB_I2C_MASTER_ADDRESS} },
+ { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 5000} },
+ };
+
+ // parse args
+ pyb_i2c_obj_t *self = pos_args[0];
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ // get the buffer to receive into
+ vstr_t vstr;
+ mp_obj_t o_ret = pyb_buf_get_for_recv(args[0].u_obj, &vstr);
+
+ // if option is set and IRQs are enabled then we can use DMA
+ bool use_dma = *self->use_dma && query_irq() == IRQ_STATE_ENABLED;
+
+ DMA_HandleTypeDef rx_dma;
+ if (use_dma) {
+ dma_init(&rx_dma, self->rx_dma_descr, self->i2c);
+ self->i2c->hdmatx = NULL;
+ self->i2c->hdmarx = &rx_dma;
+ }
+
+ // receive the data
+ HAL_StatusTypeDef status;
+ if (in_master_mode(self)) {
+ if (args[1].u_int == PYB_I2C_MASTER_ADDRESS) {
+ mp_raise_TypeError("addr argument required");
+ }
+ mp_uint_t i2c_addr = args[1].u_int << 1;
+ if (!use_dma) {
+ status = HAL_I2C_Master_Receive(self->i2c, i2c_addr, (uint8_t*)vstr.buf, vstr.len, args[2].u_int);
+ } else {
+ MP_HAL_CLEANINVALIDATE_DCACHE(vstr.buf, vstr.len);
+ status = HAL_I2C_Master_Receive_DMA(self->i2c, i2c_addr, (uint8_t*)vstr.buf, vstr.len);
+ }
+ } else {
+ if (!use_dma) {
+ status = HAL_I2C_Slave_Receive(self->i2c, (uint8_t*)vstr.buf, vstr.len, args[2].u_int);
+ } else {
+ MP_HAL_CLEANINVALIDATE_DCACHE(vstr.buf, vstr.len);
+ status = HAL_I2C_Slave_Receive_DMA(self->i2c, (uint8_t*)vstr.buf, vstr.len);
+ }
+ }
+
+ // if we used DMA, wait for it to finish
+ if (use_dma) {
+ if (status == HAL_OK) {
+ status = i2c_wait_dma_finished(self->i2c, args[2].u_int);
+ }
+ dma_deinit(self->rx_dma_descr);
+ }
+
+ if (status != HAL_OK) {
+ i2c_reset_after_error(self->i2c);
+ mp_hal_raise(status);
+ }
+
+ // return the received data
+ if (o_ret != MP_OBJ_NULL) {
+ return o_ret;
+ } else {
+ return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
+ }
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_i2c_recv_obj, 1, pyb_i2c_recv);
+
+/// \method mem_read(data, addr, memaddr, timeout=5000, addr_size=8)
+///
+/// Read from the memory of an I2C device:
+///
+/// - `data` can be an integer or a buffer to read into
+/// - `addr` is the I2C device address
+/// - `memaddr` is the memory location within the I2C device
+/// - `timeout` is the timeout in milliseconds to wait for the read
+/// - `addr_size` selects width of memaddr: 8 or 16 bits
+///
+/// Returns the read data.
+/// This is only valid in master mode.
+STATIC const mp_arg_t pyb_i2c_mem_read_allowed_args[] = {
+ { MP_QSTR_data, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+ { MP_QSTR_addr, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} },
+ { MP_QSTR_memaddr, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} },
+ { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 5000} },
+ { MP_QSTR_addr_size, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 8} },
+};
+
+STATIC mp_obj_t pyb_i2c_mem_read(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ // parse args
+ pyb_i2c_obj_t *self = pos_args[0];
+ mp_arg_val_t args[MP_ARRAY_SIZE(pyb_i2c_mem_read_allowed_args)];
+ mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(pyb_i2c_mem_read_allowed_args), pyb_i2c_mem_read_allowed_args, args);
+
+ if (!in_master_mode(self)) {
+ mp_raise_TypeError("I2C must be a master");
+ }
+
+ // get the buffer to read into
+ vstr_t vstr;
+ mp_obj_t o_ret = pyb_buf_get_for_recv(args[0].u_obj, &vstr);
+
+ // get the addresses
+ mp_uint_t i2c_addr = args[1].u_int << 1;
+ mp_uint_t mem_addr = args[2].u_int;
+ // determine width of mem_addr; default is 8 bits, entering any other value gives 16 bit width
+ mp_uint_t mem_addr_size = I2C_MEMADD_SIZE_8BIT;
+ if (args[4].u_int != 8) {
+ mem_addr_size = I2C_MEMADD_SIZE_16BIT;
+ }
+
+ // if option is set and IRQs are enabled then we can use DMA
+ bool use_dma = *self->use_dma && query_irq() == IRQ_STATE_ENABLED;
+
+ HAL_StatusTypeDef status;
+ if (!use_dma) {
+ status = HAL_I2C_Mem_Read(self->i2c, i2c_addr, mem_addr, mem_addr_size, (uint8_t*)vstr.buf, vstr.len, args[3].u_int);
+ } else {
+ DMA_HandleTypeDef rx_dma;
+ dma_init(&rx_dma, self->rx_dma_descr, self->i2c);
+ self->i2c->hdmatx = NULL;
+ self->i2c->hdmarx = &rx_dma;
+ MP_HAL_CLEANINVALIDATE_DCACHE(vstr.buf, vstr.len);
+ status = HAL_I2C_Mem_Read_DMA(self->i2c, i2c_addr, mem_addr, mem_addr_size, (uint8_t*)vstr.buf, vstr.len);
+ if (status == HAL_OK) {
+ status = i2c_wait_dma_finished(self->i2c, args[3].u_int);
+ }
+ dma_deinit(self->rx_dma_descr);
+ }
+
+ if (status != HAL_OK) {
+ i2c_reset_after_error(self->i2c);
+ mp_hal_raise(status);
+ }
+
+ // return the read data
+ if (o_ret != MP_OBJ_NULL) {
+ return o_ret;
+ } else {
+ return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
+ }
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_i2c_mem_read_obj, 1, pyb_i2c_mem_read);
+
+/// \method mem_write(data, addr, memaddr, timeout=5000, addr_size=8)
+///
+/// Write to the memory of an I2C device:
+///
+/// - `data` can be an integer or a buffer to write from
+/// - `addr` is the I2C device address
+/// - `memaddr` is the memory location within the I2C device
+/// - `timeout` is the timeout in milliseconds to wait for the write
+/// - `addr_size` selects width of memaddr: 8 or 16 bits
+///
+/// Returns `None`.
+/// This is only valid in master mode.
+STATIC mp_obj_t pyb_i2c_mem_write(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ // parse args (same as mem_read)
+ pyb_i2c_obj_t *self = pos_args[0];
+ mp_arg_val_t args[MP_ARRAY_SIZE(pyb_i2c_mem_read_allowed_args)];
+ mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(pyb_i2c_mem_read_allowed_args), pyb_i2c_mem_read_allowed_args, args);
+
+ if (!in_master_mode(self)) {
+ mp_raise_TypeError("I2C must be a master");
+ }
+
+ // get the buffer to write from
+ mp_buffer_info_t bufinfo;
+ uint8_t data[1];
+ pyb_buf_get_for_send(args[0].u_obj, &bufinfo, data);
+
+ // get the addresses
+ mp_uint_t i2c_addr = args[1].u_int << 1;
+ mp_uint_t mem_addr = args[2].u_int;
+ // determine width of mem_addr; default is 8 bits, entering any other value gives 16 bit width
+ mp_uint_t mem_addr_size = I2C_MEMADD_SIZE_8BIT;
+ if (args[4].u_int != 8) {
+ mem_addr_size = I2C_MEMADD_SIZE_16BIT;
+ }
+
+ // if option is set and IRQs are enabled then we can use DMA
+ bool use_dma = *self->use_dma && query_irq() == IRQ_STATE_ENABLED;
+
+ HAL_StatusTypeDef status;
+ if (!use_dma) {
+ status = HAL_I2C_Mem_Write(self->i2c, i2c_addr, mem_addr, mem_addr_size, bufinfo.buf, bufinfo.len, args[3].u_int);
+ } else {
+ DMA_HandleTypeDef tx_dma;
+ dma_init(&tx_dma, self->tx_dma_descr, self->i2c);
+ self->i2c->hdmatx = &tx_dma;
+ self->i2c->hdmarx = NULL;
+ MP_HAL_CLEAN_DCACHE(bufinfo.buf, bufinfo.len);
+ status = HAL_I2C_Mem_Write_DMA(self->i2c, i2c_addr, mem_addr, mem_addr_size, bufinfo.buf, bufinfo.len);
+ if (status == HAL_OK) {
+ status = i2c_wait_dma_finished(self->i2c, args[3].u_int);
+ }
+ dma_deinit(self->tx_dma_descr);
+ }
+
+ if (status != HAL_OK) {
+ i2c_reset_after_error(self->i2c);
+ mp_hal_raise(status);
+ }
+
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_i2c_mem_write_obj, 1, pyb_i2c_mem_write);
+
+STATIC const mp_rom_map_elem_t pyb_i2c_locals_dict_table[] = {
+ // instance methods
+ { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&pyb_i2c_init_obj) },
+ { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&pyb_i2c_deinit_obj) },
+ { MP_ROM_QSTR(MP_QSTR_is_ready), MP_ROM_PTR(&pyb_i2c_is_ready_obj) },
+ { MP_ROM_QSTR(MP_QSTR_scan), MP_ROM_PTR(&pyb_i2c_scan_obj) },
+ { MP_ROM_QSTR(MP_QSTR_send), MP_ROM_PTR(&pyb_i2c_send_obj) },
+ { MP_ROM_QSTR(MP_QSTR_recv), MP_ROM_PTR(&pyb_i2c_recv_obj) },
+ { MP_ROM_QSTR(MP_QSTR_mem_read), MP_ROM_PTR(&pyb_i2c_mem_read_obj) },
+ { MP_ROM_QSTR(MP_QSTR_mem_write), MP_ROM_PTR(&pyb_i2c_mem_write_obj) },
+
+ // class constants
+ /// \constant MASTER - for initialising the bus to master mode
+ /// \constant SLAVE - for initialising the bus to slave mode
+ { MP_ROM_QSTR(MP_QSTR_MASTER), MP_ROM_INT(PYB_I2C_MASTER) },
+ { MP_ROM_QSTR(MP_QSTR_SLAVE), MP_ROM_INT(PYB_I2C_SLAVE) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(pyb_i2c_locals_dict, pyb_i2c_locals_dict_table);
+
+const mp_obj_type_t pyb_i2c_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_I2C,
+ .print = pyb_i2c_print,
+ .make_new = pyb_i2c_make_new,
+ .locals_dict = (mp_obj_dict_t*)&pyb_i2c_locals_dict,
+};
+
+#endif // MICROPY_PY_PYB_LEGACY && MICROPY_HW_ENABLE_HW_I2C
diff --git a/ports/stm32/pybthread.h b/ports/stm32/pybthread.h
index f628f934b..42300508c 100644
--- a/ports/stm32/pybthread.h
+++ b/ports/stm32/pybthread.h
@@ -23,8 +23,8 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
-#ifndef MICROPY_INCLUDED_STMHAL_PYBTHREAD_H
-#define MICROPY_INCLUDED_STMHAL_PYBTHREAD_H
+#ifndef MICROPY_INCLUDED_STM32_PYBTHREAD_H
+#define MICROPY_INCLUDED_STM32_PYBTHREAD_H
typedef struct _pyb_thread_t {
void *sp;
@@ -74,4 +74,4 @@ void pyb_mutex_init(pyb_mutex_t *m);
int pyb_mutex_lock(pyb_mutex_t *m, int wait);
void pyb_mutex_unlock(pyb_mutex_t *m);
-#endif // MICROPY_INCLUDED_STMHAL_PYBTHREAD_H
+#endif // MICROPY_INCLUDED_STM32_PYBTHREAD_H
diff --git a/ports/stm32/qspi.c b/ports/stm32/qspi.c
new file mode 100644
index 000000000..a7cbbde01
--- /dev/null
+++ b/ports/stm32/qspi.c
@@ -0,0 +1,282 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <string.h>
+
+#include "py/mperrno.h"
+#include "py/mphal.h"
+#include "qspi.h"
+
+#if defined(MICROPY_HW_QSPIFLASH_SIZE_BITS_LOG2)
+
+void qspi_init(void) {
+ // Configure pins
+ mp_hal_pin_config(MICROPY_HW_QSPIFLASH_CS, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, 10);
+ mp_hal_pin_config(MICROPY_HW_QSPIFLASH_SCK, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, 9);
+ mp_hal_pin_config(MICROPY_HW_QSPIFLASH_IO0, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, 9);
+ mp_hal_pin_config(MICROPY_HW_QSPIFLASH_IO1, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, 9);
+ mp_hal_pin_config(MICROPY_HW_QSPIFLASH_IO2, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, 9);
+ mp_hal_pin_config(MICROPY_HW_QSPIFLASH_IO3, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, 9);
+
+ // Bring up the QSPI peripheral
+
+ __HAL_RCC_QSPI_CLK_ENABLE();
+
+ QUADSPI->CR =
+ 2 << QUADSPI_CR_PRESCALER_Pos // F_CLK = F_AHB/3 (72MHz when CPU is 216MHz)
+ | 3 << QUADSPI_CR_FTHRES_Pos // 4 bytes must be available to read/write
+ #if defined(QUADSPI_CR_FSEL_Pos)
+ | 0 << QUADSPI_CR_FSEL_Pos // FLASH 1 selected
+ #endif
+ #if defined(QUADSPI_CR_DFM_Pos)
+ | 0 << QUADSPI_CR_DFM_Pos // dual-flash mode disabled
+ #endif
+ | 0 << QUADSPI_CR_SSHIFT_Pos // no sample shift
+ | 1 << QUADSPI_CR_TCEN_Pos // timeout counter enabled
+ | 1 << QUADSPI_CR_EN_Pos // enable the peripheral
+ ;
+
+ QUADSPI->DCR =
+ (MICROPY_HW_QSPIFLASH_SIZE_BITS_LOG2 - 3 - 1) << QUADSPI_DCR_FSIZE_Pos
+ | 1 << QUADSPI_DCR_CSHT_Pos // nCS stays high for 2 cycles
+ | 0 << QUADSPI_DCR_CKMODE_Pos // CLK idles at low state
+ ;
+}
+
+void qspi_memory_map(void) {
+ // Enable memory-mapped mode
+
+ QUADSPI->ABR = 0; // disable continuous read mode
+ QUADSPI->LPTR = 100; // to tune
+ QUADSPI->CCR =
+ 0 << QUADSPI_CCR_DDRM_Pos // DDR mode disabled
+ | 0 << QUADSPI_CCR_SIOO_Pos // send instruction every transaction
+ | 3 << QUADSPI_CCR_FMODE_Pos // memory-mapped mode
+ | 3 << QUADSPI_CCR_DMODE_Pos // data on 4 lines
+ | 4 << QUADSPI_CCR_DCYC_Pos // 4 dummy cycles
+ | 0 << QUADSPI_CCR_ABSIZE_Pos // 8-bit alternate byte
+ | 3 << QUADSPI_CCR_ABMODE_Pos // alternate byte on 4 lines
+ | 2 << QUADSPI_CCR_ADSIZE_Pos // 24-bit address size
+ | 3 << QUADSPI_CCR_ADMODE_Pos // address on 4 lines
+ | 1 << QUADSPI_CCR_IMODE_Pos // instruction on 1 line
+ | 0xeb << QUADSPI_CCR_INSTRUCTION_Pos // quad read opcode
+ ;
+}
+
+STATIC int qspi_ioctl(void *self_in, uint32_t cmd) {
+ (void)self_in;
+ switch (cmd) {
+ case MP_QSPI_IOCTL_INIT:
+ qspi_init();
+ break;
+ case MP_QSPI_IOCTL_BUS_RELEASE:
+ // Switch to memory-map mode when bus is idle
+ qspi_memory_map();
+ break;
+ }
+ return 0; // success
+}
+
+STATIC void qspi_write_cmd_data(void *self_in, uint8_t cmd, size_t len, uint32_t data) {
+ (void)self_in;
+
+ QUADSPI->FCR = QUADSPI_FCR_CTCF; // clear TC flag
+
+ if (len == 0) {
+ QUADSPI->CCR =
+ 0 << QUADSPI_CCR_DDRM_Pos // DDR mode disabled
+ | 0 << QUADSPI_CCR_SIOO_Pos // send instruction every transaction
+ | 0 << QUADSPI_CCR_FMODE_Pos // indirect write mode
+ | 0 << QUADSPI_CCR_DMODE_Pos // no data
+ | 0 << QUADSPI_CCR_DCYC_Pos // 0 dummy cycles
+ | 0 << QUADSPI_CCR_ABMODE_Pos // no alternate byte
+ | 0 << QUADSPI_CCR_ADMODE_Pos // no address
+ | 1 << QUADSPI_CCR_IMODE_Pos // instruction on 1 line
+ | cmd << QUADSPI_CCR_INSTRUCTION_Pos // write opcode
+ ;
+ } else {
+ QUADSPI->DLR = len - 1;
+
+ QUADSPI->CCR =
+ 0 << QUADSPI_CCR_DDRM_Pos // DDR mode disabled
+ | 0 << QUADSPI_CCR_SIOO_Pos // send instruction every transaction
+ | 0 << QUADSPI_CCR_FMODE_Pos // indirect write mode
+ | 1 << QUADSPI_CCR_DMODE_Pos // data on 1 line
+ | 0 << QUADSPI_CCR_DCYC_Pos // 0 dummy cycles
+ | 0 << QUADSPI_CCR_ABMODE_Pos // no alternate byte
+ | 0 << QUADSPI_CCR_ADMODE_Pos // no address
+ | 1 << QUADSPI_CCR_IMODE_Pos // instruction on 1 line
+ | cmd << QUADSPI_CCR_INSTRUCTION_Pos // write opcode
+ ;
+
+ // This assumes len==2
+ *(uint16_t*)&QUADSPI->DR = data;
+ }
+
+ // Wait for write to finish
+ while (!(QUADSPI->SR & QUADSPI_SR_TCF)) {
+ }
+
+ QUADSPI->FCR = QUADSPI_FCR_CTCF; // clear TC flag
+}
+
+STATIC void qspi_write_cmd_addr_data(void *self_in, uint8_t cmd, uint32_t addr, size_t len, const uint8_t *src) {
+ (void)self_in;
+
+ QUADSPI->FCR = QUADSPI_FCR_CTCF; // clear TC flag
+
+ if (len == 0) {
+ QUADSPI->CCR =
+ 0 << QUADSPI_CCR_DDRM_Pos // DDR mode disabled
+ | 0 << QUADSPI_CCR_SIOO_Pos // send instruction every transaction
+ | 0 << QUADSPI_CCR_FMODE_Pos // indirect write mode
+ | 0 << QUADSPI_CCR_DMODE_Pos // no data
+ | 0 << QUADSPI_CCR_DCYC_Pos // 0 dummy cycles
+ | 0 << QUADSPI_CCR_ABMODE_Pos // no alternate byte
+ | 2 << QUADSPI_CCR_ADSIZE_Pos // 24-bit address size
+ | 1 << QUADSPI_CCR_ADMODE_Pos // address on 1 line
+ | 1 << QUADSPI_CCR_IMODE_Pos // instruction on 1 line
+ | cmd << QUADSPI_CCR_INSTRUCTION_Pos // write opcode
+ ;
+
+ QUADSPI->AR = addr;
+ } else {
+ QUADSPI->DLR = len - 1;
+
+ QUADSPI->CCR =
+ 0 << QUADSPI_CCR_DDRM_Pos // DDR mode disabled
+ | 0 << QUADSPI_CCR_SIOO_Pos // send instruction every transaction
+ | 0 << QUADSPI_CCR_FMODE_Pos // indirect write mode
+ | 1 << QUADSPI_CCR_DMODE_Pos // data on 1 line
+ | 0 << QUADSPI_CCR_DCYC_Pos // 0 dummy cycles
+ | 0 << QUADSPI_CCR_ABMODE_Pos // no alternate byte
+ | 2 << QUADSPI_CCR_ADSIZE_Pos // 24-bit address size
+ | 1 << QUADSPI_CCR_ADMODE_Pos // address on 1 line
+ | 1 << QUADSPI_CCR_IMODE_Pos // instruction on 1 line
+ | cmd << QUADSPI_CCR_INSTRUCTION_Pos // write opcode
+ ;
+
+ QUADSPI->AR = addr;
+
+ // Write out the data 1 byte at a time
+ while (len) {
+ while (!(QUADSPI->SR & QUADSPI_SR_FTF)) {
+ }
+ *(volatile uint8_t*)&QUADSPI->DR = *src++;
+ --len;
+ }
+ }
+
+ // Wait for write to finish
+ while (!(QUADSPI->SR & QUADSPI_SR_TCF)) {
+ }
+
+ QUADSPI->FCR = QUADSPI_FCR_CTCF; // clear TC flag
+}
+
+STATIC uint32_t qspi_read_cmd(void *self_in, uint8_t cmd, size_t len) {
+ (void)self_in;
+
+ QUADSPI->FCR = QUADSPI_FCR_CTCF; // clear TC flag
+
+ QUADSPI->DLR = len - 1; // number of bytes to read
+
+ QUADSPI->CCR =
+ 0 << QUADSPI_CCR_DDRM_Pos // DDR mode disabled
+ | 0 << QUADSPI_CCR_SIOO_Pos // send instruction every transaction
+ | 1 << QUADSPI_CCR_FMODE_Pos // indirect read mode
+ | 1 << QUADSPI_CCR_DMODE_Pos // data on 1 line
+ | 0 << QUADSPI_CCR_DCYC_Pos // 0 dummy cycles
+ | 0 << QUADSPI_CCR_ABMODE_Pos // no alternate byte
+ | 0 << QUADSPI_CCR_ADMODE_Pos // no address
+ | 1 << QUADSPI_CCR_IMODE_Pos // instruction on 1 line
+ | cmd << QUADSPI_CCR_INSTRUCTION_Pos // read opcode
+ ;
+
+ // Wait for read to finish
+ while (!(QUADSPI->SR & QUADSPI_SR_TCF)) {
+ }
+
+ QUADSPI->FCR = QUADSPI_FCR_CTCF; // clear TC flag
+
+ // Read result
+ return QUADSPI->DR;
+}
+
+STATIC void qspi_read_cmd_qaddr_qdata(void *self_in, uint8_t cmd, uint32_t addr, size_t len, uint8_t *dest) {
+ (void)self_in;
+ QUADSPI->FCR = QUADSPI_FCR_CTCF; // clear TC flag
+
+ QUADSPI->DLR = len - 1; // number of bytes to read
+
+ QUADSPI->CCR =
+ 0 << QUADSPI_CCR_DDRM_Pos // DDR mode disabled
+ | 0 << QUADSPI_CCR_SIOO_Pos // send instruction every transaction
+ | 1 << QUADSPI_CCR_FMODE_Pos // indirect read mode
+ | 3 << QUADSPI_CCR_DMODE_Pos // data on 4 lines
+ | 4 << QUADSPI_CCR_DCYC_Pos // 4 dummy cycles
+ | 0 << QUADSPI_CCR_ABSIZE_Pos // 8-bit alternate byte
+ | 3 << QUADSPI_CCR_ABMODE_Pos // alternate byte on 4 lines
+ | 2 << QUADSPI_CCR_ADSIZE_Pos // 24-bit address size
+ | 3 << QUADSPI_CCR_ADMODE_Pos // address on 4 lines
+ | 1 << QUADSPI_CCR_IMODE_Pos // instruction on 1 line
+ | cmd << QUADSPI_CCR_INSTRUCTION_Pos // quad read opcode
+ ;
+
+ QUADSPI->ABR = 0; // alternate byte: disable continuous read mode
+ QUADSPI->AR = addr; // addres to read from
+
+ // Read in the data 4 bytes at a time if dest is aligned
+ if (((uintptr_t)dest & 3) == 0) {
+ while (len >= 4) {
+ while (!(QUADSPI->SR & QUADSPI_SR_FTF)) {
+ }
+ *(uint32_t*)dest = QUADSPI->DR;
+ dest += 4;
+ len -= 4;
+ }
+ }
+
+ // Read in remaining data 1 byte at a time
+ while (len) {
+ while (!((QUADSPI->SR >> QUADSPI_SR_FLEVEL_Pos) & 0x3f)) {
+ }
+ *dest++ = *(volatile uint8_t*)&QUADSPI->DR;
+ --len;
+ }
+
+ QUADSPI->FCR = QUADSPI_FCR_CTCF; // clear TC flag
+}
+
+const mp_qspi_proto_t qspi_proto = {
+ .ioctl = qspi_ioctl,
+ .write_cmd_data = qspi_write_cmd_data,
+ .write_cmd_addr_data = qspi_write_cmd_addr_data,
+ .read_cmd = qspi_read_cmd,
+ .read_cmd_qaddr_qdata = qspi_read_cmd_qaddr_qdata,
+};
+
+#endif // defined(MICROPY_HW_QSPIFLASH_SIZE_BITS_LOG2)
diff --git a/ports/stm32/qspi.h b/ports/stm32/qspi.h
new file mode 100644
index 000000000..c774b1258
--- /dev/null
+++ b/ports/stm32/qspi.h
@@ -0,0 +1,36 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#ifndef MICROPY_INCLUDED_STM32_QSPI_H
+#define MICROPY_INCLUDED_STM32_QSPI_H
+
+#include "drivers/bus/qspi.h"
+
+extern const mp_qspi_proto_t qspi_proto;
+
+void qspi_init(void);
+void qspi_memory_map(void);
+
+#endif // MICROPY_INCLUDED_STM32_QSPI_H
diff --git a/ports/stm32/resethandler.s b/ports/stm32/resethandler.s
new file mode 100644
index 000000000..7f0973346
--- /dev/null
+++ b/ports/stm32/resethandler.s
@@ -0,0 +1,70 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+ .syntax unified
+ .cpu cortex-m4
+ .thumb
+
+ .section .text.Reset_Handler
+ .global Reset_Handler
+ .type Reset_Handler, %function
+
+Reset_Handler:
+ /* Save the first argument to pass through to stm32_main */
+ mov r4, r0
+
+ /* Load the stack pointer */
+ ldr sp, =_estack
+
+ /* Initialise the data section */
+ ldr r1, =_sidata
+ ldr r2, =_sdata
+ ldr r3, =_edata
+ b .data_copy_entry
+.data_copy_loop:
+ ldr r0, [r1], #4 /* Should be 4-aligned to be as fast as possible */
+ str r0, [r2], #4
+.data_copy_entry:
+ cmp r2, r3
+ bcc .data_copy_loop
+
+ /* Zero out the BSS section */
+ movs r0, #0
+ ldr r1, =_sbss
+ ldr r2, =_ebss
+ b .bss_zero_entry
+.bss_zero_loop:
+ str r0, [r1], #4 /* Should be 4-aligned to be as fast as possible */
+.bss_zero_entry:
+ cmp r1, r2
+ bcc .bss_zero_loop
+
+ /* Initialise the system and jump to the main code */
+ bl SystemInit
+ mov r0, r4
+ b stm32_main
+
+ .size Reset_Handler, .-Reset_Handler
diff --git a/ports/stm32/resethandler_m0.s b/ports/stm32/resethandler_m0.s
new file mode 100644
index 000000000..bb88e8dae
--- /dev/null
+++ b/ports/stm32/resethandler_m0.s
@@ -0,0 +1,74 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+ .syntax unified
+ .cpu cortex-m0
+ .thumb
+
+ .section .text.Reset_Handler
+ .global Reset_Handler
+ .type Reset_Handler, %function
+
+Reset_Handler:
+ /* Save the first argument to pass through to stm32_main */
+ mov r4, r0
+
+ /* Load the stack pointer */
+ ldr r0, =_estack
+ mov sp, r0
+
+ /* Initialise the data section */
+ ldr r1, =_sidata
+ ldr r2, =_sdata
+ ldr r3, =_edata
+ b .data_copy_entry
+.data_copy_loop:
+ ldr r0, [r1]
+ adds r1, #4
+ str r0, [r2]
+ adds r2, #4
+.data_copy_entry:
+ cmp r2, r3
+ bcc .data_copy_loop
+
+ /* Zero out the BSS section */
+ movs r0, #0
+ ldr r1, =_sbss
+ ldr r2, =_ebss
+ b .bss_zero_entry
+.bss_zero_loop:
+ str r0, [r1]
+ adds r1, #4
+.bss_zero_entry:
+ cmp r1, r2
+ bcc .bss_zero_loop
+
+ /* Initialise the system and jump to the main code */
+ bl SystemInit
+ mov r0, r4
+ bl stm32_main
+
+ .size Reset_Handler, .-Reset_Handler
diff --git a/ports/stm32/rng.c b/ports/stm32/rng.c
index c0c5e9aeb..b23941998 100644
--- a/ports/stm32/rng.c
+++ b/ports/stm32/rng.c
@@ -3,7 +3,7 @@
*
* The MIT License (MIT)
*
- * Copyright (c) 2013, 2014 Damien P. George
+ * Copyright (c) 2013-2018 Damien P. George
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -24,44 +24,66 @@
* THE SOFTWARE.
*/
-#include <string.h>
-
-#include "py/obj.h"
#include "rng.h"
#if MICROPY_HW_ENABLE_RNG
-/// \moduleref pyb
+#define RNG_TIMEOUT_MS (10)
-STATIC RNG_HandleTypeDef RNGHandle = {.Instance = NULL};
+uint32_t rng_get(void) {
+ // Enable the RNG peripheral if it's not already enabled
+ if (!(RNG->CR & RNG_CR_RNGEN)) {
+ #if defined(STM32H7)
+ // Set RNG Clock source
+ __HAL_RCC_PLLCLKOUT_ENABLE(RCC_PLL1_DIVQ);
+ __HAL_RCC_RNG_CONFIG(RCC_RNGCLKSOURCE_PLL);
+ #endif
+ __HAL_RCC_RNG_CLK_ENABLE();
+ RNG->CR |= RNG_CR_RNGEN;
+ }
-void rng_init0(void) {
- // reset the RNG handle
- memset(&RNGHandle, 0, sizeof(RNG_HandleTypeDef));
- RNGHandle.Instance = RNG;
-}
+ // Wait for a new random number to be ready, takes on the order of 10us
+ uint32_t start = HAL_GetTick();
+ while (!(RNG->SR & RNG_SR_DRDY)) {
+ if (HAL_GetTick() - start >= RNG_TIMEOUT_MS) {
+ return 0;
+ }
+ }
-void rng_init(void) {
- __RNG_CLK_ENABLE();
- HAL_RNG_Init(&RNGHandle);
+ // Get and return the new random number
+ return RNG->DR;
}
-uint32_t rng_get(void) {
- if (RNGHandle.State == HAL_RNG_STATE_RESET) {
- rng_init();
- }
- return HAL_RNG_GetRandomNumber(&RNGHandle);
+// Return a 30-bit hardware generated random number.
+STATIC mp_obj_t pyb_rng_get(void) {
+ return mp_obj_new_int(rng_get() >> 2);
}
+MP_DEFINE_CONST_FUN_OBJ_0(pyb_rng_get_obj, pyb_rng_get);
-/// \function rng()
-/// Return a 30-bit hardware generated random number.
-STATIC mp_obj_t pyb_rng_get(void) {
- if (RNGHandle.State == HAL_RNG_STATE_RESET) {
- rng_init();
- }
- return mp_obj_new_int(HAL_RNG_GetRandomNumber(&RNGHandle) >> 2);
+#else // MICROPY_HW_ENABLE_RNG
+
+// For MCUs that don't have an RNG we still need to provide a rng_get() function,
+// eg for lwIP. A pseudo-RNG is not really ideal but we go with it for now. We
+// don't want to use urandom's pRNG because then the user won't see a reproducible
+// random stream.
+
+// Yasmarang random number generator by Ilya Levin
+// http://www.literatecode.com/yasmarang
+STATIC uint32_t pyb_rng_yasmarang(void) {
+ static uint32_t pad = 0xeda4baba, n = 69, d = 233;
+ static uint8_t dat = 0;
+
+ pad += dat + d * n;
+ pad = (pad << 3) + (pad >> 29);
+ n = pad | 2;
+ d ^= (pad << 31) + (pad >> 1);
+ dat ^= (char)pad ^ (d >> 8) ^ 1;
+
+ return pad ^ (d << 5) ^ (pad >> 18) ^ (dat << 1);
}
-MP_DEFINE_CONST_FUN_OBJ_0(pyb_rng_get_obj, pyb_rng_get);
+uint32_t rng_get(void) {
+ return pyb_rng_yasmarang();
+}
#endif // MICROPY_HW_ENABLE_RNG
diff --git a/ports/stm32/rng.h b/ports/stm32/rng.h
index 43e49fe72..ed9cc80f2 100644
--- a/ports/stm32/rng.h
+++ b/ports/stm32/rng.h
@@ -23,12 +23,13 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
-#ifndef MICROPY_INCLUDED_STMHAL_RNG_H
-#define MICROPY_INCLUDED_STMHAL_RNG_H
+#ifndef MICROPY_INCLUDED_STM32_RNG_H
+#define MICROPY_INCLUDED_STM32_RNG_H
+
+#include "py/obj.h"
-void rng_init0(void);
uint32_t rng_get(void);
MP_DECLARE_CONST_FUN_OBJ_0(pyb_rng_get_obj);
-#endif // MICROPY_INCLUDED_STMHAL_RNG_H
+#endif // MICROPY_INCLUDED_STM32_RNG_H
diff --git a/ports/stm32/rtc.c b/ports/stm32/rtc.c
index 73272d363..c51dfab11 100644
--- a/ports/stm32/rtc.c
+++ b/ports/stm32/rtc.c
@@ -132,13 +132,14 @@ void rtc_init_start(bool force_init) {
// provide some status information
rtc_info |= 0x40000 | (RCC->BDCR & 7) | (RCC->CSR & 3) << 8;
return;
- } else if (((RCC->BDCR & RCC_BDCR_RTCSEL) == RCC_BDCR_RTCSEL_1) && ((RCC->CSR & 3) == 3)) {
- // LSI configured & enabled & ready --> no need to (re-)init RTC
+ } else if ((RCC->BDCR & RCC_BDCR_RTCSEL) == RCC_BDCR_RTCSEL_1) {
+ // LSI configured as the RTC clock source --> no need to (re-)init RTC
// remove Backup Domain write protection
HAL_PWR_EnableBkUpAccess();
// Clear source Reset Flag
__HAL_RCC_CLEAR_RESET_FLAGS();
- RCC->CSR |= 1;
+ // Turn the LSI on (it may need this even if the RTC is running)
+ RCC->CSR |= RCC_CSR_LSION;
// provide some status information
rtc_info |= 0x80000 | (RCC->BDCR & 7) | (RCC->CSR & 3) << 8;
return;
@@ -162,7 +163,7 @@ void rtc_init_finalise() {
return;
}
- rtc_info = 0x20000000 | (rtc_use_lse << 28);
+ rtc_info = 0x20000000;
if (PYB_RTC_Init(&RTCHandle) != HAL_OK) {
if (rtc_use_lse) {
// fall back to LSI...
@@ -182,12 +183,15 @@ void rtc_init_finalise() {
}
}
+ // record if LSE or LSI is used
+ rtc_info |= (rtc_use_lse << 28);
+
// record how long it took for the RTC to start up
rtc_info |= (HAL_GetTick() - rtc_startup_tick) & 0xffff;
// fresh reset; configure RTC Calendar
RTC_CalendarConfig();
- #if defined(MCU_SERIES_L4)
+ #if defined(STM32L4)
if(__HAL_RCC_GET_FLAG(RCC_FLAG_BORRST) != RESET) {
#else
if(__HAL_RCC_GET_FLAG(RCC_FLAG_PORRST) != RESET) {
@@ -219,12 +223,16 @@ STATIC HAL_StatusTypeDef PYB_RCC_OscConfig(RCC_OscInitTypeDef *RCC_OscInitStruc
/*------------------------------ LSE Configuration -------------------------*/
if ((RCC_OscInitStruct->OscillatorType & RCC_OSCILLATORTYPE_LSE) == RCC_OSCILLATORTYPE_LSE) {
+ #if !defined(STM32H7)
// Enable Power Clock
- __PWR_CLK_ENABLE();
+ __HAL_RCC_PWR_CLK_ENABLE();
+ #endif
+
+ // Enable access to the backup domain
HAL_PWR_EnableBkUpAccess();
uint32_t tickstart = HAL_GetTick();
- #if defined(MCU_SERIES_F7) || defined(MCU_SERIES_L4)
+ #if defined(STM32F7) || defined(STM32L4) || defined(STM32H7)
//__HAL_RCC_PWR_CLK_ENABLE();
// Enable write access to Backup domain
//PWR->CR1 |= PWR_CR1_DBP;
@@ -239,7 +247,7 @@ STATIC HAL_StatusTypeDef PYB_RCC_OscConfig(RCC_OscInitTypeDef *RCC_OscInitStruc
//PWR->CR |= PWR_CR_DBP;
// Wait for Backup domain Write protection disable
while ((PWR->CR & PWR_CR_DBP) == RESET) {
- if (HAL_GetTick() - tickstart > DBP_TIMEOUT_VALUE) {
+ if (HAL_GetTick() - tickstart > RCC_DBP_TIMEOUT_VALUE) {
return HAL_TIMEOUT;
}
}
@@ -294,10 +302,10 @@ STATIC HAL_StatusTypeDef PYB_RTC_Init(RTC_HandleTypeDef *hrtc) {
// Exit Initialization mode
hrtc->Instance->ISR &= (uint32_t)~RTC_ISR_INIT;
- #if defined(MCU_SERIES_L4)
+ #if defined(STM32L4) || defined(STM32H7)
hrtc->Instance->OR &= (uint32_t)~RTC_OR_ALARMOUTTYPE;
hrtc->Instance->OR |= (uint32_t)(hrtc->Init.OutPutType);
- #elif defined(MCU_SERIES_F7)
+ #elif defined(STM32F7)
hrtc->Instance->OR &= (uint32_t)~RTC_OR_ALARMTYPE;
hrtc->Instance->OR |= (uint32_t)(hrtc->Init.OutPutType);
#else
@@ -331,7 +339,11 @@ STATIC void PYB_RTC_MspInit_Kick(RTC_HandleTypeDef *hrtc, bool rtc_use_lse) {
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSI | RCC_OSCILLATORTYPE_LSE;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
if (rtc_use_lse) {
+ #if MICROPY_HW_RTC_USE_BYPASS
+ RCC_OscInitStruct.LSEState = RCC_LSE_BYPASS;
+ #else
RCC_OscInitStruct.LSEState = RCC_LSE_ON;
+ #endif
RCC_OscInitStruct.LSIState = RCC_LSI_OFF;
} else {
RCC_OscInitStruct.LSEState = RCC_LSE_OFF;
@@ -391,7 +403,7 @@ STATIC void RTC_CalendarConfig(void) {
date.Date = 1;
date.WeekDay = RTC_WEEKDAY_THURSDAY;
- if(HAL_RTC_SetDate(&RTCHandle, &date, FORMAT_BIN) != HAL_OK) {
+ if(HAL_RTC_SetDate(&RTCHandle, &date, RTC_FORMAT_BIN) != HAL_OK) {
// init error
return;
}
@@ -405,7 +417,7 @@ STATIC void RTC_CalendarConfig(void) {
time.DayLightSaving = RTC_DAYLIGHTSAVING_NONE;
time.StoreOperation = RTC_STOREOPERATION_RESET;
- if (HAL_RTC_SetTime(&RTCHandle, &time, FORMAT_BIN) != HAL_OK) {
+ if (HAL_RTC_SetTime(&RTCHandle, &time, RTC_FORMAT_BIN) != HAL_OK) {
// init error
return;
}
@@ -488,8 +500,8 @@ mp_obj_t pyb_rtc_datetime(size_t n_args, const mp_obj_t *args) {
// note: need to call get time then get date to correctly access the registers
RTC_DateTypeDef date;
RTC_TimeTypeDef time;
- HAL_RTC_GetTime(&RTCHandle, &time, FORMAT_BIN);
- HAL_RTC_GetDate(&RTCHandle, &date, FORMAT_BIN);
+ HAL_RTC_GetTime(&RTCHandle, &time, RTC_FORMAT_BIN);
+ HAL_RTC_GetDate(&RTCHandle, &date, RTC_FORMAT_BIN);
mp_obj_t tuple[8] = {
mp_obj_new_int(2000 + date.Year),
mp_obj_new_int(date.Month),
@@ -511,23 +523,26 @@ mp_obj_t pyb_rtc_datetime(size_t n_args, const mp_obj_t *args) {
date.Month = mp_obj_get_int(items[1]);
date.Date = mp_obj_get_int(items[2]);
date.WeekDay = mp_obj_get_int(items[3]);
- HAL_RTC_SetDate(&RTCHandle, &date, FORMAT_BIN);
+ HAL_RTC_SetDate(&RTCHandle, &date, RTC_FORMAT_BIN);
RTC_TimeTypeDef time;
time.Hours = mp_obj_get_int(items[4]);
time.Minutes = mp_obj_get_int(items[5]);
time.Seconds = mp_obj_get_int(items[6]);
- time.SubSeconds = rtc_us_to_subsec(mp_obj_get_int(items[7]));
time.TimeFormat = RTC_HOURFORMAT12_AM;
time.DayLightSaving = RTC_DAYLIGHTSAVING_NONE;
time.StoreOperation = RTC_STOREOPERATION_SET;
- HAL_RTC_SetTime(&RTCHandle, &time, FORMAT_BIN);
+ HAL_RTC_SetTime(&RTCHandle, &time, RTC_FORMAT_BIN);
return mp_const_none;
}
}
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_rtc_datetime_obj, 1, 2, pyb_rtc_datetime);
+#if defined(STM32F0)
+#define RTC_WKUP_IRQn RTC_IRQn
+#endif
+
// wakeup(None)
// wakeup(ms, callback=None)
// wakeup(wucksel, wut, callback)
@@ -623,9 +638,12 @@ mp_obj_t pyb_rtc_wakeup(size_t n_args, const mp_obj_t *args) {
RTC->WPR = 0xff;
// enable external interrupts on line 22
- #if defined(MCU_SERIES_L4)
+ #if defined(STM32L4)
EXTI->IMR1 |= 1 << 22;
EXTI->RTSR1 |= 1 << 22;
+ #elif defined(STM32H7)
+ EXTI_D1->IMR1 |= 1 << 22;
+ EXTI->RTSR1 |= 1 << 22;
#else
EXTI->IMR |= 1 << 22;
EXTI->RTSR |= 1 << 22;
@@ -633,13 +651,15 @@ mp_obj_t pyb_rtc_wakeup(size_t n_args, const mp_obj_t *args) {
// clear interrupt flags
RTC->ISR &= ~(1 << 10);
- #if defined(MCU_SERIES_L4)
+ #if defined(STM32L4)
EXTI->PR1 = 1 << 22;
+ #elif defined(STM32H7)
+ EXTI_D1->PR1 = 1 << 22;
#else
EXTI->PR = 1 << 22;
#endif
- HAL_NVIC_SetPriority(RTC_WKUP_IRQn, IRQ_PRI_RTC_WKUP, IRQ_SUBPRI_RTC_WKUP);
+ NVIC_SetPriority(RTC_WKUP_IRQn, IRQ_PRI_RTC_WKUP);
HAL_NVIC_EnableIRQ(RTC_WKUP_IRQn);
//printf("wut=%d wucksel=%d\n", wut, wucksel);
@@ -651,8 +671,10 @@ mp_obj_t pyb_rtc_wakeup(size_t n_args, const mp_obj_t *args) {
RTC->WPR = 0xff;
// disable external interrupts on line 22
- #if defined(MCU_SERIES_L4)
+ #if defined(STM32L4)
EXTI->IMR1 &= ~(1 << 22);
+ #elif defined(STM32H7)
+ EXTI_D1->IMR1 |= 1 << 22;
#else
EXTI->IMR &= ~(1 << 22);
#endif
diff --git a/ports/stm32/rtc.h b/ports/stm32/rtc.h
index 09ab2aedf..307f8885e 100644
--- a/ports/stm32/rtc.h
+++ b/ports/stm32/rtc.h
@@ -23,8 +23,8 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
-#ifndef MICROPY_INCLUDED_STMHAL_RTC_H
-#define MICROPY_INCLUDED_STMHAL_RTC_H
+#ifndef MICROPY_INCLUDED_STM32_RTC_H
+#define MICROPY_INCLUDED_STM32_RTC_H
extern RTC_HandleTypeDef RTCHandle;
extern const mp_obj_type_t pyb_rtc_type;
@@ -32,4 +32,4 @@ extern const mp_obj_type_t pyb_rtc_type;
void rtc_init_start(bool force_init);
void rtc_init_finalise(void);
-#endif // MICROPY_INCLUDED_STMHAL_RTC_H
+#endif // MICROPY_INCLUDED_STM32_RTC_H
diff --git a/ports/stm32/sdcard.c b/ports/stm32/sdcard.c
index 484426b84..27e7a34b2 100644
--- a/ports/stm32/sdcard.c
+++ b/ports/stm32/sdcard.c
@@ -33,14 +33,13 @@
#include "sdcard.h"
#include "pin.h"
-#include "genhdr/pins.h"
#include "bufhelper.h"
#include "dma.h"
#include "irq.h"
#if MICROPY_HW_HAS_SDCARD
-#if defined(MCU_SERIES_F7) || defined(MCU_SERIES_L4)
+#if defined(STM32F7) || defined(STM32H7) || defined(STM32L4)
// The F7 has 2 SDMMC units but at the moment we only support using one of them in
// a given build. If a boards config file defines MICROPY_HW_SDMMC2_CK then SDMMC2
@@ -81,7 +80,15 @@
#define SDIO_HARDWARE_FLOW_CONTROL_DISABLE SDMMC_HARDWARE_FLOW_CONTROL_DISABLE
#define SDIO_HARDWARE_FLOW_CONTROL_ENABLE SDMMC_HARDWARE_FLOW_CONTROL_ENABLE
+#if defined(STM32H7)
+#define GPIO_AF12_SDIO GPIO_AF12_SDIO1
+#define SDIO_IRQHandler SDMMC1_IRQHandler
+#define SDIO_TRANSFER_CLK_DIV SDMMC_NSpeed_CLK_DIV
+#define SDIO_USE_GPDMA 0
+#else
#define SDIO_TRANSFER_CLK_DIV SDMMC_TRANSFER_CLK_DIV
+#define SDIO_USE_GPDMA 1
+#endif
#else
@@ -92,6 +99,7 @@
#define SDMMC_IRQn SDIO_IRQn
#define SDMMC_TX_DMA dma_SDIO_0_TX
#define SDMMC_RX_DMA dma_SDIO_0_RX
+#define SDIO_USE_GPDMA 1
#endif
@@ -117,7 +125,9 @@
// if an sd card is detected. This will save approx 260 bytes of RAM
// when no sdcard was being used.
static SD_HandleTypeDef sd_handle;
+#if SDIO_USE_GPDMA
static DMA_HandleTypeDef sd_rx_dma, sd_tx_dma;
+#endif
void sdcard_init(void) {
// invalidate the sd_handle
@@ -131,33 +141,39 @@ void sdcard_init(void) {
// which clocks up to 25MHz maximum.
#if defined(MICROPY_HW_SDMMC2_CK)
// Use SDMMC2 peripheral with pins provided by the board's config
- mp_hal_pin_config_alt(&MICROPY_HW_SDMMC2_CK, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, AF_FN_SDMMC, 2);
- mp_hal_pin_config_alt(&MICROPY_HW_SDMMC2_CMD, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, AF_FN_SDMMC, 2);
- mp_hal_pin_config_alt(&MICROPY_HW_SDMMC2_D0, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, AF_FN_SDMMC, 2);
- mp_hal_pin_config_alt(&MICROPY_HW_SDMMC2_D1, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, AF_FN_SDMMC, 2);
- mp_hal_pin_config_alt(&MICROPY_HW_SDMMC2_D2, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, AF_FN_SDMMC, 2);
- mp_hal_pin_config_alt(&MICROPY_HW_SDMMC2_D3, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, AF_FN_SDMMC, 2);
+ mp_hal_pin_config_alt(MICROPY_HW_SDMMC2_CK, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, AF_FN_SDMMC, 2);
+ mp_hal_pin_config_alt(MICROPY_HW_SDMMC2_CMD, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, AF_FN_SDMMC, 2);
+ mp_hal_pin_config_alt(MICROPY_HW_SDMMC2_D0, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, AF_FN_SDMMC, 2);
+ mp_hal_pin_config_alt(MICROPY_HW_SDMMC2_D1, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, AF_FN_SDMMC, 2);
+ mp_hal_pin_config_alt(MICROPY_HW_SDMMC2_D2, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, AF_FN_SDMMC, 2);
+ mp_hal_pin_config_alt(MICROPY_HW_SDMMC2_D3, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, AF_FN_SDMMC, 2);
#else
// Default SDIO/SDMMC1 config
- mp_hal_pin_config(&MICROPY_HW_SDMMC_D0, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, GPIO_AF12_SDIO);
- mp_hal_pin_config(&MICROPY_HW_SDMMC_D1, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, GPIO_AF12_SDIO);
- mp_hal_pin_config(&MICROPY_HW_SDMMC_D2, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, GPIO_AF12_SDIO);
- mp_hal_pin_config(&MICROPY_HW_SDMMC_D3, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, GPIO_AF12_SDIO);
- mp_hal_pin_config(&MICROPY_HW_SDMMC_CK, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, GPIO_AF12_SDIO);
- mp_hal_pin_config(&MICROPY_HW_SDMMC_CMD, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, GPIO_AF12_SDIO);
+ mp_hal_pin_config(MICROPY_HW_SDMMC_D0, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, GPIO_AF12_SDIO);
+ mp_hal_pin_config(MICROPY_HW_SDMMC_D1, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, GPIO_AF12_SDIO);
+ mp_hal_pin_config(MICROPY_HW_SDMMC_D2, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, GPIO_AF12_SDIO);
+ mp_hal_pin_config(MICROPY_HW_SDMMC_D3, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, GPIO_AF12_SDIO);
+ mp_hal_pin_config(MICROPY_HW_SDMMC_CK, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, GPIO_AF12_SDIO);
+ mp_hal_pin_config(MICROPY_HW_SDMMC_CMD, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, GPIO_AF12_SDIO);
#endif
// configure the SD card detect pin
// we do this here so we can detect if the SD card is inserted before powering it on
- mp_hal_pin_config(&MICROPY_HW_SDCARD_DETECT_PIN, MP_HAL_PIN_MODE_INPUT, MICROPY_HW_SDCARD_DETECT_PULL, 0);
+ mp_hal_pin_config(MICROPY_HW_SDCARD_DETECT_PIN, MP_HAL_PIN_MODE_INPUT, MICROPY_HW_SDCARD_DETECT_PULL, 0);
}
void HAL_SD_MspInit(SD_HandleTypeDef *hsd) {
// enable SDIO clock
SDMMC_CLK_ENABLE();
+ #if defined(STM32H7)
+ // Reset SDMMC
+ __HAL_RCC_SDMMC1_FORCE_RESET();
+ __HAL_RCC_SDMMC1_RELEASE_RESET();
+ #endif
+
// NVIC configuration for SDIO interrupts
- HAL_NVIC_SetPriority(SDMMC_IRQn, IRQ_PRI_SDIO, IRQ_SUBPRI_SDIO);
+ NVIC_SetPriority(SDMMC_IRQn, IRQ_PRI_SDIO);
HAL_NVIC_EnableIRQ(SDMMC_IRQn);
// GPIO have already been initialised by sdcard_init
@@ -169,7 +185,7 @@ void HAL_SD_MspDeInit(SD_HandleTypeDef *hsd) {
}
bool sdcard_is_present(void) {
- return HAL_GPIO_ReadPin(MICROPY_HW_SDCARD_DETECT_PIN.gpio, MICROPY_HW_SDCARD_DETECT_PIN.pin_mask) == MICROPY_HW_SDCARD_DETECT_PRESENT;
+ return HAL_GPIO_ReadPin(MICROPY_HW_SDCARD_DETECT_PIN->gpio, MICROPY_HW_SDCARD_DETECT_PIN->pin_mask) == MICROPY_HW_SDCARD_DETECT_PRESENT;
}
bool sdcard_power_on(void) {
@@ -183,7 +199,9 @@ bool sdcard_power_on(void) {
// SD device interface configuration
sd_handle.Instance = SDIO;
sd_handle.Init.ClockEdge = SDIO_CLOCK_EDGE_RISING;
+ #ifndef STM32H7
sd_handle.Init.ClockBypass = SDIO_CLOCK_BYPASS_DISABLE;
+ #endif
sd_handle.Init.ClockPowerSave = SDIO_CLOCK_POWER_SAVE_ENABLE;
sd_handle.Init.BusWide = SDIO_BUS_WIDE_1B;
sd_handle.Init.HardwareFlowControl = SDIO_HARDWARE_FLOW_CONTROL_DISABLE;
@@ -198,6 +216,10 @@ bool sdcard_power_on(void) {
}
// configure the SD bus width for wide operation
+ #if defined(STM32F7)
+ // use maximum SDMMC clock speed on F7 MCUs
+ sd_handle.Init.ClockBypass = SDMMC_CLOCK_BYPASS_ENABLE;
+ #endif
if (HAL_SD_ConfigWideBusOperation(&sd_handle, SDIO_BUS_WIDE_4B) != HAL_OK) {
HAL_SD_DeInit(&sd_handle);
goto error;
@@ -227,13 +249,15 @@ uint64_t sdcard_get_capacity_in_bytes(void) {
return (uint64_t)cardinfo.LogBlockNbr * (uint64_t)cardinfo.LogBlockSize;
}
+#if !defined(MICROPY_HW_SDMMC2_CK)
void SDIO_IRQHandler(void) {
IRQ_ENTER(SDIO_IRQn);
HAL_SD_IRQHandler(&sd_handle);
IRQ_EXIT(SDIO_IRQn);
}
+#endif
-#if defined(MCU_SERIES_F7)
+#if defined(STM32F7)
void SDMMC2_IRQHandler(void) {
IRQ_ENTER(SDMMC2_IRQn);
HAL_SD_IRQHandler(&sd_handle);
@@ -244,14 +268,23 @@ void SDMMC2_IRQHandler(void) {
STATIC HAL_StatusTypeDef sdcard_wait_finished(SD_HandleTypeDef *sd, uint32_t timeout) {
// Wait for HAL driver to be ready (eg for DMA to finish)
uint32_t start = HAL_GetTick();
- while (sd->State == HAL_SD_STATE_BUSY) {
+ for (;;) {
+ // Do an atomic check of the state; WFI will exit even if IRQs are disabled
+ uint32_t irq_state = disable_irq();
+ if (sd->State != HAL_SD_STATE_BUSY) {
+ enable_irq(irq_state);
+ break;
+ }
+ __WFI();
+ enable_irq(irq_state);
if (HAL_GetTick() - start >= timeout) {
return HAL_TIMEOUT;
}
}
+
// Wait for SD card to complete the operation
for (;;) {
- HAL_SD_CardStateTypeDef state = HAL_SD_GetCardState(sd);
+ HAL_SD_CardStateTypedef state = HAL_SD_GetCardState(sd);
if (state == HAL_SD_CARD_TRANSFER) {
return HAL_OK;
}
@@ -261,6 +294,7 @@ STATIC HAL_StatusTypeDef sdcard_wait_finished(SD_HandleTypeDef *sd, uint32_t tim
if (HAL_GetTick() - start >= timeout) {
return HAL_TIMEOUT;
}
+ __WFI();
}
return HAL_OK;
}
@@ -295,8 +329,10 @@ mp_uint_t sdcard_read_blocks(uint8_t *dest, uint32_t block_num, uint32_t num_blo
// we must disable USB irqs to prevent MSC contention with SD card
uint32_t basepri = raise_irq_pri(IRQ_PRI_OTG_FS);
+ #if SDIO_USE_GPDMA
dma_init(&sd_rx_dma, &SDMMC_RX_DMA, &sd_handle);
sd_handle.hdmarx = &sd_rx_dma;
+ #endif
// make sure cache is flushed and invalidated so when DMA updates the RAM
// from reading the peripheral the CPU then reads the new data
@@ -307,8 +343,10 @@ mp_uint_t sdcard_read_blocks(uint8_t *dest, uint32_t block_num, uint32_t num_blo
err = sdcard_wait_finished(&sd_handle, 60000);
}
+ #if SDIO_USE_GPDMA
dma_deinit(&SDMMC_RX_DMA);
sd_handle.hdmarx = NULL;
+ #endif
restore_irq_pri(basepri);
} else {
@@ -357,8 +395,10 @@ mp_uint_t sdcard_write_blocks(const uint8_t *src, uint32_t block_num, uint32_t n
// we must disable USB irqs to prevent MSC contention with SD card
uint32_t basepri = raise_irq_pri(IRQ_PRI_OTG_FS);
+ #if SDIO_USE_GPDMA
dma_init(&sd_tx_dma, &SDMMC_TX_DMA, &sd_handle);
sd_handle.hdmatx = &sd_tx_dma;
+ #endif
// make sure cache is flushed to RAM so the DMA can read the correct data
MP_HAL_CLEAN_DCACHE(src, num_blocks * SDCARD_BLOCK_SIZE);
@@ -367,8 +407,11 @@ mp_uint_t sdcard_write_blocks(const uint8_t *src, uint32_t block_num, uint32_t n
if (err == HAL_OK) {
err = sdcard_wait_finished(&sd_handle, 60000);
}
+
+ #if SDIO_USE_GPDMA
dma_deinit(&SDMMC_TX_DMA);
sd_handle.hdmatx = NULL;
+ #endif
restore_irq_pri(basepri);
} else {
@@ -496,7 +539,7 @@ STATIC mp_obj_t pyb_sdcard_ioctl(mp_obj_t self, mp_obj_t cmd_in, mp_obj_t arg_in
return MP_OBJ_NEW_SMALL_INT(0); // success
case BP_IOCTL_SEC_COUNT:
- return MP_OBJ_NEW_SMALL_INT(0); // TODO
+ return MP_OBJ_NEW_SMALL_INT(sdcard_get_capacity_in_bytes() / SDCARD_BLOCK_SIZE);
case BP_IOCTL_SEC_SIZE:
return MP_OBJ_NEW_SMALL_INT(SDCARD_BLOCK_SIZE);
diff --git a/ports/stm32/sdcard.h b/ports/stm32/sdcard.h
index 8c698fc2f..4afc258aa 100644
--- a/ports/stm32/sdcard.h
+++ b/ports/stm32/sdcard.h
@@ -23,8 +23,8 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
-#ifndef MICROPY_INCLUDED_STMHAL_SDCARD_H
-#define MICROPY_INCLUDED_STMHAL_SDCARD_H
+#ifndef MICROPY_INCLUDED_STM32_SDCARD_H
+#define MICROPY_INCLUDED_STM32_SDCARD_H
// this is a fixed size and should not be changed
#define SDCARD_BLOCK_SIZE (512)
@@ -45,4 +45,4 @@ extern const struct _mp_obj_base_t pyb_sdcard_obj;
struct _fs_user_mount_t;
void sdcard_init_vfs(struct _fs_user_mount_t *vfs, int part);
-#endif // MICROPY_INCLUDED_STMHAL_SDCARD_H
+#endif // MICROPY_INCLUDED_STM32_SDCARD_H
diff --git a/ports/stm32/servo.c b/ports/stm32/servo.c
index 0e54b4d0a..dc92872eb 100644
--- a/ports/stm32/servo.c
+++ b/ports/stm32/servo.c
@@ -29,7 +29,6 @@
#include "py/runtime.h"
#include "py/mphal.h"
#include "pin.h"
-#include "genhdr/pins.h"
#include "timer.h"
#include "servo.h"
@@ -81,15 +80,15 @@ void servo_init(void) {
// assign servo objects to specific pins (must be some permutation of PA0-PA3)
#ifdef pyb_pin_X1
- pyb_servo_obj[0].pin = &pyb_pin_X1;
- pyb_servo_obj[1].pin = &pyb_pin_X2;
- pyb_servo_obj[2].pin = &pyb_pin_X3;
- pyb_servo_obj[3].pin = &pyb_pin_X4;
+ pyb_servo_obj[0].pin = pyb_pin_X1;
+ pyb_servo_obj[1].pin = pyb_pin_X2;
+ pyb_servo_obj[2].pin = pyb_pin_X3;
+ pyb_servo_obj[3].pin = pyb_pin_X4;
#else
- pyb_servo_obj[0].pin = &pin_A0;
- pyb_servo_obj[1].pin = &pin_A1;
- pyb_servo_obj[2].pin = &pin_A2;
- pyb_servo_obj[3].pin = &pin_A3;
+ pyb_servo_obj[0].pin = pin_A0;
+ pyb_servo_obj[1].pin = pin_A1;
+ pyb_servo_obj[2].pin = pin_A2;
+ pyb_servo_obj[3].pin = pin_A3;
#endif
}
@@ -177,7 +176,7 @@ MP_DEFINE_CONST_FUN_OBJ_2(pyb_pwm_set_obj, pyb_pwm_set);
STATIC void pyb_servo_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
pyb_servo_obj_t *self = self_in;
- mp_printf(print, "<Servo %lu at %luus>", self - &pyb_servo_obj[0] + 1, 10 * self->pulse_cur);
+ mp_printf(print, "<Servo %u at %uus>", self - &pyb_servo_obj[0] + 1, 10 * self->pulse_cur);
}
/// \classmethod \constructor(id)
diff --git a/ports/stm32/servo.h b/ports/stm32/servo.h
index c602a07da..0160568af 100644
--- a/ports/stm32/servo.h
+++ b/ports/stm32/servo.h
@@ -23,8 +23,8 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
-#ifndef MICROPY_INCLUDED_STMHAL_SERVO_H
-#define MICROPY_INCLUDED_STMHAL_SERVO_H
+#ifndef MICROPY_INCLUDED_STM32_SERVO_H
+#define MICROPY_INCLUDED_STM32_SERVO_H
void servo_init(void);
void servo_timer_irq_callback(void);
@@ -34,4 +34,4 @@ extern const mp_obj_type_t pyb_servo_type;
MP_DECLARE_CONST_FUN_OBJ_2(pyb_servo_set_obj);
MP_DECLARE_CONST_FUN_OBJ_2(pyb_pwm_set_obj);
-#endif // MICROPY_INCLUDED_STMHAL_SERVO_H
+#endif // MICROPY_INCLUDED_STM32_SERVO_H
diff --git a/ports/stm32/spi.c b/ports/stm32/spi.c
index cfd9c2667..e8621b0ab 100644
--- a/ports/stm32/spi.c
+++ b/ports/stm32/spi.c
@@ -32,9 +32,7 @@
#include "extmod/machine_spi.h"
#include "irq.h"
#include "pin.h"
-#include "genhdr/pins.h"
#include "bufhelper.h"
-#include "dma.h"
#include "spi.h"
/// \moduleref pyb
@@ -75,13 +73,6 @@
// SPI6_TX: DMA2_Stream5.CHANNEL_1
// SPI6_RX: DMA2_Stream6.CHANNEL_1
-typedef struct _pyb_spi_obj_t {
- mp_obj_base_t base;
- SPI_HandleTypeDef *spi;
- const dma_descr_t *tx_dma_descr;
- const dma_descr_t *rx_dma_descr;
-} pyb_spi_obj_t;
-
#if defined(MICROPY_HW_SPI1_SCK)
SPI_HandleTypeDef SPIHandle1 = {.Instance = NULL};
#endif
@@ -101,63 +92,58 @@ SPI_HandleTypeDef SPIHandle5 = {.Instance = NULL};
SPI_HandleTypeDef SPIHandle6 = {.Instance = NULL};
#endif
-STATIC const pyb_spi_obj_t pyb_spi_obj[] = {
+const spi_t spi_obj[6] = {
#if defined(MICROPY_HW_SPI1_SCK)
- {{&pyb_spi_type}, &SPIHandle1, &dma_SPI_1_TX, &dma_SPI_1_RX},
+ {&SPIHandle1, &dma_SPI_1_TX, &dma_SPI_1_RX},
#else
- {{&pyb_spi_type}, NULL, NULL, NULL},
+ {NULL, NULL, NULL},
#endif
#if defined(MICROPY_HW_SPI2_SCK)
- {{&pyb_spi_type}, &SPIHandle2, &dma_SPI_2_TX, &dma_SPI_2_RX},
+ {&SPIHandle2, &dma_SPI_2_TX, &dma_SPI_2_RX},
#else
- {{&pyb_spi_type}, NULL, NULL, NULL},
+ {NULL, NULL, NULL},
#endif
#if defined(MICROPY_HW_SPI3_SCK)
- {{&pyb_spi_type}, &SPIHandle3, &dma_SPI_3_TX, &dma_SPI_3_RX},
+ {&SPIHandle3, &dma_SPI_3_TX, &dma_SPI_3_RX},
#else
- {{&pyb_spi_type}, NULL, NULL, NULL},
+ {NULL, NULL, NULL},
#endif
#if defined(MICROPY_HW_SPI4_SCK)
- {{&pyb_spi_type}, &SPIHandle4, &dma_SPI_4_TX, &dma_SPI_4_RX},
+ {&SPIHandle4, &dma_SPI_4_TX, &dma_SPI_4_RX},
#else
- {{&pyb_spi_type}, NULL, NULL, NULL},
+ {NULL, NULL, NULL},
#endif
#if defined(MICROPY_HW_SPI5_SCK)
- {{&pyb_spi_type}, &SPIHandle5, &dma_SPI_5_TX, &dma_SPI_5_RX},
+ {&SPIHandle5, &dma_SPI_5_TX, &dma_SPI_5_RX},
#else
- {{&pyb_spi_type}, NULL, NULL, NULL},
+ {NULL, NULL, NULL},
#endif
#if defined(MICROPY_HW_SPI6_SCK)
- {{&pyb_spi_type}, &SPIHandle6, &dma_SPI_6_TX, &dma_SPI_6_RX},
+ {&SPIHandle6, &dma_SPI_6_TX, &dma_SPI_6_RX},
#else
- {{&pyb_spi_type}, NULL, NULL, NULL},
+ {NULL, NULL, NULL},
#endif
};
void spi_init0(void) {
- // reset the SPI handles
+ // Initialise the SPI handles.
+ // The structs live on the BSS so all other fields will be zero after a reset.
#if defined(MICROPY_HW_SPI1_SCK)
- memset(&SPIHandle1, 0, sizeof(SPI_HandleTypeDef));
SPIHandle1.Instance = SPI1;
#endif
#if defined(MICROPY_HW_SPI2_SCK)
- memset(&SPIHandle2, 0, sizeof(SPI_HandleTypeDef));
SPIHandle2.Instance = SPI2;
#endif
#if defined(MICROPY_HW_SPI3_SCK)
- memset(&SPIHandle3, 0, sizeof(SPI_HandleTypeDef));
SPIHandle3.Instance = SPI3;
#endif
#if defined(MICROPY_HW_SPI4_SCK)
- memset(&SPIHandle4, 0, sizeof(SPI_HandleTypeDef));
SPIHandle4.Instance = SPI4;
#endif
#if defined(MICROPY_HW_SPI5_SCK)
- memset(&SPIHandle5, 0, sizeof(SPI_HandleTypeDef));
SPIHandle5.Instance = SPI5;
#endif
#if defined(MICROPY_HW_SPI6_SCK)
- memset(&SPIHandle6, 0, sizeof(SPI_HandleTypeDef));
SPIHandle6.Instance = SPI6;
#endif
}
@@ -179,14 +165,26 @@ STATIC int spi_find(mp_obj_t id) {
} else if (strcmp(port, MICROPY_HW_SPI3_NAME) == 0) {
return 3;
#endif
+ #ifdef MICROPY_HW_SPI4_NAME
+ } else if (strcmp(port, MICROPY_HW_SPI4_NAME) == 0) {
+ return 4;
+ #endif
+ #ifdef MICROPY_HW_SPI5_NAME
+ } else if (strcmp(port, MICROPY_HW_SPI5_NAME) == 0) {
+ return 5;
+ #endif
+ #ifdef MICROPY_HW_SPI6_NAME
+ } else if (strcmp(port, MICROPY_HW_SPI6_NAME) == 0) {
+ return 6;
+ #endif
}
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError,
"SPI(%s) doesn't exist", port));
} else {
// given an integer id
int spi_id = mp_obj_get_int(id);
- if (spi_id >= 1 && spi_id <= MP_ARRAY_SIZE(pyb_spi_obj)
- && pyb_spi_obj[spi_id - 1].spi != NULL) {
+ if (spi_id >= 1 && spi_id <= MP_ARRAY_SIZE(spi_obj)
+ && spi_obj[spi_id - 1].spi != NULL) {
return spi_id;
}
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError,
@@ -196,14 +194,18 @@ STATIC int spi_find(mp_obj_t id) {
// sets the parameters in the SPI_InitTypeDef struct
// if an argument is -1 then the corresponding parameter is not changed
-STATIC void spi_set_params(SPI_HandleTypeDef *spi, uint32_t prescale, int32_t baudrate,
+STATIC void spi_set_params(const spi_t *spi_obj, uint32_t prescale, int32_t baudrate,
int32_t polarity, int32_t phase, int32_t bits, int32_t firstbit) {
+ SPI_HandleTypeDef *spi = spi_obj->spi;
SPI_InitTypeDef *init = &spi->Init;
if (prescale != 0xffffffff || baudrate != -1) {
if (prescale == 0xffffffff) {
// prescaler not given, so select one that yields at most the requested baudrate
mp_uint_t spi_clock;
+ #if defined(STM32F0)
+ spi_clock = HAL_RCC_GetPCLK1Freq();
+ #else
if (spi->Instance == SPI2 || spi->Instance == SPI3) {
// SPI2 and SPI3 are on APB1
spi_clock = HAL_RCC_GetPCLK1Freq();
@@ -211,6 +213,7 @@ STATIC void spi_set_params(SPI_HandleTypeDef *spi, uint32_t prescale, int32_t ba
// SPI1, SPI4, SPI5 and SPI6 are on APB2
spi_clock = HAL_RCC_GetPCLK2Freq();
}
+ #endif
prescale = spi_clock / baudrate;
}
if (prescale <= 2) { init->BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2; }
@@ -241,83 +244,88 @@ STATIC void spi_set_params(SPI_HandleTypeDef *spi, uint32_t prescale, int32_t ba
}
// TODO allow to take a list of pins to use
-void spi_init(SPI_HandleTypeDef *spi, bool enable_nss_pin) {
- const pyb_spi_obj_t *self;
- const pin_obj_t *pins[4];
- pins[0] = NULL;
+void spi_init(const spi_t *self, bool enable_nss_pin) {
+ SPI_HandleTypeDef *spi = self->spi;
+ const pin_obj_t *pins[4] = { NULL, NULL, NULL, NULL };
if (0) {
#if defined(MICROPY_HW_SPI1_SCK)
} else if (spi->Instance == SPI1) {
- self = &pyb_spi_obj[0];
#if defined(MICROPY_HW_SPI1_NSS)
- pins[0] = &MICROPY_HW_SPI1_NSS;
+ pins[0] = MICROPY_HW_SPI1_NSS;
+ #endif
+ pins[1] = MICROPY_HW_SPI1_SCK;
+ #if defined(MICROPY_HW_SPI1_MISO)
+ pins[2] = MICROPY_HW_SPI1_MISO;
#endif
- pins[1] = &MICROPY_HW_SPI1_SCK;
- pins[2] = &MICROPY_HW_SPI1_MISO;
- pins[3] = &MICROPY_HW_SPI1_MOSI;
+ pins[3] = MICROPY_HW_SPI1_MOSI;
// enable the SPI clock
- __SPI1_CLK_ENABLE();
+ __HAL_RCC_SPI1_CLK_ENABLE();
#endif
#if defined(MICROPY_HW_SPI2_SCK)
} else if (spi->Instance == SPI2) {
- self = &pyb_spi_obj[1];
#if defined(MICROPY_HW_SPI2_NSS)
- pins[0] = &MICROPY_HW_SPI2_NSS;
+ pins[0] = MICROPY_HW_SPI2_NSS;
#endif
- pins[1] = &MICROPY_HW_SPI2_SCK;
- pins[2] = &MICROPY_HW_SPI2_MISO;
- pins[3] = &MICROPY_HW_SPI2_MOSI;
+ pins[1] = MICROPY_HW_SPI2_SCK;
+ #if defined(MICROPY_HW_SPI2_MISO)
+ pins[2] = MICROPY_HW_SPI2_MISO;
+ #endif
+ pins[3] = MICROPY_HW_SPI2_MOSI;
// enable the SPI clock
- __SPI2_CLK_ENABLE();
+ __HAL_RCC_SPI2_CLK_ENABLE();
#endif
#if defined(MICROPY_HW_SPI3_SCK)
} else if (spi->Instance == SPI3) {
- self = &pyb_spi_obj[2];
#if defined(MICROPY_HW_SPI3_NSS)
- pins[0] = &MICROPY_HW_SPI3_NSS;
+ pins[0] = MICROPY_HW_SPI3_NSS;
+ #endif
+ pins[1] = MICROPY_HW_SPI3_SCK;
+ #if defined(MICROPY_HW_SPI3_MISO)
+ pins[2] = MICROPY_HW_SPI3_MISO;
#endif
- pins[1] = &MICROPY_HW_SPI3_SCK;
- pins[2] = &MICROPY_HW_SPI3_MISO;
- pins[3] = &MICROPY_HW_SPI3_MOSI;
+ pins[3] = MICROPY_HW_SPI3_MOSI;
// enable the SPI clock
- __SPI3_CLK_ENABLE();
+ __HAL_RCC_SPI3_CLK_ENABLE();
#endif
#if defined(MICROPY_HW_SPI4_SCK)
} else if (spi->Instance == SPI4) {
- self = &pyb_spi_obj[3];
#if defined(MICROPY_HW_SPI4_NSS)
- pins[0] = &MICROPY_HW_SPI4_NSS;
+ pins[0] = MICROPY_HW_SPI4_NSS;
+ #endif
+ pins[1] = MICROPY_HW_SPI4_SCK;
+ #if defined(MICROPY_HW_SPI4_MISO)
+ pins[2] = MICROPY_HW_SPI4_MISO;
#endif
- pins[1] = &MICROPY_HW_SPI4_SCK;
- pins[2] = &MICROPY_HW_SPI4_MISO;
- pins[3] = &MICROPY_HW_SPI4_MOSI;
+ pins[3] = MICROPY_HW_SPI4_MOSI;
// enable the SPI clock
- __SPI4_CLK_ENABLE();
+ __HAL_RCC_SPI4_CLK_ENABLE();
#endif
#if defined(MICROPY_HW_SPI5_SCK)
} else if (spi->Instance == SPI5) {
- self = &pyb_spi_obj[4];
#if defined(MICROPY_HW_SPI5_NSS)
- pins[0] = &MICROPY_HW_SPI5_NSS;
+ pins[0] = MICROPY_HW_SPI5_NSS;
#endif
- pins[1] = &MICROPY_HW_SPI5_SCK;
- pins[2] = &MICROPY_HW_SPI5_MISO;
- pins[3] = &MICROPY_HW_SPI5_MOSI;
+ pins[1] = MICROPY_HW_SPI5_SCK;
+ #if defined(MICROPY_HW_SPI5_MISO)
+ pins[2] = MICROPY_HW_SPI5_MISO;
+ #endif
+ pins[3] = MICROPY_HW_SPI5_MOSI;
// enable the SPI clock
- __SPI5_CLK_ENABLE();
+ __HAL_RCC_SPI5_CLK_ENABLE();
#endif
#if defined(MICROPY_HW_SPI6_SCK)
} else if (spi->Instance == SPI6) {
- self = &pyb_spi_obj[5];
#if defined(MICROPY_HW_SPI6_NSS)
- pins[0] = &MICROPY_HW_SPI6_NSS;
+ pins[0] = MICROPY_HW_SPI6_NSS;
+ #endif
+ pins[1] = MICROPY_HW_SPI6_SCK;
+ #if defined(MICROPY_HW_SPI6_MISO)
+ pins[2] = MICROPY_HW_SPI6_MISO;
#endif
- pins[1] = &MICROPY_HW_SPI6_SCK;
- pins[2] = &MICROPY_HW_SPI6_MISO;
- pins[3] = &MICROPY_HW_SPI6_MOSI;
+ pins[3] = MICROPY_HW_SPI6_MOSI;
// enable the SPI clock
- __SPI6_CLK_ENABLE();
+ __HAL_RCC_SPI6_CLK_ENABLE();
#endif
} else {
// SPI does not exist for this board (shouldn't get here, should be checked by caller)
@@ -327,8 +335,11 @@ void spi_init(SPI_HandleTypeDef *spi, bool enable_nss_pin) {
// init the GPIO lines
uint32_t mode = MP_HAL_PIN_MODE_ALT;
uint32_t pull = spi->Init.CLKPolarity == SPI_POLARITY_LOW ? MP_HAL_PIN_PULL_DOWN : MP_HAL_PIN_PULL_UP;
- for (uint i = (enable_nss_pin && pins[0] ? 0 : 1); i < 4; i++) {
- mp_hal_pin_config_alt(pins[i], mode, pull, AF_FN_SPI, (self - &pyb_spi_obj[0]) + 1);
+ for (uint i = (enable_nss_pin ? 0 : 1); i < 4; i++) {
+ if (pins[i] == NULL) {
+ continue;
+ }
+ mp_hal_pin_config_alt(pins[i], mode, pull, AF_FN_SPI, (self - &spi_obj[0]) + 1);
}
// init the SPI device
@@ -347,55 +358,61 @@ void spi_init(SPI_HandleTypeDef *spi, bool enable_nss_pin) {
dma_invalidate_channel(self->rx_dma_descr);
}
-void spi_deinit(SPI_HandleTypeDef *spi) {
+void spi_deinit(const spi_t *spi_obj) {
+ SPI_HandleTypeDef *spi = spi_obj->spi;
HAL_SPI_DeInit(spi);
if (0) {
#if defined(MICROPY_HW_SPI1_SCK)
} else if (spi->Instance == SPI1) {
- __SPI1_FORCE_RESET();
- __SPI1_RELEASE_RESET();
- __SPI1_CLK_DISABLE();
+ __HAL_RCC_SPI1_FORCE_RESET();
+ __HAL_RCC_SPI1_RELEASE_RESET();
+ __HAL_RCC_SPI1_CLK_DISABLE();
#endif
#if defined(MICROPY_HW_SPI2_SCK)
} else if (spi->Instance == SPI2) {
- __SPI2_FORCE_RESET();
- __SPI2_RELEASE_RESET();
- __SPI2_CLK_DISABLE();
+ __HAL_RCC_SPI2_FORCE_RESET();
+ __HAL_RCC_SPI2_RELEASE_RESET();
+ __HAL_RCC_SPI2_CLK_DISABLE();
#endif
#if defined(MICROPY_HW_SPI3_SCK)
} else if (spi->Instance == SPI3) {
- __SPI3_FORCE_RESET();
- __SPI3_RELEASE_RESET();
- __SPI3_CLK_DISABLE();
+ __HAL_RCC_SPI3_FORCE_RESET();
+ __HAL_RCC_SPI3_RELEASE_RESET();
+ __HAL_RCC_SPI3_CLK_DISABLE();
#endif
#if defined(MICROPY_HW_SPI4_SCK)
} else if (spi->Instance == SPI4) {
- __SPI4_FORCE_RESET();
- __SPI4_RELEASE_RESET();
- __SPI4_CLK_DISABLE();
+ __HAL_RCC_SPI4_FORCE_RESET();
+ __HAL_RCC_SPI4_RELEASE_RESET();
+ __HAL_RCC_SPI4_CLK_DISABLE();
#endif
#if defined(MICROPY_HW_SPI5_SCK)
} else if (spi->Instance == SPI5) {
- __SPI5_FORCE_RESET();
- __SPI5_RELEASE_RESET();
- __SPI5_CLK_DISABLE();
+ __HAL_RCC_SPI5_FORCE_RESET();
+ __HAL_RCC_SPI5_RELEASE_RESET();
+ __HAL_RCC_SPI5_CLK_DISABLE();
#endif
#if defined(MICROPY_HW_SPI6_SCK)
} else if (spi->Instance == SPI6) {
- __SPI6_FORCE_RESET();
- __SPI6_RELEASE_RESET();
- __SPI6_CLK_DISABLE();
+ __HAL_RCC_SPI6_FORCE_RESET();
+ __HAL_RCC_SPI6_RELEASE_RESET();
+ __HAL_RCC_SPI6_CLK_DISABLE();
#endif
}
}
-STATIC HAL_StatusTypeDef spi_wait_dma_finished(SPI_HandleTypeDef *spi, uint32_t timeout) {
- // Note: we can't use WFI to idle in this loop because the DMA completion
- // interrupt may occur before the WFI. Hence we miss it and have to wait
- // until the next sys-tick (up to 1ms).
- uint32_t start = HAL_GetTick();
- while (HAL_SPI_GetState(spi) != HAL_SPI_STATE_READY) {
- if (HAL_GetTick() - start >= timeout) {
+STATIC HAL_StatusTypeDef spi_wait_dma_finished(const spi_t *spi, uint32_t t_start, uint32_t timeout) {
+ volatile HAL_SPI_StateTypeDef *state = &spi->spi->State;
+ for (;;) {
+ // Do an atomic check of the state; WFI will exit even if IRQs are disabled
+ uint32_t irq_state = disable_irq();
+ if (*state == HAL_SPI_STATE_READY) {
+ enable_irq(irq_state);
+ return HAL_OK;
+ }
+ __WFI();
+ enable_irq(irq_state);
+ if (HAL_GetTick() - t_start >= timeout) {
return HAL_TIMEOUT;
}
}
@@ -407,11 +424,13 @@ STATIC HAL_StatusTypeDef spi_wait_dma_finished(SPI_HandleTypeDef *spi, uint32_t
// and use that value for the baudrate in the formula, plus a small constant.
#define SPI_TRANSFER_TIMEOUT(len) ((len) + 100)
-STATIC void spi_transfer(const pyb_spi_obj_t *self, size_t len, const uint8_t *src, uint8_t *dest, uint32_t timeout) {
+STATIC void spi_transfer(const spi_t *self, size_t len, const uint8_t *src, uint8_t *dest, uint32_t timeout) {
// Note: there seems to be a problem sending 1 byte using DMA the first
// time directly after the SPI/DMA is initialised. The cause of this is
// unknown but we sidestep the issue by using polling for 1 byte transfer.
+ // Note: DMA transfers are limited to 65535 bytes at a time.
+
HAL_StatusTypeDef status;
if (dest == NULL) {
@@ -424,10 +443,20 @@ STATIC void spi_transfer(const pyb_spi_obj_t *self, size_t len, const uint8_t *s
self->spi->hdmatx = &tx_dma;
self->spi->hdmarx = NULL;
MP_HAL_CLEAN_DCACHE(src, len);
- status = HAL_SPI_Transmit_DMA(self->spi, (uint8_t*)src, len);
- if (status == HAL_OK) {
- status = spi_wait_dma_finished(self->spi, timeout);
- }
+ uint32_t t_start = HAL_GetTick();
+ do {
+ uint32_t l = MIN(len, 65535);
+ status = HAL_SPI_Transmit_DMA(self->spi, (uint8_t*)src, l);
+ if (status != HAL_OK) {
+ break;
+ }
+ status = spi_wait_dma_finished(self, t_start, timeout);
+ if (status != HAL_OK) {
+ break;
+ }
+ len -= l;
+ src += l;
+ } while (len);
dma_deinit(self->tx_dma_descr);
}
} else if (src == NULL) {
@@ -446,10 +475,20 @@ STATIC void spi_transfer(const pyb_spi_obj_t *self, size_t len, const uint8_t *s
dma_init(&rx_dma, self->rx_dma_descr, self->spi);
self->spi->hdmarx = &rx_dma;
MP_HAL_CLEANINVALIDATE_DCACHE(dest, len);
- status = HAL_SPI_Receive_DMA(self->spi, dest, len);
- if (status == HAL_OK) {
- status = spi_wait_dma_finished(self->spi, timeout);
- }
+ uint32_t t_start = HAL_GetTick();
+ do {
+ uint32_t l = MIN(len, 65535);
+ status = HAL_SPI_Receive_DMA(self->spi, dest, l);
+ if (status != HAL_OK) {
+ break;
+ }
+ status = spi_wait_dma_finished(self, t_start, timeout);
+ if (status != HAL_OK) {
+ break;
+ }
+ len -= l;
+ dest += l;
+ } while (len);
if (self->spi->hdmatx != NULL) {
dma_deinit(self->tx_dma_descr);
}
@@ -467,10 +506,21 @@ STATIC void spi_transfer(const pyb_spi_obj_t *self, size_t len, const uint8_t *s
self->spi->hdmarx = &rx_dma;
MP_HAL_CLEAN_DCACHE(src, len);
MP_HAL_CLEANINVALIDATE_DCACHE(dest, len);
- status = HAL_SPI_TransmitReceive_DMA(self->spi, (uint8_t*)src, dest, len);
- if (status == HAL_OK) {
- status = spi_wait_dma_finished(self->spi, timeout);
- }
+ uint32_t t_start = HAL_GetTick();
+ do {
+ uint32_t l = MIN(len, 65535);
+ status = HAL_SPI_TransmitReceive_DMA(self->spi, (uint8_t*)src, dest, l);
+ if (status != HAL_OK) {
+ break;
+ }
+ status = spi_wait_dma_finished(self, t_start, timeout);
+ if (status != HAL_OK) {
+ break;
+ }
+ len -= l;
+ src += l;
+ dest += l;
+ } while (len);
dma_deinit(self->tx_dma_descr);
dma_deinit(self->rx_dma_descr);
}
@@ -481,10 +531,14 @@ STATIC void spi_transfer(const pyb_spi_obj_t *self, size_t len, const uint8_t *s
}
}
-STATIC void spi_print(const mp_print_t *print, SPI_HandleTypeDef *spi, bool legacy) {
+STATIC void spi_print(const mp_print_t *print, const spi_t *spi_obj, bool legacy) {
+ SPI_HandleTypeDef *spi = spi_obj->spi;
+
uint spi_num = 1; // default to SPI1
if (spi->Instance == SPI2) { spi_num = 2; }
+ #if defined(SPI3)
else if (spi->Instance == SPI3) { spi_num = 3; }
+ #endif
#if defined(SPI4)
else if (spi->Instance == SPI4) { spi_num = 4; }
#endif
@@ -500,6 +554,9 @@ STATIC void spi_print(const mp_print_t *print, SPI_HandleTypeDef *spi, bool lega
if (spi->Init.Mode == SPI_MODE_MASTER) {
// compute baudrate
uint spi_clock;
+ #if defined(STM32F0)
+ spi_clock = HAL_RCC_GetPCLK1Freq();
+ #else
if (spi->Instance == SPI2 || spi->Instance == SPI3) {
// SPI2 and SPI3 are on APB1
spi_clock = HAL_RCC_GetPCLK1Freq();
@@ -507,6 +564,7 @@ STATIC void spi_print(const mp_print_t *print, SPI_HandleTypeDef *spi, bool lega
// SPI1, SPI4, SPI5 and SPI6 are on APB2
spi_clock = HAL_RCC_GetPCLK2Freq();
}
+ #endif
uint log_prescaler = (spi->Init.BaudRatePrescaler >> 3) + 1;
uint baudrate = spi_clock >> log_prescaler;
if (legacy) {
@@ -520,7 +578,7 @@ STATIC void spi_print(const mp_print_t *print, SPI_HandleTypeDef *spi, bool lega
mp_printf(print, ", SPI.SLAVE");
}
mp_printf(print, ", polarity=%u, phase=%u, bits=%u", spi->Init.CLKPolarity == SPI_POLARITY_LOW ? 0 : 1, spi->Init.CLKPhase == SPI_PHASE_1EDGE ? 0 : 1, spi->Init.DataSize == SPI_DATASIZE_8BIT ? 8 : 16);
- if (spi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLED) {
+ if (spi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLE) {
mp_printf(print, ", crc=0x%x", spi->Init.CRCPolynomial);
}
}
@@ -530,13 +588,19 @@ STATIC void spi_print(const mp_print_t *print, SPI_HandleTypeDef *spi, bool lega
/******************************************************************************/
/* MicroPython bindings for legacy pyb API */
-SPI_HandleTypeDef *spi_get_handle(mp_obj_t o) {
- if (!MP_OBJ_IS_TYPE(o, &pyb_spi_type)) {
- mp_raise_ValueError("expecting an SPI object");
- }
- pyb_spi_obj_t *self = o;
- return self->spi;
-}
+typedef struct _pyb_spi_obj_t {
+ mp_obj_base_t base;
+ const spi_t *spi;
+} pyb_spi_obj_t;
+
+STATIC const pyb_spi_obj_t pyb_spi_obj[] = {
+ {{&pyb_spi_type}, &spi_obj[0]},
+ {{&pyb_spi_type}, &spi_obj[1]},
+ {{&pyb_spi_type}, &spi_obj[2]},
+ {{&pyb_spi_type}, &spi_obj[3]},
+ {{&pyb_spi_type}, &spi_obj[4]},
+ {{&pyb_spi_type}, &spi_obj[5]},
+};
STATIC void pyb_spi_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
pyb_spi_obj_t *self = self_in;
@@ -569,7 +633,7 @@ STATIC mp_obj_t pyb_spi_init_helper(const pyb_spi_obj_t *self, size_t n_args, co
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
// set the SPI configuration values
- SPI_InitTypeDef *init = &self->spi->Init;
+ SPI_InitTypeDef *init = &self->spi->spi->Init;
init->Mode = args[0].u_int;
spi_set_params(self->spi, args[2].u_int, args[1].u_int, args[3].u_int, args[4].u_int,
@@ -577,12 +641,12 @@ STATIC mp_obj_t pyb_spi_init_helper(const pyb_spi_obj_t *self, size_t n_args, co
init->Direction = args[5].u_int;
init->NSS = args[7].u_int;
- init->TIMode = args[9].u_bool ? SPI_TIMODE_ENABLED : SPI_TIMODE_DISABLED;
+ init->TIMode = args[9].u_bool ? SPI_TIMODE_ENABLE : SPI_TIMODE_DISABLE;
if (args[10].u_obj == mp_const_none) {
- init->CRCCalculation = SPI_CRCCALCULATION_DISABLED;
+ init->CRCCalculation = SPI_CRCCALCULATION_DISABLE;
init->CRCPolynomial = 0;
} else {
- init->CRCCalculation = SPI_CRCCALCULATION_ENABLED;
+ init->CRCCalculation = SPI_CRCCALCULATION_ENABLE;
init->CRCPolynomial = mp_obj_get_int(args[10].u_obj);
}
@@ -667,7 +731,7 @@ STATIC mp_obj_t pyb_spi_send(size_t n_args, const mp_obj_t *pos_args, mp_map_t *
pyb_buf_get_for_send(args[0].u_obj, &bufinfo, data);
// send the data
- spi_transfer(self, bufinfo.len, bufinfo.buf, NULL, args[1].u_int);
+ spi_transfer(self->spi, bufinfo.len, bufinfo.buf, NULL, args[1].u_int);
return mp_const_none;
}
@@ -701,7 +765,7 @@ STATIC mp_obj_t pyb_spi_recv(size_t n_args, const mp_obj_t *pos_args, mp_map_t *
mp_obj_t o_ret = pyb_buf_get_for_recv(args[0].u_obj, &vstr);
// receive the data
- spi_transfer(self, vstr.len, NULL, (uint8_t*)vstr.buf, args[1].u_int);
+ spi_transfer(self->spi, vstr.len, NULL, (uint8_t*)vstr.buf, args[1].u_int);
// return the received data
if (o_ret != MP_OBJ_NULL) {
@@ -771,7 +835,7 @@ STATIC mp_obj_t pyb_spi_send_recv(size_t n_args, const mp_obj_t *pos_args, mp_ma
}
// do the transfer
- spi_transfer(self, bufinfo_send.len, bufinfo_send.buf, bufinfo_recv.buf, args[2].u_int);
+ spi_transfer(self->spi, bufinfo_send.len, bufinfo_send.buf, bufinfo_recv.buf, args[2].u_int);
// return the received data
if (o_ret != MP_OBJ_NULL) {
@@ -819,7 +883,8 @@ STATIC const mp_rom_map_elem_t pyb_spi_locals_dict_table[] = {
STATIC MP_DEFINE_CONST_DICT(pyb_spi_locals_dict, pyb_spi_locals_dict_table);
STATIC void spi_transfer_machine(mp_obj_base_t *self_in, size_t len, const uint8_t *src, uint8_t *dest) {
- spi_transfer((pyb_spi_obj_t*)self_in, len, src, dest, SPI_TRANSFER_TIMEOUT(len));
+ pyb_spi_obj_t *self = (pyb_spi_obj_t*)self_in;
+ spi_transfer(self->spi, len, src, dest, SPI_TRANSFER_TIMEOUT(len));
}
STATIC const mp_machine_spi_p_t pyb_spi_p = {
@@ -840,21 +905,21 @@ const mp_obj_type_t pyb_spi_type = {
typedef struct _machine_hard_spi_obj_t {
mp_obj_base_t base;
- const pyb_spi_obj_t *pyb;
+ const spi_t *spi;
} machine_hard_spi_obj_t;
STATIC const machine_hard_spi_obj_t machine_hard_spi_obj[] = {
- {{&machine_hard_spi_type}, &pyb_spi_obj[0]},
- {{&machine_hard_spi_type}, &pyb_spi_obj[1]},
- {{&machine_hard_spi_type}, &pyb_spi_obj[2]},
- {{&machine_hard_spi_type}, &pyb_spi_obj[3]},
- {{&machine_hard_spi_type}, &pyb_spi_obj[4]},
- {{&machine_hard_spi_type}, &pyb_spi_obj[5]},
+ {{&machine_hard_spi_type}, &spi_obj[0]},
+ {{&machine_hard_spi_type}, &spi_obj[1]},
+ {{&machine_hard_spi_type}, &spi_obj[2]},
+ {{&machine_hard_spi_type}, &spi_obj[3]},
+ {{&machine_hard_spi_type}, &spi_obj[4]},
+ {{&machine_hard_spi_type}, &spi_obj[5]},
};
STATIC void machine_hard_spi_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
machine_hard_spi_obj_t *self = (machine_hard_spi_obj_t*)self_in;
- spi_print(print, self->pyb->spi, false);
+ spi_print(print, self->spi, false);
}
mp_obj_t machine_hard_spi_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
@@ -885,23 +950,23 @@ mp_obj_t machine_hard_spi_make_new(const mp_obj_type_t *type, size_t n_args, siz
}
// set the SPI configuration values
- SPI_InitTypeDef *init = &self->pyb->spi->Init;
+ SPI_InitTypeDef *init = &self->spi->spi->Init;
init->Mode = SPI_MODE_MASTER;
// these parameters are not currently configurable
init->Direction = SPI_DIRECTION_2LINES;
init->NSS = SPI_NSS_SOFT;
- init->TIMode = SPI_TIMODE_DISABLED;
- init->CRCCalculation = SPI_CRCCALCULATION_DISABLED;
+ init->TIMode = SPI_TIMODE_DISABLE;
+ init->CRCCalculation = SPI_CRCCALCULATION_DISABLE;
init->CRCPolynomial = 0;
// set configurable paramaters
- spi_set_params(self->pyb->spi, 0xffffffff, args[ARG_baudrate].u_int,
+ spi_set_params(self->spi, 0xffffffff, args[ARG_baudrate].u_int,
args[ARG_polarity].u_int, args[ARG_phase].u_int, args[ARG_bits].u_int,
args[ARG_firstbit].u_int);
// init the SPI bus
- spi_init(self->pyb->spi, false);
+ spi_init(self->spi, false);
return MP_OBJ_FROM_PTR(self);
}
@@ -921,22 +986,22 @@ STATIC void machine_hard_spi_init(mp_obj_base_t *self_in, size_t n_args, const m
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
// set the SPI configuration values
- spi_set_params(self->pyb->spi, 0xffffffff, args[ARG_baudrate].u_int,
+ spi_set_params(self->spi, 0xffffffff, args[ARG_baudrate].u_int,
args[ARG_polarity].u_int, args[ARG_phase].u_int, args[ARG_bits].u_int,
args[ARG_firstbit].u_int);
// re-init the SPI bus
- spi_init(self->pyb->spi, false);
+ spi_init(self->spi, false);
}
STATIC void machine_hard_spi_deinit(mp_obj_base_t *self_in) {
machine_hard_spi_obj_t *self = (machine_hard_spi_obj_t*)self_in;
- spi_deinit(self->pyb->spi);
+ spi_deinit(self->spi);
}
STATIC void machine_hard_spi_transfer(mp_obj_base_t *self_in, size_t len, const uint8_t *src, uint8_t *dest) {
machine_hard_spi_obj_t *self = (machine_hard_spi_obj_t*)self_in;
- spi_transfer(self->pyb, len, src, dest, SPI_TRANSFER_TIMEOUT(len));
+ spi_transfer(self->spi, len, src, dest, SPI_TRANSFER_TIMEOUT(len));
}
STATIC const mp_machine_spi_p_t machine_hard_spi_p = {
@@ -953,3 +1018,15 @@ const mp_obj_type_t machine_hard_spi_type = {
.protocol = &machine_hard_spi_p,
.locals_dict = (mp_obj_t)&mp_machine_spi_locals_dict,
};
+
+const spi_t *spi_from_mp_obj(mp_obj_t o) {
+ if (MP_OBJ_IS_TYPE(o, &pyb_spi_type)) {
+ pyb_spi_obj_t *self = o;
+ return self->spi;
+ } else if (MP_OBJ_IS_TYPE(o, &machine_hard_spi_type)) {
+ machine_hard_spi_obj_t *self = o;;
+ return self->spi;
+ } else {
+ mp_raise_TypeError("expecting an SPI object");
+ }
+}
diff --git a/ports/stm32/spi.h b/ports/stm32/spi.h
index eda109a7e..41f91b289 100644
--- a/ports/stm32/spi.h
+++ b/ports/stm32/spi.h
@@ -23,8 +23,16 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
-#ifndef MICROPY_INCLUDED_STMHAL_SPI_H
-#define MICROPY_INCLUDED_STMHAL_SPI_H
+#ifndef MICROPY_INCLUDED_STM32_SPI_H
+#define MICROPY_INCLUDED_STM32_SPI_H
+
+#include "dma.h"
+
+typedef struct _spi_t {
+ SPI_HandleTypeDef *spi;
+ const dma_descr_t *tx_dma_descr;
+ const dma_descr_t *rx_dma_descr;
+} spi_t;
extern SPI_HandleTypeDef SPIHandle1;
extern SPI_HandleTypeDef SPIHandle2;
@@ -32,12 +40,15 @@ extern SPI_HandleTypeDef SPIHandle3;
extern SPI_HandleTypeDef SPIHandle4;
extern SPI_HandleTypeDef SPIHandle5;
extern SPI_HandleTypeDef SPIHandle6;
+
+extern const spi_t spi_obj[6];
+
extern const mp_obj_type_t pyb_spi_type;
extern const mp_obj_type_t machine_soft_spi_type;
extern const mp_obj_type_t machine_hard_spi_type;
void spi_init0(void);
-void spi_init(SPI_HandleTypeDef *spi, bool enable_nss_pin);
-SPI_HandleTypeDef *spi_get_handle(mp_obj_t o);
+void spi_init(const spi_t *spi, bool enable_nss_pin);
+const spi_t *spi_from_mp_obj(mp_obj_t o);
-#endif // MICROPY_INCLUDED_STMHAL_SPI_H
+#endif // MICROPY_INCLUDED_STM32_SPI_H
diff --git a/ports/stm32/spibdev.c b/ports/stm32/spibdev.c
new file mode 100644
index 000000000..368e63966
--- /dev/null
+++ b/ports/stm32/spibdev.c
@@ -0,0 +1,85 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017-2018 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/obj.h"
+#include "py/mperrno.h"
+#include "irq.h"
+#include "led.h"
+#include "storage.h"
+
+#if MICROPY_HW_ENABLE_STORAGE
+
+int32_t spi_bdev_ioctl(spi_bdev_t *bdev, uint32_t op, uint32_t arg) {
+ switch (op) {
+ case BDEV_IOCTL_INIT:
+ bdev->spiflash.config = (const mp_spiflash_config_t*)arg;
+ mp_spiflash_init(&bdev->spiflash);
+ bdev->flash_tick_counter_last_write = 0;
+ return 0;
+
+ case BDEV_IOCTL_IRQ_HANDLER:
+ if ((bdev->spiflash.flags & 1) && HAL_GetTick() - bdev->flash_tick_counter_last_write >= 1000) {
+ mp_spiflash_cache_flush(&bdev->spiflash);
+ led_state(PYB_LED_RED, 0); // indicate a clean cache with LED off
+ }
+ return 0;
+
+ case BDEV_IOCTL_SYNC:
+ if (bdev->spiflash.flags & 1) {
+ // we must disable USB irqs to prevent MSC contention with SPI flash
+ uint32_t basepri = raise_irq_pri(IRQ_PRI_OTG_FS);
+ mp_spiflash_cache_flush(&bdev->spiflash);
+ led_state(PYB_LED_RED, 0); // indicate a clean cache with LED off
+ restore_irq_pri(basepri);
+ }
+ return 0;
+ }
+ return -MP_EINVAL;
+}
+
+int spi_bdev_readblocks(spi_bdev_t *bdev, uint8_t *dest, uint32_t block_num, uint32_t num_blocks) {
+ // we must disable USB irqs to prevent MSC contention with SPI flash
+ uint32_t basepri = raise_irq_pri(IRQ_PRI_OTG_FS);
+ mp_spiflash_cached_read(&bdev->spiflash, block_num * FLASH_BLOCK_SIZE, num_blocks * FLASH_BLOCK_SIZE, dest);
+ restore_irq_pri(basepri);
+
+ return 0;
+}
+
+int spi_bdev_writeblocks(spi_bdev_t *bdev, const uint8_t *src, uint32_t block_num, uint32_t num_blocks) {
+ // we must disable USB irqs to prevent MSC contention with SPI flash
+ uint32_t basepri = raise_irq_pri(IRQ_PRI_OTG_FS);
+ int ret = mp_spiflash_cached_write(&bdev->spiflash, block_num * FLASH_BLOCK_SIZE, num_blocks * FLASH_BLOCK_SIZE, src);
+ if (bdev->spiflash.flags & 1) {
+ led_state(PYB_LED_RED, 1); // indicate a dirty cache with LED on
+ bdev->flash_tick_counter_last_write = HAL_GetTick();
+ }
+ restore_irq_pri(basepri);
+
+ return ret;
+}
+
+#endif
diff --git a/ports/stm32/stm32_it.c b/ports/stm32/stm32_it.c
index f1ac9b6b8..a2a8d0f2e 100644
--- a/ports/stm32/stm32_it.c
+++ b/ports/stm32/stm32_it.c
@@ -84,8 +84,12 @@
#include "usb.h"
extern void __fatal_error(const char*);
+#if defined(MICROPY_HW_USB_FS)
extern PCD_HandleTypeDef pcd_fs_handle;
+#endif
+#if defined(MICROPY_HW_USB_HS)
extern PCD_HandleTypeDef pcd_hs_handle;
+#endif
/******************************************************************************/
/* Cortex-M4 Processor Exceptions Handlers */
@@ -143,9 +147,11 @@ void HardFault_C_Handler(ExceptionRegisters_t *regs) {
NVIC_SystemReset();
}
+ #if MICROPY_HW_ENABLE_USB
// We need to disable the USB so it doesn't try to write data out on
// the VCP and then block indefinitely waiting for the buffer to drain.
pyb_usb_flags = 0;
+ #endif
mp_hal_stdout_tx_str("HardFault\r\n");
@@ -159,6 +165,7 @@ void HardFault_C_Handler(ExceptionRegisters_t *regs) {
print_reg("PC ", regs->pc);
print_reg("XPSR ", regs->xpsr);
+ #if __CORTEX_M >= 3
uint32_t cfsr = SCB->CFSR;
print_reg("HFSR ", SCB->HFSR);
@@ -169,6 +176,7 @@ void HardFault_C_Handler(ExceptionRegisters_t *regs) {
if (cfsr & 0x8000) {
print_reg("BFAR ", SCB->BFAR);
}
+ #endif
if ((void*)&_ram_start <= (void*)regs && (void*)regs < (void*)&_ram_end) {
mp_hal_stdout_tx_str("Stack:\r\n");
@@ -201,6 +209,17 @@ void HardFault_Handler(void) {
// main stack pointer (aka MSP). If CONTROL.SPSEL is 1, then the exception
// was stacked up using the process stack pointer (aka PSP).
+ #if __CORTEX_M == 0
+ __asm volatile(
+ " mov r0, lr \n"
+ " lsr r0, r0, #3 \n" // Shift Bit 3 into carry to see which stack pointer we should use.
+ " mrs r0, msp \n" // Make R0 point to main stack pointer
+ " bcc .use_msp \n" // Keep MSP in R0 if SPSEL (carry) is 0
+ " mrs r0, psp \n" // Make R0 point to process stack pointer
+ " .use_msp: \n"
+ " b HardFault_C_Handler \n" // Off to C land
+ );
+ #else
__asm volatile(
" tst lr, #4 \n" // Test Bit 3 to see which stack pointer we should use.
" ite eq \n" // Tell the assembler that the nest 2 instructions are if-then-else
@@ -208,6 +227,7 @@ void HardFault_Handler(void) {
" mrsne r0, psp \n" // Make R0 point to process stack pointer
" b HardFault_C_Handler \n" // Off to C land
);
+ #endif
}
/**
@@ -304,9 +324,11 @@ void SysTick_Handler(void) {
// be generalised in the future then a dispatch table can be used as
// follows: ((void(*)(void))(systick_dispatch[uwTick & 0xf]))();
+ #if MICROPY_HW_ENABLE_STORAGE
if (STORAGE_IDLE_TICK(uwTick)) {
NVIC->STIR = FLASH_IRQn;
}
+ #endif
if (DMA_IDLE_ENABLED() && DMA_IDLE_TICK(uwTick)) {
dma_idle_handler(uwTick);
@@ -337,14 +359,14 @@ void SysTick_Handler(void) {
* @param None
* @retval None
*/
-#if defined(USE_USB_FS)
+#if MICROPY_HW_USB_FS
void OTG_FS_IRQHandler(void) {
IRQ_ENTER(OTG_FS_IRQn);
HAL_PCD_IRQHandler(&pcd_fs_handle);
IRQ_EXIT(OTG_FS_IRQn);
}
#endif
-#if defined(USE_USB_HS)
+#if MICROPY_HW_USB_HS
void OTG_HS_IRQHandler(void) {
IRQ_ENTER(OTG_HS_IRQn);
HAL_PCD_IRQHandler(&pcd_hs_handle);
@@ -352,7 +374,7 @@ void OTG_HS_IRQHandler(void) {
}
#endif
-#if defined(USE_USB_FS) || defined(USE_USB_HS)
+#if MICROPY_HW_USB_FS || MICROPY_HW_USB_HS
/**
* @brief This function handles USB OTG Common FS/HS Wakeup functions.
* @param *pcd_handle for FS or HS
@@ -367,7 +389,7 @@ STATIC void OTG_CMD_WKUP_Handler(PCD_HandleTypeDef *pcd_handle) {
/* Configures system clock after wake-up from STOP: enable HSE, PLL and select
PLL as system clock source (HSE and PLL are disabled in STOP mode) */
- __HAL_RCC_HSE_CONFIG(RCC_HSE_ON);
+ __HAL_RCC_HSE_CONFIG(MICROPY_HW_CLK_HSE_STATE);
/* Wait till HSE is ready */
while(__HAL_RCC_GET_FLAG(RCC_FLAG_HSERDY) == RESET)
@@ -383,8 +405,13 @@ STATIC void OTG_CMD_WKUP_Handler(PCD_HandleTypeDef *pcd_handle) {
/* Select PLL as SYSCLK */
MODIFY_REG(RCC->CFGR, RCC_CFGR_SW, RCC_SYSCLKSOURCE_PLLCLK);
+ #if defined(STM32H7)
+ while (__HAL_RCC_GET_SYSCLK_SOURCE() != RCC_CFGR_SWS_PLL1)
+ {}
+ #else
while (__HAL_RCC_GET_SYSCLK_SOURCE() != RCC_CFGR_SWS_PLL)
{}
+ #endif
/* ungate PHY clock */
__HAL_PCD_UNGATE_PHYCLOCK(pcd_handle);
@@ -393,7 +420,7 @@ STATIC void OTG_CMD_WKUP_Handler(PCD_HandleTypeDef *pcd_handle) {
}
#endif
-#if defined(USE_USB_FS)
+#if MICROPY_HW_USB_FS
/**
* @brief This function handles USB OTG FS Wakeup IRQ Handler.
* @param None
@@ -411,7 +438,7 @@ void OTG_FS_WKUP_IRQHandler(void) {
}
#endif
-#if defined(USE_USB_HS)
+#if MICROPY_HW_USB_HS
/**
* @brief This function handles USB OTG HS Wakeup IRQ Handler.
* @param None
@@ -448,8 +475,10 @@ void FLASH_IRQHandler(void) {
HAL_FLASH_IRQHandler();
}
*/
+ #if MICROPY_HW_ENABLE_STORAGE
// This call the storage IRQ handler, to check if the flash cache needs flushing
storage_irq_handler();
+ #endif
IRQ_EXIT(FLASH_IRQn);
}
@@ -515,7 +544,7 @@ void PVD_IRQHandler(void) {
IRQ_EXIT(PVD_IRQn);
}
-#if defined(MCU_SERIES_L4)
+#if defined(STM32L4)
void PVD_PVM_IRQHandler(void) {
IRQ_ENTER(PVD_PVM_IRQn);
Handle_EXTI_Irq(EXTI_PVD_OUTPUT);
@@ -550,13 +579,52 @@ void RTC_WKUP_IRQHandler(void) {
IRQ_EXIT(RTC_WKUP_IRQn);
}
+#if defined(STM32F0)
+
+void RTC_IRQHandler(void) {
+ IRQ_ENTER(RTC_IRQn);
+ RTC->ISR &= ~(1 << 10); // clear wakeup interrupt flag
+ Handle_EXTI_Irq(EXTI_RTC_WAKEUP); // clear EXTI flag and execute optional callback
+ IRQ_EXIT(RTC_IRQn);
+}
+
+void EXTI0_1_IRQHandler(void) {
+ IRQ_ENTER(EXTI0_1_IRQn);
+ Handle_EXTI_Irq(0);
+ Handle_EXTI_Irq(1);
+ IRQ_EXIT(EXTI0_1_IRQn);
+}
+
+void EXTI2_3_IRQHandler(void) {
+ IRQ_ENTER(EXTI2_3_IRQn);
+ Handle_EXTI_Irq(2);
+ Handle_EXTI_Irq(3);
+ IRQ_EXIT(EXTI2_3_IRQn);
+}
+
+void EXTI4_15_IRQHandler(void) {
+ IRQ_ENTER(EXTI4_15_IRQn);
+ for (int i = 4; i <= 15; ++i) {
+ Handle_EXTI_Irq(i);
+ }
+ IRQ_EXIT(EXTI4_15_IRQn);
+}
+
+void TIM1_BRK_UP_TRG_COM_IRQHandler(void) {
+ IRQ_ENTER(TIM1_BRK_UP_TRG_COM_IRQn);
+ timer_irq_handler(1);
+ IRQ_EXIT(TIM1_BRK_UP_TRG_COM_IRQn);
+}
+
+#endif
+
void TIM1_BRK_TIM9_IRQHandler(void) {
IRQ_ENTER(TIM1_BRK_TIM9_IRQn);
timer_irq_handler(9);
IRQ_EXIT(TIM1_BRK_TIM9_IRQn);
}
-#if defined(MCU_SERIES_L4)
+#if defined(STM32L4)
void TIM1_BRK_TIM15_IRQHandler(void) {
IRQ_ENTER(TIM1_BRK_TIM15_IRQn);
timer_irq_handler(15);
@@ -571,7 +639,7 @@ void TIM1_UP_TIM10_IRQHandler(void) {
IRQ_EXIT(TIM1_UP_TIM10_IRQn);
}
-#if defined(MCU_SERIES_L4)
+#if defined(STM32L4)
void TIM1_UP_TIM16_IRQHandler(void) {
IRQ_ENTER(TIM1_UP_TIM16_IRQn);
timer_irq_handler(1);
@@ -586,7 +654,7 @@ void TIM1_TRG_COM_TIM11_IRQHandler(void) {
IRQ_EXIT(TIM1_TRG_COM_TIM11_IRQn);
}
-#if defined(MCU_SERIES_L4)
+#if defined(STM32L4)
void TIM1_TRG_COM_TIM17_IRQHandler(void) {
IRQ_ENTER(TIM1_TRG_COM_TIM17_IRQn);
timer_irq_handler(17);
@@ -655,7 +723,7 @@ void TIM8_UP_TIM13_IRQHandler(void) {
IRQ_EXIT(TIM8_UP_TIM13_IRQn);
}
-#if defined(MCU_SERIES_L4)
+#if defined(STM32L4)
void TIM8_UP_IRQHandler(void) {
IRQ_ENTER(TIM8_UP_IRQn);
timer_irq_handler(8);
@@ -689,6 +757,21 @@ void USART2_IRQHandler(void) {
IRQ_EXIT(USART2_IRQn);
}
+#if defined(STM32F0)
+
+void USART3_8_IRQHandler(void) {
+ IRQ_ENTER(USART3_8_IRQn);
+ uart_irq_handler(3);
+ uart_irq_handler(4);
+ uart_irq_handler(5);
+ uart_irq_handler(6);
+ uart_irq_handler(7);
+ uart_irq_handler(8);
+ IRQ_EXIT(USART3_8_IRQn);
+}
+
+#else
+
void USART3_IRQHandler(void) {
IRQ_ENTER(USART3_IRQn);
uart_irq_handler(3);
@@ -713,7 +796,7 @@ void USART6_IRQHandler(void) {
IRQ_EXIT(USART6_IRQn);
}
-#if defined(MICROPY_HW_UART7_TX)
+#if defined(UART8)
void UART7_IRQHandler(void) {
IRQ_ENTER(UART7_IRQn);
uart_irq_handler(7);
@@ -721,7 +804,7 @@ void UART7_IRQHandler(void) {
}
#endif
-#if defined(MICROPY_HW_UART8_TX)
+#if defined(UART8)
void UART8_IRQHandler(void) {
IRQ_ENTER(UART8_IRQn);
uart_irq_handler(8);
@@ -729,7 +812,9 @@ void UART8_IRQHandler(void) {
}
#endif
-#if MICROPY_HW_ENABLE_CAN
+#endif
+
+#if defined(MICROPY_HW_CAN1_TX)
void CAN1_RX0_IRQHandler(void) {
IRQ_ENTER(CAN1_RX0_IRQn);
can_rx_irq_handler(PYB_CAN_1, CAN_FIFO0);
@@ -742,6 +827,14 @@ void CAN1_RX1_IRQHandler(void) {
IRQ_EXIT(CAN1_RX1_IRQn);
}
+void CAN1_SCE_IRQHandler(void) {
+ IRQ_ENTER(CAN1_SCE_IRQn);
+ can_sce_irq_handler(PYB_CAN_1);
+ IRQ_EXIT(CAN1_SCE_IRQn);
+}
+#endif
+
+#if defined(MICROPY_HW_CAN2_TX)
void CAN2_RX0_IRQHandler(void) {
IRQ_ENTER(CAN2_RX0_IRQn);
can_rx_irq_handler(PYB_CAN_2, CAN_FIFO0);
@@ -753,7 +846,15 @@ void CAN2_RX1_IRQHandler(void) {
can_rx_irq_handler(PYB_CAN_2, CAN_FIFO1);
IRQ_EXIT(CAN2_RX1_IRQn);
}
-#endif // MICROPY_HW_ENABLE_CAN
+
+void CAN2_SCE_IRQHandler(void) {
+ IRQ_ENTER(CAN2_SCE_IRQn);
+ can_sce_irq_handler(PYB_CAN_2);
+ IRQ_EXIT(CAN2_SCE_IRQn);
+}
+#endif
+
+#if MICROPY_PY_PYB_LEGACY
#if defined(MICROPY_HW_I2C1_SCL)
void I2C1_EV_IRQHandler(void) {
@@ -796,3 +897,19 @@ void I2C3_ER_IRQHandler(void) {
IRQ_EXIT(I2C3_ER_IRQn);
}
#endif // defined(MICROPY_HW_I2C3_SCL)
+
+#if defined(MICROPY_HW_I2C4_SCL)
+void I2C4_EV_IRQHandler(void) {
+ IRQ_ENTER(I2C4_EV_IRQn);
+ i2c_ev_irq_handler(4);
+ IRQ_EXIT(I2C4_EV_IRQn);
+}
+
+void I2C4_ER_IRQHandler(void) {
+ IRQ_ENTER(I2C4_ER_IRQn);
+ i2c_er_irq_handler(4);
+ IRQ_EXIT(I2C4_ER_IRQn);
+}
+#endif // defined(MICROPY_HW_I2C4_SCL)
+
+#endif // MICROPY_PY_PYB_LEGACY
diff --git a/ports/stm32/stm32_it.h b/ports/stm32/stm32_it.h
index b498dee8d..46523e567 100644
--- a/ports/stm32/stm32_it.h
+++ b/ports/stm32/stm32_it.h
@@ -25,8 +25,8 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
-#ifndef MICROPY_INCLUDED_STMHAL_STM32_IT_H
-#define MICROPY_INCLUDED_STMHAL_STM32_IT_H
+#ifndef MICROPY_INCLUDED_STM32_STM32_IT_H
+#define MICROPY_INCLUDED_STM32_STM32_IT_H
/**
******************************************************************************
@@ -76,11 +76,7 @@ void SVC_Handler(void);
void DebugMon_Handler(void);
void PendSV_Handler(void);
void SysTick_Handler(void);
-#ifdef USE_USB_FS
void OTG_FS_IRQHandler(void);
-#endif
-#ifdef USE_USB_HS
void OTG_HS_IRQHandler(void);
-#endif
-#endif // MICROPY_INCLUDED_STMHAL_STM32_IT_H
+#endif // MICROPY_INCLUDED_STM32_STM32_IT_H
diff --git a/ports/stm32/storage.c b/ports/stm32/storage.c
index 4b329c2db..761db0b52 100644
--- a/ports/stm32/storage.c
+++ b/ports/stm32/storage.c
@@ -3,7 +3,7 @@
*
* The MIT License (MIT)
*
- * Copyright (c) 2013, 2014 Damien P. George
+ * Copyright (c) 2013-2018 Damien P. George
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -27,191 +27,39 @@
#include <stdint.h>
#include <string.h>
-#include "py/obj.h"
#include "py/runtime.h"
-#include "lib/oofatfs/ff.h"
#include "extmod/vfs_fat.h"
-#include "systick.h"
#include "led.h"
-#include "flash.h"
#include "storage.h"
#include "irq.h"
-#if defined(MICROPY_HW_SPIFLASH_SIZE_BITS)
-#define USE_INTERNAL (0)
-#else
-#define USE_INTERNAL (1)
-#endif
-
-#if USE_INTERNAL
-
-#if defined(STM32F405xx) || defined(STM32F415xx) || defined(STM32F407xx)
-
-#define CACHE_MEM_START_ADDR (0x10000000) // CCM data RAM, 64k
-#define FLASH_SECTOR_SIZE_MAX (0x10000) // 64k max, size of CCM
-#define FLASH_MEM_SEG1_START_ADDR (0x08004000) // sector 1
-#define FLASH_MEM_SEG1_NUM_BLOCKS (224) // sectors 1,2,3,4: 16k+16k+16k+64k=112k
-
-// enable this to get an extra 64k of storage (uses the last sector of the flash)
-#if 0
-#define FLASH_MEM_SEG2_START_ADDR (0x080e0000) // sector 11
-#define FLASH_MEM_SEG2_NUM_BLOCKS (128) // sector 11: 128k
-#endif
-
-#elif defined(STM32F401xE) || defined(STM32F411xE) || defined(STM32F446xx)
-
-STATIC byte flash_cache_mem[0x4000] __attribute__((aligned(4))); // 16k
-#define CACHE_MEM_START_ADDR (&flash_cache_mem[0])
-#define FLASH_SECTOR_SIZE_MAX (0x4000) // 16k max due to size of cache buffer
-#define FLASH_MEM_SEG1_START_ADDR (0x08004000) // sector 1
-#define FLASH_MEM_SEG1_NUM_BLOCKS (128) // sectors 1,2,3,4: 16k+16k+16k+16k(of 64k)=64k
-
-#elif defined(STM32F429xx)
-
-#define CACHE_MEM_START_ADDR (0x10000000) // CCM data RAM, 64k
-#define FLASH_SECTOR_SIZE_MAX (0x10000) // 64k max, size of CCM
-#define FLASH_MEM_SEG1_START_ADDR (0x08004000) // sector 1
-#define FLASH_MEM_SEG1_NUM_BLOCKS (224) // sectors 1,2,3,4: 16k+16k+16k+64k=112k
-
-#elif defined(STM32F439xx)
-
-#define CACHE_MEM_START_ADDR (0x10000000) // CCM data RAM, 64k
-#define FLASH_SECTOR_SIZE_MAX (0x10000) // 64k max, size of CCM
-#define FLASH_MEM_SEG1_START_ADDR (0x08100000) // sector 12
-#define FLASH_MEM_SEG1_NUM_BLOCKS (384) // sectors 12,13,14,15,16,17: 16k+16k+16k+16k+64k+64k(of 128k)=192k
-#define FLASH_MEM_SEG2_START_ADDR (0x08140000) // sector 18
-#define FLASH_MEM_SEG2_NUM_BLOCKS (128) // sector 18: 64k(of 128k)
-
-#elif defined(STM32F746xx) || defined(STM32F767xx) || defined(STM32F769xx)
-
-// The STM32F746 doesn't really have CCRAM, so we use the 64K DTCM for this.
-
-#define CACHE_MEM_START_ADDR (0x20000000) // DTCM data RAM, 64k
-#define FLASH_SECTOR_SIZE_MAX (0x08000) // 32k max
-#define FLASH_MEM_SEG1_START_ADDR (0x08008000) // sector 1
-#define FLASH_MEM_SEG1_NUM_BLOCKS (192) // sectors 1,2,3: 32k+32k+32=96k
-
-#elif defined(STM32L475xx) || defined(STM32L476xx)
-
-extern uint8_t _flash_fs_start;
-extern uint8_t _flash_fs_end;
-
-// The STM32L475/6 doesn't have CCRAM, so we use the 32K SRAM2 for this.
-#define CACHE_MEM_START_ADDR (0x10000000) // SRAM2 data RAM, 32k
-#define FLASH_SECTOR_SIZE_MAX (0x00800) // 2k max
-#define FLASH_MEM_SEG1_START_ADDR ((long)&_flash_fs_start)
-#define FLASH_MEM_SEG1_NUM_BLOCKS ((&_flash_fs_end - &_flash_fs_start) / 512)
-
-#else
-#error "no storage support for this MCU"
-#endif
-
-#if !defined(FLASH_MEM_SEG2_START_ADDR)
-#define FLASH_MEM_SEG2_START_ADDR (0) // no second segment
-#define FLASH_MEM_SEG2_NUM_BLOCKS (0) // no second segment
-#endif
+#if MICROPY_HW_ENABLE_STORAGE
#define FLASH_PART1_START_BLOCK (0x100)
-#define FLASH_PART1_NUM_BLOCKS (FLASH_MEM_SEG1_NUM_BLOCKS + FLASH_MEM_SEG2_NUM_BLOCKS)
-
-#define FLASH_FLAG_DIRTY (1)
-#define FLASH_FLAG_FORCE_WRITE (2)
-#define FLASH_FLAG_ERASED (4)
-static bool flash_is_initialised = false;
-static __IO uint8_t flash_flags = 0;
-static uint32_t flash_cache_sector_id;
-static uint32_t flash_cache_sector_start;
-static uint32_t flash_cache_sector_size;
-static uint32_t flash_tick_counter_last_write;
-
-static void flash_cache_flush(void) {
- if (flash_flags & FLASH_FLAG_DIRTY) {
- flash_flags |= FLASH_FLAG_FORCE_WRITE;
- while (flash_flags & FLASH_FLAG_DIRTY) {
- NVIC->STIR = FLASH_IRQn;
- }
- }
-}
-
-static uint8_t *flash_cache_get_addr_for_write(uint32_t flash_addr) {
- uint32_t flash_sector_start;
- uint32_t flash_sector_size;
- uint32_t flash_sector_id = flash_get_sector_info(flash_addr, &flash_sector_start, &flash_sector_size);
- if (flash_sector_size > FLASH_SECTOR_SIZE_MAX) {
- flash_sector_size = FLASH_SECTOR_SIZE_MAX;
- }
- if (flash_cache_sector_id != flash_sector_id) {
- flash_cache_flush();
- memcpy((void*)CACHE_MEM_START_ADDR, (const void*)flash_sector_start, flash_sector_size);
- flash_cache_sector_id = flash_sector_id;
- flash_cache_sector_start = flash_sector_start;
- flash_cache_sector_size = flash_sector_size;
- }
- flash_flags |= FLASH_FLAG_DIRTY;
- led_state(PYB_LED_RED, 1); // indicate a dirty cache with LED on
- flash_tick_counter_last_write = HAL_GetTick();
- return (uint8_t*)CACHE_MEM_START_ADDR + flash_addr - flash_sector_start;
-}
-
-static uint8_t *flash_cache_get_addr_for_read(uint32_t flash_addr) {
- uint32_t flash_sector_start;
- uint32_t flash_sector_size;
- uint32_t flash_sector_id = flash_get_sector_info(flash_addr, &flash_sector_start, &flash_sector_size);
- if (flash_cache_sector_id == flash_sector_id) {
- // in cache, copy from there
- return (uint8_t*)CACHE_MEM_START_ADDR + flash_addr - flash_sector_start;
- }
- // not in cache, copy straight from flash
- return (uint8_t*)flash_addr;
-}
-#else
-
-#include "drivers/memory/spiflash.h"
-#include "genhdr/pins.h"
+#if defined(MICROPY_HW_BDEV2_IOCTL)
+#define FLASH_PART2_START_BLOCK (FLASH_PART1_START_BLOCK + MICROPY_HW_BDEV2_IOCTL(BDEV_IOCTL_NUM_BLOCKS, 0))
+#endif
-#define FLASH_PART1_START_BLOCK (0x100)
-#define FLASH_PART1_NUM_BLOCKS (MICROPY_HW_SPIFLASH_SIZE_BITS / 8 / FLASH_BLOCK_SIZE)
-
-static bool flash_is_initialised = false;
-
-STATIC const mp_machine_soft_spi_obj_t spiflash_spi_bus = {
- .base = {&mp_machine_soft_spi_type},
- .delay_half = MICROPY_PY_MACHINE_SPI_MIN_DELAY,
- .polarity = 0,
- .phase = 0,
- .sck = &MICROPY_HW_SPIFLASH_SCK,
- .mosi = &MICROPY_HW_SPIFLASH_MOSI,
- .miso = &MICROPY_HW_SPIFLASH_MISO,
-};
+static bool storage_is_initialised = false;
-STATIC const mp_spiflash_t spiflash = {
- .cs = &MICROPY_HW_SPIFLASH_CS,
- .spi = (mp_obj_base_t*)&spiflash_spi_bus.base,
-};
+void storage_init(void) {
+ if (!storage_is_initialised) {
+ storage_is_initialised = true;
-#endif
+ MICROPY_HW_BDEV_IOCTL(BDEV_IOCTL_INIT, 0);
-void storage_init(void) {
- if (!flash_is_initialised) {
- #if USE_INTERNAL
- flash_flags = 0;
- flash_cache_sector_id = 0;
- flash_tick_counter_last_write = 0;
- #else
- mp_spiflash_init((mp_spiflash_t*)&spiflash);
+ #if defined(MICROPY_HW_BDEV2_IOCTL)
+ MICROPY_HW_BDEV2_IOCTL(BDEV_IOCTL_INIT, 0);
#endif
- flash_is_initialised = true;
- }
- #if USE_INTERNAL
- // Enable the flash IRQ, which is used to also call our storage IRQ handler
- // It needs to go at a higher priority than all those components that rely on
- // the flash storage (eg higher than USB MSC).
- HAL_NVIC_SetPriority(FLASH_IRQn, IRQ_PRI_FLASH, IRQ_SUBPRI_FLASH);
- HAL_NVIC_EnableIRQ(FLASH_IRQn);
- #endif
+ // Enable the flash IRQ, which is used to also call our storage IRQ handler
+ // It needs to go at a higher priority than all those components that rely on
+ // the flash storage (eg higher than USB MSC).
+ NVIC_SetPriority(FLASH_IRQn, IRQ_PRI_FLASH);
+ HAL_NVIC_EnableIRQ(FLASH_IRQn);
+ }
}
uint32_t storage_get_block_size(void) {
@@ -219,59 +67,24 @@ uint32_t storage_get_block_size(void) {
}
uint32_t storage_get_block_count(void) {
- return FLASH_PART1_START_BLOCK + FLASH_PART1_NUM_BLOCKS;
+ #if defined(MICROPY_HW_BDEV2_IOCTL)
+ return FLASH_PART2_START_BLOCK + MICROPY_HW_BDEV2_IOCTL(BDEV_IOCTL_NUM_BLOCKS, 0);
+ #else
+ return FLASH_PART1_START_BLOCK + MICROPY_HW_BDEV_IOCTL(BDEV_IOCTL_NUM_BLOCKS, 0);
+ #endif
}
void storage_irq_handler(void) {
- #if USE_INTERNAL
-
- if (!(flash_flags & FLASH_FLAG_DIRTY)) {
- return;
- }
-
- // This code uses interrupts to erase the flash
- /*
- if (flash_erase_state == 0) {
- flash_erase_it(flash_cache_sector_start, (const uint32_t*)CACHE_MEM_START_ADDR, flash_cache_sector_size / 4);
- flash_erase_state = 1;
- return;
- }
-
- if (flash_erase_state == 1) {
- // wait for erase
- // TODO add timeout
- #define flash_erase_done() (__HAL_FLASH_GET_FLAG(FLASH_FLAG_BSY) == RESET)
- if (!flash_erase_done()) {
- return;
- }
- flash_erase_state = 2;
- }
- */
-
- // This code erases the flash directly, waiting for it to finish
- if (!(flash_flags & FLASH_FLAG_ERASED)) {
- flash_erase(flash_cache_sector_start, (const uint32_t*)CACHE_MEM_START_ADDR, flash_cache_sector_size / 4);
- flash_flags |= FLASH_FLAG_ERASED;
- return;
- }
-
- // If not a forced write, wait at least 5 seconds after last write to flush
- // On file close and flash unmount we get a forced write, so we can afford to wait a while
- if ((flash_flags & FLASH_FLAG_FORCE_WRITE) || sys_tick_has_passed(flash_tick_counter_last_write, 5000)) {
- // sync the cache RAM buffer by writing it to the flash page
- flash_write(flash_cache_sector_start, (const uint32_t*)CACHE_MEM_START_ADDR, flash_cache_sector_size / 4);
- // clear the flash flags now that we have a clean cache
- flash_flags = 0;
- // indicate a clean cache with LED off
- led_state(PYB_LED_RED, 0);
- }
-
+ MICROPY_HW_BDEV_IOCTL(BDEV_IOCTL_IRQ_HANDLER, 0);
+ #if defined(MICROPY_HW_BDEV2_IOCTL)
+ MICROPY_HW_BDEV2_IOCTL(BDEV_IOCTL_IRQ_HANDLER, 0);
#endif
}
void storage_flush(void) {
- #if USE_INTERNAL
- flash_cache_flush();
+ MICROPY_HW_BDEV_IOCTL(BDEV_IOCTL_SYNC, 0);
+ #if defined(MICROPY_HW_BDEV2_IOCTL)
+ MICROPY_HW_BDEV2_IOCTL(BDEV_IOCTL_SYNC, 0);
#endif
}
@@ -311,25 +124,6 @@ static void build_partition(uint8_t *buf, int boot, int type, uint32_t start_blo
buf[15] = num_blocks >> 24;
}
-#if USE_INTERNAL
-
-static uint32_t convert_block_to_flash_addr(uint32_t block) {
- if (FLASH_PART1_START_BLOCK <= block && block < FLASH_PART1_START_BLOCK + FLASH_PART1_NUM_BLOCKS) {
- // a block in partition 1
- block -= FLASH_PART1_START_BLOCK;
- if (block < FLASH_MEM_SEG1_NUM_BLOCKS) {
- return FLASH_MEM_SEG1_START_ADDR + block * FLASH_BLOCK_SIZE;
- } else if (block < FLASH_MEM_SEG1_NUM_BLOCKS + FLASH_MEM_SEG2_NUM_BLOCKS) {
- return FLASH_MEM_SEG2_START_ADDR + (block - FLASH_MEM_SEG1_NUM_BLOCKS) * FLASH_BLOCK_SIZE;
- }
- // can add more flash segments here if needed, following above pattern
- }
- // bad block
- return -1;
-}
-
-#endif
-
bool storage_read_block(uint8_t *dest, uint32_t block) {
//printf("RD %u\n", block);
if (block == 0) {
@@ -339,8 +133,12 @@ bool storage_read_block(uint8_t *dest, uint32_t block) {
dest[i] = 0;
}
- build_partition(dest + 446, 0, 0x01 /* FAT12 */, FLASH_PART1_START_BLOCK, FLASH_PART1_NUM_BLOCKS);
+ build_partition(dest + 446, 0, 0x01 /* FAT12 */, FLASH_PART1_START_BLOCK, MICROPY_HW_BDEV_IOCTL(BDEV_IOCTL_NUM_BLOCKS, 0));
+ #if defined(MICROPY_HW_BDEV2_IOCTL)
+ build_partition(dest + 462, 0, 0x01 /* FAT12 */, FLASH_PART2_START_BLOCK, MICROPY_HW_BDEV2_IOCTL(BDEV_IOCTL_NUM_BLOCKS, 0));
+ #else
build_partition(dest + 462, 0, 0, 0, 0);
+ #endif
build_partition(dest + 478, 0, 0, 0, 0);
build_partition(dest + 494, 0, 0, 0, 0);
@@ -349,39 +147,12 @@ bool storage_read_block(uint8_t *dest, uint32_t block) {
return true;
+ #if defined(MICROPY_HW_BDEV_READBLOCK)
+ } else if (FLASH_PART1_START_BLOCK <= block && block < FLASH_PART1_START_BLOCK + MICROPY_HW_BDEV_IOCTL(BDEV_IOCTL_NUM_BLOCKS, 0)) {
+ return MICROPY_HW_BDEV_READBLOCK(dest, block - FLASH_PART1_START_BLOCK);
+ #endif
} else {
- #if USE_INTERNAL
-
- // non-MBR block, get data from flash memory, possibly via cache
- uint32_t flash_addr = convert_block_to_flash_addr(block);
- if (flash_addr == -1) {
- // bad block number
- return false;
- }
- uint8_t *src = flash_cache_get_addr_for_read(flash_addr);
- memcpy(dest, src, FLASH_BLOCK_SIZE);
- return true;
-
- #else
-
- // non-MBR block, get data from SPI flash
-
- if (block < FLASH_PART1_START_BLOCK || block >= FLASH_PART1_START_BLOCK + FLASH_PART1_NUM_BLOCKS) {
- // bad block number
- return false;
- }
-
- // we must disable USB irqs to prevent MSC contention with SPI flash
- uint32_t basepri = raise_irq_pri(IRQ_PRI_OTG_FS);
-
- mp_spiflash_read((mp_spiflash_t*)&spiflash,
- (block - FLASH_PART1_START_BLOCK) * FLASH_BLOCK_SIZE, FLASH_BLOCK_SIZE, dest);
-
- restore_irq_pri(basepri);
-
- return true;
-
- #endif
+ return false;
}
}
@@ -390,44 +161,28 @@ bool storage_write_block(const uint8_t *src, uint32_t block) {
if (block == 0) {
// can't write MBR, but pretend we did
return true;
-
+ #if defined(MICROPY_HW_BDEV_WRITEBLOCK)
+ } else if (FLASH_PART1_START_BLOCK <= block && block < FLASH_PART1_START_BLOCK + MICROPY_HW_BDEV_IOCTL(BDEV_IOCTL_NUM_BLOCKS, 0)) {
+ return MICROPY_HW_BDEV_WRITEBLOCK(src, block - FLASH_PART1_START_BLOCK);
+ #endif
} else {
- #if USE_INTERNAL
-
- // non-MBR block, copy to cache
- uint32_t flash_addr = convert_block_to_flash_addr(block);
- if (flash_addr == -1) {
- // bad block number
- return false;
- }
- uint8_t *dest = flash_cache_get_addr_for_write(flash_addr);
- memcpy(dest, src, FLASH_BLOCK_SIZE);
- return true;
-
- #else
-
- // non-MBR block, write to SPI flash
-
- if (block < FLASH_PART1_START_BLOCK || block >= FLASH_PART1_START_BLOCK + FLASH_PART1_NUM_BLOCKS) {
- // bad block number
- return false;
- }
-
- // we must disable USB irqs to prevent MSC contention with SPI flash
- uint32_t basepri = raise_irq_pri(IRQ_PRI_OTG_FS);
-
- int ret = mp_spiflash_write((mp_spiflash_t*)&spiflash,
- (block - FLASH_PART1_START_BLOCK) * FLASH_BLOCK_SIZE, FLASH_BLOCK_SIZE, src);
-
- restore_irq_pri(basepri);
-
- return ret == 0;
-
- #endif
+ return false;
}
}
mp_uint_t storage_read_blocks(uint8_t *dest, uint32_t block_num, uint32_t num_blocks) {
+ #if defined(MICROPY_HW_BDEV_READBLOCKS)
+ if (FLASH_PART1_START_BLOCK <= block_num && block_num + num_blocks <= FLASH_PART1_START_BLOCK + MICROPY_HW_BDEV_IOCTL(BDEV_IOCTL_NUM_BLOCKS, 0)) {
+ return MICROPY_HW_BDEV_READBLOCKS(dest, block_num - FLASH_PART1_START_BLOCK, num_blocks);
+ }
+ #endif
+
+ #if defined(MICROPY_HW_BDEV2_READBLOCKS)
+ if (FLASH_PART2_START_BLOCK <= block_num && block_num + num_blocks <= FLASH_PART2_START_BLOCK + MICROPY_HW_BDEV2_IOCTL(BDEV_IOCTL_NUM_BLOCKS, 0)) {
+ return MICROPY_HW_BDEV2_READBLOCKS(dest, block_num - FLASH_PART2_START_BLOCK, num_blocks);
+ }
+ #endif
+
for (size_t i = 0; i < num_blocks; i++) {
if (!storage_read_block(dest + i * FLASH_BLOCK_SIZE, block_num + i)) {
return 1; // error
@@ -437,6 +192,18 @@ mp_uint_t storage_read_blocks(uint8_t *dest, uint32_t block_num, uint32_t num_bl
}
mp_uint_t storage_write_blocks(const uint8_t *src, uint32_t block_num, uint32_t num_blocks) {
+ #if defined(MICROPY_HW_BDEV_WRITEBLOCKS)
+ if (FLASH_PART1_START_BLOCK <= block_num && block_num + num_blocks <= FLASH_PART1_START_BLOCK + MICROPY_HW_BDEV_IOCTL(BDEV_IOCTL_NUM_BLOCKS, 0)) {
+ return MICROPY_HW_BDEV_WRITEBLOCKS(src, block_num - FLASH_PART1_START_BLOCK, num_blocks);
+ }
+ #endif
+
+ #if defined(MICROPY_HW_BDEV2_WRITEBLOCKS)
+ if (FLASH_PART2_START_BLOCK <= block_num && block_num + num_blocks <= FLASH_PART2_START_BLOCK + MICROPY_HW_BDEV2_IOCTL(BDEV_IOCTL_NUM_BLOCKS, 0)) {
+ return MICROPY_HW_BDEV2_WRITEBLOCKS(src, block_num - FLASH_PART2_START_BLOCK, num_blocks);
+ }
+ #endif
+
for (size_t i = 0; i < num_blocks; i++) {
if (!storage_write_block(src + i * FLASH_BLOCK_SIZE, block_num + i)) {
return 1; // error
@@ -519,3 +286,5 @@ void pyb_flash_init_vfs(fs_user_mount_t *vfs) {
vfs->u.ioctl[0] = (mp_obj_t)&pyb_flash_ioctl_obj;
vfs->u.ioctl[1] = (mp_obj_t)&pyb_flash_obj;
}
+
+#endif
diff --git a/ports/stm32/storage.h b/ports/stm32/storage.h
index 291e09a9a..7250b6dbf 100644
--- a/ports/stm32/storage.h
+++ b/ports/stm32/storage.h
@@ -23,14 +23,24 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
-#ifndef MICROPY_INCLUDED_STMHAL_STORAGE_H
-#define MICROPY_INCLUDED_STMHAL_STORAGE_H
+#ifndef MICROPY_INCLUDED_STM32_STORAGE_H
+#define MICROPY_INCLUDED_STM32_STORAGE_H
+
+#include "drivers/memory/spiflash.h"
#define FLASH_BLOCK_SIZE (512)
#define STORAGE_SYSTICK_MASK (0x1ff) // 512ms
#define STORAGE_IDLE_TICK(tick) (((tick) & STORAGE_SYSTICK_MASK) == 2)
+// Try to match Python-level VFS block protocol where possible for these constants
+enum {
+ BDEV_IOCTL_INIT = 1,
+ BDEV_IOCTL_SYNC = 3,
+ BDEV_IOCTL_NUM_BLOCKS = 4,
+ BDEV_IOCTL_IRQ_HANDLER = 6,
+};
+
void storage_init(void);
uint32_t storage_get_block_size(void);
uint32_t storage_get_block_count(void);
@@ -43,9 +53,22 @@ bool storage_write_block(const uint8_t *src, uint32_t block);
mp_uint_t storage_read_blocks(uint8_t *dest, uint32_t block_num, uint32_t num_blocks);
mp_uint_t storage_write_blocks(const uint8_t *src, uint32_t block_num, uint32_t num_blocks);
+int32_t flash_bdev_ioctl(uint32_t op, uint32_t arg);
+bool flash_bdev_readblock(uint8_t *dest, uint32_t block);
+bool flash_bdev_writeblock(const uint8_t *src, uint32_t block);
+
+typedef struct _spi_bdev_t {
+ mp_spiflash_t spiflash;
+ uint32_t flash_tick_counter_last_write;
+} spi_bdev_t;
+
+int32_t spi_bdev_ioctl(spi_bdev_t *bdev, uint32_t op, uint32_t arg);
+int spi_bdev_readblocks(spi_bdev_t *bdev, uint8_t *dest, uint32_t block_num, uint32_t num_blocks);
+int spi_bdev_writeblocks(spi_bdev_t *bdev, const uint8_t *src, uint32_t block_num, uint32_t num_blocks);
+
extern const struct _mp_obj_type_t pyb_flash_type;
struct _fs_user_mount_t;
void pyb_flash_init_vfs(struct _fs_user_mount_t *vfs);
-#endif // MICROPY_INCLUDED_STMHAL_STORAGE_H
+#endif // MICROPY_INCLUDED_STM32_STORAGE_H
diff --git a/ports/stm32/system_stm32.c b/ports/stm32/system_stm32.c
index b71a03181..0cf0753bd 100644
--- a/ports/stm32/system_stm32.c
+++ b/ports/stm32/system_stm32.c
@@ -107,24 +107,24 @@ void __fatal_error(const char *msg);
* @{
*/
-#if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7)
+#if defined(STM32F4) || defined(STM32F7)
#define CONFIG_RCC_CR_1ST (RCC_CR_HSION)
-#define CONFIG_RCC_CR_2ND (RCC_CR_HSEON || RCC_CR_CSSON || RCC_CR_PLLON)
+#define CONFIG_RCC_CR_2ND (RCC_CR_HSEON | RCC_CR_CSSON | RCC_CR_PLLON)
#define CONFIG_RCC_PLLCFGR (0x24003010)
-#if defined(MCU_SERIES_F4)
+#if defined(STM32F4)
const uint8_t AHBPrescTable[16] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9};
const uint8_t APBPrescTable[8] = {0, 0, 0, 0, 1, 2, 3, 4};
-#elif defined(MCU_SERIES_F7)
+#elif defined(STM32F7)
const uint8_t AHBPrescTable[16] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9};
const uint8_t APBPrescTable[8] = {0, 0, 0, 0, 1, 2, 3, 4};
#endif
-#elif defined(MCU_SERIES_L4)
+#elif defined(STM32L4)
#define CONFIG_RCC_CR_1ST (RCC_CR_MSION)
-#define CONFIG_RCC_CR_2ND (RCC_CR_HSEON || RCC_CR_CSSON || RCC_CR_HSION || RCC_CR_PLLON)
+#define CONFIG_RCC_CR_2ND (RCC_CR_HSEON | RCC_CR_CSSON | RCC_CR_HSION | RCC_CR_PLLON)
#define CONFIG_RCC_PLLCFGR (0x00001000)
/*
* FIXME Do not know why I have to define these arrays here! they should be defined in the
@@ -135,6 +135,17 @@ const uint8_t AHBPrescTable[16] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8,
const uint8_t APBPrescTable[8] = {0, 0, 0, 0, 1, 2, 3, 4};
const uint32_t MSIRangeTable[12] = {100000, 200000, 400000, 800000, 1000000, 2000000, \
4000000, 8000000, 16000000, 24000000, 32000000, 48000000};
+#elif defined(STM32H7)
+
+#define CONFIG_RCC_CR_1ST (RCC_CR_HSION)
+#define CONFIG_RCC_CR_2ND (~0xEAF6ED7F)
+#define CONFIG_RCC_PLLCFGR (0x00000000)
+
+#define SRAM_BASE D1_AXISRAM_BASE
+#define FLASH_BASE FLASH_BANK1_BASE
+uint32_t SystemD2Clock = 64000000;
+const uint8_t D1CorePrescTable[16] = {0, 0, 0, 0, 1, 2, 3, 4, 1, 2, 3, 4, 6, 7, 8, 9};
+
#else
#error Unknown processor
#endif
@@ -204,7 +215,7 @@ void SystemInit(void)
#endif
/* Reset the RCC clock configuration to the default reset state ------------*/
- /* Set HSION bit */
+ /* Set configured startup clk source */
RCC->CR |= CONFIG_RCC_CR_1ST;
/* Reset CFGR register */
@@ -216,22 +227,63 @@ void SystemInit(void)
/* Reset PLLCFGR register */
RCC->PLLCFGR = CONFIG_RCC_PLLCFGR;
+ #if defined(STM32H7)
+ /* Reset D1CFGR register */
+ RCC->D1CFGR = 0x00000000;
+
+ /* Reset D2CFGR register */
+ RCC->D2CFGR = 0x00000000;
+
+ /* Reset D3CFGR register */
+ RCC->D3CFGR = 0x00000000;
+
+ /* Reset PLLCKSELR register */
+ RCC->PLLCKSELR = 0x00000000;
+
+ /* Reset PLL1DIVR register */
+ RCC->PLL1DIVR = 0x00000000;
+
+ /* Reset PLL1FRACR register */
+ RCC->PLL1FRACR = 0x00000000;
+
+ /* Reset PLL2DIVR register */
+ RCC->PLL2DIVR = 0x00000000;
+
+ /* Reset PLL2FRACR register */
+ RCC->PLL2FRACR = 0x00000000;
+
+ /* Reset PLL3DIVR register */
+ RCC->PLL3DIVR = 0x00000000;
+
+ /* Reset PLL3FRACR register */
+ RCC->PLL3FRACR = 0x00000000;
+ #endif
+
/* Reset HSEBYP bit */
RCC->CR &= (uint32_t)0xFFFBFFFF;
/* Disable all interrupts */
- #if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7)
+ #if defined(STM32F4) || defined(STM32F7)
RCC->CIR = 0x00000000;
- #elif defined(MCU_SERIES_L4)
+ #elif defined(STM32L4) || defined(STM32H7)
RCC->CIER = 0x00000000;
#endif
+ #if defined(STM32H7)
+ /* Change the switch matrix read issuing capability to 1 for the AXI SRAM target (Target 7) */
+ *((__IO uint32_t*)0x51008108) = 0x00000001;
+ #endif
+
/* Configure the Vector Table location add offset address ------------------*/
+#ifdef MICROPY_HW_VTOR
+ SCB->VTOR = MICROPY_HW_VTOR;
+#else
#ifdef VECT_TAB_SRAM
SCB->VTOR = SRAM1_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM */
#else
SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH */
#endif
+#endif
/* dpgeorge: enable 8-byte stack alignment for IRQ handlers, in accord with EABI */
SCB->CCR |= SCB_CCR_STKALIGN_Msk;
@@ -319,29 +371,47 @@ void SystemInit(void)
*/
void SystemClock_Config(void)
{
- RCC_ClkInitTypeDef RCC_ClkInitStruct;
- RCC_OscInitTypeDef RCC_OscInitStruct;
-
- #if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7)
- /* Enable Power Control clock */
- __PWR_CLK_ENABLE();
-
- /* The voltage scaling allows optimizing the power consumption when the device is
- clocked below the maximum system frequency, to update the voltage scaling value
- regarding system frequency refer to product datasheet. */
- __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
- #elif defined(MCU_SERIES_L4)
+ RCC_ClkInitTypeDef RCC_ClkInitStruct;
+ RCC_OscInitTypeDef RCC_OscInitStruct;
+ #if defined(STM32H7)
+ RCC_PeriphCLKInitTypeDef PeriphClkInitStruct;
+ #endif
+
+ #if defined(STM32F4) || defined(STM32F7) || defined(STM32H7)
+
+ /* Enable Power Control clock */
+ #if defined(STM32H7)
+ MODIFY_REG(PWR->CR3, PWR_CR3_SCUEN, 0);
+ #else
+ __PWR_CLK_ENABLE();
+ #endif
+
+ /* The voltage scaling allows optimizing the power consumption when the device is
+ clocked below the maximum system frequency, to update the voltage scaling value
+ regarding system frequency refer to product datasheet. */
+ __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
+ #elif defined(STM32L4)
// Configure LSE Drive Capability
__HAL_RCC_LSEDRIVE_CONFIG(RCC_LSEDRIVE_LOW);
#endif
+ #if defined(STM32H7)
+ // Wait for PWR_FLAG_VOSRDY
+ while ((PWR->D3CR & (PWR_D3CR_VOSRDY)) != PWR_D3CR_VOSRDY) {
+ }
+ #endif
+
/* Enable HSE Oscillator and activate PLL with HSE as source */
- #if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7)
+ #if defined(STM32F4) || defined(STM32F7) || defined(STM32H7)
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
- RCC_OscInitStruct.HSEState = RCC_HSE_ON;
+ RCC_OscInitStruct.HSEState = MICROPY_HW_CLK_HSE_STATE;
+ RCC_OscInitStruct.HSIState = RCC_HSI_OFF;
+ #if defined(STM32H7)
+ RCC_OscInitStruct.CSIState = RCC_CSI_OFF;
+ #endif
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
- #elif defined(MCU_SERIES_L4)
- RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSE|RCC_OSCILLATORTYPE_MSI;
+ #elif defined(STM32L4)
+ RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSE|RCC_OSCILLATORTYPE_MSI;
RCC_OscInitStruct.LSEState = RCC_LSE_ON;
RCC_OscInitStruct.MSIState = RCC_MSI_ON;
RCC_OscInitStruct.MSICalibrationValue = RCC_MSICALIBRATION_DEFAULT;
@@ -352,12 +422,15 @@ void SystemClock_Config(void)
/* Select PLL as system clock source and configure the HCLK, PCLK1 and PCLK2
clocks dividers */
RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2);
+ #if defined(STM32H7)
+ RCC_ClkInitStruct.ClockType |= (RCC_CLOCKTYPE_D3PCLK1 | RCC_CLOCKTYPE_D1PCLK1);
+ #endif
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
#if defined(MICROPY_HW_CLK_LAST_FREQ) && MICROPY_HW_CLK_LAST_FREQ
- #if defined(MCU_SERIES_F7)
+ #if defined(STM32F7)
#define FREQ_BKP BKP31R
- #elif defined(MCU_SERIES_L4)
+ #elif defined(STM32L4)
#error Unsupported Processor
#else
#define FREQ_BKP BKP19R
@@ -401,25 +474,56 @@ void SystemClock_Config(void)
RCC_OscInitStruct.PLL.PLLN = MICROPY_HW_CLK_PLLN;
RCC_OscInitStruct.PLL.PLLP = MICROPY_HW_CLK_PLLP;
RCC_OscInitStruct.PLL.PLLQ = MICROPY_HW_CLK_PLLQ;
- #if defined(MCU_SERIES_L4)
+ #if defined(STM32L4) || defined(STM32H7)
RCC_OscInitStruct.PLL.PLLR = MICROPY_HW_CLK_PLLR;
#endif
- RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
- #if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7)
+ #if defined(STM32H7)
+ RCC_OscInitStruct.PLL.PLLRGE = RCC_PLL1VCIRANGE_1;
+ RCC_OscInitStruct.PLL.PLLVCOSEL = RCC_PLL1VCOWIDE;
+ RCC_OscInitStruct.PLL.PLLFRACN = 0;
+ #endif
+
+ #if defined(STM32F4) || defined(STM32F7)
+ RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
- #elif defined(MCU_SERIES_L4)
+ #elif defined(STM32L4)
+ RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
+ #elif defined(STM32H7)
+ RCC_ClkInitStruct.SYSCLKDivider = RCC_SYSCLK_DIV1;
+ RCC_ClkInitStruct.AHBCLKDivider = RCC_HCLK_DIV2;
+ RCC_ClkInitStruct.APB3CLKDivider = RCC_APB3_DIV2;
+ RCC_ClkInitStruct.APB1CLKDivider = RCC_APB1_DIV2;
+ RCC_ClkInitStruct.APB2CLKDivider = RCC_APB2_DIV2;
+ RCC_ClkInitStruct.APB4CLKDivider = RCC_APB4_DIV2;
#endif
#endif
- if(HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
- {
- __fatal_error("HAL_RCC_OscConfig");
- }
-#if defined(MCU_SERIES_F7)
+ if(HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {
+ __fatal_error("HAL_RCC_OscConfig");
+ }
+
+#if defined(STM32H7)
+ /* PLL3 for USB Clock */
+ PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_USB;
+ PeriphClkInitStruct.UsbClockSelection = RCC_USBCLKSOURCE_PLL3;
+ PeriphClkInitStruct.PLL3.PLL3M = 4;
+ PeriphClkInitStruct.PLL3.PLL3N = 120;
+ PeriphClkInitStruct.PLL3.PLL3P = 2;
+ PeriphClkInitStruct.PLL3.PLL3Q = 5;
+ PeriphClkInitStruct.PLL3.PLL3R = 2;
+ PeriphClkInitStruct.PLL3.PLL3RGE = RCC_PLL3VCIRANGE_1;
+ PeriphClkInitStruct.PLL3.PLL3VCOSEL = RCC_PLL3VCOWIDE;
+ PeriphClkInitStruct.PLL3.PLL3FRACN = 0;
+ if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK) {
+ __fatal_error("HAL_RCCEx_PeriphCLKConfig");
+ }
+#endif
+
+#if defined(STM32F7)
/* Activate the OverDrive to reach the 200 MHz Frequency */
if (HAL_PWREx_EnableOverDrive() != HAL_OK)
{
@@ -436,14 +540,28 @@ void SystemClock_Config(void)
__fatal_error("HAL_RCC_ClockConfig");
}
-#if defined(MCU_SERIES_F7)
+#if defined(STM32H7)
+ /* Activate CSI clock mandatory for I/O Compensation Cell*/
+ __HAL_RCC_CSI_ENABLE() ;
+
+ /* Enable SYSCFG clock mandatory for I/O Compensation Cell */
+ __HAL_RCC_SYSCFG_CLK_ENABLE() ;
+
+ /* Enable the I/O Compensation Cell */
+ HAL_EnableCompensationCell();
+
+ /* Enable the USB voltage level detector */
+ HAL_PWREx_EnableUSBVoltageDetector();
+#endif
+
+#if defined(STM32F7)
// The DFU bootloader changes the clocksource register from its default power
// on reset value, so we set it back here, so the clocksources are the same
// whether we were started from DFU or from a power on reset.
RCC->DCKCFGR2 = 0;
#endif
-#if defined(MCU_SERIES_L4)
+#if defined(STM32L4)
// Enable MSI-Hardware auto calibration mode with LSE
HAL_RCCEx_EnableMSIPLLMode();
@@ -453,7 +571,7 @@ void SystemClock_Config(void)
|RCC_PERIPHCLK_RNG |RCC_PERIPHCLK_RTC;
PeriphClkInitStruct.I2c1ClockSelection = RCC_I2C1CLKSOURCE_PCLK1;
/* PLLSAI is used to clock USB, ADC, I2C1 and RNG. The frequency is
- HSE(8MHz)/PLLM(2)*PLLSAI1N(24)/PLLSAIQ(2) = 48MHz. See the STM32CubeMx
+ MSI(4MHz)/PLLM(1)*PLLSAI1N(24)/PLLSAIQ(2) = 48MHz. See the STM32CubeMx
application or the reference manual. */
PeriphClkInitStruct.Sai1ClockSelection = RCC_SAI1CLKSOURCE_PLLSAI1;
PeriphClkInitStruct.AdcClockSelection = RCC_ADCCLKSOURCE_PLLSAI1;
@@ -480,17 +598,7 @@ void SystemClock_Config(void)
HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1);
HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000);
-
HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);
-#endif
-}
-
-void HAL_MspInit(void) {
-#if defined(MCU_SERIES_F7)
- /* Enable I-Cache */
- SCB_EnableICache();
-
- /* Enable D-Cache */
- SCB_EnableDCache();
+ NVIC_SetPriority(SysTick_IRQn, NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, TICK_INT_PRIORITY, 0));
#endif
}
diff --git a/ports/stm32/system_stm32f0.c b/ports/stm32/system_stm32f0.c
new file mode 100644
index 000000000..9d4b06e56
--- /dev/null
+++ b/ports/stm32/system_stm32f0.c
@@ -0,0 +1,203 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * Taken from ST Cube library and modified. See below for original header.
+ */
+
+/**
+ ******************************************************************************
+ * @file system_stm32f0xx.c
+ * @author MCD Application Team
+ * @brief CMSIS Cortex-M0 Device Peripheral Access Layer System Source File.
+ *
+ ******************************************************************************
+ * @attention
+ *
+ * <h2><center>&copy; COPYRIGHT(c) 2016 STMicroelectronics</center></h2>
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of STMicroelectronics nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ******************************************************************************
+ */
+
+#include STM32_HAL_H
+
+#ifndef HSE_VALUE
+#define HSE_VALUE (8000000)
+#endif
+
+#ifndef HSI_VALUE
+#define HSI_VALUE (8000000)
+#endif
+
+#ifndef HSI48_VALUE
+#define HSI48_VALUE (48000000)
+#endif
+
+/* This variable is updated in three ways:
+ 1) by calling CMSIS function SystemCoreClockUpdate()
+ 2) by calling HAL API function HAL_RCC_GetHCLKFreq()
+ 3) each time HAL_RCC_ClockConfig() is called to configure the system clock frequency
+ Note: If you use this function to configure the system clock there is no need to
+ call the 2 first functions listed above, since SystemCoreClock variable is
+ updated automatically.
+*/
+uint32_t SystemCoreClock = 8000000;
+
+const uint8_t AHBPrescTable[16] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9};
+const uint8_t APBPrescTable[8] = {0, 0, 0, 0, 1, 2, 3, 4};
+
+void SystemInit(void) {
+ // Set HSION bit
+ RCC->CR |= (uint32_t)0x00000001U;
+
+ #if defined(STM32F051x8) || defined(STM32F058x8)
+ // Reset SW[1:0], HPRE[3:0], PPRE[2:0], ADCPRE and MCOSEL[2:0] bits
+ RCC->CFGR &= (uint32_t)0xF8FFB80CU;
+ #else
+ // Reset SW[1:0], HPRE[3:0], PPRE[2:0], ADCPRE, MCOSEL[2:0], MCOPRE[2:0] and PLLNODIV bits
+ RCC->CFGR &= (uint32_t)0x08FFB80CU;
+ #endif
+
+ // Reset HSEON, CSSON and PLLON bits
+ RCC->CR &= (uint32_t)0xFEF6FFFFU;
+
+ // Reset HSEBYP bit
+ RCC->CR &= (uint32_t)0xFFFBFFFFU;
+
+ // Reset PLLSRC, PLLXTPRE and PLLMUL[3:0] bits
+ RCC->CFGR &= (uint32_t)0xFFC0FFFFU;
+
+ // Reset PREDIV[3:0] bits
+ RCC->CFGR2 &= (uint32_t)0xFFFFFFF0U;
+
+ #if defined(STM32F072xB) || defined(STM32F078xx)
+ // Reset USART2SW[1:0], USART1SW[1:0], I2C1SW, CECSW, USBSW and ADCSW bits
+ RCC->CFGR3 &= (uint32_t)0xFFFCFE2CU;
+ #elif defined(STM32F071xB)
+ // Reset USART2SW[1:0], USART1SW[1:0], I2C1SW, CECSW and ADCSW bits
+ RCC->CFGR3 &= (uint32_t)0xFFFFCEACU;
+ #elif defined(STM32F091xC) || defined(STM32F098xx)
+ // Reset USART3SW[1:0], USART2SW[1:0], USART1SW[1:0], I2C1SW, CECSW and ADCSW bits
+ RCC->CFGR3 &= (uint32_t)0xFFF0FEACU;
+ #elif defined(STM32F030x6) || defined(STM32F030x8) || defined(STM32F031x6) || defined(STM32F038xx) || defined(STM32F030xC)
+ // Reset USART1SW[1:0], I2C1SW and ADCSW bits
+ RCC->CFGR3 &= (uint32_t)0xFFFFFEECU;
+ #elif defined(STM32F051x8) || defined(STM32F058xx)
+ // Reset USART1SW[1:0], I2C1SW, CECSW and ADCSW bits
+ RCC->CFGR3 &= (uint32_t)0xFFFFFEACU;
+ #elif defined(STM32F042x6) || defined(STM32F048xx)
+ // Reset USART1SW[1:0], I2C1SW, CECSW, USBSW and ADCSW bits
+ RCC->CFGR3 &= (uint32_t)0xFFFFFE2CU;
+ #elif defined(STM32F070x6) || defined(STM32F070xB)
+ // Reset USART1SW[1:0], I2C1SW, USBSW and ADCSW bits
+ RCC->CFGR3 &= (uint32_t)0xFFFFFE6CU;
+ // Set default USB clock to PLLCLK, since there is no HSI48
+ RCC->CFGR3 |= (uint32_t)0x00000080U;
+ #else
+ #warning "No target selected"
+ #endif
+
+ // Reset HSI14 bit
+ RCC->CR2 &= (uint32_t)0xFFFFFFFEU;
+
+ // Disable all interrupts
+ RCC->CIR = 0x00000000U;
+
+ // dpgeorge: enable 8-byte stack alignment for IRQ handlers, in accord with EABI
+ SCB->CCR |= SCB_CCR_STKALIGN_Msk;
+}
+
+void SystemClock_Config(void) {
+ // Set flash latency to 1 because SYSCLK > 24MHz
+ FLASH->ACR = (FLASH->ACR & ~0x7) | 0x1;
+
+ // Use the 48MHz internal oscillator
+ RCC->CR2 |= RCC_CR2_HSI48ON;
+ while ((RCC->CR2 & RCC_CR2_HSI48RDY) == 0) {
+ }
+ RCC->CFGR |= 3 << RCC_CFGR_SW_Pos;
+ while (((RCC->CFGR >> RCC_CFGR_SWS_Pos) & 0x3) != 0x03) {
+ // Wait for SYSCLK source to change
+ }
+
+ SystemCoreClockUpdate();
+
+ HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq() / 1000);
+ HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);
+}
+
+void SystemCoreClockUpdate(void) {
+ // Get SYSCLK source
+ uint32_t tmp = RCC->CFGR & RCC_CFGR_SWS;
+
+ switch (tmp) {
+ case RCC_CFGR_SWS_HSI:
+ SystemCoreClock = HSI_VALUE;
+ break;
+ case RCC_CFGR_SWS_HSE:
+ SystemCoreClock = HSE_VALUE;
+ break;
+ case RCC_CFGR_SWS_PLL: {
+ /* Get PLL clock source and multiplication factor */
+ uint32_t pllmull = RCC->CFGR & RCC_CFGR_PLLMUL;
+ uint32_t pllsource = RCC->CFGR & RCC_CFGR_PLLSRC;
+ pllmull = (pllmull >> 18) + 2;
+ uint32_t predivfactor = (RCC->CFGR2 & RCC_CFGR2_PREDIV) + 1;
+
+ if (pllsource == RCC_CFGR_PLLSRC_HSE_PREDIV) {
+ /* HSE used as PLL clock source : SystemCoreClock = HSE/PREDIV * PLLMUL */
+ SystemCoreClock = (HSE_VALUE/predivfactor) * pllmull;
+ #if defined(STM32F042x6) || defined(STM32F048xx) || defined(STM32F072xB) \
+ || defined(STM32F078xx) || defined(STM32F091xC) || defined(STM32F098xx)
+ } else if (pllsource == RCC_CFGR_PLLSRC_HSI48_PREDIV) {
+ /* HSI48 used as PLL clock source : SystemCoreClock = HSI48/PREDIV * PLLMUL */
+ SystemCoreClock = (HSI48_VALUE/predivfactor) * pllmull;
+ #endif
+ } else {
+ #if defined(STM32F042x6) || defined(STM32F048xx) || defined(STM32F070x6) \
+ || defined(STM32F078xx) || defined(STM32F071xB) || defined(STM32F072xB) \
+ || defined(STM32F070xB) || defined(STM32F091xC) || defined(STM32F098xx) || defined(STM32F030xC)
+ /* HSI used as PLL clock source : SystemCoreClock = HSI/PREDIV * PLLMUL */
+ SystemCoreClock = (HSI_VALUE / predivfactor) * pllmull;
+ #else
+ /* HSI used as PLL clock source : SystemCoreClock = HSI/2 * PLLMUL */
+ SystemCoreClock = (HSI_VALUE >> 1) * pllmull;
+ #endif
+ }
+ break;
+ }
+ case RCC_CFGR_SWS_HSI48:
+ SystemCoreClock = HSI48_VALUE;
+ break;
+ default:
+ SystemCoreClock = HSI_VALUE;
+ break;
+ }
+
+ // Compute HCLK clock frequency
+ tmp = AHBPrescTable[((RCC->CFGR & RCC_CFGR_HPRE) >> 4)];
+ SystemCoreClock >>= tmp;
+}
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/ports/stm32/systick.h b/ports/stm32/systick.h
index c1def50c2..256a500c2 100644
--- a/ports/stm32/systick.h
+++ b/ports/stm32/systick.h
@@ -23,10 +23,10 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
-#ifndef MICROPY_INCLUDED_STMHAL_SYSTICK_H
-#define MICROPY_INCLUDED_STMHAL_SYSTICK_H
+#ifndef MICROPY_INCLUDED_STM32_SYSTICK_H
+#define MICROPY_INCLUDED_STM32_SYSTICK_H
void sys_tick_wait_at_least(uint32_t stc, uint32_t delay_ms);
bool sys_tick_has_passed(uint32_t stc, uint32_t delay_ms);
-#endif // MICROPY_INCLUDED_STMHAL_SYSTICK_H
+#endif // MICROPY_INCLUDED_STM32_SYSTICK_H
diff --git a/ports/stm32/timer.c b/ports/stm32/timer.c
index 96a6baa02..cf198e865 100644
--- a/ports/stm32/timer.c
+++ b/ports/stm32/timer.c
@@ -162,14 +162,15 @@ void timer_deinit(void) {
}
}
+#if defined(TIM5)
// TIM5 is set-up for the servo controller
// This function inits but does not start the timer
void timer_tim5_init(void) {
// TIM5 clock enable
- __TIM5_CLK_ENABLE();
+ __HAL_RCC_TIM5_CLK_ENABLE();
// set up and enable interrupt
- HAL_NVIC_SetPriority(TIM5_IRQn, IRQ_PRI_TIM5, IRQ_SUBPRI_TIM5);
+ NVIC_SetPriority(TIM5_IRQn, IRQ_PRI_TIM5);
HAL_NVIC_EnableIRQ(TIM5_IRQn);
// PWM clock configuration
@@ -181,6 +182,7 @@ void timer_tim5_init(void) {
HAL_TIM_PWM_Init(&TIM5_Handle);
}
+#endif
#if defined(TIM6)
// Init TIM6 with a counter-overflow at the given frequency (given in Hz)
@@ -188,7 +190,7 @@ void timer_tim5_init(void) {
// This function inits but does not start the timer
TIM_HandleTypeDef *timer_tim6_init(uint freq) {
// TIM6 clock enable
- __TIM6_CLK_ENABLE();
+ __HAL_RCC_TIM6_CLK_ENABLE();
// Timer runs at SystemCoreClock / 2
// Compute the prescaler value so TIM6 triggers at freq-Hz
@@ -226,19 +228,33 @@ void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {
// APB clock. Otherwise (APB prescaler > 1) the timer clock is twice its
// respective APB clock. See DM00031020 Rev 4, page 115.
uint32_t timer_get_source_freq(uint32_t tim_id) {
- uint32_t source;
+ uint32_t source, clk_div;
if (tim_id == 1 || (8 <= tim_id && tim_id <= 11)) {
// TIM{1,8,9,10,11} are on APB2
+ #if defined(STM32F0)
+ source = HAL_RCC_GetPCLK1Freq();
+ clk_div = RCC->CFGR & RCC_CFGR_PPRE;
+ #elif defined(STM32H7)
source = HAL_RCC_GetPCLK2Freq();
- if ((uint32_t)((RCC->CFGR & RCC_CFGR_PPRE2) >> 3) != RCC_HCLK_DIV1) {
- source *= 2;
- }
+ clk_div = RCC->D2CFGR & RCC_D2CFGR_D2PPRE2;
+ #else
+ source = HAL_RCC_GetPCLK2Freq();
+ clk_div = RCC->CFGR & RCC_CFGR_PPRE2;
+ #endif
} else {
// TIM{2,3,4,5,6,7,12,13,14} are on APB1
source = HAL_RCC_GetPCLK1Freq();
- if ((uint32_t)(RCC->CFGR & RCC_CFGR_PPRE1) != RCC_HCLK_DIV1) {
- source *= 2;
- }
+ #if defined(STM32F0)
+ clk_div = RCC->CFGR & RCC_CFGR_PPRE;
+ #elif defined(STM32H7)
+ clk_div = RCC->D2CFGR & RCC_D2CFGR_D2PPRE1;
+ #else
+ clk_div = RCC->CFGR & RCC_CFGR_PPRE1;
+ #endif
+ }
+ if (clk_div != 0) {
+ // APB prescaler for this timer is > 1
+ source *= 2;
}
return source;
}
@@ -302,7 +318,7 @@ STATIC uint32_t compute_prescaler_period_from_freq(pyb_timer_obj_t *self, mp_obj
STATIC uint32_t compute_period(pyb_timer_obj_t *self) {
// In center mode, compare == period corresponds to 100%
// In edge mode, compare == (period + 1) corresponds to 100%
- uint32_t period = (__HAL_TIM_GetAutoreload(&self->tim) & TIMER_CNT_MASK(self));
+ uint32_t period = (__HAL_TIM_GET_AUTORELOAD(&self->tim) & TIMER_CNT_MASK(self));
if (period != 0xffffffff) {
if (self->tim.Init.CounterMode == TIM_COUNTERMODE_UP ||
self->tim.Init.CounterMode == TIM_COUNTERMODE_DOWN) {
@@ -439,7 +455,7 @@ STATIC void pyb_timer_print(const mp_print_t *print, mp_obj_t self_in, mp_print_
mp_printf(print, "Timer(%u)", self->tim_id);
} else {
uint32_t prescaler = self->tim.Instance->PSC & 0xffff;
- uint32_t period = __HAL_TIM_GetAutoreload(&self->tim) & TIMER_CNT_MASK(self);
+ uint32_t period = __HAL_TIM_GET_AUTORELOAD(&self->tim) & TIMER_CNT_MASK(self);
// for efficiency, we compute and print freq as an int (not a float)
uint32_t freq = timer_get_source_freq(self->tim_id) / ((prescaler + 1) * (period + 1));
mp_printf(print, "Timer(%u, freq=%u, prescaler=%u, period=%u, mode=%s, div=%u",
@@ -554,57 +570,61 @@ STATIC mp_obj_t pyb_timer_init_helper(pyb_timer_obj_t *self, size_t n_args, cons
// enable TIM clock
switch (self->tim_id) {
- case 1: __TIM1_CLK_ENABLE(); break;
- case 2: __TIM2_CLK_ENABLE(); break;
- case 3: __TIM3_CLK_ENABLE(); break;
- case 4: __TIM4_CLK_ENABLE(); break;
- case 5: __TIM5_CLK_ENABLE(); break;
+ case 1: __HAL_RCC_TIM1_CLK_ENABLE(); break;
+ case 2: __HAL_RCC_TIM2_CLK_ENABLE(); break;
+ case 3: __HAL_RCC_TIM3_CLK_ENABLE(); break;
+ #if defined(TIM4)
+ case 4: __HAL_RCC_TIM4_CLK_ENABLE(); break;
+ #endif
+ #if defined(TIM5)
+ case 5: __HAL_RCC_TIM5_CLK_ENABLE(); break;
+ #endif
#if defined(TIM6)
- case 6: __TIM6_CLK_ENABLE(); break;
+ case 6: __HAL_RCC_TIM6_CLK_ENABLE(); break;
#endif
#if defined(TIM7)
- case 7: __TIM7_CLK_ENABLE(); break;
+ case 7: __HAL_RCC_TIM7_CLK_ENABLE(); break;
#endif
#if defined(TIM8)
- case 8: __TIM8_CLK_ENABLE(); break;
+ case 8: __HAL_RCC_TIM8_CLK_ENABLE(); break;
#endif
#if defined(TIM9)
- case 9: __TIM9_CLK_ENABLE(); break;
+ case 9: __HAL_RCC_TIM9_CLK_ENABLE(); break;
#endif
#if defined(TIM10)
- case 10: __TIM10_CLK_ENABLE(); break;
+ case 10: __HAL_RCC_TIM10_CLK_ENABLE(); break;
#endif
#if defined(TIM11)
- case 11: __TIM11_CLK_ENABLE(); break;
+ case 11: __HAL_RCC_TIM11_CLK_ENABLE(); break;
#endif
#if defined(TIM12)
- case 12: __TIM12_CLK_ENABLE(); break;
+ case 12: __HAL_RCC_TIM12_CLK_ENABLE(); break;
#endif
#if defined(TIM13)
- case 13: __TIM13_CLK_ENABLE(); break;
+ case 13: __HAL_RCC_TIM13_CLK_ENABLE(); break;
#endif
#if defined(TIM14)
- case 14: __TIM14_CLK_ENABLE(); break;
+ case 14: __HAL_RCC_TIM14_CLK_ENABLE(); break;
#endif
#if defined(TIM15)
- case 15: __TIM15_CLK_ENABLE(); break;
+ case 15: __HAL_RCC_TIM15_CLK_ENABLE(); break;
#endif
#if defined(TIM16)
- case 16: __TIM16_CLK_ENABLE(); break;
+ case 16: __HAL_RCC_TIM16_CLK_ENABLE(); break;
#endif
#if defined(TIM17)
- case 17: __TIM17_CLK_ENABLE(); break;
+ case 17: __HAL_RCC_TIM17_CLK_ENABLE(); break;
#endif
}
// set IRQ priority (if not a special timer)
if (self->tim_id != 5) {
- HAL_NVIC_SetPriority(self->irqn, IRQ_PRI_TIMX, IRQ_SUBPRI_TIMX);
+ NVIC_SetPriority(IRQn_NONNEG(self->irqn), IRQ_PRI_TIMX);
if (self->tim_id == 1) {
- HAL_NVIC_SetPriority(TIM1_CC_IRQn, IRQ_PRI_TIMX, IRQ_SUBPRI_TIMX);
+ NVIC_SetPriority(TIM1_CC_IRQn, IRQ_PRI_TIMX);
#if defined(TIM8)
} else if (self->tim_id == 8) {
- HAL_NVIC_SetPriority(TIM8_CC_IRQn, IRQ_PRI_TIMX, IRQ_SUBPRI_TIMX);
+ NVIC_SetPriority(TIM8_CC_IRQn, IRQ_PRI_TIMX);
#endif
}
}
@@ -635,19 +655,25 @@ STATIC mp_obj_t pyb_timer_init_helper(pyb_timer_obj_t *self, size_t n_args, cons
return mp_const_none;
}
-// This table encodes the timer instance and irq number.
+// This table encodes the timer instance and irq number (for the update irq).
// It assumes that timer instance pointer has the lower 8 bits cleared.
#define TIM_ENTRY(id, irq) [id - 1] = (uint32_t)TIM##id | irq
STATIC const uint32_t tim_instance_table[MICROPY_HW_MAX_TIMER] = {
- #if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7)
+ #if defined(STM32F0)
+ TIM_ENTRY(1, TIM1_BRK_UP_TRG_COM_IRQn),
+ #elif defined(STM32F4) || defined(STM32F7)
TIM_ENTRY(1, TIM1_UP_TIM10_IRQn),
- #elif defined(MCU_SERIES_L4)
+ #elif defined(STM32L4)
TIM_ENTRY(1, TIM1_UP_TIM16_IRQn),
#endif
TIM_ENTRY(2, TIM2_IRQn),
TIM_ENTRY(3, TIM3_IRQn),
+ #if defined(TIM4)
TIM_ENTRY(4, TIM4_IRQn),
+ #endif
+ #if defined(TIM5)
TIM_ENTRY(5, TIM5_IRQn),
+ #endif
#if defined(TIM6)
TIM_ENTRY(6, TIM6_DAC_IRQn),
#endif
@@ -655,9 +681,9 @@ STATIC const uint32_t tim_instance_table[MICROPY_HW_MAX_TIMER] = {
TIM_ENTRY(7, TIM7_IRQn),
#endif
#if defined(TIM8)
- #if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7)
+ #if defined(STM32F4) || defined(STM32F7)
TIM_ENTRY(8, TIM8_UP_TIM13_IRQn),
- #elif defined(MCU_SERIES_L4)
+ #elif defined(STM32L4)
TIM_ENTRY(8, TIM8_UP_IRQn),
#endif
#endif
@@ -676,18 +702,32 @@ STATIC const uint32_t tim_instance_table[MICROPY_HW_MAX_TIMER] = {
#if defined(TIM13)
TIM_ENTRY(13, TIM8_UP_TIM13_IRQn),
#endif
- #if defined(TIM14)
+ #if defined(STM32F0)
+ TIM_ENTRY(14, TIM14_IRQn),
+ #elif defined(TIM14)
TIM_ENTRY(14, TIM8_TRG_COM_TIM14_IRQn),
#endif
#if defined(TIM15)
+ #if defined(STM32F0) || defined(STM32H7)
+ TIM_ENTRY(15, TIM15_IRQn),
+ #else
TIM_ENTRY(15, TIM1_BRK_TIM15_IRQn),
#endif
+ #endif
#if defined(TIM16)
+ #if defined(STM32F0) || defined(STM32H7)
+ TIM_ENTRY(16, TIM16_IRQn),
+ #else
TIM_ENTRY(16, TIM1_UP_TIM16_IRQn),
#endif
+ #endif
#if defined(TIM17)
+ #if defined(STM32F0) || defined(STM32H7)
+ TIM_ENTRY(17, TIM17_IRQn),
+ #else
TIM_ENTRY(17, TIM1_TRG_COM_TIM17_IRQn),
#endif
+ #endif
};
#undef TIM_ENTRY
@@ -1049,8 +1089,12 @@ STATIC mp_obj_t pyb_timer_channel(size_t n_args, const mp_obj_t *pos_args, mp_ma
if (self->tim.Instance != TIM1
&& self->tim.Instance != TIM2
&& self->tim.Instance != TIM3
+ #if defined(TIM4)
&& self->tim.Instance != TIM4
+ #endif
+ #if defined(TIM5)
&& self->tim.Instance != TIM5
+ #endif
#if defined(TIM8)
&& self->tim.Instance != TIM8
#endif
@@ -1062,7 +1106,7 @@ STATIC mp_obj_t pyb_timer_channel(size_t n_args, const mp_obj_t *pos_args, mp_ma
// an interrupt by initializing the timer.
__HAL_TIM_DISABLE_IT(&self->tim, TIM_IT_UPDATE);
HAL_TIM_Encoder_Init(&self->tim, &enc_config);
- __HAL_TIM_SetCounter(&self->tim, 0);
+ __HAL_TIM_SET_COUNTER(&self->tim, 0);
if (self->callback != mp_const_none) {
__HAL_TIM_CLEAR_FLAG(&self->tim, TIM_IT_UPDATE);
__HAL_TIM_ENABLE_IT(&self->tim, TIM_IT_UPDATE);
@@ -1088,7 +1132,7 @@ STATIC mp_obj_t pyb_timer_counter(size_t n_args, const mp_obj_t *args) {
return mp_obj_new_int(self->tim.Instance->CNT);
} else {
// set
- __HAL_TIM_SetCounter(&self->tim, mp_obj_get_int(args[1]));
+ __HAL_TIM_SET_COUNTER(&self->tim, mp_obj_get_int(args[1]));
return mp_const_none;
}
}
@@ -1110,7 +1154,7 @@ STATIC mp_obj_t pyb_timer_freq(size_t n_args, const mp_obj_t *args) {
if (n_args == 1) {
// get
uint32_t prescaler = self->tim.Instance->PSC & 0xffff;
- uint32_t period = __HAL_TIM_GetAutoreload(&self->tim) & TIMER_CNT_MASK(self);
+ uint32_t period = __HAL_TIM_GET_AUTORELOAD(&self->tim) & TIMER_CNT_MASK(self);
uint32_t source_freq = timer_get_source_freq(self->tim_id);
uint32_t divide = ((prescaler + 1) * (period + 1));
#if MICROPY_PY_BUILTINS_FLOAT
@@ -1126,7 +1170,7 @@ STATIC mp_obj_t pyb_timer_freq(size_t n_args, const mp_obj_t *args) {
uint32_t period;
uint32_t prescaler = compute_prescaler_period_from_freq(self, args[1], &period);
self->tim.Instance->PSC = prescaler;
- __HAL_TIM_SetAutoreload(&self->tim, period);
+ __HAL_TIM_SET_AUTORELOAD(&self->tim, period);
return mp_const_none;
}
}
@@ -1153,10 +1197,10 @@ STATIC mp_obj_t pyb_timer_period(size_t n_args, const mp_obj_t *args) {
pyb_timer_obj_t *self = args[0];
if (n_args == 1) {
// get
- return mp_obj_new_int(__HAL_TIM_GetAutoreload(&self->tim) & TIMER_CNT_MASK(self));
+ return mp_obj_new_int(__HAL_TIM_GET_AUTORELOAD(&self->tim) & TIMER_CNT_MASK(self));
} else {
// set
- __HAL_TIM_SetAutoreload(&self->tim, mp_obj_get_int(args[1]) & TIMER_CNT_MASK(self));
+ __HAL_TIM_SET_AUTORELOAD(&self->tim, mp_obj_get_int(args[1]) & TIMER_CNT_MASK(self));
return mp_const_none;
}
}
@@ -1265,10 +1309,10 @@ STATIC mp_obj_t pyb_timer_channel_capture_compare(size_t n_args, const mp_obj_t
pyb_timer_channel_obj_t *self = args[0];
if (n_args == 1) {
// get
- return mp_obj_new_int(__HAL_TIM_GetCompare(&self->timer->tim, TIMER_CHANNEL(self)) & TIMER_CNT_MASK(self->timer));
+ return mp_obj_new_int(__HAL_TIM_GET_COMPARE(&self->timer->tim, TIMER_CHANNEL(self)) & TIMER_CNT_MASK(self->timer));
} else {
// set
- __HAL_TIM_SetCompare(&self->timer->tim, TIMER_CHANNEL(self), mp_obj_get_int(args[1]) & TIMER_CNT_MASK(self->timer));
+ __HAL_TIM_SET_COMPARE(&self->timer->tim, TIMER_CHANNEL(self), mp_obj_get_int(args[1]) & TIMER_CNT_MASK(self->timer));
return mp_const_none;
}
}
@@ -1285,12 +1329,12 @@ STATIC mp_obj_t pyb_timer_channel_pulse_width_percent(size_t n_args, const mp_ob
uint32_t period = compute_period(self->timer);
if (n_args == 1) {
// get
- uint32_t cmp = __HAL_TIM_GetCompare(&self->timer->tim, TIMER_CHANNEL(self)) & TIMER_CNT_MASK(self->timer);
+ uint32_t cmp = __HAL_TIM_GET_COMPARE(&self->timer->tim, TIMER_CHANNEL(self)) & TIMER_CNT_MASK(self->timer);
return compute_percent_from_pwm_value(period, cmp);
} else {
// set
uint32_t cmp = compute_pwm_value_from_percent(period, args[1]);
- __HAL_TIM_SetCompare(&self->timer->tim, TIMER_CHANNEL(self), cmp & TIMER_CNT_MASK(self->timer));
+ __HAL_TIM_SET_COMPARE(&self->timer->tim, TIMER_CHANNEL(self), cmp & TIMER_CNT_MASK(self->timer));
return mp_const_none;
}
}
@@ -1365,7 +1409,7 @@ STATIC void timer_handle_irq_channel(pyb_timer_obj_t *tim, uint8_t channel, mp_o
uint32_t irq_mask = TIMER_IRQ_MASK(channel);
if (__HAL_TIM_GET_FLAG(&tim->tim, irq_mask) != RESET) {
- if (__HAL_TIM_GET_ITSTATUS(&tim->tim, irq_mask) != RESET) {
+ if (__HAL_TIM_GET_IT_SOURCE(&tim->tim, irq_mask) != RESET) {
// clear the interrupt
__HAL_TIM_CLEAR_IT(&tim->tim, irq_mask);
@@ -1427,7 +1471,7 @@ void timer_irq_handler(uint tim_id) {
if (unhandled != 0) {
__HAL_TIM_DISABLE_IT(&tim->tim, unhandled);
__HAL_TIM_CLEAR_IT(&tim->tim, unhandled);
- printf("Unhandled interrupt SR=0x%02lx (now disabled)\n", unhandled);
+ printf("Unhandled interrupt SR=0x%02x (now disabled)\n", (unsigned int)unhandled);
}
}
}
diff --git a/ports/stm32/timer.h b/ports/stm32/timer.h
index 775accc3d..2ba91cf15 100644
--- a/ports/stm32/timer.h
+++ b/ports/stm32/timer.h
@@ -23,8 +23,8 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
-#ifndef MICROPY_INCLUDED_STMHAL_TIMER_H
-#define MICROPY_INCLUDED_STMHAL_TIMER_H
+#ifndef MICROPY_INCLUDED_STM32_TIMER_H
+#define MICROPY_INCLUDED_STM32_TIMER_H
extern TIM_HandleTypeDef TIM5_Handle;
@@ -39,4 +39,4 @@ void timer_irq_handler(uint tim_id);
TIM_HandleTypeDef *pyb_timer_get_handle(mp_obj_t timer);
-#endif // MICROPY_INCLUDED_STMHAL_TIMER_H
+#endif // MICROPY_INCLUDED_STM32_TIMER_H
diff --git a/ports/stm32/uart.c b/ports/stm32/uart.c
index 8f0513e8c..5d3076ccd 100644
--- a/ports/stm32/uart.c
+++ b/ports/stm32/uart.c
@@ -34,9 +34,10 @@
#include "py/stream.h"
#include "py/mperrno.h"
#include "py/mphal.h"
+#include "lib/utils/interrupt_char.h"
#include "uart.h"
#include "irq.h"
-#include "genhdr/pins.h"
+#include "pendsv.h"
/// \moduleref pyb
/// \class UART - duplex serial communication bus
@@ -82,6 +83,7 @@ struct _pyb_uart_obj_t {
IRQn_Type irqn;
pyb_uart_t uart_id : 8;
bool is_enabled : 1;
+ bool attached_to_repl; // whether the UART is attached to REPL
byte char_width; // 0 for 7,8 bit chars, 1 for 9 bit chars
uint16_t char_mask; // 0x7f for 7 bit, 0xff for 8 bit, 0x1ff for 9 bit
uint16_t timeout; // timeout waiting for first char
@@ -93,8 +95,26 @@ struct _pyb_uart_obj_t {
};
STATIC mp_obj_t pyb_uart_deinit(mp_obj_t self_in);
+extern void NORETURN __fatal_error(const char *msg);
void uart_init0(void) {
+ #if defined(STM32H7)
+ RCC_PeriphCLKInitTypeDef RCC_PeriphClkInit = {0};
+ // Configure USART1/6 clock source
+ RCC_PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART16;
+ RCC_PeriphClkInit.Usart16ClockSelection = RCC_USART16CLKSOURCE_D2PCLK2;
+ if (HAL_RCCEx_PeriphCLKConfig(&RCC_PeriphClkInit) != HAL_OK) {
+ __fatal_error("HAL_RCCEx_PeriphCLKConfig");
+ }
+
+ // Configure USART2/3/4/5/7/8 clock source
+ RCC_PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART234578;
+ RCC_PeriphClkInit.Usart16ClockSelection = RCC_USART234578CLKSOURCE_D2PCLK1;
+ if (HAL_RCCEx_PeriphCLKConfig(&RCC_PeriphClkInit) != HAL_OK) {
+ __fatal_error("HAL_RCCEx_PeriphCLKConfig");
+ }
+ #endif
+
for (int i = 0; i < MP_ARRAY_SIZE(MP_STATE_PORT(pyb_uart_obj_all)); i++) {
MP_STATE_PORT(pyb_uart_obj_all)[i] = NULL;
}
@@ -166,9 +186,9 @@ STATIC bool uart_init2(pyb_uart_obj_t *uart_obj) {
uart_unit = 1;
UARTx = USART1;
irqn = USART1_IRQn;
- pins[0] = &MICROPY_HW_UART1_TX;
- pins[1] = &MICROPY_HW_UART1_RX;
- __USART1_CLK_ENABLE();
+ pins[0] = MICROPY_HW_UART1_TX;
+ pins[1] = MICROPY_HW_UART1_RX;
+ __HAL_RCC_USART1_CLK_ENABLE();
break;
#endif
@@ -177,19 +197,19 @@ STATIC bool uart_init2(pyb_uart_obj_t *uart_obj) {
uart_unit = 2;
UARTx = USART2;
irqn = USART2_IRQn;
- pins[0] = &MICROPY_HW_UART2_TX;
- pins[1] = &MICROPY_HW_UART2_RX;
+ pins[0] = MICROPY_HW_UART2_TX;
+ pins[1] = MICROPY_HW_UART2_RX;
#if defined(MICROPY_HW_UART2_RTS)
if (uart_obj->uart.Init.HwFlowCtl & UART_HWCONTROL_RTS) {
- pins[2] = &MICROPY_HW_UART2_RTS;
+ pins[2] = MICROPY_HW_UART2_RTS;
}
#endif
#if defined(MICROPY_HW_UART2_CTS)
if (uart_obj->uart.Init.HwFlowCtl & UART_HWCONTROL_CTS) {
- pins[3] = &MICROPY_HW_UART2_CTS;
+ pins[3] = MICROPY_HW_UART2_CTS;
}
#endif
- __USART2_CLK_ENABLE();
+ __HAL_RCC_USART2_CLK_ENABLE();
break;
#endif
@@ -198,19 +218,19 @@ STATIC bool uart_init2(pyb_uart_obj_t *uart_obj) {
uart_unit = 3;
UARTx = USART3;
irqn = USART3_IRQn;
- pins[0] = &MICROPY_HW_UART3_TX;
- pins[1] = &MICROPY_HW_UART3_RX;
+ pins[0] = MICROPY_HW_UART3_TX;
+ pins[1] = MICROPY_HW_UART3_RX;
#if defined(MICROPY_HW_UART3_RTS)
if (uart_obj->uart.Init.HwFlowCtl & UART_HWCONTROL_RTS) {
- pins[2] = &MICROPY_HW_UART3_RTS;
+ pins[2] = MICROPY_HW_UART3_RTS;
}
#endif
#if defined(MICROPY_HW_UART3_CTS)
if (uart_obj->uart.Init.HwFlowCtl & UART_HWCONTROL_CTS) {
- pins[3] = &MICROPY_HW_UART3_CTS;
+ pins[3] = MICROPY_HW_UART3_CTS;
}
#endif
- __USART3_CLK_ENABLE();
+ __HAL_RCC_USART3_CLK_ENABLE();
break;
#endif
@@ -219,9 +239,9 @@ STATIC bool uart_init2(pyb_uart_obj_t *uart_obj) {
uart_unit = 4;
UARTx = UART4;
irqn = UART4_IRQn;
- pins[0] = &MICROPY_HW_UART4_TX;
- pins[1] = &MICROPY_HW_UART4_RX;
- __UART4_CLK_ENABLE();
+ pins[0] = MICROPY_HW_UART4_TX;
+ pins[1] = MICROPY_HW_UART4_RX;
+ __HAL_RCC_UART4_CLK_ENABLE();
break;
#endif
@@ -230,9 +250,9 @@ STATIC bool uart_init2(pyb_uart_obj_t *uart_obj) {
uart_unit = 5;
UARTx = UART5;
irqn = UART5_IRQn;
- pins[0] = &MICROPY_HW_UART5_TX;
- pins[1] = &MICROPY_HW_UART5_RX;
- __UART5_CLK_ENABLE();
+ pins[0] = MICROPY_HW_UART5_TX;
+ pins[1] = MICROPY_HW_UART5_RX;
+ __HAL_RCC_UART5_CLK_ENABLE();
break;
#endif
@@ -241,9 +261,19 @@ STATIC bool uart_init2(pyb_uart_obj_t *uart_obj) {
uart_unit = 6;
UARTx = USART6;
irqn = USART6_IRQn;
- pins[0] = &MICROPY_HW_UART6_TX;
- pins[1] = &MICROPY_HW_UART6_RX;
- __USART6_CLK_ENABLE();
+ pins[0] = MICROPY_HW_UART6_TX;
+ pins[1] = MICROPY_HW_UART6_RX;
+ #if defined(MICROPY_HW_UART6_RTS)
+ if (uart_obj->uart.Init.HwFlowCtl & UART_HWCONTROL_RTS) {
+ pins[2] = MICROPY_HW_UART6_RTS;
+ }
+ #endif
+ #if defined(MICROPY_HW_UART6_CTS)
+ if (uart_obj->uart.Init.HwFlowCtl & UART_HWCONTROL_CTS) {
+ pins[3] = MICROPY_HW_UART6_CTS;
+ }
+ #endif
+ __HAL_RCC_USART6_CLK_ENABLE();
break;
#endif
@@ -252,20 +282,26 @@ STATIC bool uart_init2(pyb_uart_obj_t *uart_obj) {
uart_unit = 7;
UARTx = UART7;
irqn = UART7_IRQn;
- pins[0] = &MICROPY_HW_UART7_TX;
- pins[1] = &MICROPY_HW_UART7_RX;
- __UART7_CLK_ENABLE();
+ pins[0] = MICROPY_HW_UART7_TX;
+ pins[1] = MICROPY_HW_UART7_RX;
+ __HAL_RCC_UART7_CLK_ENABLE();
break;
#endif
#if defined(MICROPY_HW_UART8_TX) && defined(MICROPY_HW_UART8_RX)
case PYB_UART_8:
uart_unit = 8;
+ #if defined(STM32F0)
+ UARTx = USART8;
+ irqn = USART3_8_IRQn;
+ __HAL_RCC_USART8_CLK_ENABLE();
+ #else
UARTx = UART8;
irqn = UART8_IRQn;
- pins[0] = &MICROPY_HW_UART8_TX;
- pins[1] = &MICROPY_HW_UART8_RX;
- __UART8_CLK_ENABLE();
+ __HAL_RCC_UART8_CLK_ENABLE();
+ #endif
+ pins[0] = MICROPY_HW_UART8_TX;
+ pins[1] = MICROPY_HW_UART8_RX;
break;
#endif
@@ -293,10 +329,15 @@ STATIC bool uart_init2(pyb_uart_obj_t *uart_obj) {
HAL_UART_Init(&uart_obj->uart);
uart_obj->is_enabled = true;
+ uart_obj->attached_to_repl = false;
return true;
}
+void uart_attach_to_repl(pyb_uart_obj_t *self, bool attached) {
+ self->attached_to_repl = attached;
+}
+
/* obsolete and unused
bool uart_init(pyb_uart_obj_t *uart_obj, uint32_t baudrate) {
UART_HandleTypeDef *uh = &uart_obj->uart;
@@ -357,7 +398,7 @@ int uart_rx_char(pyb_uart_obj_t *self) {
return data;
} else {
// no buffering
- #if defined(MCU_SERIES_F7) || defined(MCU_SERIES_L4)
+ #if defined(STM32F0) || defined(STM32F7) || defined(STM32L4) || defined(STM32H7)
return self->uart.Instance->RDR & self->char_mask;
#else
return self->uart.Instance->DR & self->char_mask;
@@ -436,7 +477,7 @@ STATIC size_t uart_tx_data(pyb_uart_obj_t *self, const void *src_in, size_t num_
} else {
data = *src++;
}
- #if defined(MCU_SERIES_F4)
+ #if defined(STM32F4)
uart->DR = data;
#else
uart->TDR = data;
@@ -475,12 +516,17 @@ void uart_irq_handler(mp_uint_t uart_id) {
uint16_t next_head = (self->read_buf_head + 1) % self->read_buf_len;
if (next_head != self->read_buf_tail) {
// only read data if room in buf
- #if defined(MCU_SERIES_F7) || defined(MCU_SERIES_L4)
+ #if defined(STM32F0) || defined(STM32F7) || defined(STM32L4) || defined(STM32H7)
int data = self->uart.Instance->RDR; // clears UART_FLAG_RXNE
#else
int data = self->uart.Instance->DR; // clears UART_FLAG_RXNE
#endif
data &= self->char_mask;
+ // Handle interrupt coming in on a UART REPL
+ if (self->attached_to_repl && data == mp_interrupt_char) {
+ pendsv_kbd_intr();
+ return;
+ }
if (self->char_width == CHAR_WIDTH_9BIT) {
((uint16_t*)self->read_buf)[self->read_buf_head] = data;
} else {
@@ -502,7 +548,14 @@ STATIC void pyb_uart_print(const mp_print_t *print, mp_obj_t self_in, mp_print_k
if (!self->is_enabled) {
mp_printf(print, "UART(%u)", self->uart_id);
} else {
- mp_int_t bits = (self->uart.Init.WordLength == UART_WORDLENGTH_8B ? 8 : 9);
+ mp_int_t bits;
+ switch (self->uart.Init.WordLength) {
+ #ifdef UART_WORDLENGTH_7B
+ case UART_WORDLENGTH_7B: bits = 7; break;
+ #endif
+ case UART_WORDLENGTH_8B: bits = 8; break;
+ case UART_WORDLENGTH_9B: default: bits = 9; break;
+ }
if (self->uart.Init.Parity != UART_PARITY_NONE) {
bits -= 1;
}
@@ -582,6 +635,10 @@ STATIC mp_obj_t pyb_uart_init_helper(pyb_uart_obj_t *self, size_t n_args, const
init->WordLength = UART_WORDLENGTH_8B;
} else if (bits == 9) {
init->WordLength = UART_WORDLENGTH_9B;
+ #ifdef UART_WORDLENGTH_7B
+ } else if (bits == 7) {
+ init->WordLength = UART_WORDLENGTH_7B;
+ #endif
} else {
mp_raise_ValueError("unsupported combination of bits and parity");
}
@@ -642,22 +699,37 @@ STATIC mp_obj_t pyb_uart_init_helper(pyb_uart_obj_t *self, size_t n_args, const
self->read_buf_len = args.read_buf_len.u_int + 1; // +1 to adjust for usable length of buffer
self->read_buf = m_new(byte, self->read_buf_len << self->char_width);
__HAL_UART_ENABLE_IT(&self->uart, UART_IT_RXNE);
- HAL_NVIC_SetPriority(self->irqn, IRQ_PRI_UART, IRQ_SUBPRI_UART);
+ NVIC_SetPriority(IRQn_NONNEG(self->irqn), IRQ_PRI_UART);
HAL_NVIC_EnableIRQ(self->irqn);
}
// compute actual baudrate that was configured
// (this formula assumes UART_OVERSAMPLING_16)
uint32_t actual_baudrate = 0;
- #if defined(MCU_SERIES_F7)
+ #if defined(STM32F0)
+ actual_baudrate = HAL_RCC_GetPCLK1Freq();
+ #elif defined(STM32F7) || defined(STM32H7)
UART_ClockSourceTypeDef clocksource = UART_CLOCKSOURCE_UNDEFINED;
UART_GETCLOCKSOURCE(&self->uart, clocksource);
switch (clocksource) {
+ #if defined(STM32H7)
+ case UART_CLOCKSOURCE_D2PCLK1: actual_baudrate = HAL_RCC_GetPCLK1Freq(); break;
+ case UART_CLOCKSOURCE_D3PCLK1: actual_baudrate = HAL_RCC_GetPCLK1Freq(); break;
+ case UART_CLOCKSOURCE_D2PCLK2: actual_baudrate = HAL_RCC_GetPCLK2Freq(); break;
+ #else
case UART_CLOCKSOURCE_PCLK1: actual_baudrate = HAL_RCC_GetPCLK1Freq(); break;
case UART_CLOCKSOURCE_PCLK2: actual_baudrate = HAL_RCC_GetPCLK2Freq(); break;
- case UART_CLOCKSOURCE_HSI: actual_baudrate = HSI_VALUE; break;
case UART_CLOCKSOURCE_SYSCLK: actual_baudrate = HAL_RCC_GetSysClockFreq(); break;
+ #endif
+ #if defined(STM32H7)
+ case UART_CLOCKSOURCE_CSI: actual_baudrate = CSI_VALUE; break;
+ #endif
+ case UART_CLOCKSOURCE_HSI: actual_baudrate = HSI_VALUE; break;
case UART_CLOCKSOURCE_LSE: actual_baudrate = LSE_VALUE; break;
+ #if defined(STM32H7)
+ case UART_CLOCKSOURCE_PLL2:
+ case UART_CLOCKSOURCE_PLL3:
+ #endif
case UART_CLOCKSOURCE_UNDEFINED: break;
}
#else
@@ -782,55 +854,57 @@ STATIC mp_obj_t pyb_uart_deinit(mp_obj_t self_in) {
HAL_UART_DeInit(uart);
if (uart->Instance == USART1) {
HAL_NVIC_DisableIRQ(USART1_IRQn);
- __USART1_FORCE_RESET();
- __USART1_RELEASE_RESET();
- __USART1_CLK_DISABLE();
+ __HAL_RCC_USART1_FORCE_RESET();
+ __HAL_RCC_USART1_RELEASE_RESET();
+ __HAL_RCC_USART1_CLK_DISABLE();
} else if (uart->Instance == USART2) {
HAL_NVIC_DisableIRQ(USART2_IRQn);
- __USART2_FORCE_RESET();
- __USART2_RELEASE_RESET();
- __USART2_CLK_DISABLE();
+ __HAL_RCC_USART2_FORCE_RESET();
+ __HAL_RCC_USART2_RELEASE_RESET();
+ __HAL_RCC_USART2_CLK_DISABLE();
#if defined(USART3)
} else if (uart->Instance == USART3) {
+ #if !defined(STM32F0)
HAL_NVIC_DisableIRQ(USART3_IRQn);
- __USART3_FORCE_RESET();
- __USART3_RELEASE_RESET();
- __USART3_CLK_DISABLE();
+ #endif
+ __HAL_RCC_USART3_FORCE_RESET();
+ __HAL_RCC_USART3_RELEASE_RESET();
+ __HAL_RCC_USART3_CLK_DISABLE();
#endif
#if defined(UART4)
} else if (uart->Instance == UART4) {
HAL_NVIC_DisableIRQ(UART4_IRQn);
- __UART4_FORCE_RESET();
- __UART4_RELEASE_RESET();
- __UART4_CLK_DISABLE();
+ __HAL_RCC_UART4_FORCE_RESET();
+ __HAL_RCC_UART4_RELEASE_RESET();
+ __HAL_RCC_UART4_CLK_DISABLE();
#endif
#if defined(UART5)
} else if (uart->Instance == UART5) {
HAL_NVIC_DisableIRQ(UART5_IRQn);
- __UART5_FORCE_RESET();
- __UART5_RELEASE_RESET();
- __UART5_CLK_DISABLE();
+ __HAL_RCC_UART5_FORCE_RESET();
+ __HAL_RCC_UART5_RELEASE_RESET();
+ __HAL_RCC_UART5_CLK_DISABLE();
#endif
#if defined(UART6)
} else if (uart->Instance == USART6) {
HAL_NVIC_DisableIRQ(USART6_IRQn);
- __USART6_FORCE_RESET();
- __USART6_RELEASE_RESET();
- __USART6_CLK_DISABLE();
+ __HAL_RCC_USART6_FORCE_RESET();
+ __HAL_RCC_USART6_RELEASE_RESET();
+ __HAL_RCC_USART6_CLK_DISABLE();
#endif
#if defined(UART7)
} else if (uart->Instance == UART7) {
HAL_NVIC_DisableIRQ(UART7_IRQn);
- __UART7_FORCE_RESET();
- __UART7_RELEASE_RESET();
- __UART7_CLK_DISABLE();
+ __HAL_RCC_UART7_FORCE_RESET();
+ __HAL_RCC_UART7_RELEASE_RESET();
+ __HAL_RCC_UART7_CLK_DISABLE();
#endif
#if defined(UART8)
} else if (uart->Instance == UART8) {
HAL_NVIC_DisableIRQ(UART8_IRQn);
- __UART8_FORCE_RESET();
- __UART8_RELEASE_RESET();
- __UART8_CLK_DISABLE();
+ __HAL_RCC_UART8_FORCE_RESET();
+ __HAL_RCC_UART8_RELEASE_RESET();
+ __HAL_RCC_UART8_CLK_DISABLE();
#endif
}
return mp_const_none;
@@ -887,7 +961,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_uart_readchar_obj, pyb_uart_readchar);
// uart.sendbreak()
STATIC mp_obj_t pyb_uart_sendbreak(mp_obj_t self_in) {
pyb_uart_obj_t *self = self_in;
- #if defined(MCU_SERIES_F7) || defined(MCU_SERIES_L4)
+ #if defined(STM32F0) || defined(STM32F7) || defined(STM32L4) || defined(STM32H7)
self->uart.Instance->RQR = USART_RQR_SBKRQ; // write-only register
#else
self->uart.Instance->CR1 |= USART_CR1_SBK;
diff --git a/ports/stm32/uart.h b/ports/stm32/uart.h
index d176520a1..4ab18ff22 100644
--- a/ports/stm32/uart.h
+++ b/ports/stm32/uart.h
@@ -23,8 +23,8 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
-#ifndef MICROPY_INCLUDED_STMHAL_UART_H
-#define MICROPY_INCLUDED_STMHAL_UART_H
+#ifndef MICROPY_INCLUDED_STM32_UART_H
+#define MICROPY_INCLUDED_STM32_UART_H
typedef enum {
PYB_UART_NONE = 0,
@@ -45,8 +45,9 @@ void uart_init0(void);
void uart_deinit(void);
void uart_irq_handler(mp_uint_t uart_id);
+void uart_attach_to_repl(pyb_uart_obj_t *self, bool attached);
mp_uint_t uart_rx_any(pyb_uart_obj_t *uart_obj);
int uart_rx_char(pyb_uart_obj_t *uart_obj);
void uart_tx_strn(pyb_uart_obj_t *uart_obj, const char *str, uint len);
-#endif // MICROPY_INCLUDED_STMHAL_UART_H
+#endif // MICROPY_INCLUDED_STM32_UART_H
diff --git a/ports/stm32/usb.c b/ports/stm32/usb.c
index 5017bb930..c6fc86e05 100644
--- a/ports/stm32/usb.c
+++ b/ports/stm32/usb.c
@@ -43,12 +43,17 @@
#include "bufhelper.h"
#include "usb.h"
-#if defined(USE_USB_FS)
-#define USB_PHY_ID USB_PHY_FS_ID
-#elif defined(USE_USB_HS) && defined(USE_USB_HS_IN_FS)
-#define USB_PHY_ID USB_PHY_HS_ID
+#if MICROPY_HW_ENABLE_USB
+
+// Work out which USB device to use as the main one (the one with the REPL)
+#if !defined(MICROPY_HW_USB_MAIN_DEV)
+#if defined(MICROPY_HW_USB_FS)
+#define MICROPY_HW_USB_MAIN_DEV (USB_PHY_FS_ID)
+#elif defined(MICROPY_HW_USB_HS) && defined(MICROPY_HW_USB_HS_IN_FS)
+#define MICROPY_HW_USB_MAIN_DEV (USB_PHY_HS_ID)
#else
-#error Unable to determine proper USB_PHY_ID to use
+#error Unable to determine proper MICROPY_HW_USB_MAIN_DEV to use
+#endif
#endif
// this will be persistent across a soft-reset
@@ -59,13 +64,14 @@ typedef struct _usb_device_t {
USBD_HandleTypeDef hUSBDDevice;
usbd_cdc_msc_hid_state_t usbd_cdc_msc_hid_state;
usbd_cdc_itf_t usbd_cdc_itf;
+ #if MICROPY_HW_USB_ENABLE_CDC2
+ usbd_cdc_itf_t usbd_cdc2_itf;
+ #endif
usbd_hid_itf_t usbd_hid_itf;
} usb_device_t;
-#ifdef USE_DEVICE_MODE
usb_device_t usb_device;
pyb_usb_storage_medium_t pyb_usb_storage_medium = PYB_USB_STORAGE_MEDIUM_NONE;
-#endif
// predefined hid mouse data
STATIC const mp_obj_str_t pyb_usb_hid_mouse_desc_obj = {
@@ -111,28 +117,32 @@ void pyb_usb_init0(void) {
}
bool pyb_usb_dev_init(uint16_t vid, uint16_t pid, usb_device_mode_t mode, USBD_HID_ModeInfoTypeDef *hid_info) {
-#ifdef USE_DEVICE_MODE
+ bool high_speed = (mode & USBD_MODE_HIGH_SPEED) != 0;
+ mode &= 0x7f;
usb_device_t *usb_dev = &usb_device;
if (!usb_dev->enabled) {
// only init USB once in the device's power-lifetime
- // configure the VID, PID and the USBD mode (interfaces it will expose)
- USBD_SetVIDPIDRelease(&usb_dev->usbd_cdc_msc_hid_state, vid, pid, 0x0200, mode == USBD_MODE_CDC);
- if (USBD_SelectMode(&usb_dev->usbd_cdc_msc_hid_state, mode, hid_info) != 0) {
- return false;
- }
-
// set up the USBD state
USBD_HandleTypeDef *usbd = &usb_dev->hUSBDDevice;
- usbd->id = USB_PHY_ID;
+ usbd->id = MICROPY_HW_USB_MAIN_DEV;
usbd->dev_state = USBD_STATE_DEFAULT;
usbd->pDesc = (USBD_DescriptorsTypeDef*)&USBD_Descriptors;
usbd->pClass = &USBD_CDC_MSC_HID;
usb_dev->usbd_cdc_msc_hid_state.pdev = usbd;
- usb_dev->usbd_cdc_msc_hid_state.cdc = &usb_dev->usbd_cdc_itf;
- usb_dev->usbd_cdc_msc_hid_state.hid = &usb_dev->usbd_hid_itf;
+ usb_dev->usbd_cdc_msc_hid_state.cdc = &usb_dev->usbd_cdc_itf.base;
+ #if MICROPY_HW_USB_ENABLE_CDC2
+ usb_dev->usbd_cdc_msc_hid_state.cdc2 = &usb_dev->usbd_cdc2_itf.base;
+ #endif
+ usb_dev->usbd_cdc_msc_hid_state.hid = &usb_dev->usbd_hid_itf.base;
usbd->pClassData = &usb_dev->usbd_cdc_msc_hid_state;
+ // configure the VID, PID and the USBD mode (interfaces it will expose)
+ USBD_SetVIDPIDRelease(&usb_dev->usbd_cdc_msc_hid_state, vid, pid, 0x0200, mode == USBD_MODE_CDC);
+ if (USBD_SelectMode(&usb_dev->usbd_cdc_msc_hid_state, mode, hid_info) != 0) {
+ return false;
+ }
+
switch (pyb_usb_storage_medium) {
#if MICROPY_HW_HAS_SDCARD
case PYB_USB_STORAGE_MEDIUM_SDCARD:
@@ -145,11 +155,10 @@ bool pyb_usb_dev_init(uint16_t vid, uint16_t pid, usb_device_mode_t mode, USBD_H
}
// start the USB device
- USBD_LL_Init(usbd);
+ USBD_LL_Init(usbd, high_speed);
USBD_LL_Start(usbd);
usb_dev->enabled = true;
}
-#endif
return true;
}
@@ -171,11 +180,18 @@ int usb_vcp_recv_byte(uint8_t *c) {
}
void usb_vcp_send_strn(const char *str, int len) {
-#ifdef USE_DEVICE_MODE
if (usb_device.enabled) {
usbd_cdc_tx_always(&usb_device.usbd_cdc_itf, (const uint8_t*)str, len);
}
-#endif
+}
+
+usbd_cdc_itf_t *usb_vcp_get(int idx) {
+ #if MICROPY_HW_USB_ENABLE_CDC2
+ if (idx == 1) {
+ return &usb_device.usbd_cdc2_itf;
+ }
+ #endif
+ return &usb_device.usbd_cdc_itf;
}
/******************************************************************************/
@@ -213,13 +229,16 @@ STATIC mp_obj_t pyb_usb_mode(size_t n_args, const mp_obj_t *pos_args, mp_map_t *
{ MP_QSTR_vid, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = USBD_VID} },
{ MP_QSTR_pid, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
{ MP_QSTR_hid, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = (mp_obj_t)&pyb_usb_hid_mouse_obj} },
+ #if USBD_SUPPORT_HS_MODE
+ { MP_QSTR_high_speed, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
+ #endif
};
// fetch the current usb mode -> pyb.usb_mode()
if (n_args == 0) {
#if defined(USE_HOST_MODE)
return MP_OBJ_NEW_QSTR(MP_QSTR_host);
- #elif defined(USE_DEVICE_MODE)
+ #else
uint8_t mode = USBD_GetMode(&usb_device.usbd_cdc_msc_hid_state);
switch (mode) {
case USBD_MODE_CDC:
@@ -250,9 +269,7 @@ STATIC mp_obj_t pyb_usb_mode(size_t n_args, const mp_obj_t *pos_args, mp_map_t *
// check if user wants to disable the USB
if (args[0].u_obj == mp_const_none) {
// disable usb
- #if defined(USE_DEVICE_MODE)
pyb_usb_dev_deinit();
- #endif
return mp_const_none;
}
@@ -269,7 +286,7 @@ STATIC mp_obj_t pyb_usb_mode(size_t n_args, const mp_obj_t *pos_args, mp_map_t *
goto bad_mode;
}
-#elif defined(USE_DEVICE_MODE)
+#else
// hardware configured for USB device mode
@@ -284,6 +301,13 @@ STATIC mp_obj_t pyb_usb_mode(size_t n_args, const mp_obj_t *pos_args, mp_map_t *
pid = USBD_PID_CDC_MSC;
}
mode = USBD_MODE_CDC_MSC;
+ #if MICROPY_HW_USB_ENABLE_CDC2
+ } else if (strcmp(mode_str, "VCP+VCP+MSC") == 0) {
+ if (args[2].u_int == -1) {
+ pid = USBD_PID_CDC2_MSC;
+ }
+ mode = USBD_MODE_CDC2_MSC;
+ #endif
} else if (strcmp(mode_str, "CDC+HID") == 0 || strcmp(mode_str, "VCP+HID") == 0) {
if (args[2].u_int == -1) {
pid = USBD_PID_CDC_HID;
@@ -294,6 +318,11 @@ STATIC mp_obj_t pyb_usb_mode(size_t n_args, const mp_obj_t *pos_args, mp_map_t *
pid = USBD_PID_CDC;
}
mode = USBD_MODE_CDC;
+ } else if (strcmp(mode_str, "MSC") == 0) {
+ if (args[2].u_int == -1) {
+ pid = USBD_PID_MSC;
+ }
+ mode = USBD_MODE_MSC;
} else {
goto bad_mode;
}
@@ -316,14 +345,17 @@ STATIC mp_obj_t pyb_usb_mode(size_t n_args, const mp_obj_t *pos_args, mp_map_t *
MP_STATE_PORT(pyb_hid_report_desc) = items[4];
}
+ #if USBD_SUPPORT_HS_MODE
+ if (args[4].u_bool) {
+ mode |= USBD_MODE_HIGH_SPEED;
+ }
+ #endif
+
// init the USB device
if (!pyb_usb_dev_init(vid, pid, mode, &hid_info)) {
goto bad_mode;
}
-#else
- // hardware not configured for USB
- goto bad_mode;
#endif
return mp_const_none;
@@ -345,25 +377,37 @@ MP_DEFINE_CONST_FUN_OBJ_KW(pyb_usb_mode_obj, 0, pyb_usb_mode);
typedef struct _pyb_usb_vcp_obj_t {
mp_obj_base_t base;
- usb_device_t *usb_dev;
+ usbd_cdc_itf_t *cdc_itf;
} pyb_usb_vcp_obj_t;
-STATIC const pyb_usb_vcp_obj_t pyb_usb_vcp_obj = {{&pyb_usb_vcp_type}, &usb_device};
+STATIC const pyb_usb_vcp_obj_t pyb_usb_vcp_obj = {{&pyb_usb_vcp_type}, &usb_device.usbd_cdc_itf};
+#if MICROPY_HW_USB_ENABLE_CDC2
+STATIC const pyb_usb_vcp_obj_t pyb_usb_vcp2_obj = {{&pyb_usb_vcp_type}, &usb_device.usbd_cdc2_itf};
+#endif
STATIC void pyb_usb_vcp_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
- mp_print_str(print, "USB_VCP()");
+ int id = ((pyb_usb_vcp_obj_t*)self_in)->cdc_itf - &usb_device.usbd_cdc_itf;
+ mp_printf(print, "USB_VCP(%u)", id);
}
/// \classmethod \constructor()
/// Create a new USB_VCP object.
STATIC mp_obj_t pyb_usb_vcp_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
// check arguments
- mp_arg_check_num(n_args, n_kw, 0, 0, false);
+ mp_arg_check_num(n_args, n_kw, 0, 1, false);
// TODO raise exception if USB is not configured for VCP
- // return the USB VCP object
- return (mp_obj_t)&pyb_usb_vcp_obj;
+ int id = (n_args == 0) ? 0 : mp_obj_get_int(args[0]);
+ if (id == 0) {
+ return MP_OBJ_FROM_PTR(&pyb_usb_vcp_obj);
+ #if MICROPY_HW_USB_ENABLE_CDC2
+ } else if (id == 1) {
+ return MP_OBJ_FROM_PTR(&pyb_usb_vcp2_obj);
+ #endif
+ } else {
+ mp_raise_ValueError(NULL);
+ }
}
STATIC mp_obj_t pyb_usb_vcp_setinterrupt(mp_obj_t self_in, mp_obj_t int_chr_in) {
@@ -374,13 +418,13 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(pyb_usb_vcp_setinterrupt_obj, pyb_usb_vcp_setin
STATIC mp_obj_t pyb_usb_vcp_isconnected(mp_obj_t self_in) {
pyb_usb_vcp_obj_t *self = MP_OBJ_TO_PTR(self_in);
- return mp_obj_new_bool(usbd_cdc_is_connected(&self->usb_dev->usbd_cdc_itf));
+ return mp_obj_new_bool(usbd_cdc_is_connected(self->cdc_itf));
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_usb_vcp_isconnected_obj, pyb_usb_vcp_isconnected);
// deprecated in favour of USB_VCP.isconnected
STATIC mp_obj_t pyb_have_cdc(void) {
- return pyb_usb_vcp_isconnected(MP_OBJ_NULL);
+ return pyb_usb_vcp_isconnected(MP_OBJ_FROM_PTR(&pyb_usb_vcp_obj));
}
MP_DEFINE_CONST_FUN_OBJ_0(pyb_have_cdc_obj, pyb_have_cdc);
@@ -388,7 +432,7 @@ MP_DEFINE_CONST_FUN_OBJ_0(pyb_have_cdc_obj, pyb_have_cdc);
/// Return `True` if any characters waiting, else `False`.
STATIC mp_obj_t pyb_usb_vcp_any(mp_obj_t self_in) {
pyb_usb_vcp_obj_t *self = MP_OBJ_TO_PTR(self_in);
- if (usbd_cdc_rx_num(&self->usb_dev->usbd_cdc_itf) > 0) {
+ if (usbd_cdc_rx_num(self->cdc_itf) > 0) {
return mp_const_true;
} else {
return mp_const_false;
@@ -421,7 +465,7 @@ STATIC mp_obj_t pyb_usb_vcp_send(size_t n_args, const mp_obj_t *args, mp_map_t *
pyb_buf_get_for_send(vals[0].u_obj, &bufinfo, data);
// send the data
- int ret = usbd_cdc_tx(&self->usb_dev->usbd_cdc_itf, bufinfo.buf, bufinfo.len, vals[1].u_int);
+ int ret = usbd_cdc_tx(self->cdc_itf, bufinfo.buf, bufinfo.len, vals[1].u_int);
return mp_obj_new_int(ret);
}
@@ -448,7 +492,7 @@ STATIC mp_obj_t pyb_usb_vcp_recv(size_t n_args, const mp_obj_t *args, mp_map_t *
mp_obj_t o_ret = pyb_buf_get_for_recv(vals[0].u_obj, &vstr);
// receive the data
- int ret = usbd_cdc_rx(&self->usb_dev->usbd_cdc_itf, (uint8_t*)vstr.buf, vstr.len, vals[1].u_int);
+ int ret = usbd_cdc_rx(self->cdc_itf, (uint8_t*)vstr.buf, vstr.len, vals[1].u_int);
// return the received data
if (o_ret != MP_OBJ_NULL) {
@@ -486,7 +530,7 @@ STATIC MP_DEFINE_CONST_DICT(pyb_usb_vcp_locals_dict, pyb_usb_vcp_locals_dict_tab
STATIC mp_uint_t pyb_usb_vcp_read(mp_obj_t self_in, void *buf, mp_uint_t size, int *errcode) {
pyb_usb_vcp_obj_t *self = MP_OBJ_TO_PTR(self_in);
- int ret = usbd_cdc_rx(&self->usb_dev->usbd_cdc_itf, (byte*)buf, size, 0);
+ int ret = usbd_cdc_rx(self->cdc_itf, (byte*)buf, size, 0);
if (ret == 0) {
// return EAGAIN error to indicate non-blocking
*errcode = MP_EAGAIN;
@@ -497,7 +541,7 @@ STATIC mp_uint_t pyb_usb_vcp_read(mp_obj_t self_in, void *buf, mp_uint_t size, i
STATIC mp_uint_t pyb_usb_vcp_write(mp_obj_t self_in, const void *buf, mp_uint_t size, int *errcode) {
pyb_usb_vcp_obj_t *self = MP_OBJ_TO_PTR(self_in);
- int ret = usbd_cdc_tx(&self->usb_dev->usbd_cdc_itf, (const byte*)buf, size, 0);
+ int ret = usbd_cdc_tx(self->cdc_itf, (const byte*)buf, size, 0);
if (ret == 0) {
// return EAGAIN error to indicate non-blocking
*errcode = MP_EAGAIN;
@@ -512,10 +556,10 @@ STATIC mp_uint_t pyb_usb_vcp_ioctl(mp_obj_t self_in, mp_uint_t request, mp_uint_
if (request == MP_STREAM_POLL) {
mp_uint_t flags = arg;
ret = 0;
- if ((flags & MP_STREAM_POLL_RD) && usbd_cdc_rx_num(&self->usb_dev->usbd_cdc_itf) > 0) {
+ if ((flags & MP_STREAM_POLL_RD) && usbd_cdc_rx_num(self->cdc_itf) > 0) {
ret |= MP_STREAM_POLL_RD;
}
- if ((flags & MP_STREAM_POLL_WR) && usbd_cdc_tx_half_empty(&self->usb_dev->usbd_cdc_itf)) {
+ if ((flags & MP_STREAM_POLL_WR) && usbd_cdc_tx_half_empty(self->cdc_itf)) {
ret |= MP_STREAM_POLL_WR;
}
} else {
@@ -579,7 +623,7 @@ STATIC mp_obj_t pyb_usb_hid_recv(size_t n_args, const mp_obj_t *args, mp_map_t *
};
// parse args
- pyb_usb_vcp_obj_t *self = MP_OBJ_TO_PTR(args[0]);
+ pyb_usb_hid_obj_t *self = MP_OBJ_TO_PTR(args[0]);
mp_arg_val_t vals[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args - 1, args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, vals);
@@ -601,8 +645,7 @@ STATIC mp_obj_t pyb_usb_hid_recv(size_t n_args, const mp_obj_t *args, mp_map_t *
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_usb_hid_recv_obj, 1, pyb_usb_hid_recv);
STATIC mp_obj_t pyb_usb_hid_send(mp_obj_t self_in, mp_obj_t report_in) {
-#ifdef USE_DEVICE_MODE
- pyb_usb_vcp_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ pyb_usb_hid_obj_t *self = MP_OBJ_TO_PTR(self_in);
mp_buffer_info_t bufinfo;
byte temp_buf[8];
// get the buffer to send from
@@ -620,12 +663,11 @@ STATIC mp_obj_t pyb_usb_hid_send(mp_obj_t self_in, mp_obj_t report_in) {
}
// send the data
- if (USBD_OK == USBD_HID_SendReport(&self->usb_dev->usbd_cdc_msc_hid_state, bufinfo.buf, bufinfo.len)) {
+ if (USBD_OK == USBD_HID_SendReport(&self->usb_dev->usbd_hid_itf.base, bufinfo.buf, bufinfo.len)) {
return mp_obj_new_int(bufinfo.len);
} else {
return mp_obj_new_int(0);
}
-#endif
return mp_const_none;
}
@@ -645,7 +687,7 @@ STATIC const mp_rom_map_elem_t pyb_usb_hid_locals_dict_table[] = {
STATIC MP_DEFINE_CONST_DICT(pyb_usb_hid_locals_dict, pyb_usb_hid_locals_dict_table);
STATIC mp_uint_t pyb_usb_hid_ioctl(mp_obj_t self_in, mp_uint_t request, mp_uint_t arg, int *errcode) {
- pyb_usb_vcp_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ pyb_usb_hid_obj_t *self = MP_OBJ_TO_PTR(self_in);
mp_uint_t ret;
if (request == MP_STREAM_POLL) {
mp_uint_t flags = arg;
@@ -653,7 +695,7 @@ STATIC mp_uint_t pyb_usb_hid_ioctl(mp_obj_t self_in, mp_uint_t request, mp_uint_
if ((flags & MP_STREAM_POLL_RD) && usbd_hid_rx_num(&self->usb_dev->usbd_hid_itf) > 0) {
ret |= MP_STREAM_POLL_RD;
}
- if ((flags & MP_STREAM_POLL_WR) && USBD_HID_CanSendReport(&self->usb_dev->usbd_cdc_msc_hid_state)) {
+ if ((flags & MP_STREAM_POLL_WR) && USBD_HID_CanSendReport(&self->usb_dev->usbd_hid_itf.base)) {
ret |= MP_STREAM_POLL_WR;
}
} else {
@@ -739,3 +781,5 @@ void USR_KEYBRD_ProcessData(uint8_t pbuf) {
}
#endif // USE_HOST_MODE
+
+#endif // MICROPY_HW_ENABLE_USB
diff --git a/ports/stm32/usb.h b/ports/stm32/usb.h
index 41c461fb2..1de9e5d0e 100644
--- a/ports/stm32/usb.h
+++ b/ports/stm32/usb.h
@@ -23,8 +23,8 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
-#ifndef MICROPY_INCLUDED_STMHAL_USB_H
-#define MICROPY_INCLUDED_STMHAL_USB_H
+#ifndef MICROPY_INCLUDED_STM32_USB_H
+#define MICROPY_INCLUDED_STM32_USB_H
#include "usbd_cdc_msc_hid0.h"
@@ -35,6 +35,8 @@
#define USBD_PID_CDC_MSC (0x9800)
#define USBD_PID_CDC_HID (0x9801)
#define USBD_PID_CDC (0x9802)
+#define USBD_PID_MSC (0x9803)
+#define USBD_PID_CDC2_MSC (0x9804)
typedef enum {
PYB_USB_STORAGE_MEDIUM_NONE = 0,
@@ -68,4 +70,4 @@ void pyb_usb_host_init(void);
void pyb_usb_host_process(void);
uint pyb_usb_host_get_keyboard(void);
-#endif // MICROPY_INCLUDED_STMHAL_USB_H
+#endif // MICROPY_INCLUDED_STM32_USB_H
diff --git a/ports/stm32/usbd_cdc_interface.c b/ports/stm32/usbd_cdc_interface.c
index 2e9fba917..91ae81bb3 100644
--- a/ports/stm32/usbd_cdc_interface.c
+++ b/ports/stm32/usbd_cdc_interface.c
@@ -45,6 +45,8 @@
#include "lib/utils/interrupt_char.h"
#include "irq.h"
+#if MICROPY_HW_ENABLE_USB
+
// CDC control commands
#define CDC_SEND_ENCAPSULATED_COMMAND 0x00
#define CDC_GET_ENCAPSULATED_RESPONSE 0x01
@@ -56,9 +58,8 @@
#define CDC_SET_CONTROL_LINE_STATE 0x22
#define CDC_SEND_BREAK 0x23
-uint8_t *usbd_cdc_init(usbd_cdc_itf_t *cdc, usbd_cdc_msc_hid_state_t *usbd) {
- // Link the parent state
- cdc->usbd = usbd;
+uint8_t *usbd_cdc_init(usbd_cdc_state_t *cdc_in) {
+ usbd_cdc_itf_t *cdc = (usbd_cdc_itf_t*)cdc_in;
// Reset all the CDC state
// Note: we don't reset tx_buf_ptr_in in order to allow the output buffer to
@@ -70,6 +71,11 @@ uint8_t *usbd_cdc_init(usbd_cdc_itf_t *cdc, usbd_cdc_msc_hid_state_t *usbd) {
cdc->tx_buf_ptr_wait_count = 0;
cdc->tx_need_empty_packet = 0;
cdc->dev_is_connected = 0;
+ #if MICROPY_HW_USB_ENABLE_CDC2
+ cdc->attached_to_repl = &cdc->base == cdc->base.usbd->cdc;
+ #else
+ cdc->attached_to_repl = 1;
+ #endif
// Return the buffer to place the first USB OUT packet
return cdc->rx_packet_buf;
@@ -80,7 +86,9 @@ uint8_t *usbd_cdc_init(usbd_cdc_itf_t *cdc, usbd_cdc_msc_hid_state_t *usbd) {
// pbuf: buffer containing command data (request parameters)
// length: number of data to be sent (in bytes)
// Returns USBD_OK if all operations are OK else USBD_FAIL
-int8_t usbd_cdc_control(usbd_cdc_itf_t *cdc, uint8_t cmd, uint8_t* pbuf, uint16_t length) {
+int8_t usbd_cdc_control(usbd_cdc_state_t *cdc_in, uint8_t cmd, uint8_t* pbuf, uint16_t length) {
+ usbd_cdc_itf_t *cdc = (usbd_cdc_itf_t*)cdc_in;
+
switch (cmd) {
case CDC_SEND_ENCAPSULATED_COMMAND:
/* Add your code here */
@@ -142,10 +150,7 @@ int8_t usbd_cdc_control(usbd_cdc_itf_t *cdc, uint8_t cmd, uint8_t* pbuf, uint16_
// This function is called to process outgoing data. We hook directly into the
// SOF (start of frame) callback so that it is called exactly at the time it is
// needed (reducing latency), and often enough (increasing bandwidth).
-void HAL_PCD_SOFCallback(PCD_HandleTypeDef *hpcd) {
- usbd_cdc_msc_hid_state_t *usbd = ((USBD_HandleTypeDef*)hpcd->pData)->pClassData;
- usbd_cdc_itf_t *cdc = usbd->cdc;
-
+static void usbd_cdc_sof(PCD_HandleTypeDef *hpcd, usbd_cdc_itf_t *cdc) {
if (cdc == NULL || !cdc->dev_is_connected) {
// CDC device is not connected to a host, so we are unable to send any data
return;
@@ -164,7 +169,7 @@ void HAL_PCD_SOFCallback(PCD_HandleTypeDef *hpcd) {
// doing other things and we must give it a chance to read our data.
if (cdc->tx_buf_ptr_wait_count < 500) {
USB_OTG_GlobalTypeDef *USBx = hpcd->Instance;
- if (USBx_INEP(CDC_IN_EP & 0x7f)->DIEPTSIZ & USB_OTG_DIEPTSIZ_XFRSIZ) {
+ if (USBx_INEP(cdc->base.in_ep & 0x7f)->DIEPTSIZ & USB_OTG_DIEPTSIZ_XFRSIZ) {
// USB in-endpoint is still reading the data
cdc->tx_buf_ptr_wait_count++;
return;
@@ -185,7 +190,7 @@ void HAL_PCD_SOFCallback(PCD_HandleTypeDef *hpcd) {
buffptr = cdc->tx_buf_ptr_out_shadow;
- if (USBD_CDC_TransmitPacket(cdc->usbd, buffsize, &cdc->tx_buf[buffptr]) == USBD_OK) {
+ if (USBD_CDC_TransmitPacket(&cdc->base, buffsize, &cdc->tx_buf[buffptr]) == USBD_OK) {
cdc->tx_buf_ptr_out_shadow += buffsize;
if (cdc->tx_buf_ptr_out_shadow == USBD_CDC_TX_DATA_SIZE) {
cdc->tx_buf_ptr_out_shadow = 0;
@@ -198,18 +203,28 @@ void HAL_PCD_SOFCallback(PCD_HandleTypeDef *hpcd) {
// the host waits for all data to arrive (ie, waits for a packet < max packet size).
// To flush a packet of exactly max packet size, we need to send a zero-size packet.
// See eg http://www.cypress.com/?id=4&rID=92719
- cdc->tx_need_empty_packet = (buffsize > 0 && buffsize % CDC_DATA_FS_MAX_PACKET_SIZE == 0 && cdc->tx_buf_ptr_out_shadow == cdc->tx_buf_ptr_in);
+ cdc->tx_need_empty_packet = (buffsize > 0 && buffsize % usbd_cdc_max_packet(cdc->base.usbd->pdev) == 0 && cdc->tx_buf_ptr_out_shadow == cdc->tx_buf_ptr_in);
}
}
}
+void HAL_PCD_SOFCallback(PCD_HandleTypeDef *hpcd) {
+ usbd_cdc_msc_hid_state_t *usbd = ((USBD_HandleTypeDef*)hpcd->pData)->pClassData;
+ usbd_cdc_sof(hpcd, (usbd_cdc_itf_t*)usbd->cdc);
+ #if MICROPY_HW_USB_ENABLE_CDC2
+ usbd_cdc_sof(hpcd, (usbd_cdc_itf_t*)usbd->cdc2);
+ #endif
+}
+
// Data received over USB OUT endpoint is processed here.
// len: number of bytes received into the buffer we passed to USBD_CDC_ReceivePacket
// Returns USBD_OK if all operations are OK else USBD_FAIL
-int8_t usbd_cdc_receive(usbd_cdc_itf_t *cdc, size_t len) {
+int8_t usbd_cdc_receive(usbd_cdc_state_t *cdc_in, size_t len) {
+ usbd_cdc_itf_t *cdc = (usbd_cdc_itf_t*)cdc_in;
+
// copy the incoming data into the circular buffer
for (const uint8_t *src = cdc->rx_packet_buf, *top = cdc->rx_packet_buf + len; src < top; ++src) {
- if (mp_interrupt_char != -1 && *src == mp_interrupt_char) {
+ if (cdc->attached_to_repl && mp_interrupt_char != -1 && *src == mp_interrupt_char) {
pendsv_kbd_intr();
} else {
uint16_t next_put = (cdc->rx_buf_put + 1) & (USBD_CDC_RX_DATA_SIZE - 1);
@@ -223,7 +238,7 @@ int8_t usbd_cdc_receive(usbd_cdc_itf_t *cdc, size_t len) {
}
// initiate next USB packet transfer
- USBD_CDC_ReceivePacket(cdc->usbd, cdc->rx_packet_buf);
+ USBD_CDC_ReceivePacket(&cdc->base, cdc->rx_packet_buf);
return USBD_OK;
}
@@ -347,3 +362,5 @@ int usbd_cdc_rx(usbd_cdc_itf_t *cdc, uint8_t *buf, uint32_t len, uint32_t timeou
// Success, return number of bytes read
return len;
}
+
+#endif
diff --git a/ports/stm32/usbd_cdc_interface.h b/ports/stm32/usbd_cdc_interface.h
index 98b8fc077..cdf556d4e 100644
--- a/ports/stm32/usbd_cdc_interface.h
+++ b/ports/stm32/usbd_cdc_interface.h
@@ -1,8 +1,8 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*/
-#ifndef MICROPY_INCLUDED_STMHAL_USBD_CDC_INTERFACE_H
-#define MICROPY_INCLUDED_STMHAL_USBD_CDC_INTERFACE_H
+#ifndef MICROPY_INCLUDED_STM32_USBD_CDC_INTERFACE_H
+#define MICROPY_INCLUDED_STM32_USBD_CDC_INTERFACE_H
/**
******************************************************************************
@@ -35,9 +35,9 @@
#define USBD_CDC_TX_DATA_SIZE (1024) // I think this can be any value (was 2048)
typedef struct _usbd_cdc_itf_t {
- usbd_cdc_msc_hid_state_t *usbd; // the parent USB device
+ usbd_cdc_state_t base; // state for the base CDC layer
- uint8_t rx_packet_buf[CDC_DATA_FS_MAX_PACKET_SIZE]; // received data from USB OUT endpoint is stored in this buffer
+ uint8_t rx_packet_buf[CDC_DATA_MAX_PACKET_SIZE]; // received data from USB OUT endpoint is stored in this buffer
uint8_t rx_user_buf[USBD_CDC_RX_DATA_SIZE]; // received data is buffered here until the user reads it
volatile uint16_t rx_buf_put; // circular buffer index
uint16_t rx_buf_get; // circular buffer index
@@ -50,8 +50,12 @@ typedef struct _usbd_cdc_itf_t {
uint8_t tx_need_empty_packet; // used to flush the USB IN endpoint if the last packet was exactly the endpoint packet size
volatile uint8_t dev_is_connected; // indicates if we are connected
+ uint8_t attached_to_repl; // indicates if interface is connected to REPL
} usbd_cdc_itf_t;
+// This is implemented in usb.c
+usbd_cdc_itf_t *usb_vcp_get(int idx);
+
static inline int usbd_cdc_is_connected(usbd_cdc_itf_t *cdc) {
return cdc->dev_is_connected;
}
@@ -63,4 +67,4 @@ void usbd_cdc_tx_always(usbd_cdc_itf_t *cdc, const uint8_t *buf, uint32_t len);
int usbd_cdc_rx_num(usbd_cdc_itf_t *cdc);
int usbd_cdc_rx(usbd_cdc_itf_t *cdc, uint8_t *buf, uint32_t len, uint32_t timeout);
-#endif // MICROPY_INCLUDED_STMHAL_USBD_CDC_INTERFACE_H
+#endif // MICROPY_INCLUDED_STM32_USBD_CDC_INTERFACE_H
diff --git a/ports/stm32/usbd_conf.c b/ports/stm32/usbd_conf.c
index d39144851..41a835304 100644
--- a/ports/stm32/usbd_conf.c
+++ b/ports/stm32/usbd_conf.c
@@ -1,689 +1,670 @@
-/*
- * This file is part of the MicroPython project, http://micropython.org/
- */
-
-/**
- ******************************************************************************
- * @file USB_Device/CDC_Standalone/Src/usbd_conf.c
- * @author MCD Application Team
- * @version V1.0.1
- * @date 26-February-2014
- * @brief This file implements the USB Device library callbacks and MSP
- ******************************************************************************
- * @attention
- *
- * <h2><center>&copy; COPYRIGHT(c) 2014 STMicroelectronics</center></h2>
- *
- * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
- * You may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.st.com/software_license_agreement_liberty_v2
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- ******************************************************************************
- */
-
-/* Includes ------------------------------------------------------------------*/
-#include "usbd_core.h"
-#include "py/obj.h"
-#include "irq.h"
-#include "usb.h"
-
-/* Private typedef -----------------------------------------------------------*/
-/* Private define ------------------------------------------------------------*/
-/* Private macro -------------------------------------------------------------*/
-/* Private variables ---------------------------------------------------------*/
-#ifdef USE_USB_FS
-PCD_HandleTypeDef pcd_fs_handle;
-#endif
-#ifdef USE_USB_HS
-PCD_HandleTypeDef pcd_hs_handle;
-#endif
-/* Private function prototypes -----------------------------------------------*/
-/* Private functions ---------------------------------------------------------*/
-
-/*******************************************************************************
- PCD BSP Routines
-*******************************************************************************/
-/**
- * @brief Initializes the PCD MSP.
- * @param hpcd: PCD handle
- * @retval None
- */
-void HAL_PCD_MspInit(PCD_HandleTypeDef *hpcd)
-{
- GPIO_InitTypeDef GPIO_InitStruct;
-
- if(hpcd->Instance == USB_OTG_FS)
- {
- /* Configure USB FS GPIOs */
- __GPIOA_CLK_ENABLE();
-
- GPIO_InitStruct.Pin = (GPIO_PIN_11 | GPIO_PIN_12);
- GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
- GPIO_InitStruct.Pull = GPIO_NOPULL;
- GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
- GPIO_InitStruct.Alternate = GPIO_AF10_OTG_FS;
- HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
-
- /* Configure VBUS Pin */
-#if defined(MICROPY_HW_USB_VBUS_DETECT_PIN)
- // USB VBUS detect pin is always A9
- GPIO_InitStruct.Pin = GPIO_PIN_9;
- GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
- GPIO_InitStruct.Pull = GPIO_NOPULL;
- HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
-#endif
-
-#if defined(MICROPY_HW_USB_OTG_ID_PIN)
- // USB ID pin is always A10
- GPIO_InitStruct.Pin = GPIO_PIN_10;
- GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
- GPIO_InitStruct.Pull = GPIO_PULLUP;
- GPIO_InitStruct.Alternate = GPIO_AF10_OTG_FS;
- HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
-#endif
-
- /* Enable USB FS Clocks */
- __USB_OTG_FS_CLK_ENABLE();
-
-#if defined (MCU_SERIES_L4)
- /* Enable VDDUSB */
- if(__HAL_RCC_PWR_IS_CLK_DISABLED())
- {
- __HAL_RCC_PWR_CLK_ENABLE();
- HAL_PWREx_EnableVddUSB();
- __HAL_RCC_PWR_CLK_DISABLE();
- }
- else
- {
- HAL_PWREx_EnableVddUSB();
- }
-#endif
-
- /* Set USBFS Interrupt priority */
- HAL_NVIC_SetPriority(OTG_FS_IRQn, IRQ_PRI_OTG_FS, IRQ_SUBPRI_OTG_FS);
-
- /* Enable USBFS Interrupt */
- HAL_NVIC_EnableIRQ(OTG_FS_IRQn);
- }
-#if defined(USE_USB_HS)
- else if(hpcd->Instance == USB_OTG_HS)
- {
-#if defined(USE_USB_HS_IN_FS)
-
- /* Configure USB FS GPIOs */
- __GPIOB_CLK_ENABLE();
-
- /* Configure DM DP Pins */
- GPIO_InitStruct.Pin = (GPIO_PIN_14 | GPIO_PIN_15);
- GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
- GPIO_InitStruct.Pull = GPIO_NOPULL;
- GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
- GPIO_InitStruct.Alternate = GPIO_AF12_OTG_HS_FS;
- HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
-
-#if defined(MICROPY_HW_USB_VBUS_DETECT_PIN)
- /* Configure VBUS Pin */
- GPIO_InitStruct.Pin = GPIO_PIN_13;
- GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
- GPIO_InitStruct.Pull = GPIO_NOPULL;
- GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
- GPIO_InitStruct.Alternate = GPIO_AF12_OTG_HS_FS;
- HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
-#endif
-
-#if defined(MICROPY_HW_USB_OTG_ID_PIN)
- /* Configure ID pin */
- GPIO_InitStruct.Pin = GPIO_PIN_12;
- GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
- GPIO_InitStruct.Pull = GPIO_PULLUP;
- GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
- GPIO_InitStruct.Alternate = GPIO_AF12_OTG_HS_FS;
- HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
-#endif
- /*
- * Enable calling WFI and correct
- * function of the embedded USB_FS_IN_HS phy
- */
- __OTGHSULPI_CLK_SLEEP_DISABLE();
- __OTGHS_CLK_SLEEP_ENABLE();
- /* Enable USB HS Clocks */
- __USB_OTG_HS_CLK_ENABLE();
-
-#else // !USE_USB_HS_IN_FS
-
- /* Configure USB HS GPIOs */
- __GPIOA_CLK_ENABLE();
- __GPIOB_CLK_ENABLE();
- __GPIOC_CLK_ENABLE();
- __GPIOH_CLK_ENABLE();
- __GPIOI_CLK_ENABLE();
-
- /* CLK */
- GPIO_InitStruct.Pin = GPIO_PIN_5;
- GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
- GPIO_InitStruct.Pull = GPIO_NOPULL;
- GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
- GPIO_InitStruct.Alternate = GPIO_AF10_OTG_HS;
- HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
-
- /* D0 */
- GPIO_InitStruct.Pin = GPIO_PIN_3;
- GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
- GPIO_InitStruct.Pull = GPIO_NOPULL;
- GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
- GPIO_InitStruct.Alternate = GPIO_AF10_OTG_HS;
- HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
-
- /* D1 D2 D3 D4 D5 D6 D7 */
- GPIO_InitStruct.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_5 |\
- GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12 | GPIO_PIN_13;
- GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
- GPIO_InitStruct.Pull = GPIO_NOPULL;
- GPIO_InitStruct.Alternate = GPIO_AF10_OTG_HS;
- HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
-
- /* STP */
- GPIO_InitStruct.Pin = GPIO_PIN_0;
- GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
- GPIO_InitStruct.Pull = GPIO_NOPULL;
- GPIO_InitStruct.Alternate = GPIO_AF10_OTG_HS;
- HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
-
- /* NXT */
- GPIO_InitStruct.Pin = GPIO_PIN_4;
- GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
- GPIO_InitStruct.Pull = GPIO_NOPULL;
- GPIO_InitStruct.Alternate = GPIO_AF10_OTG_HS;
- HAL_GPIO_Init(GPIOH, &GPIO_InitStruct);
-
- /* DIR */
- GPIO_InitStruct.Pin = GPIO_PIN_11;
- GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
- GPIO_InitStruct.Pull = GPIO_NOPULL;
- GPIO_InitStruct.Alternate = GPIO_AF10_OTG_HS;
- HAL_GPIO_Init(GPIOI, &GPIO_InitStruct);
-
- /* Enable USB HS Clocks */
- __USB_OTG_HS_CLK_ENABLE();
- __USB_OTG_HS_ULPI_CLK_ENABLE();
-#endif // !USE_USB_HS_IN_FS
-
- /* Set USBHS Interrupt to the lowest priority */
- HAL_NVIC_SetPriority(OTG_HS_IRQn, IRQ_PRI_OTG_HS, IRQ_SUBPRI_OTG_HS);
-
- /* Enable USBHS Interrupt */
- HAL_NVIC_EnableIRQ(OTG_HS_IRQn);
- }
-#endif // USE_USB_HS
-}
-/**
- * @brief DeInitializes the PCD MSP.
- * @param hpcd: PCD handle
- * @retval None
- */
-void HAL_PCD_MspDeInit(PCD_HandleTypeDef *hpcd)
-{
- if(hpcd->Instance == USB_OTG_FS)
- {
- /* Disable USB FS Clocks */
- __USB_OTG_FS_CLK_DISABLE();
- __SYSCFG_CLK_DISABLE();
- }
- #if defined(USE_USB_HS)
- else if(hpcd->Instance == USB_OTG_HS)
- {
- /* Disable USB FS Clocks */
- __USB_OTG_HS_CLK_DISABLE();
- __SYSCFG_CLK_DISABLE();
- }
- #endif
-}
-
-/*******************************************************************************
- LL Driver Callbacks (PCD -> USB Device Library)
-*******************************************************************************/
-
-
-/**
- * @brief Setup stage callback.
- * @param hpcd: PCD handle
- * @retval None
- */
-void HAL_PCD_SetupStageCallback(PCD_HandleTypeDef *hpcd)
-{
- USBD_LL_SetupStage(hpcd->pData, (uint8_t *)hpcd->Setup);
-}
-
-/**
- * @brief Data Out stage callback.
- * @param hpcd: PCD handle
- * @param epnum: Endpoint Number
- * @retval None
- */
-void HAL_PCD_DataOutStageCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum)
-{
- USBD_LL_DataOutStage(hpcd->pData, epnum, hpcd->OUT_ep[epnum].xfer_buff);
-}
-
-/**
- * @brief Data In stage callback.
- * @param hpcd: PCD handle
- * @param epnum: Endpoint Number
- * @retval None
- */
-void HAL_PCD_DataInStageCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum)
-{
- USBD_LL_DataInStage(hpcd->pData, epnum, hpcd->IN_ep[epnum].xfer_buff);
-}
-
-/**
- * @brief SOF callback.
- * @param hpcd: PCD handle
- * @retval None
- */
-/*
-This is now handled by the USB CDC interface.
-void HAL_PCD_SOFCallback(PCD_HandleTypeDef *hpcd)
-{
- USBD_LL_SOF(hpcd->pData);
-}
-*/
-
-/**
- * @brief Reset callback.
- * @param hpcd: PCD handle
- * @retval None
- */
-void HAL_PCD_ResetCallback(PCD_HandleTypeDef *hpcd)
-{
- USBD_SpeedTypeDef speed = USBD_SPEED_FULL;
-
- /* Set USB Current Speed */
- switch(hpcd->Init.speed)
- {
-#if defined(PCD_SPEED_HIGH)
- case PCD_SPEED_HIGH:
- speed = USBD_SPEED_HIGH;
- break;
-#endif
-
- case PCD_SPEED_FULL:
- speed = USBD_SPEED_FULL;
- break;
-
- default:
- speed = USBD_SPEED_FULL;
- break;
- }
- USBD_LL_SetSpeed(hpcd->pData, speed);
-
- /* Reset Device */
- USBD_LL_Reset(hpcd->pData);
-}
-
-/**
- * @brief Suspend callback.
- * @param hpcd: PCD handle
- * @retval None
- */
-void HAL_PCD_SuspendCallback(PCD_HandleTypeDef *hpcd)
-{
- USBD_LL_Suspend(hpcd->pData);
-}
-
-/**
- * @brief Resume callback.
- * @param hpcd: PCD handle
- * @retval None
- */
-void HAL_PCD_ResumeCallback(PCD_HandleTypeDef *hpcd)
-{
- USBD_LL_Resume(hpcd->pData);
-}
-
-/**
- * @brief ISOC Out Incomplete callback.
- * @param hpcd: PCD handle
- * @param epnum: Endpoint Number
- * @retval None
- */
-void HAL_PCD_ISOOUTIncompleteCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum)
-{
- USBD_LL_IsoOUTIncomplete(hpcd->pData, epnum);
-}
-
-/**
- * @brief ISOC In Incomplete callback.
- * @param hpcd: PCD handle
- * @param epnum: Endpoint Number
- * @retval None
- */
-void HAL_PCD_ISOINIncompleteCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum)
-{
- USBD_LL_IsoINIncomplete(hpcd->pData, epnum);
-}
-
-/**
- * @brief Connect callback.
- * @param hpcd: PCD handle
- * @retval None
- */
-void HAL_PCD_ConnectCallback(PCD_HandleTypeDef *hpcd)
-{
- USBD_LL_DevConnected(hpcd->pData);
-}
-
-/**
- * @brief Disconnect callback.
- * @param hpcd: PCD handle
- * @retval None
- */
-void HAL_PCD_DisconnectCallback(PCD_HandleTypeDef *hpcd)
-{
- USBD_LL_DevDisconnected(hpcd->pData);
-}
-
-/*******************************************************************************
- LL Driver Interface (USB Device Library --> PCD)
-*******************************************************************************/
-/**
- * @brief Initializes the Low Level portion of the Device driver.
- * @param pdev: Device handle
- * @retval USBD Status
- */
-USBD_StatusTypeDef USBD_LL_Init (USBD_HandleTypeDef *pdev)
-{
-#if defined(USE_USB_FS)
-if (pdev->id == USB_PHY_FS_ID)
-{
- /*Set LL Driver parameters */
- pcd_fs_handle.Instance = USB_OTG_FS;
- pcd_fs_handle.Init.dev_endpoints = 4;
- pcd_fs_handle.Init.use_dedicated_ep1 = 0;
- pcd_fs_handle.Init.ep0_mps = 0x40;
- pcd_fs_handle.Init.dma_enable = 0;
- pcd_fs_handle.Init.low_power_enable = 0;
- pcd_fs_handle.Init.phy_itface = PCD_PHY_EMBEDDED;
- pcd_fs_handle.Init.Sof_enable = 1;
- pcd_fs_handle.Init.speed = PCD_SPEED_FULL;
-#if defined(MCU_SERIES_L4)
- pcd_fs_handle.Init.lpm_enable = DISABLE;
- pcd_fs_handle.Init.battery_charging_enable = DISABLE;
-#endif
-#if !defined(MICROPY_HW_USB_VBUS_DETECT_PIN)
- pcd_fs_handle.Init.vbus_sensing_enable = 0; // No VBUS Sensing on USB0
-#else
- pcd_fs_handle.Init.vbus_sensing_enable = 1;
-#endif
- /* Link The driver to the stack */
- pcd_fs_handle.pData = pdev;
- pdev->pData = &pcd_fs_handle;
- /*Initialize LL Driver */
- HAL_PCD_Init(&pcd_fs_handle);
-
- HAL_PCD_SetRxFiFo(&pcd_fs_handle, 0x80);
- HAL_PCD_SetTxFiFo(&pcd_fs_handle, 0, 0x20);
- HAL_PCD_SetTxFiFo(&pcd_fs_handle, 1, 0x40);
- HAL_PCD_SetTxFiFo(&pcd_fs_handle, 2, 0x20);
- HAL_PCD_SetTxFiFo(&pcd_fs_handle, 3, 0x40);
-}
-#endif
-#if defined(USE_USB_HS)
-if (pdev->id == USB_PHY_HS_ID)
-{
-#if defined(USE_USB_HS_IN_FS)
- /*Set LL Driver parameters */
- pcd_hs_handle.Instance = USB_OTG_HS;
- pcd_hs_handle.Init.dev_endpoints = 4;
- pcd_hs_handle.Init.use_dedicated_ep1 = 0;
- pcd_hs_handle.Init.ep0_mps = 0x40;
- pcd_hs_handle.Init.dma_enable = 0;
- pcd_hs_handle.Init.low_power_enable = 0;
- pcd_hs_handle.Init.phy_itface = PCD_PHY_EMBEDDED;
- pcd_hs_handle.Init.Sof_enable = 1;
- pcd_hs_handle.Init.speed = PCD_SPEED_HIGH_IN_FULL;
-#if !defined(MICROPY_HW_USB_VBUS_DETECT_PIN)
- pcd_hs_handle.Init.vbus_sensing_enable = 0; // No VBUS Sensing on USB0
-#else
- pcd_hs_handle.Init.vbus_sensing_enable = 1;
-#endif
- /* Link The driver to the stack */
- pcd_hs_handle.pData = pdev;
- pdev->pData = &pcd_hs_handle;
- /*Initialize LL Driver */
- HAL_PCD_Init(&pcd_hs_handle);
-
- HAL_PCD_SetRxFiFo(&pcd_hs_handle, 0x80);
- HAL_PCD_SetTxFiFo(&pcd_hs_handle, 0, 0x20);
- HAL_PCD_SetTxFiFo(&pcd_hs_handle, 1, 0x40);
- HAL_PCD_SetTxFiFo(&pcd_hs_handle, 2, 0x20);
- HAL_PCD_SetTxFiFo(&pcd_hs_handle, 3, 0x40);
-#else // !defined(USE_USB_HS_IN_FS)
- /*Set LL Driver parameters */
- pcd_hs_handle.Instance = USB_OTG_HS;
- pcd_hs_handle.Init.dev_endpoints = 6;
- pcd_hs_handle.Init.use_dedicated_ep1 = 0;
- pcd_hs_handle.Init.ep0_mps = 0x40;
-
- /* Be aware that enabling USB-DMA mode will result in data being sent only by
- multiple of 4 packet sizes. This is due to the fact that USB-DMA does
- not allow sending data from non word-aligned addresses.
- For this specific application, it is advised to not enable this option
- unless required. */
- pcd_hs_handle.Init.dma_enable = 0;
-
- pcd_hs_handle.Init.low_power_enable = 0;
- pcd_hs_handle.Init.phy_itface = PCD_PHY_ULPI;
- pcd_hs_handle.Init.Sof_enable = 1;
- pcd_hs_handle.Init.speed = PCD_SPEED_HIGH;
- pcd_hs_handle.Init.vbus_sensing_enable = 1;
- /* Link The driver to the stack */
- pcd_hs_handle.pData = pdev;
- pdev->pData = &pcd_hs_handle;
- /*Initialize LL Driver */
- HAL_PCD_Init(&pcd_hs_handle);
-
- HAL_PCD_SetRxFiFo(&pcd_hs_handle, 0x200);
- HAL_PCD_SetTxFiFo(&pcd_hs_handle, 0, 0x80);
- HAL_PCD_SetTxFiFo(&pcd_hs_handle, 1, 0x174);
-
-#endif // !USE_USB_HS_IN_FS
-}
-#endif // USE_USB_HS
- return USBD_OK;
-}
-
-/**
- * @brief De-Initializes the Low Level portion of the Device driver.
- * @param pdev: Device handle
- * @retval USBD Status
- */
-USBD_StatusTypeDef USBD_LL_DeInit(USBD_HandleTypeDef *pdev)
-{
- HAL_PCD_DeInit(pdev->pData);
- return USBD_OK;
-}
-
-/**
- * @brief Starts the Low Level portion of the Device driver.
- * @param pdev: Device handle
- * @retval USBD Status
- */
-USBD_StatusTypeDef USBD_LL_Start(USBD_HandleTypeDef *pdev)
-{
- HAL_PCD_Start(pdev->pData);
- return USBD_OK;
-}
-
-/**
- * @brief Stops the Low Level portion of the Device driver.
- * @param pdev: Device handle
- * @retval USBD Status
- */
-USBD_StatusTypeDef USBD_LL_Stop(USBD_HandleTypeDef *pdev)
-{
- HAL_PCD_Stop(pdev->pData);
- return USBD_OK;
-}
-
-/**
- * @brief Opens an endpoint of the Low Level Driver.
- * @param pdev: Device handle
- * @param ep_addr: Endpoint Number
- * @param ep_type: Endpoint Type
- * @param ep_mps: Endpoint Max Packet Size
- * @retval USBD Status
- */
-USBD_StatusTypeDef USBD_LL_OpenEP(USBD_HandleTypeDef *pdev,
- uint8_t ep_addr,
- uint8_t ep_type,
- uint16_t ep_mps)
-{
- HAL_PCD_EP_Open(pdev->pData, ep_addr, ep_mps, ep_type);
- return USBD_OK;
-}
-
-/**
- * @brief Closes an endpoint of the Low Level Driver.
- * @param pdev: Device handle
- * @param ep_addr: Endpoint Number
- * @retval USBD Status
- */
-USBD_StatusTypeDef USBD_LL_CloseEP(USBD_HandleTypeDef *pdev, uint8_t ep_addr)
-{
- HAL_PCD_EP_Close(pdev->pData, ep_addr);
- return USBD_OK;
-}
-
-/**
- * @brief Flushes an endpoint of the Low Level Driver.
- * @param pdev: Device handle
- * @param ep_addr: Endpoint Number
- * @retval USBD Status
- */
-USBD_StatusTypeDef USBD_LL_FlushEP(USBD_HandleTypeDef *pdev, uint8_t ep_addr)
-{
- HAL_PCD_EP_Flush(pdev->pData, ep_addr);
- return USBD_OK;
-}
-
-/**
- * @brief Sets a Stall condition on an endpoint of the Low Level Driver.
- * @param pdev: Device handle
- * @param ep_addr: Endpoint Number
- * @retval USBD Status
- */
-USBD_StatusTypeDef USBD_LL_StallEP(USBD_HandleTypeDef *pdev, uint8_t ep_addr)
-{
- HAL_PCD_EP_SetStall(pdev->pData, ep_addr);
- return USBD_OK;
-}
-
-/**
- * @brief Clears a Stall condition on an endpoint of the Low Level Driver.
- * @param pdev: Device handle
- * @param ep_addr: Endpoint Number
- * @retval USBD Status
- */
-USBD_StatusTypeDef USBD_LL_ClearStallEP(USBD_HandleTypeDef *pdev, uint8_t ep_addr)
-{
- HAL_PCD_EP_ClrStall(pdev->pData, ep_addr);
- return USBD_OK;
-}
-
-/**
- * @brief Returns Stall condition.
- * @param pdev: Device handle
- * @param ep_addr: Endpoint Number
- * @retval Stall (1: yes, 0: No)
- */
-uint8_t USBD_LL_IsStallEP(USBD_HandleTypeDef *pdev, uint8_t ep_addr)
-{
- PCD_HandleTypeDef *hpcd = pdev->pData;
-
- if((ep_addr & 0x80) == 0x80)
- {
- return hpcd->IN_ep[ep_addr & 0x7F].is_stall;
- }
- else
- {
- return hpcd->OUT_ep[ep_addr & 0x7F].is_stall;
- }
-}
-
-/**
- * @brief Assigns an USB address to the device
- * @param pdev: Device handle
- * @param dev_addr: USB address
- * @retval USBD Status
- */
-USBD_StatusTypeDef USBD_LL_SetUSBAddress(USBD_HandleTypeDef *pdev, uint8_t dev_addr)
-{
- HAL_PCD_SetAddress(pdev->pData, dev_addr);
- return USBD_OK;
-}
-
-/**
- * @brief Transmits data over an endpoint
- * @param pdev: Device handle
- * @param ep_addr: Endpoint Number
- * @param pbuf: Pointer to data to be sent
- * @param size: Data size
- * @retval USBD Status
- */
-USBD_StatusTypeDef USBD_LL_Transmit(USBD_HandleTypeDef *pdev,
- uint8_t ep_addr,
- uint8_t *pbuf,
- uint16_t size)
-{
- HAL_PCD_EP_Transmit(pdev->pData, ep_addr, pbuf, size);
- return USBD_OK;
-}
-
-/**
- * @brief Prepares an endpoint for reception
- * @param pdev: Device handle
- * @param ep_addr: Endpoint Number
- * @param pbuf:pointer to data to be received
- * @param size: data size
- * @retval USBD Status
- */
-USBD_StatusTypeDef USBD_LL_PrepareReceive(USBD_HandleTypeDef *pdev,
- uint8_t ep_addr,
- uint8_t *pbuf,
- uint16_t size)
-{
- HAL_PCD_EP_Receive(pdev->pData, ep_addr, pbuf, size);
- return USBD_OK;
-}
-
-/**
- * @brief Returns the last transfered packet size.
- * @param pdev: Device handle
- * @param ep_addr: Endpoint Number
- * @retval Recived Data Size
- */
-uint32_t USBD_LL_GetRxDataSize(USBD_HandleTypeDef *pdev, uint8_t ep_addr)
-{
- return HAL_PCD_EP_GetRxCount(pdev->pData, ep_addr);
-}
-
-/**
- * @brief Delay routine for the USB Device Library
- * @param Delay: Delay in ms
- * @retval None
- */
-void USBD_LL_Delay(uint32_t Delay)
-{
- HAL_Delay(Delay);
-}
-
-/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ */
+
+/**
+ ******************************************************************************
+ * @file USB_Device/CDC_Standalone/Src/usbd_conf.c
+ * @author MCD Application Team
+ * @version V1.0.1
+ * @date 26-February-2014
+ * @brief This file implements the USB Device library callbacks and MSP
+ ******************************************************************************
+ * @attention
+ *
+ * <h2><center>&copy; COPYRIGHT(c) 2014 STMicroelectronics</center></h2>
+ *
+ * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
+ * You may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.st.com/software_license_agreement_liberty_v2
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************
+ */
+
+#include "usbd_core.h"
+#include "py/obj.h"
+#include "py/mphal.h"
+#include "irq.h"
+#include "usb.h"
+
+#if MICROPY_HW_USB_FS || MICROPY_HW_USB_HS
+
+#if MICROPY_HW_USB_FS
+PCD_HandleTypeDef pcd_fs_handle;
+#endif
+#if MICROPY_HW_USB_HS
+PCD_HandleTypeDef pcd_hs_handle;
+#endif
+
+/*******************************************************************************
+ PCD BSP Routines
+*******************************************************************************/
+
+/**
+ * @brief Initializes the PCD MSP.
+ * @param hpcd: PCD handle
+ * @retval None
+ */
+void HAL_PCD_MspInit(PCD_HandleTypeDef *hpcd) {
+ if (hpcd->Instance == USB_OTG_FS) {
+ #if defined(STM32H7)
+ const uint32_t otg_alt = GPIO_AF10_OTG1_FS;
+ #else
+ const uint32_t otg_alt = GPIO_AF10_OTG_FS;
+ #endif
+
+ mp_hal_pin_config(pin_A11, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, otg_alt);
+ mp_hal_pin_config_speed(pin_A11, GPIO_SPEED_FREQ_VERY_HIGH);
+ mp_hal_pin_config(pin_A12, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, otg_alt);
+ mp_hal_pin_config_speed(pin_A12, GPIO_SPEED_FREQ_VERY_HIGH);
+
+ #if defined(MICROPY_HW_USB_VBUS_DETECT_PIN)
+ // USB VBUS detect pin is always A9
+ mp_hal_pin_config(MICROPY_HW_USB_VBUS_DETECT_PIN, MP_HAL_PIN_MODE_INPUT, MP_HAL_PIN_PULL_NONE, 0);
+ #endif
+
+ #if defined(MICROPY_HW_USB_OTG_ID_PIN)
+ // USB ID pin is always A10
+ mp_hal_pin_config(MICROPY_HW_USB_OTG_ID_PIN, MP_HAL_PIN_MODE_ALT_OPEN_DRAIN, MP_HAL_PIN_PULL_UP, otg_alt);
+ #endif
+
+ #if defined(STM32H7)
+ // Keep USB clock running during sleep or else __WFI() will disable the USB
+ __HAL_RCC_USB2_OTG_FS_CLK_SLEEP_ENABLE();
+ __HAL_RCC_USB2_OTG_FS_ULPI_CLK_SLEEP_DISABLE();
+ #endif
+
+ // Enable USB FS Clocks
+ __USB_OTG_FS_CLK_ENABLE();
+
+ #if defined(STM32L4)
+ // Enable VDDUSB
+ if (__HAL_RCC_PWR_IS_CLK_DISABLED()) {
+ __HAL_RCC_PWR_CLK_ENABLE();
+ HAL_PWREx_EnableVddUSB();
+ __HAL_RCC_PWR_CLK_DISABLE();
+ } else {
+ HAL_PWREx_EnableVddUSB();
+ }
+ #endif
+
+ // Configure and enable USB FS interrupt
+ NVIC_SetPriority(OTG_FS_IRQn, IRQ_PRI_OTG_FS);
+ HAL_NVIC_EnableIRQ(OTG_FS_IRQn);
+ }
+ #if MICROPY_HW_USB_HS
+ else if (hpcd->Instance == USB_OTG_HS) {
+ #if MICROPY_HW_USB_HS_IN_FS
+
+ // Configure USB FS GPIOs
+ mp_hal_pin_config(pin_B14, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, GPIO_AF12_OTG_HS_FS);
+ mp_hal_pin_config_speed(pin_B14, GPIO_SPEED_FREQ_VERY_HIGH);
+ mp_hal_pin_config(pin_B15, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, GPIO_AF12_OTG_HS_FS);
+ mp_hal_pin_config_speed(pin_B15, GPIO_SPEED_FREQ_VERY_HIGH);
+
+ #if defined(MICROPY_HW_USB_VBUS_DETECT_PIN)
+ // Configure VBUS Pin
+ mp_hal_pin_config(MICROPY_HW_USB_VBUS_DETECT_PIN, MP_HAL_PIN_MODE_INPUT, MP_HAL_PIN_PULL_NONE, 0);
+ #endif
+
+ #if defined(MICROPY_HW_USB_OTG_ID_PIN)
+ // Configure ID pin
+ mp_hal_pin_config(MICROPY_HW_USB_OTG_ID_PIN, MP_HAL_PIN_MODE_ALT_OPEN_DRAIN, MP_HAL_PIN_PULL_UP, GPIO_AF12_OTG_HS_FS);
+ #endif
+
+ // Enable calling WFI and correct function of the embedded USB_FS_IN_HS phy
+ __HAL_RCC_USB_OTG_HS_ULPI_CLK_SLEEP_DISABLE();
+ __HAL_RCC_USB_OTG_HS_CLK_SLEEP_ENABLE();
+
+ // Enable USB HS Clocks
+
+ #if defined(STM32F723xx) || defined(STM32F733xx)
+ // Needs to remain awake during sleep or else __WFI() will disable the USB
+ __HAL_RCC_USB_OTG_HS_ULPI_CLK_SLEEP_ENABLE();
+ __HAL_RCC_OTGPHYC_CLK_ENABLE();
+ __HAL_RCC_USB_OTG_HS_ULPI_CLK_ENABLE();
+ #endif
+
+ __HAL_RCC_USB_OTG_HS_CLK_ENABLE();
+
+ #else // !MICROPY_HW_USB_HS_IN_FS
+
+ GPIO_InitTypeDef GPIO_InitStruct;
+
+ // Configure USB HS GPIOs
+ __HAL_RCC_GPIOA_CLK_ENABLE();
+ __HAL_RCC_GPIOB_CLK_ENABLE();
+ __HAL_RCC_GPIOC_CLK_ENABLE();
+ __HAL_RCC_GPIOH_CLK_ENABLE();
+ __HAL_RCC_GPIOI_CLK_ENABLE();
+
+ // CLK
+ GPIO_InitStruct.Pin = GPIO_PIN_5;
+ GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
+ GPIO_InitStruct.Pull = GPIO_NOPULL;
+ GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
+ GPIO_InitStruct.Alternate = GPIO_AF10_OTG_HS;
+ HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
+
+ // D0
+ GPIO_InitStruct.Pin = GPIO_PIN_3;
+ GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
+ GPIO_InitStruct.Pull = GPIO_NOPULL;
+ GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
+ GPIO_InitStruct.Alternate = GPIO_AF10_OTG_HS;
+ HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
+
+ // D1 D2 D3 D4 D5 D6 D7
+ GPIO_InitStruct.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_5 |\
+ GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12 | GPIO_PIN_13;
+ GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
+ GPIO_InitStruct.Pull = GPIO_NOPULL;
+ GPIO_InitStruct.Alternate = GPIO_AF10_OTG_HS;
+ HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
+
+ // STP
+ GPIO_InitStruct.Pin = GPIO_PIN_0;
+ GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
+ GPIO_InitStruct.Pull = GPIO_NOPULL;
+ GPIO_InitStruct.Alternate = GPIO_AF10_OTG_HS;
+ HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
+
+ // NXT
+ GPIO_InitStruct.Pin = GPIO_PIN_4;
+ GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
+ GPIO_InitStruct.Pull = GPIO_NOPULL;
+ GPIO_InitStruct.Alternate = GPIO_AF10_OTG_HS;
+ HAL_GPIO_Init(GPIOH, &GPIO_InitStruct);
+
+ // DIR
+ GPIO_InitStruct.Pin = GPIO_PIN_11;
+ GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
+ GPIO_InitStruct.Pull = GPIO_NOPULL;
+ GPIO_InitStruct.Alternate = GPIO_AF10_OTG_HS;
+ HAL_GPIO_Init(GPIOI, &GPIO_InitStruct);
+
+ // Enable USB HS Clocks
+ __USB_OTG_HS_CLK_ENABLE();
+ __USB_OTG_HS_ULPI_CLK_ENABLE();
+
+ #endif // !MICROPY_HW_USB_HS_IN_FS
+
+ // Configure and enable USB HS interrupt
+ NVIC_SetPriority(OTG_HS_IRQn, IRQ_PRI_OTG_HS);
+ HAL_NVIC_EnableIRQ(OTG_HS_IRQn);
+ }
+ #endif // MICROPY_HW_USB_HS
+}
+
+/**
+ * @brief DeInitializes the PCD MSP.
+ * @param hpcd: PCD handle
+ * @retval None
+ */
+void HAL_PCD_MspDeInit(PCD_HandleTypeDef *hpcd) {
+ if (hpcd->Instance == USB_OTG_FS) {
+ /* Disable USB FS Clocks */
+ __USB_OTG_FS_CLK_DISABLE();
+ __SYSCFG_CLK_DISABLE();
+ }
+ #if MICROPY_HW_USB_HS
+ else if (hpcd->Instance == USB_OTG_HS) {
+ /* Disable USB FS Clocks */
+ __USB_OTG_HS_CLK_DISABLE();
+ __SYSCFG_CLK_DISABLE();
+ }
+ #endif
+}
+
+/*******************************************************************************
+ LL Driver Callbacks (PCD -> USB Device Library)
+*******************************************************************************/
+
+/**
+ * @brief Setup stage callback.
+ * @param hpcd: PCD handle
+ * @retval None
+ */
+void HAL_PCD_SetupStageCallback(PCD_HandleTypeDef *hpcd) {
+ USBD_LL_SetupStage(hpcd->pData, (uint8_t *)hpcd->Setup);
+}
+
+/**
+ * @brief Data Out stage callback.
+ * @param hpcd: PCD handle
+ * @param epnum: Endpoint Number
+ * @retval None
+ */
+void HAL_PCD_DataOutStageCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum) {
+ USBD_LL_DataOutStage(hpcd->pData, epnum, hpcd->OUT_ep[epnum].xfer_buff);
+}
+
+/**
+ * @brief Data In stage callback.
+ * @param hpcd: PCD handle
+ * @param epnum: Endpoint Number
+ * @retval None
+ */
+void HAL_PCD_DataInStageCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum) {
+ USBD_LL_DataInStage(hpcd->pData, epnum, hpcd->IN_ep[epnum].xfer_buff);
+}
+
+/**
+ * @brief SOF callback.
+ * @param hpcd: PCD handle
+ * @retval None
+ */
+/*
+This is now handled by the USB CDC interface.
+void HAL_PCD_SOFCallback(PCD_HandleTypeDef *hpcd)
+{
+ USBD_LL_SOF(hpcd->pData);
+}
+*/
+
+/**
+ * @brief Reset callback.
+ * @param hpcd: PCD handle
+ * @retval None
+ */
+void HAL_PCD_ResetCallback(PCD_HandleTypeDef *hpcd) {
+ USBD_SpeedTypeDef speed = USBD_SPEED_FULL;
+
+ // Set USB Current Speed
+ switch (hpcd->Init.speed) {
+ #if defined(PCD_SPEED_HIGH)
+ case PCD_SPEED_HIGH:
+ speed = USBD_SPEED_HIGH;
+ break;
+ #endif
+
+ case PCD_SPEED_FULL:
+ speed = USBD_SPEED_FULL;
+ break;
+
+ default:
+ speed = USBD_SPEED_FULL;
+ break;
+ }
+ USBD_LL_SetSpeed(hpcd->pData, speed);
+
+ // Reset Device
+ USBD_LL_Reset(hpcd->pData);
+}
+
+/**
+ * @brief Suspend callback.
+ * @param hpcd: PCD handle
+ * @retval None
+ */
+void HAL_PCD_SuspendCallback(PCD_HandleTypeDef *hpcd) {
+ USBD_LL_Suspend(hpcd->pData);
+}
+
+/**
+ * @brief Resume callback.
+ * @param hpcd: PCD handle
+ * @retval None
+ */
+void HAL_PCD_ResumeCallback(PCD_HandleTypeDef *hpcd) {
+ USBD_LL_Resume(hpcd->pData);
+}
+
+/**
+ * @brief ISOC Out Incomplete callback.
+ * @param hpcd: PCD handle
+ * @param epnum: Endpoint Number
+ * @retval None
+ */
+void HAL_PCD_ISOOUTIncompleteCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum) {
+ USBD_LL_IsoOUTIncomplete(hpcd->pData, epnum);
+}
+
+/**
+ * @brief ISOC In Incomplete callback.
+ * @param hpcd: PCD handle
+ * @param epnum: Endpoint Number
+ * @retval None
+ */
+void HAL_PCD_ISOINIncompleteCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum) {
+ USBD_LL_IsoINIncomplete(hpcd->pData, epnum);
+}
+
+/**
+ * @brief Connect callback.
+ * @param hpcd: PCD handle
+ * @retval None
+ */
+void HAL_PCD_ConnectCallback(PCD_HandleTypeDef *hpcd) {
+ USBD_LL_DevConnected(hpcd->pData);
+}
+
+/**
+ * @brief Disconnect callback.
+ * @param hpcd: PCD handle
+ * @retval None
+ */
+void HAL_PCD_DisconnectCallback(PCD_HandleTypeDef *hpcd) {
+ USBD_LL_DevDisconnected(hpcd->pData);
+}
+
+/*******************************************************************************
+ LL Driver Interface (USB Device Library --> PCD)
+*******************************************************************************/
+
+/**
+ * @brief Initializes the Low Level portion of the Device driver.
+ * @param pdev: Device handle
+ * @retval USBD Status
+ */
+USBD_StatusTypeDef USBD_LL_Init(USBD_HandleTypeDef *pdev, int high_speed) {
+ #if MICROPY_HW_USB_FS
+ if (pdev->id == USB_PHY_FS_ID) {
+ // Set LL Driver parameters
+ pcd_fs_handle.Instance = USB_OTG_FS;
+ #if MICROPY_HW_USB_ENABLE_CDC2
+ pcd_fs_handle.Init.dev_endpoints = 6;
+ #else
+ pcd_fs_handle.Init.dev_endpoints = 4;
+ #endif
+ pcd_fs_handle.Init.use_dedicated_ep1 = 0;
+ pcd_fs_handle.Init.ep0_mps = 0x40;
+ pcd_fs_handle.Init.dma_enable = 0;
+ pcd_fs_handle.Init.low_power_enable = 0;
+ pcd_fs_handle.Init.phy_itface = PCD_PHY_EMBEDDED;
+ pcd_fs_handle.Init.Sof_enable = 1;
+ pcd_fs_handle.Init.speed = PCD_SPEED_FULL;
+ #if defined(STM32L4)
+ pcd_fs_handle.Init.lpm_enable = DISABLE;
+ pcd_fs_handle.Init.battery_charging_enable = DISABLE;
+ #endif
+ #if !defined(MICROPY_HW_USB_VBUS_DETECT_PIN)
+ pcd_fs_handle.Init.vbus_sensing_enable = 0; // No VBUS Sensing on USB0
+ #else
+ pcd_fs_handle.Init.vbus_sensing_enable = 1;
+ #endif
+
+ // Link The driver to the stack
+ pcd_fs_handle.pData = pdev;
+ pdev->pData = &pcd_fs_handle;
+
+ // Initialize LL Driver
+ HAL_PCD_Init(&pcd_fs_handle);
+
+ // We have 320 32-bit words in total to use here
+ #if MICROPY_HW_USB_ENABLE_CDC2
+ HAL_PCD_SetRxFiFo(&pcd_fs_handle, 128);
+ HAL_PCD_SetTxFiFo(&pcd_fs_handle, 0, 32); // EP0
+ HAL_PCD_SetTxFiFo(&pcd_fs_handle, 1, 64); // MSC / HID
+ HAL_PCD_SetTxFiFo(&pcd_fs_handle, 2, 16); // CDC CMD
+ HAL_PCD_SetTxFiFo(&pcd_fs_handle, 3, 32); // CDC DATA
+ HAL_PCD_SetTxFiFo(&pcd_fs_handle, 4, 16); // CDC2 CMD
+ HAL_PCD_SetTxFiFo(&pcd_fs_handle, 5, 32); // CDC2 DATA
+ #else
+ HAL_PCD_SetRxFiFo(&pcd_fs_handle, 128);
+ HAL_PCD_SetTxFiFo(&pcd_fs_handle, 0, 32); // EP0
+ HAL_PCD_SetTxFiFo(&pcd_fs_handle, 1, 64); // MSC / HID
+ HAL_PCD_SetTxFiFo(&pcd_fs_handle, 2, 32); // CDC CMD
+ HAL_PCD_SetTxFiFo(&pcd_fs_handle, 3, 64); // CDC DATA
+ #endif
+ }
+ #endif
+ #if MICROPY_HW_USB_HS
+ if (pdev->id == USB_PHY_HS_ID) {
+ #if MICROPY_HW_USB_HS_IN_FS
+
+ // Set LL Driver parameters
+ pcd_hs_handle.Instance = USB_OTG_HS;
+ pcd_hs_handle.Init.dev_endpoints = 6;
+ pcd_hs_handle.Init.use_dedicated_ep1 = 0;
+ pcd_hs_handle.Init.ep0_mps = 0x40;
+ pcd_hs_handle.Init.dma_enable = 0;
+ pcd_hs_handle.Init.low_power_enable = 0;
+ pcd_hs_handle.Init.lpm_enable = DISABLE;
+ pcd_hs_handle.Init.battery_charging_enable = DISABLE;
+ #if defined(STM32F723xx) || defined(STM32F733xx)
+ pcd_hs_handle.Init.phy_itface = USB_OTG_HS_EMBEDDED_PHY;
+ #else
+ pcd_hs_handle.Init.phy_itface = PCD_PHY_EMBEDDED;
+ #endif
+ pcd_hs_handle.Init.Sof_enable = 1;
+ if (high_speed) {
+ pcd_hs_handle.Init.speed = PCD_SPEED_HIGH;
+ } else {
+ pcd_hs_handle.Init.speed = PCD_SPEED_HIGH_IN_FULL;
+ }
+ #if !defined(MICROPY_HW_USB_VBUS_DETECT_PIN)
+ pcd_hs_handle.Init.vbus_sensing_enable = 0; // No VBUS Sensing on USB0
+ #else
+ pcd_hs_handle.Init.vbus_sensing_enable = 1;
+ #endif
+ pcd_hs_handle.Init.use_external_vbus = 0;
+
+ // Link The driver to the stack
+ pcd_hs_handle.pData = pdev;
+ pdev->pData = &pcd_hs_handle;
+
+ // Initialize LL Driver
+ HAL_PCD_Init(&pcd_hs_handle);
+
+ // We have 1024 32-bit words in total to use here
+ HAL_PCD_SetRxFiFo(&pcd_hs_handle, 512);
+ HAL_PCD_SetTxFiFo(&pcd_hs_handle, 0, 32); // EP0
+ HAL_PCD_SetTxFiFo(&pcd_hs_handle, 1, 256); // MSC / HID
+ HAL_PCD_SetTxFiFo(&pcd_hs_handle, 2, 32); // CDC CMD
+ HAL_PCD_SetTxFiFo(&pcd_hs_handle, 3, 64); // CDC DATA
+ HAL_PCD_SetTxFiFo(&pcd_hs_handle, 4, 32); // CDC2 CMD
+ HAL_PCD_SetTxFiFo(&pcd_hs_handle, 5, 64); // CDC2 DATA
+
+ #else // !MICROPY_HW_USB_HS_IN_FS
+
+ // Set LL Driver parameters
+ pcd_hs_handle.Instance = USB_OTG_HS;
+ pcd_hs_handle.Init.dev_endpoints = 6;
+ pcd_hs_handle.Init.use_dedicated_ep1 = 0;
+ pcd_hs_handle.Init.ep0_mps = 0x40;
+
+ /* Be aware that enabling USB-DMA mode will result in data being sent only by
+ multiple of 4 packet sizes. This is due to the fact that USB-DMA does
+ not allow sending data from non word-aligned addresses.
+ For this specific application, it is advised to not enable this option
+ unless required. */
+ pcd_hs_handle.Init.dma_enable = 0;
+
+ pcd_hs_handle.Init.low_power_enable = 0;
+ pcd_hs_handle.Init.phy_itface = PCD_PHY_ULPI;
+ pcd_hs_handle.Init.Sof_enable = 1;
+ pcd_hs_handle.Init.speed = PCD_SPEED_HIGH;
+ pcd_hs_handle.Init.vbus_sensing_enable = 1;
+
+ // Link The driver to the stack
+ pcd_hs_handle.pData = pdev;
+ pdev->pData = &pcd_hs_handle;
+
+ // Initialize LL Driver
+ HAL_PCD_Init(&pcd_hs_handle);
+
+ HAL_PCD_SetRxFiFo(&pcd_hs_handle, 0x200);
+ HAL_PCD_SetTxFiFo(&pcd_hs_handle, 0, 0x80);
+ HAL_PCD_SetTxFiFo(&pcd_hs_handle, 1, 0x174);
+
+ #endif // !MICROPY_HW_USB_HS_IN_FS
+ }
+ #endif // MICROPY_HW_USB_HS
+
+ return USBD_OK;
+}
+
+/**
+ * @brief De-Initializes the Low Level portion of the Device driver.
+ * @param pdev: Device handle
+ * @retval USBD Status
+ */
+USBD_StatusTypeDef USBD_LL_DeInit(USBD_HandleTypeDef *pdev) {
+ HAL_PCD_DeInit(pdev->pData);
+ return USBD_OK;
+}
+
+/**
+ * @brief Starts the Low Level portion of the Device driver.
+ * @param pdev: Device handle
+ * @retval USBD Status
+ */
+USBD_StatusTypeDef USBD_LL_Start(USBD_HandleTypeDef *pdev) {
+ HAL_PCD_Start(pdev->pData);
+ return USBD_OK;
+}
+
+/**
+ * @brief Stops the Low Level portion of the Device driver.
+ * @param pdev: Device handle
+ * @retval USBD Status
+ */
+USBD_StatusTypeDef USBD_LL_Stop(USBD_HandleTypeDef *pdev) {
+ HAL_PCD_Stop(pdev->pData);
+ return USBD_OK;
+}
+
+/**
+ * @brief Opens an endpoint of the Low Level Driver.
+ * @param pdev: Device handle
+ * @param ep_addr: Endpoint Number
+ * @param ep_type: Endpoint Type
+ * @param ep_mps: Endpoint Max Packet Size
+ * @retval USBD Status
+ */
+USBD_StatusTypeDef USBD_LL_OpenEP(USBD_HandleTypeDef *pdev,
+ uint8_t ep_addr, uint8_t ep_type, uint16_t ep_mps) {
+ HAL_PCD_EP_Open(pdev->pData, ep_addr, ep_mps, ep_type);
+ return USBD_OK;
+}
+
+/**
+ * @brief Closes an endpoint of the Low Level Driver.
+ * @param pdev: Device handle
+ * @param ep_addr: Endpoint Number
+ * @retval USBD Status
+ */
+USBD_StatusTypeDef USBD_LL_CloseEP(USBD_HandleTypeDef *pdev, uint8_t ep_addr) {
+ HAL_PCD_EP_Close(pdev->pData, ep_addr);
+ return USBD_OK;
+}
+
+/**
+ * @brief Flushes an endpoint of the Low Level Driver.
+ * @param pdev: Device handle
+ * @param ep_addr: Endpoint Number
+ * @retval USBD Status
+ */
+USBD_StatusTypeDef USBD_LL_FlushEP(USBD_HandleTypeDef *pdev, uint8_t ep_addr) {
+ HAL_PCD_EP_Flush(pdev->pData, ep_addr);
+ return USBD_OK;
+}
+
+/**
+ * @brief Sets a Stall condition on an endpoint of the Low Level Driver.
+ * @param pdev: Device handle
+ * @param ep_addr: Endpoint Number
+ * @retval USBD Status
+ */
+USBD_StatusTypeDef USBD_LL_StallEP(USBD_HandleTypeDef *pdev, uint8_t ep_addr) {
+ HAL_PCD_EP_SetStall(pdev->pData, ep_addr);
+ return USBD_OK;
+}
+
+/**
+ * @brief Clears a Stall condition on an endpoint of the Low Level Driver.
+ * @param pdev: Device handle
+ * @param ep_addr: Endpoint Number
+ * @retval USBD Status
+ */
+USBD_StatusTypeDef USBD_LL_ClearStallEP(USBD_HandleTypeDef *pdev, uint8_t ep_addr) {
+ HAL_PCD_EP_ClrStall(pdev->pData, ep_addr);
+ return USBD_OK;
+}
+
+/**
+ * @brief Returns Stall condition.
+ * @param pdev: Device handle
+ * @param ep_addr: Endpoint Number
+ * @retval Stall (1: yes, 0: No)
+ */
+uint8_t USBD_LL_IsStallEP(USBD_HandleTypeDef *pdev, uint8_t ep_addr) {
+ PCD_HandleTypeDef *hpcd = pdev->pData;
+
+ if ((ep_addr & 0x80) == 0x80) {
+ return hpcd->IN_ep[ep_addr & 0x7F].is_stall;
+ } else {
+ return hpcd->OUT_ep[ep_addr & 0x7F].is_stall;
+ }
+}
+
+/**
+ * @brief Assigns an USB address to the device
+ * @param pdev: Device handle
+ * @param dev_addr: USB address
+ * @retval USBD Status
+ */
+USBD_StatusTypeDef USBD_LL_SetUSBAddress(USBD_HandleTypeDef *pdev, uint8_t dev_addr) {
+ HAL_PCD_SetAddress(pdev->pData, dev_addr);
+ return USBD_OK;
+}
+
+/**
+ * @brief Transmits data over an endpoint
+ * @param pdev: Device handle
+ * @param ep_addr: Endpoint Number
+ * @param pbuf: Pointer to data to be sent
+ * @param size: Data size
+ * @retval USBD Status
+ */
+USBD_StatusTypeDef USBD_LL_Transmit(USBD_HandleTypeDef *pdev,
+ uint8_t ep_addr, uint8_t *pbuf, uint16_t size) {
+ HAL_PCD_EP_Transmit(pdev->pData, ep_addr, pbuf, size);
+ return USBD_OK;
+}
+
+/**
+ * @brief Prepares an endpoint for reception
+ * @param pdev: Device handle
+ * @param ep_addr: Endpoint Number
+ * @param pbuf:pointer to data to be received
+ * @param size: data size
+ * @retval USBD Status
+ */
+USBD_StatusTypeDef USBD_LL_PrepareReceive(USBD_HandleTypeDef *pdev,
+ uint8_t ep_addr, uint8_t *pbuf, uint16_t size) {
+ HAL_PCD_EP_Receive(pdev->pData, ep_addr, pbuf, size);
+ return USBD_OK;
+}
+
+/**
+ * @brief Returns the last transfered packet size.
+ * @param pdev: Device handle
+ * @param ep_addr: Endpoint Number
+ * @retval Recived Data Size
+ */
+uint32_t USBD_LL_GetRxDataSize(USBD_HandleTypeDef *pdev, uint8_t ep_addr) {
+ return HAL_PCD_EP_GetRxCount(pdev->pData, ep_addr);
+}
+
+/**
+ * @brief Delay routine for the USB Device Library
+ * @param Delay: Delay in ms
+ * @retval None
+ */
+void USBD_LL_Delay(uint32_t Delay) {
+ HAL_Delay(Delay);
+}
+
+#endif // MICROPY_HW_USB_FS || MICROPY_HW_USB_HS
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/ports/stm32/usbd_conf.h b/ports/stm32/usbd_conf.h
index 34ebe27b9..1f8e754a2 100644
--- a/ports/stm32/usbd_conf.h
+++ b/ports/stm32/usbd_conf.h
@@ -1,93 +1,48 @@
-/*
- * This file is part of the MicroPython project, http://micropython.org/
- */
-
-/**
- ******************************************************************************
- * @file USB_Device/CDC_Standalone/Inc/usbd_conf.h
- * @author MCD Application Team
- * @version V1.0.1
- * @date 26-February-2014
- * @brief General low level driver configuration
- ******************************************************************************
- * @attention
- *
- * <h2><center>&copy; COPYRIGHT(c) 2014 STMicroelectronics</center></h2>
- *
- * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
- * You may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.st.com/software_license_agreement_liberty_v2
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- ******************************************************************************
- */
-
-/* Define to prevent recursive inclusion -------------------------------------*/
-#ifndef __USBD_CONF_H
-#define __USBD_CONF_H
-
-/* Includes ------------------------------------------------------------------*/
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "py/mpconfig.h"
-
-/* Exported types ------------------------------------------------------------*/
-/* Exported constants --------------------------------------------------------*/
-/* Common Config */
-#define USBD_MAX_NUM_INTERFACES 1
-#define USBD_MAX_NUM_CONFIGURATION 1
-#define USBD_MAX_STR_DESC_SIZ 0x100
-#define USBD_SUPPORT_USER_STRING 0
-#define USBD_SELF_POWERED 0
-#define USBD_DEBUG_LEVEL 0
-
-/* Exported macro ------------------------------------------------------------*/
-/* Memory management macros */
-/*
-these should not be used because the GC is reset on a soft reset but the usb is not
-#include "gc.h"
-#define USBD_malloc gc_alloc
-#define USBD_free gc_free
-#define USBD_memset memset
-#define USBD_memcpy memcpy
-*/
-
-/* DEBUG macros */
-#if (USBD_DEBUG_LEVEL > 0)
-#define USBD_UsrLog(...) printf(__VA_ARGS__);\
- printf("\n");
-#else
-#define USBD_UsrLog(...)
-#endif
-
-#if (USBD_DEBUG_LEVEL > 1)
-
-#define USBD_ErrLog(...) printf("ERROR: ") ;\
- printf(__VA_ARGS__);\
- printf("\n");
-#else
-#define USBD_ErrLog(...)
-#endif
-
-#if (USBD_DEBUG_LEVEL > 2)
-#define USBD_DbgLog(...) printf("DEBUG : ") ;\
- printf(__VA_ARGS__);\
- printf("\n");
-#else
-#define USBD_DbgLog(...)
-#endif
-
-/* Exported functions ------------------------------------------------------- */
-
-#endif /* __USBD_CONF_H */
-
-/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ */
+
+/**
+ ******************************************************************************
+ * @file USB_Device/CDC_Standalone/Inc/usbd_conf.h
+ * @author MCD Application Team
+ * @version V1.0.1
+ * @date 26-February-2014
+ * @brief General low level driver configuration
+ ******************************************************************************
+ * @attention
+ *
+ * <h2><center>&copy; COPYRIGHT(c) 2014 STMicroelectronics</center></h2>
+ *
+ * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
+ * You may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.st.com/software_license_agreement_liberty_v2
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************
+ */
+
+#ifndef MICROPY_INCLUDED_STM32_USBD_CONF_H
+#define MICROPY_INCLUDED_STM32_USBD_CONF_H
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define USBD_MAX_NUM_INTERFACES 4
+#define USBD_MAX_NUM_CONFIGURATION 1
+#define USBD_MAX_STR_DESC_SIZ 0x100
+#define USBD_SELF_POWERED 0
+#define USBD_DEBUG_LEVEL 0
+
+#endif // MICROPY_INCLUDED_STM32_USBD_CONF_H
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/ports/stm32/usbd_desc.c b/ports/stm32/usbd_desc.c
index 1de75aee0..4babebf64 100644
--- a/ports/stm32/usbd_desc.c
+++ b/ports/stm32/usbd_desc.c
@@ -33,8 +33,7 @@
#include "usbd_desc.h"
#include "usbd_conf.h"
-// need these headers just for MP_HAL_UNIQUE_ID_ADDRESS
-#include "py/misc.h"
+// need this header just for MP_HAL_UNIQUE_ID_ADDRESS
#include "py/mphal.h"
// So we don't clash with existing ST boards, we use the unofficial FOSS VID.
@@ -104,115 +103,82 @@ STATIC uint8_t *USBD_DeviceDescriptor(USBD_HandleTypeDef *pdev, uint16_t *length
}
/**
- * @brief Returns the LangID string descriptor.
- * @param speed: Current device speed
- * @param length: Pointer to data length variable
- * @retval Pointer to descriptor buffer
- */
-STATIC uint8_t *USBD_LangIDStrDescriptor(USBD_HandleTypeDef *pdev, uint16_t *length) {
- *length = sizeof(USBD_LangIDDesc);
- return (uint8_t*)USBD_LangIDDesc; // the data should only be read from this buf
-}
-
-/**
- * @brief Returns the product string descriptor.
- * @param speed: Current device speed
- * @param length: Pointer to data length variable
- * @retval Pointer to descriptor buffer
- */
-STATIC uint8_t *USBD_ProductStrDescriptor(USBD_HandleTypeDef *pdev, uint16_t *length) {
- uint8_t *str_desc = ((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->usbd_str_desc;
- if (pdev->dev_speed == USBD_SPEED_HIGH) {
- USBD_GetString((uint8_t *)USBD_PRODUCT_HS_STRING, str_desc, length);
- } else {
- USBD_GetString((uint8_t *)USBD_PRODUCT_FS_STRING, str_desc, length);
- }
- return str_desc;
-}
-
-/**
- * @brief Returns the manufacturer string descriptor.
- * @param speed: Current device speed
- * @param length: Pointer to data length variable
- * @retval Pointer to descriptor buffer
- */
-STATIC uint8_t *USBD_ManufacturerStrDescriptor(USBD_HandleTypeDef *pdev, uint16_t *length) {
- uint8_t *str_desc = ((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->usbd_str_desc;
- USBD_GetString((uint8_t *)USBD_MANUFACTURER_STRING, str_desc, length);
- return str_desc;
-}
-
-/**
- * @brief Returns the serial number string descriptor.
- * @param speed: Current device speed
+ * @brief Returns a string descriptor
+ * @param idx: Index of the string descriptor to retrieve
* @param length: Pointer to data length variable
- * @retval Pointer to descriptor buffer
+ * @retval Pointer to descriptor buffer, or NULL if idx is invalid
*/
-STATIC uint8_t *USBD_SerialStrDescriptor(USBD_HandleTypeDef *pdev, uint16_t *length) {
- // This document: http://www.usb.org/developers/docs/devclass_docs/usbmassbulk_10.pdf
- // says that the serial number has to be at least 12 digits long and that
- // the last 12 digits need to be unique. It also stipulates that the valid
- // character set is that of upper-case hexadecimal digits.
- //
- // The onboard DFU bootloader produces a 12-digit serial number based on
- // the 96-bit unique ID, so for consistency we go with this algorithm.
- // You can see the serial number if you do:
- //
- // dfu-util -l
- //
- // See: https://my.st.com/52d187b7 for the algorithim used.
-
- uint8_t *id = (uint8_t *)MP_HAL_UNIQUE_ID_ADDRESS;
- char serial_buf[16];
- snprintf(serial_buf, sizeof(serial_buf),
- "%02X%02X%02X%02X%02X%02X",
- id[11], id[10] + id[2], id[9], id[8] + id[0], id[7], id[6]);
-
- uint8_t *str_desc = ((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->usbd_str_desc;
- USBD_GetString((uint8_t *)serial_buf, str_desc, length);
- return str_desc;
-}
-
-/**
- * @brief Returns the configuration string descriptor.
- * @param speed: Current device speed
- * @param length: Pointer to data length variable
- * @retval Pointer to descriptor buffer
- */
-STATIC uint8_t *USBD_ConfigStrDescriptor(USBD_HandleTypeDef *pdev, uint16_t *length) {
- uint8_t *str_desc = ((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->usbd_str_desc;
- if (pdev->dev_speed == USBD_SPEED_HIGH) {
- USBD_GetString((uint8_t *)USBD_CONFIGURATION_HS_STRING, str_desc, length);
- } else {
- USBD_GetString((uint8_t *)USBD_CONFIGURATION_FS_STRING, str_desc, length);
+STATIC uint8_t *USBD_StrDescriptor(USBD_HandleTypeDef *pdev, uint8_t idx, uint16_t *length) {
+ char str_buf[16];
+ const char *str = NULL;
+
+ switch (idx) {
+ case USBD_IDX_LANGID_STR:
+ *length = sizeof(USBD_LangIDDesc);
+ return (uint8_t*)USBD_LangIDDesc; // the data should only be read from this buf
+
+ case USBD_IDX_MFC_STR:
+ str = USBD_MANUFACTURER_STRING;
+ break;
+
+ case USBD_IDX_PRODUCT_STR:
+ if (pdev->dev_speed == USBD_SPEED_HIGH) {
+ str = USBD_PRODUCT_HS_STRING;
+ } else {
+ str = USBD_PRODUCT_FS_STRING;
+ }
+ break;
+
+ case USBD_IDX_SERIAL_STR: {
+ // This document: http://www.usb.org/developers/docs/devclass_docs/usbmassbulk_10.pdf
+ // says that the serial number has to be at least 12 digits long and that
+ // the last 12 digits need to be unique. It also stipulates that the valid
+ // character set is that of upper-case hexadecimal digits.
+ //
+ // The onboard DFU bootloader produces a 12-digit serial number based on
+ // the 96-bit unique ID, so for consistency we go with this algorithm.
+ // You can see the serial number if you use: lsusb -v
+ //
+ // See: https://my.st.com/52d187b7 for the algorithim used.
+
+ uint8_t *id = (uint8_t *)MP_HAL_UNIQUE_ID_ADDRESS;
+ snprintf(str_buf, sizeof(str_buf),
+ "%02X%02X%02X%02X%02X%02X",
+ id[11], id[10] + id[2], id[9], id[8] + id[0], id[7], id[6]);
+
+ str = str_buf;
+ break;
+ }
+
+ case USBD_IDX_CONFIG_STR:
+ if (pdev->dev_speed == USBD_SPEED_HIGH) {
+ str = USBD_CONFIGURATION_HS_STRING;
+ } else {
+ str = USBD_CONFIGURATION_FS_STRING;
+ }
+ break;
+
+ case USBD_IDX_INTERFACE_STR:
+ if (pdev->dev_speed == USBD_SPEED_HIGH) {
+ str = USBD_INTERFACE_HS_STRING;
+ } else {
+ str = USBD_INTERFACE_FS_STRING;
+ }
+ break;
+
+ default:
+ // invalid string index
+ return NULL;
}
- return str_desc;
-}
-/**
- * @brief Returns the interface string descriptor.
- * @param speed: Current device speed
- * @param length: Pointer to data length variable
- * @retval Pointer to descriptor buffer
- */
-STATIC uint8_t *USBD_InterfaceStrDescriptor(USBD_HandleTypeDef *pdev, uint16_t *length) {
uint8_t *str_desc = ((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->usbd_str_desc;
- if (pdev->dev_speed == USBD_SPEED_HIGH) {
- USBD_GetString((uint8_t *)USBD_INTERFACE_HS_STRING, str_desc, length);
- } else {
- USBD_GetString((uint8_t *)USBD_INTERFACE_FS_STRING, str_desc, length);
- }
+ USBD_GetString((uint8_t*)str, str_desc, length);
return str_desc;
}
const USBD_DescriptorsTypeDef USBD_Descriptors = {
USBD_DeviceDescriptor,
- USBD_LangIDStrDescriptor,
- USBD_ManufacturerStrDescriptor,
- USBD_ProductStrDescriptor,
- USBD_SerialStrDescriptor,
- USBD_ConfigStrDescriptor,
- USBD_InterfaceStrDescriptor,
+ USBD_StrDescriptor,
};
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/ports/stm32/usbd_desc.h b/ports/stm32/usbd_desc.h
index a4de6c681..0307defa5 100644
--- a/ports/stm32/usbd_desc.h
+++ b/ports/stm32/usbd_desc.h
@@ -23,8 +23,8 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
-#ifndef MICROPY_INCLUDED_STMHAL_USBD_DESC_H
-#define MICROPY_INCLUDED_STMHAL_USBD_DESC_H
+#ifndef MICROPY_INCLUDED_STM32_USBD_DESC_H
+#define MICROPY_INCLUDED_STM32_USBD_DESC_H
#include "usbd_cdc_msc_hid.h"
@@ -32,4 +32,4 @@ extern const USBD_DescriptorsTypeDef USBD_Descriptors;
void USBD_SetVIDPIDRelease(usbd_cdc_msc_hid_state_t *usbd, uint16_t vid, uint16_t pid, uint16_t device_release_num, int cdc_only);
-#endif // MICROPY_INCLUDED_STMHAL_USBD_DESC_H
+#endif // MICROPY_INCLUDED_STM32_USBD_DESC_H
diff --git a/ports/stm32/usbd_hid_interface.c b/ports/stm32/usbd_hid_interface.c
index 4ee533c21..3ffc0b425 100644
--- a/ports/stm32/usbd_hid_interface.c
+++ b/ports/stm32/usbd_hid_interface.c
@@ -42,8 +42,9 @@
#include "irq.h"
#include "usb.h"
-uint8_t *usbd_hid_init(usbd_hid_itf_t *hid, usbd_cdc_msc_hid_state_t *usbd) {
- hid->usbd = usbd;
+uint8_t *usbd_hid_init(usbd_hid_state_t *hid_in) {
+ usbd_hid_itf_t *hid = (usbd_hid_itf_t*)hid_in;
+
hid->current_read_buffer = 0;
hid->last_read_len = 0;
hid->current_write_buffer = 0;
@@ -55,13 +56,15 @@ uint8_t *usbd_hid_init(usbd_hid_itf_t *hid, usbd_cdc_msc_hid_state_t *usbd) {
// Data received over USB OUT endpoint is processed here.
// len: number of bytes received into the buffer we passed to USBD_HID_ReceivePacket
// Returns USBD_OK if all operations are OK else USBD_FAIL
-int8_t usbd_hid_receive(usbd_hid_itf_t *hid, size_t len) {
+int8_t usbd_hid_receive(usbd_hid_state_t *hid_in, size_t len) {
+ usbd_hid_itf_t *hid = (usbd_hid_itf_t*)hid_in;
+
hid->current_write_buffer = !hid->current_write_buffer;
hid->last_read_len = len;
// initiate next USB packet transfer, to append to existing data in buffer
- USBD_HID_ReceivePacket(hid->usbd, hid->buffer[hid->current_write_buffer]);
+ USBD_HID_ReceivePacket(&hid->base, hid->buffer[hid->current_write_buffer]);
// Set NAK to indicate we need to process read buffer
- USBD_HID_SetNAK(hid->usbd);
+ USBD_HID_SetNAK(&hid->base);
return USBD_OK;
}
@@ -94,12 +97,13 @@ int usbd_hid_rx(usbd_hid_itf_t *hid, size_t len, uint8_t *buf, uint32_t timeout)
}
// Copy bytes from device to user buffer
- memcpy(buf, hid->buffer[hid->current_read_buffer], hid->last_read_len);
+ int read_len = hid->last_read_len;
+ memcpy(buf, hid->buffer[hid->current_read_buffer], read_len);
hid->current_read_buffer = !hid->current_read_buffer;
// Clear NAK to indicate we are ready to read more data
- USBD_HID_ClearNAK(hid->usbd);
+ USBD_HID_ClearNAK(&hid->base);
// Success, return number of bytes read
- return hid->last_read_len;
+ return read_len;
}
diff --git a/ports/stm32/usbd_hid_interface.h b/ports/stm32/usbd_hid_interface.h
index 79040b57e..777fa9340 100644
--- a/ports/stm32/usbd_hid_interface.h
+++ b/ports/stm32/usbd_hid_interface.h
@@ -1,13 +1,13 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*/
-#ifndef MICROPY_INCLUDED_STMHAL_USBD_HID_INTERFACE_H
-#define MICROPY_INCLUDED_STMHAL_USBD_HID_INTERFACE_H
+#ifndef MICROPY_INCLUDED_STM32_USBD_HID_INTERFACE_H
+#define MICROPY_INCLUDED_STM32_USBD_HID_INTERFACE_H
#include "usbd_cdc_msc_hid.h"
typedef struct _usbd_hid_itf_t {
- usbd_cdc_msc_hid_state_t *usbd; // the parent USB device
+ usbd_hid_state_t base; // state for the base HID layer
uint8_t buffer[2][HID_DATA_FS_MAX_PACKET_SIZE]; // pair of buffers to read individual packets into
int8_t current_read_buffer; // which buffer to read from
@@ -18,4 +18,4 @@ typedef struct _usbd_hid_itf_t {
int usbd_hid_rx_num(usbd_hid_itf_t *hid);
int usbd_hid_rx(usbd_hid_itf_t *hid, size_t len, uint8_t *buf, uint32_t timeout);
-#endif // MICROPY_INCLUDED_STMHAL_USBD_HID_INTERFACE_H
+#endif // MICROPY_INCLUDED_STM32_USBD_HID_INTERFACE_H
diff --git a/ports/stm32/usbd_msc_storage.c b/ports/stm32/usbd_msc_storage.c
index f825c3d70..7d6c19e9f 100644
--- a/ports/stm32/usbd_msc_storage.c
+++ b/ports/stm32/usbd_msc_storage.c
@@ -36,7 +36,7 @@
#include "usbd_cdc_msc_hid.h"
#include "usbd_msc_storage.h"
-#include "py/misc.h"
+#include "py/mpstate.h"
#include "storage.h"
#include "sdcard.h"
diff --git a/ports/stm32/usbd_msc_storage.h b/ports/stm32/usbd_msc_storage.h
index 6cc40d2d6..669f7df58 100644
--- a/ports/stm32/usbd_msc_storage.h
+++ b/ports/stm32/usbd_msc_storage.h
@@ -23,10 +23,10 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
-#ifndef MICROPY_INCLUDED_STMHAL_USBD_MSC_STORAGE_H
-#define MICROPY_INCLUDED_STMHAL_USBD_MSC_STORAGE_H
+#ifndef MICROPY_INCLUDED_STM32_USBD_MSC_STORAGE_H
+#define MICROPY_INCLUDED_STM32_USBD_MSC_STORAGE_H
extern const USBD_StorageTypeDef USBD_FLASH_STORAGE_fops;
extern const USBD_StorageTypeDef USBD_SDCARD_STORAGE_fops;
-#endif // MICROPY_INCLUDED_STMHAL_USBD_MSC_STORAGE_H
+#endif // MICROPY_INCLUDED_STM32_USBD_MSC_STORAGE_H
diff --git a/ports/stm32/usbdev/Release_Notes.html b/ports/stm32/usbdev/Release_Notes.html
deleted file mode 100644
index 487b45526..000000000
--- a/ports/stm32/usbdev/Release_Notes.html
+++ /dev/null
@@ -1,974 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
-<html xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:w="urn:schemas-microsoft-com:office:word" xmlns:m="http://schemas.microsoft.com/office/2004/12/omml" xmlns="http://www.w3.org/TR/REC-html40"><head>
-
-
-
-
-<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
-<link rel="File-List" href="Release_Notes_for_STM32F2xx_StdPeriph_Driver_files/filelist.xml">
-<link rel="Edit-Time-Data" href="Release_Notes_for_STM32F2xx_StdPeriph_Driver_files/editdata.mso"><!--[if !mso]>
-<style>
-v\:* {behavior:url(#default#VML);}
-o\:* {behavior:url(#default#VML);}
-w\:* {behavior:url(#default#VML);}
-.shape {behavior:url(#default#VML);}
-</style>
-<![endif]--><title>Release Notes for STM32 USB Device Library</title><!--[if gte mso 9]><xml>
- <o:DocumentProperties>
- <o:Author>STMicroelectronics</o:Author>
- <o:LastAuthor>Raouf Hosni</o:LastAuthor>
- <o:Revision>39</o:Revision>
- <o:TotalTime>137</o:TotalTime>
- <o:Created>2009-02-27T19:26:00Z</o:Created>
- <o:LastSaved>2010-10-15T11:07:00Z</o:LastSaved>
- <o:Pages>3</o:Pages>
- <o:Words>973</o:Words>
- <o:Characters>5548</o:Characters>
- <o:Company>STMicroelectronics</o:Company>
- <o:Lines>46</o:Lines>
- <o:Paragraphs>13</o:Paragraphs>
- <o:CharactersWithSpaces>6508</o:CharactersWithSpaces>
- <o:Version>12.00</o:Version>
- </o:DocumentProperties>
-</xml><![endif]-->
-
-
-
-<link rel="themeData" href="Release_Notes_for_STM32F2xx_StdPeriph_Driver_files/themedata.thmx">
-<link rel="colorSchemeMapping" href="Release_Notes_for_STM32F2xx_StdPeriph_Driver_files/colorschememapping.xml"><!--[if gte mso 9]><xml>
- <w:WordDocument>
- <w:Zoom>110</w:Zoom>
- <w:TrackMoves>false</w:TrackMoves>
- <w:TrackFormatting/>
- <w:ValidateAgainstSchemas/>
- <w:SaveIfXMLInvalid>false</w:SaveIfXMLInvalid>
- <w:IgnoreMixedContent>false</w:IgnoreMixedContent>
- <w:AlwaysShowPlaceholderText>false</w:AlwaysShowPlaceholderText>
- <w:DoNotPromoteQF/>
- <w:LidThemeOther>EN-US</w:LidThemeOther>
- <w:LidThemeAsian>X-NONE</w:LidThemeAsian>
- <w:LidThemeComplexScript>X-NONE</w:LidThemeComplexScript>
- <w:Compatibility>
- <w:BreakWrappedTables/>
- <w:SnapToGridInCell/>
- <w:WrapTextWithPunct/>
- <w:UseAsianBreakRules/>
- <w:DontGrowAutofit/>
- <w:SplitPgBreakAndParaMark/>
- <w:DontVertAlignCellWithSp/>
- <w:DontBreakConstrainedForcedTables/>
- <w:DontVertAlignInTxbx/>
- <w:Word11KerningPairs/>
- <w:CachedColBalance/>
- </w:Compatibility>
- <w:BrowserLevel>MicrosoftInternetExplorer4</w:BrowserLevel>
- <m:mathPr>
- <m:mathFont m:val="Cambria Math"/>
- <m:brkBin m:val="before"/>
- <m:brkBinSub m:val="&#45;-"/>
- <m:smallFrac m:val="off"/>
- <m:dispDef/>
- <m:lMargin m:val="0"/>
- <m:rMargin m:val="0"/>
- <m:defJc m:val="centerGroup"/>
- <m:wrapIndent m:val="1440"/>
- <m:intLim m:val="subSup"/>
- <m:naryLim m:val="undOvr"/>
- </m:mathPr></w:WordDocument>
-</xml><![endif]--><!--[if gte mso 9]><xml>
- <w:LatentStyles DefLockedState="false" DefUnhideWhenUsed="false"
- DefSemiHidden="false" DefQFormat="false" LatentStyleCount="267">
- <w:LsdException Locked="false" QFormat="true" Name="Normal"/>
- <w:LsdException Locked="false" QFormat="true" Name="heading 1"/>
- <w:LsdException Locked="false" QFormat="true" Name="heading 2"/>
- <w:LsdException Locked="false" QFormat="true" Name="heading 3"/>
- <w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
- QFormat="true" Name="heading 4"/>
- <w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
- QFormat="true" Name="heading 5"/>
- <w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
- QFormat="true" Name="heading 6"/>
- <w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
- QFormat="true" Name="heading 7"/>
- <w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
- QFormat="true" Name="heading 8"/>
- <w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
- QFormat="true" Name="heading 9"/>
- <w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
- QFormat="true" Name="caption"/>
- <w:LsdException Locked="false" QFormat="true" Name="Title"/>
- <w:LsdException Locked="false" Priority="1" Name="Default Paragraph Font"/>
- <w:LsdException Locked="false" QFormat="true" Name="Subtitle"/>
- <w:LsdException Locked="false" QFormat="true" Name="Strong"/>
- <w:LsdException Locked="false" QFormat="true" Name="Emphasis"/>
- <w:LsdException Locked="false" Priority="99" Name="No List"/>
- <w:LsdException Locked="false" Priority="99" SemiHidden="true"
- Name="Placeholder Text"/>
- <w:LsdException Locked="false" Priority="1" QFormat="true" Name="No Spacing"/>
- <w:LsdException Locked="false" Priority="60" Name="Light Shading"/>
- <w:LsdException Locked="false" Priority="61" Name="Light List"/>
- <w:LsdException Locked="false" Priority="62" Name="Light Grid"/>
- <w:LsdException Locked="false" Priority="63" Name="Medium Shading 1"/>
- <w:LsdException Locked="false" Priority="64" Name="Medium Shading 2"/>
- <w:LsdException Locked="false" Priority="65" Name="Medium List 1"/>
- <w:LsdException Locked="false" Priority="66" Name="Medium List 2"/>
- <w:LsdException Locked="false" Priority="67" Name="Medium Grid 1"/>
- <w:LsdException Locked="false" Priority="68" Name="Medium Grid 2"/>
- <w:LsdException Locked="false" Priority="69" Name="Medium Grid 3"/>
- <w:LsdException Locked="false" Priority="70" Name="Dark List"/>
- <w:LsdException Locked="false" Priority="71" Name="Colorful Shading"/>
- <w:LsdException Locked="false" Priority="72" Name="Colorful List"/>
- <w:LsdException Locked="false" Priority="73" Name="Colorful Grid"/>
- <w:LsdException Locked="false" Priority="60" Name="Light Shading Accent 1"/>
- <w:LsdException Locked="false" Priority="61" Name="Light List Accent 1"/>
- <w:LsdException Locked="false" Priority="62" Name="Light Grid Accent 1"/>
- <w:LsdException Locked="false" Priority="63" Name="Medium Shading 1 Accent 1"/>
- <w:LsdException Locked="false" Priority="64" Name="Medium Shading 2 Accent 1"/>
- <w:LsdException Locked="false" Priority="65" Name="Medium List 1 Accent 1"/>
- <w:LsdException Locked="false" Priority="99" SemiHidden="true" Name="Revision"/>
- <w:LsdException Locked="false" Priority="34" QFormat="true"
- Name="List Paragraph"/>
- <w:LsdException Locked="false" Priority="29" QFormat="true" Name="Quote"/>
- <w:LsdException Locked="false" Priority="30" QFormat="true"
- Name="Intense Quote"/>
- <w:LsdException Locked="false" Priority="66" Name="Medium List 2 Accent 1"/>
- <w:LsdException Locked="false" Priority="67" Name="Medium Grid 1 Accent 1"/>
- <w:LsdException Locked="false" Priority="68" Name="Medium Grid 2 Accent 1"/>
- <w:LsdException Locked="false" Priority="69" Name="Medium Grid 3 Accent 1"/>
- <w:LsdException Locked="false" Priority="70" Name="Dark List Accent 1"/>
- <w:LsdException Locked="false" Priority="71" Name="Colorful Shading Accent 1"/>
- <w:LsdException Locked="false" Priority="72" Name="Colorful List Accent 1"/>
- <w:LsdException Locked="false" Priority="73" Name="Colorful Grid Accent 1"/>
- <w:LsdException Locked="false" Priority="60" Name="Light Shading Accent 2"/>
- <w:LsdException Locked="false" Priority="61" Name="Light List Accent 2"/>
- <w:LsdException Locked="false" Priority="62" Name="Light Grid Accent 2"/>
- <w:LsdException Locked="false" Priority="63" Name="Medium Shading 1 Accent 2"/>
- <w:LsdException Locked="false" Priority="64" Name="Medium Shading 2 Accent 2"/>
- <w:LsdException Locked="false" Priority="65" Name="Medium List 1 Accent 2"/>
- <w:LsdException Locked="false" Priority="66" Name="Medium List 2 Accent 2"/>
- <w:LsdException Locked="false" Priority="67" Name="Medium Grid 1 Accent 2"/>
- <w:LsdException Locked="false" Priority="68" Name="Medium Grid 2 Accent 2"/>
- <w:LsdException Locked="false" Priority="69" Name="Medium Grid 3 Accent 2"/>
- <w:LsdException Locked="false" Priority="70" Name="Dark List Accent 2"/>
- <w:LsdException Locked="false" Priority="71" Name="Colorful Shading Accent 2"/>
- <w:LsdException Locked="false" Priority="72" Name="Colorful List Accent 2"/>
- <w:LsdException Locked="false" Priority="73" Name="Colorful Grid Accent 2"/>
- <w:LsdException Locked="false" Priority="60" Name="Light Shading Accent 3"/>
- <w:LsdException Locked="false" Priority="61" Name="Light List Accent 3"/>
- <w:LsdException Locked="false" Priority="62" Name="Light Grid Accent 3"/>
- <w:LsdException Locked="false" Priority="63" Name="Medium Shading 1 Accent 3"/>
- <w:LsdException Locked="false" Priority="64" Name="Medium Shading 2 Accent 3"/>
- <w:LsdException Locked="false" Priority="65" Name="Medium List 1 Accent 3"/>
- <w:LsdException Locked="false" Priority="66" Name="Medium List 2 Accent 3"/>
- <w:LsdException Locked="false" Priority="67" Name="Medium Grid 1 Accent 3"/>
- <w:LsdException Locked="false" Priority="68" Name="Medium Grid 2 Accent 3"/>
- <w:LsdException Locked="false" Priority="69" Name="Medium Grid 3 Accent 3"/>
- <w:LsdException Locked="false" Priority="70" Name="Dark List Accent 3"/>
- <w:LsdException Locked="false" Priority="71" Name="Colorful Shading Accent 3"/>
- <w:LsdException Locked="false" Priority="72" Name="Colorful List Accent 3"/>
- <w:LsdException Locked="false" Priority="73" Name="Colorful Grid Accent 3"/>
- <w:LsdException Locked="false" Priority="60" Name="Light Shading Accent 4"/>
- <w:LsdException Locked="false" Priority="61" Name="Light List Accent 4"/>
- <w:LsdException Locked="false" Priority="62" Name="Light Grid Accent 4"/>
- <w:LsdException Locked="false" Priority="63" Name="Medium Shading 1 Accent 4"/>
- <w:LsdException Locked="false" Priority="64" Name="Medium Shading 2 Accent 4"/>
- <w:LsdException Locked="false" Priority="65" Name="Medium List 1 Accent 4"/>
- <w:LsdException Locked="false" Priority="66" Name="Medium List 2 Accent 4"/>
- <w:LsdException Locked="false" Priority="67" Name="Medium Grid 1 Accent 4"/>
- <w:LsdException Locked="false" Priority="68" Name="Medium Grid 2 Accent 4"/>
- <w:LsdException Locked="false" Priority="69" Name="Medium Grid 3 Accent 4"/>
- <w:LsdException Locked="false" Priority="70" Name="Dark List Accent 4"/>
- <w:LsdException Locked="false" Priority="71" Name="Colorful Shading Accent 4"/>
- <w:LsdException Locked="false" Priority="72" Name="Colorful List Accent 4"/>
- <w:LsdException Locked="false" Priority="73" Name="Colorful Grid Accent 4"/>
- <w:LsdException Locked="false" Priority="60" Name="Light Shading Accent 5"/>
- <w:LsdException Locked="false" Priority="61" Name="Light List Accent 5"/>
- <w:LsdException Locked="false" Priority="62" Name="Light Grid Accent 5"/>
- <w:LsdException Locked="false" Priority="63" Name="Medium Shading 1 Accent 5"/>
- <w:LsdException Locked="false" Priority="64" Name="Medium Shading 2 Accent 5"/>
- <w:LsdException Locked="false" Priority="65" Name="Medium List 1 Accent 5"/>
- <w:LsdException Locked="false" Priority="66" Name="Medium List 2 Accent 5"/>
- <w:LsdException Locked="false" Priority="67" Name="Medium Grid 1 Accent 5"/>
- <w:LsdException Locked="false" Priority="68" Name="Medium Grid 2 Accent 5"/>
- <w:LsdException Locked="false" Priority="69" Name="Medium Grid 3 Accent 5"/>
- <w:LsdException Locked="false" Priority="70" Name="Dark List Accent 5"/>
- <w:LsdException Locked="false" Priority="71" Name="Colorful Shading Accent 5"/>
- <w:LsdException Locked="false" Priority="72" Name="Colorful List Accent 5"/>
- <w:LsdException Locked="false" Priority="73" Name="Colorful Grid Accent 5"/>
- <w:LsdException Locked="false" Priority="60" Name="Light Shading Accent 6"/>
- <w:LsdException Locked="false" Priority="61" Name="Light List Accent 6"/>
- <w:LsdException Locked="false" Priority="62" Name="Light Grid Accent 6"/>
- <w:LsdException Locked="false" Priority="63" Name="Medium Shading 1 Accent 6"/>
- <w:LsdException Locked="false" Priority="64" Name="Medium Shading 2 Accent 6"/>
- <w:LsdException Locked="false" Priority="65" Name="Medium List 1 Accent 6"/>
- <w:LsdException Locked="false" Priority="66" Name="Medium List 2 Accent 6"/>
- <w:LsdException Locked="false" Priority="67" Name="Medium Grid 1 Accent 6"/>
- <w:LsdException Locked="false" Priority="68" Name="Medium Grid 2 Accent 6"/>
- <w:LsdException Locked="false" Priority="69" Name="Medium Grid 3 Accent 6"/>
- <w:LsdException Locked="false" Priority="70" Name="Dark List Accent 6"/>
- <w:LsdException Locked="false" Priority="71" Name="Colorful Shading Accent 6"/>
- <w:LsdException Locked="false" Priority="72" Name="Colorful List Accent 6"/>
- <w:LsdException Locked="false" Priority="73" Name="Colorful Grid Accent 6"/>
- <w:LsdException Locked="false" Priority="19" QFormat="true"
- Name="Subtle Emphasis"/>
- <w:LsdException Locked="false" Priority="21" QFormat="true"
- Name="Intense Emphasis"/>
- <w:LsdException Locked="false" Priority="31" QFormat="true"
- Name="Subtle Reference"/>
- <w:LsdException Locked="false" Priority="32" QFormat="true"
- Name="Intense Reference"/>
- <w:LsdException Locked="false" Priority="33" QFormat="true" Name="Book Title"/>
- <w:LsdException Locked="false" Priority="37" SemiHidden="true"
- UnhideWhenUsed="true" Name="Bibliography"/>
- <w:LsdException Locked="false" Priority="39" SemiHidden="true"
- UnhideWhenUsed="true" QFormat="true" Name="TOC Heading"/>
- </w:LatentStyles>
-</xml><![endif]-->
-
-<style>
-<!--
- /* Font Definitions */
- @font-face
- {font-family:"Cambria Math";
- panose-1:2 4 5 3 5 4 6 3 2 4;
- mso-font-charset:1;
- mso-generic-font-family:roman;
- mso-font-format:other;
- mso-font-pitch:variable;
- mso-font-signature:0 0 0 0 0 0;}
-@font-face
- {font-family:Calibri;
- panose-1:2 15 5 2 2 2 4 3 2 4;
- mso-font-charset:0;
- mso-generic-font-family:swiss;
- mso-font-pitch:variable;
- mso-font-signature:-1610611985 1073750139 0 0 159 0;}
-@font-face
- {font-family:Tahoma;
- panose-1:2 11 6 4 3 5 4 4 2 4;
- mso-font-charset:0;
- mso-generic-font-family:swiss;
- mso-font-pitch:variable;
- mso-font-signature:1627400839 -2147483648 8 0 66047 0;}
-@font-face
- {font-family:Verdana;
- panose-1:2 11 6 4 3 5 4 4 2 4;
- mso-font-charset:0;
- mso-generic-font-family:swiss;
- mso-font-pitch:variable;
- mso-font-signature:536871559 0 0 0 415 0;}
- /* Style Definitions */
- p.MsoNormal, li.MsoNormal, div.MsoNormal
- {mso-style-unhide:no;
- mso-style-qformat:yes;
- mso-style-parent:"";
- margin:0in;
- margin-bottom:.0001pt;
- mso-pagination:widow-orphan;
- font-size:12.0pt;
- font-family:"Times New Roman","serif";
- mso-fareast-font-family:"Times New Roman";}
-h1
- {mso-style-unhide:no;
- mso-style-qformat:yes;
- mso-style-link:"Heading 1 Char";
- mso-margin-top-alt:auto;
- margin-right:0in;
- mso-margin-bottom-alt:auto;
- margin-left:0in;
- mso-pagination:widow-orphan;
- mso-outline-level:1;
- font-size:24.0pt;
- font-family:"Times New Roman","serif";
- mso-fareast-font-family:"Times New Roman";
- mso-fareast-theme-font:minor-fareast;
- font-weight:bold;}
-h2
- {mso-style-unhide:no;
- mso-style-qformat:yes;
- mso-style-link:"Heading 2 Char";
- mso-style-next:Normal;
- margin-top:12.0pt;
- margin-right:0in;
- margin-bottom:3.0pt;
- margin-left:0in;
- mso-pagination:widow-orphan;
- page-break-after:avoid;
- mso-outline-level:2;
- font-size:14.0pt;
- font-family:"Arial","sans-serif";
- mso-fareast-font-family:"Times New Roman";
- mso-fareast-theme-font:minor-fareast;
- font-weight:bold;
- font-style:italic;}
-h3
- {mso-style-unhide:no;
- mso-style-qformat:yes;
- mso-style-link:"Heading 3 Char";
- mso-margin-top-alt:auto;
- margin-right:0in;
- mso-margin-bottom-alt:auto;
- margin-left:0in;
- mso-pagination:widow-orphan;
- mso-outline-level:3;
- font-size:13.5pt;
- font-family:"Times New Roman","serif";
- mso-fareast-font-family:"Times New Roman";
- mso-fareast-theme-font:minor-fareast;
- font-weight:bold;}
-a:link, span.MsoHyperlink
- {mso-style-unhide:no;
- color:blue;
- text-decoration:underline;
- text-underline:single;}
-a:visited, span.MsoHyperlinkFollowed
- {mso-style-unhide:no;
- color:blue;
- text-decoration:underline;
- text-underline:single;}
-p
- {mso-style-unhide:no;
- mso-margin-top-alt:auto;
- margin-right:0in;
- mso-margin-bottom-alt:auto;
- margin-left:0in;
- mso-pagination:widow-orphan;
- font-size:12.0pt;
- font-family:"Times New Roman","serif";
- mso-fareast-font-family:"Times New Roman";}
-p.MsoAcetate, li.MsoAcetate, div.MsoAcetate
- {mso-style-unhide:no;
- mso-style-link:"Balloon Text Char";
- margin:0in;
- margin-bottom:.0001pt;
- mso-pagination:widow-orphan;
- font-size:8.0pt;
- font-family:"Tahoma","sans-serif";
- mso-fareast-font-family:"Times New Roman";}
-span.Heading1Char
- {mso-style-name:"Heading 1 Char";
- mso-style-unhide:no;
- mso-style-locked:yes;
- mso-style-link:"Heading 1";
- mso-ansi-font-size:14.0pt;
- mso-bidi-font-size:14.0pt;
- font-family:"Cambria","serif";
- mso-ascii-font-family:Cambria;
- mso-ascii-theme-font:major-latin;
- mso-fareast-font-family:"Times New Roman";
- mso-fareast-theme-font:major-fareast;
- mso-hansi-font-family:Cambria;
- mso-hansi-theme-font:major-latin;
- mso-bidi-font-family:"Times New Roman";
- mso-bidi-theme-font:major-bidi;
- color:#365F91;
- mso-themecolor:accent1;
- mso-themeshade:191;
- font-weight:bold;}
-span.Heading2Char
- {mso-style-name:"Heading 2 Char";
- mso-style-unhide:no;
- mso-style-locked:yes;
- mso-style-link:"Heading 2";
- mso-ansi-font-size:13.0pt;
- mso-bidi-font-size:13.0pt;
- font-family:"Cambria","serif";
- mso-ascii-font-family:Cambria;
- mso-ascii-theme-font:major-latin;
- mso-fareast-font-family:"Times New Roman";
- mso-fareast-theme-font:major-fareast;
- mso-hansi-font-family:Cambria;
- mso-hansi-theme-font:major-latin;
- mso-bidi-font-family:"Times New Roman";
- mso-bidi-theme-font:major-bidi;
- color:#4F81BD;
- mso-themecolor:accent1;
- font-weight:bold;}
-span.Heading3Char
- {mso-style-name:"Heading 3 Char";
- mso-style-unhide:no;
- mso-style-locked:yes;
- mso-style-link:"Heading 3";
- mso-ansi-font-size:12.0pt;
- mso-bidi-font-size:12.0pt;
- font-family:"Cambria","serif";
- mso-ascii-font-family:Cambria;
- mso-ascii-theme-font:major-latin;
- mso-fareast-font-family:"Times New Roman";
- mso-fareast-theme-font:major-fareast;
- mso-hansi-font-family:Cambria;
- mso-hansi-theme-font:major-latin;
- mso-bidi-font-family:"Times New Roman";
- mso-bidi-theme-font:major-bidi;
- color:#4F81BD;
- mso-themecolor:accent1;
- font-weight:bold;}
-span.BalloonTextChar
- {mso-style-name:"Balloon Text Char";
- mso-style-unhide:no;
- mso-style-locked:yes;
- mso-style-link:"Balloon Text";
- mso-ansi-font-size:8.0pt;
- mso-bidi-font-size:8.0pt;
- font-family:"Tahoma","sans-serif";
- mso-ascii-font-family:Tahoma;
- mso-hansi-font-family:Tahoma;
- mso-bidi-font-family:Tahoma;}
-.MsoChpDefault
- {mso-style-type:export-only;
- mso-default-props:yes;
- font-size:10.0pt;
- mso-ansi-font-size:10.0pt;
- mso-bidi-font-size:10.0pt;}
-@page WordSection1
- {size:8.5in 11.0in;
- margin:1.0in 1.25in 1.0in 1.25in;
- mso-header-margin:.5in;
- mso-footer-margin:.5in;
- mso-paper-source:0;}
-div.WordSection1
- {page:WordSection1;}
- /* List Definitions */
- @list l0
- {mso-list-id:62067358;
- mso-list-template-ids:-174943062;}
-@list l0:level1
- {mso-level-number-format:bullet;
- mso-level-text:\F0B7;
- mso-level-tab-stop:.5in;
- mso-level-number-position:left;
- text-indent:-.25in;
- mso-ansi-font-size:10.0pt;
- font-family:Symbol;}
-@list l0:level2
- {mso-level-tab-stop:1.0in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l0:level3
- {mso-level-tab-stop:1.5in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l0:level4
- {mso-level-tab-stop:2.0in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l0:level5
- {mso-level-tab-stop:2.5in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l0:level6
- {mso-level-tab-stop:3.0in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l0:level7
- {mso-level-tab-stop:3.5in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l0:level8
- {mso-level-tab-stop:4.0in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l0:level9
- {mso-level-tab-stop:4.5in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l1
- {mso-list-id:128015942;
- mso-list-template-ids:-90681214;}
-@list l1:level1
- {mso-level-tab-stop:.5in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l1:level2
- {mso-level-tab-stop:1.0in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l1:level3
- {mso-level-tab-stop:1.5in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l1:level4
- {mso-level-tab-stop:2.0in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l1:level5
- {mso-level-tab-stop:2.5in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l1:level6
- {mso-level-tab-stop:3.0in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l1:level7
- {mso-level-tab-stop:3.5in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l1:level8
- {mso-level-tab-stop:4.0in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l1:level9
- {mso-level-tab-stop:4.5in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l2
- {mso-list-id:216556000;
- mso-list-template-ids:925924412;}
-@list l2:level1
- {mso-level-number-format:bullet;
- mso-level-text:\F0B7;
- mso-level-tab-stop:.5in;
- mso-level-number-position:left;
- text-indent:-.25in;
- mso-ansi-font-size:10.0pt;
- font-family:Symbol;}
-@list l2:level2
- {mso-level-number-format:bullet;
- mso-level-text:\F0B7;
- mso-level-tab-stop:1.0in;
- mso-level-number-position:left;
- text-indent:-.25in;
- mso-ansi-font-size:10.0pt;
- font-family:Symbol;}
-@list l2:level3
- {mso-level-tab-stop:1.5in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l2:level4
- {mso-level-tab-stop:2.0in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l2:level5
- {mso-level-tab-stop:2.5in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l2:level6
- {mso-level-tab-stop:3.0in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l2:level7
- {mso-level-tab-stop:3.5in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l2:level8
- {mso-level-tab-stop:4.0in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l2:level9
- {mso-level-tab-stop:4.5in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l3
- {mso-list-id:562446694;
- mso-list-template-ids:913898366;}
-@list l3:level1
- {mso-level-number-format:bullet;
- mso-level-text:\F0B7;
- mso-level-tab-stop:.5in;
- mso-level-number-position:left;
- text-indent:-.25in;
- mso-ansi-font-size:10.0pt;
- font-family:Symbol;}
-@list l3:level2
- {mso-level-tab-stop:1.0in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l3:level3
- {mso-level-tab-stop:1.5in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l3:level4
- {mso-level-tab-stop:2.0in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l3:level5
- {mso-level-tab-stop:2.5in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l3:level6
- {mso-level-tab-stop:3.0in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l3:level7
- {mso-level-tab-stop:3.5in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l3:level8
- {mso-level-tab-stop:4.0in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l3:level9
- {mso-level-tab-stop:4.5in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l4
- {mso-list-id:797802132;
- mso-list-template-ids:-1971191336;}
-@list l4:level1
- {mso-level-tab-stop:.5in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l4:level2
- {mso-level-tab-stop:1.0in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l4:level3
- {mso-level-tab-stop:1.5in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l4:level4
- {mso-level-tab-stop:2.0in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l4:level5
- {mso-level-tab-stop:2.5in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l4:level6
- {mso-level-tab-stop:3.0in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l4:level7
- {mso-level-tab-stop:3.5in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l4:level8
- {mso-level-tab-stop:4.0in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l4:level9
- {mso-level-tab-stop:4.5in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l5
- {mso-list-id:907304066;
- mso-list-template-ids:1969781532;}
-@list l5:level1
- {mso-level-tab-stop:.5in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l5:level2
- {mso-level-tab-stop:1.0in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l5:level3
- {mso-level-tab-stop:1.5in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l5:level4
- {mso-level-tab-stop:2.0in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l5:level5
- {mso-level-tab-stop:2.5in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l5:level6
- {mso-level-tab-stop:3.0in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l5:level7
- {mso-level-tab-stop:3.5in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l5:level8
- {mso-level-tab-stop:4.0in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l5:level9
- {mso-level-tab-stop:4.5in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l6
- {mso-list-id:1050613616;
- mso-list-template-ids:-1009886748;}
-@list l6:level1
- {mso-level-number-format:bullet;
- mso-level-text:\F0B7;
- mso-level-tab-stop:.5in;
- mso-level-number-position:left;
- text-indent:-.25in;
- mso-ansi-font-size:10.0pt;
- font-family:Symbol;}
-@list l6:level2
- {mso-level-number-format:bullet;
- mso-level-text:\F0B7;
- mso-level-tab-stop:1.0in;
- mso-level-number-position:left;
- text-indent:-.25in;
- mso-ansi-font-size:10.0pt;
- font-family:Symbol;}
-@list l6:level3
- {mso-level-tab-stop:1.5in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l6:level4
- {mso-level-tab-stop:2.0in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l6:level5
- {mso-level-tab-stop:2.5in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l6:level6
- {mso-level-tab-stop:3.0in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l6:level7
- {mso-level-tab-stop:3.5in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l6:level8
- {mso-level-tab-stop:4.0in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l6:level9
- {mso-level-tab-stop:4.5in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l7
- {mso-list-id:1234970193;
- mso-list-template-ids:2055904002;}
-@list l7:level1
- {mso-level-number-format:bullet;
- mso-level-text:\F0B7;
- mso-level-tab-stop:.5in;
- mso-level-number-position:left;
- text-indent:-.25in;
- mso-ansi-font-size:10.0pt;
- font-family:Symbol;}
-@list l7:level2
- {mso-level-number-format:bullet;
- mso-level-text:\F0B7;
- mso-level-tab-stop:1.0in;
- mso-level-number-position:left;
- text-indent:-.25in;
- mso-ansi-font-size:10.0pt;
- font-family:Symbol;}
-@list l7:level3
- {mso-level-tab-stop:1.5in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l7:level4
- {mso-level-tab-stop:2.0in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l7:level5
- {mso-level-tab-stop:2.5in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l7:level6
- {mso-level-tab-stop:3.0in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l7:level7
- {mso-level-tab-stop:3.5in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l7:level8
- {mso-level-tab-stop:4.0in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l7:level9
- {mso-level-tab-stop:4.5in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l8
- {mso-list-id:1846092290;
- mso-list-template-ids:-768590846;}
-@list l8:level1
- {mso-level-start-at:2;
- mso-level-tab-stop:.5in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l8:level2
- {mso-level-tab-stop:1.0in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l8:level3
- {mso-level-tab-stop:1.5in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l8:level4
- {mso-level-tab-stop:2.0in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l8:level5
- {mso-level-tab-stop:2.5in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l8:level6
- {mso-level-tab-stop:3.0in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l8:level7
- {mso-level-tab-stop:3.5in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l8:level8
- {mso-level-tab-stop:4.0in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l8:level9
- {mso-level-tab-stop:4.5in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l9
- {mso-list-id:1894656566;
- mso-list-template-ids:1199983812;}
-@list l9:level1
- {mso-level-start-at:2;
- mso-level-tab-stop:.5in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l9:level2
- {mso-level-tab-stop:1.0in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l9:level3
- {mso-level-tab-stop:1.5in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l9:level4
- {mso-level-tab-stop:2.0in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l9:level5
- {mso-level-tab-stop:2.5in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l9:level6
- {mso-level-tab-stop:3.0in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l9:level7
- {mso-level-tab-stop:3.5in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l9:level8
- {mso-level-tab-stop:4.0in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l9:level9
- {mso-level-tab-stop:4.5in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-ol
- {margin-bottom:0in;}
-ul
- {margin-bottom:0in;}
--->
-</style><!--[if gte mso 10]>
-<style>
- /* Style Definitions */
- table.MsoNormalTable
- {mso-style-name:"Table Normal";
- mso-tstyle-rowband-size:0;
- mso-tstyle-colband-size:0;
- mso-style-noshow:yes;
- mso-style-priority:99;
- mso-style-qformat:yes;
- mso-style-parent:"";
- mso-padding-alt:0in 5.4pt 0in 5.4pt;
- mso-para-margin:0in;
- mso-para-margin-bottom:.0001pt;
- mso-pagination:widow-orphan;
- font-size:10.0pt;
- font-family:"Times New Roman","serif";}
-</style>
-<![endif]--><!--[if gte mso 9]><xml>
- <o:shapedefaults v:ext="edit" spidmax="7170"/>
-</xml><![endif]--><!--[if gte mso 9]><xml>
- <o:shapelayout v:ext="edit">
- <o:idmap v:ext="edit" data="1"/>
- </o:shapelayout></xml><![endif]--><meta content="MCD Application Team" name="author"></head><body style="" link="blue" vlink="blue">
-
-<div class="WordSection1">
-
-<p class="MsoNormal"><span style="font-family: &quot;Arial&quot;,&quot;sans-serif&quot;;"><o:p>&nbsp;</o:p></span></p>
-
-<div align="center">
-
-<table class="MsoNormalTable" style="width: 675pt;" border="0" cellpadding="0" cellspacing="0" width="900">
- <tbody><tr style="">
- <td style="padding: 0in;" valign="top">
- <table class="MsoNormalTable" style="width: 675pt;" border="0" cellpadding="0" cellspacing="0" width="900">
- <tbody><tr style="">
- <td style="padding: 0in 5.4pt;" valign="top">
- <p class="MsoNormal"><span style="font-size: 8pt; font-family: &quot;Arial&quot;,&quot;sans-serif&quot;; color: blue;"><a href="../../../Release_Notes.html">Back to Release page</a></span><span style="font-size: 10pt;"><o:p></o:p></span></p>
- </td>
- </tr>
- <tr style="">
- <td style="padding: 1.5pt;">
- <h1 style="margin-bottom: 0.25in; text-align: center;" align="center"><span style="font-size: 20pt; font-family: &quot;Verdana&quot;,&quot;sans-serif&quot;; color: rgb(51, 102, 255);">Release Notes for STM32 USB Device Library</span><span style="font-size: 20pt; font-family: &quot;Verdana&quot;,&quot;sans-serif&quot;;"><o:p></o:p></span></h1>
- <p class="MsoNormal" style="text-align: center;" align="center"><span style="font-size: 10pt; font-family: &quot;Arial&quot;,&quot;sans-serif&quot;; color: black;">Copyright
- 2014 STMicroelectronics</span><span style="color: black;"><u1:p></u1:p><o:p></o:p></span></p>
- <p class="MsoNormal" style="text-align: center;" align="center"><span style="font-size: 10pt; font-family: &quot;Arial&quot;,&quot;sans-serif&quot;; color: black;"><img style="border: 0px solid ; width: 86px; height: 65px;" alt="" id="_x0000_i1026" src="../../../_htmresc/st_logo.png"></span><span style="font-size: 10pt;"><o:p></o:p></span></p>
- </td>
- </tr>
- </tbody></table>
- <p class="MsoNormal"><span style="font-family: &quot;Arial&quot;,&quot;sans-serif&quot;; display: none;"><o:p>&nbsp;</o:p></span></p>
- <table class="MsoNormalTable" style="width: 675pt;" border="0" cellpadding="0" width="900">
- <tbody><tr style="">
- <td style="padding: 0in;" valign="top">
- <h2 style="background: rgb(51, 102, 255) none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;"><a name="History"></a><span style="font-size: 12pt; color: white;">Update History</span></h2>
- <h3 style="background: rgb(51, 102, 255) none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-right: 500pt; width: 180px;"><span style="font-size: 10pt; font-family: Arial; color: white;">V2.0.0 / 18-February-2014</span></h3>
-
-
-
-
-
- <p class="MsoNormal" style="margin: 4.5pt 0cm 4.5pt 18pt;"><b style=""><u><span style="font-size: 10pt; font-family: Verdana; color: black;">Main
-Changes</span></u></b><u><span style="font-size: 10pt; font-family: Verdana; color: black;"><o:p></o:p></span></u></p>
-
-
-
-
-
-
-
-
-
- <ul style="margin-top: 0cm;" type="square">
-<li><span style="font-size: 10pt; font-family: Verdana;">Major update
-based on STM32Cube specification: Library Core, Classes architecture and APIs
-modified vs. V1.1.0, and thus the 2 versions are not compatible.<br>
-</span></li><li style="font-weight: bold;"><span style="font-size: 10pt; font-family: Verdana;">This version has to be used only with </span><span style="font-size: 10pt; font-family: Verdana;">STM32Cube</span><span style="font-size: 10pt; font-family: Verdana;"> based development</span></li>
- </ul>
-
-
-<h3 style="background: rgb(51, 102, 255) none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-right: 500pt; width: 200px;"><span style="font-size: 10pt; font-family: Arial; color: white;">V1.1.0 / 19-March-2012<o:p></o:p></span></h3>
- <p class="MsoNormal" style="margin: 4.5pt 0cm 4.5pt 18pt;"><b style=""><u><span style="font-size: 10pt; font-family: Verdana; color: black;">Main
-Changes<o:p></o:p></span></u></b></p>
-
- <ul style="margin-top: 0cm;" type="square"><li class="MsoNormal" style="color: black; margin-top: 4.5pt; margin-bottom: 4.5pt;"><span style="font-size: 10pt; font-family: Verdana;">Official support of </span><span style="font-size: 10pt; font-family: Verdana;"><span style="font-weight: bold; font-style: italic;">STM32F4xx</span> devices</span></li><li class="MsoNormal" style="color: black; margin-top: 4.5pt; margin-bottom: 4.5pt;"><span style="font-size: 10pt; font-family: Verdana;">All source files: license disclaimer text update and add link to the License file on ST Internet.<br></span></li><li class="MsoNormal" style="color: black; margin-top: 4.5pt; margin-bottom: 4.5pt;"><span style="font-size: 10pt; font-family: Verdana;">Handle test mode in the set feature request</span></li><li class="MsoNormal" style="color: black; margin-top: 4.5pt; margin-bottom: 4.5pt;"><span style="font-size: 10pt; font-family: Verdana;">Handle dynamically the USB SELF POWERED feature</span></li><li class="MsoNormal" style="color: black; margin-top: 4.5pt; margin-bottom: 4.5pt;"><span style="font-size: 10pt; font-family: Verdana;">Handle correctly the USBD_CtlError process to take into account error during Control OUT stage</span></li><li class="MsoNormal" style="color: black; margin-top: 4.5pt; margin-bottom: 4.5pt;"><span style="font-size: 10pt; font-family: Verdana;">Miscellaneous bug fix</span></li></ul><h3 style="background: rgb(51, 102, 255) none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-right: 500pt; width: 171px;"><span style="font-size: 10pt; font-family: Arial; color: white;">V1.0.0 / 22-July-2011<o:p></o:p></span></h3><p class="MsoNormal" style="margin: 4.5pt 0cm 4.5pt 18pt;"><b style=""><u><span style="font-size: 10pt; font-family: Verdana; color: black;">Main
-Changes<o:p></o:p></span></u></b></p>
-<ul style="margin-top: 0cm;" type="square"><li class="MsoNormal" style="color: black; margin-top: 4.5pt; margin-bottom: 4.5pt;"><span style="font-size: 10pt; font-family: Verdana;">First official version for <span style="font-weight: bold; font-style: italic;">STM32F105/7xx</span> and <span style="font-weight: bold; font-style: italic;">STM32F2xx</span> devices</span></li></ul><span style="font-size: 10pt; font-family: Verdana;"></span><br><span style="font-size: 10pt; font-family: &quot;Verdana&quot;,&quot;sans-serif&quot;;"></span>
- <h2 style="background: rgb(51, 102, 255) none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;"><a name="License"></a><span style="font-size: 12pt; color: white;">License<o:p></o:p></span></h2>
- <p class="MsoNormal"><span style="font-size: 10pt; font-family: &quot;Verdana&quot;,&quot;sans-serif&quot;; color: black;">Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); You may not use this&nbsp;</span><span style="font-size: 10pt; font-family: &quot;Verdana&quot;,&quot;sans-serif&quot;; color: black;">package</span><span style="font-size: 10pt; font-family: &quot;Verdana&quot;,&quot;sans-serif&quot;; color: black;"> except in compliance with the License. You may obtain a copy of the License at:<br><br></span></p><div style="text-align: center;"><span style="font-size: 10pt; font-family: &quot;Verdana&quot;,&quot;sans-serif&quot;; color: black;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <a target="_blank" href="http://www.st.com/software_license_agreement_liberty_v2">http://www.st.com/software_license_agreement_liberty_v2</a></span><br><span style="font-size: 10pt; font-family: &quot;Verdana&quot;,&quot;sans-serif&quot;; color: black;"></span></div><span style="font-size: 10pt; font-family: &quot;Verdana&quot;,&quot;sans-serif&quot;; color: black;"><br>Unless
-required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS, <br>WITHOUT
-WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See
-the License for the specific language governing permissions and
-limitations under the License.</span>
- <div class="MsoNormal" style="text-align: center;" align="center"><span style="color: black;">
- <hr align="center" size="2" width="100%">
- </span></div>
- <p class="MsoNormal" style="margin: 4.5pt 0in 4.5pt 0.25in; text-align: center;" align="center"><span style="font-size: 10pt; font-family: &quot;Verdana&quot;,&quot;sans-serif&quot;; color: black;">For
- complete documentation on </span><span style="font-size: 10pt; font-family: &quot;Verdana&quot;,&quot;sans-serif&quot;;">STM32<span style="color: black;">
- Microcontrollers visit </span><u><span style="color: blue;"><a href="http://www.st.com/internet/mcu/family/141.jsp" target="_blank">www.st.com/STM32</a></span></u></span><span style="font-size: 10pt; font-family: &quot;Verdana&quot;,&quot;sans-serif&quot;;"><u><span style="color: blue;"><a href="http://www.st.com/stm32" target="_blank"></a></span></u></span><span style="color: black;"><o:p></o:p></span></p>
- </td>
- </tr>
- </tbody></table>
- <p class="MsoNormal"><span style="font-size: 10pt;"><o:p></o:p></span></p>
- </td>
- </tr>
-</tbody></table>
-
-</div>
-
-<p class="MsoNormal"><o:p>&nbsp;</o:p></p>
-
-</div>
-
-</body></html> \ No newline at end of file
diff --git a/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid.h b/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid.h
index a26b1df0d..a4f81f10d 100644
--- a/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid.h
+++ b/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid.h
@@ -6,12 +6,36 @@
#include "usbd_msc_scsi.h"
#include "usbd_ioreq.h"
+// These are included to get direct access the MICROPY_HW_USB_xxx config
+#include "mpconfigboard.h"
+#include "mpconfigboard_common.h"
+
+// Work out if we should support USB high-speed device mode
+#if MICROPY_HW_USB_HS \
+ && (!MICROPY_HW_USB_HS_IN_FS || defined(STM32F723xx) || defined(STM32F733xx))
+#define USBD_SUPPORT_HS_MODE (1)
+#else
+#define USBD_SUPPORT_HS_MODE (0)
+#endif
+
// Needed for the CDC+MSC+HID state and should be maximum of all template
// config descriptors defined in usbd_cdc_msc_hid.c
+#if MICROPY_HW_USB_ENABLE_CDC2
+#define MAX_TEMPLATE_CONFIG_DESC_SIZE (9 + 23 + (8 + 58) + (8 + 58))
+#else
#define MAX_TEMPLATE_CONFIG_DESC_SIZE (107)
+#endif
// CDC, MSC and HID packet sizes
+#define MSC_FS_MAX_PACKET (64)
+#define MSC_HS_MAX_PACKET (512)
#define CDC_DATA_FS_MAX_PACKET_SIZE (64) // endpoint IN & OUT packet size
+#define CDC_DATA_HS_MAX_PACKET_SIZE (512) // endpoint IN & OUT packet size
+#if USBD_SUPPORT_HS_MODE
+#define CDC_DATA_MAX_PACKET_SIZE CDC_DATA_HS_MAX_PACKET_SIZE
+#else
+#define CDC_DATA_MAX_PACKET_SIZE CDC_DATA_FS_MAX_PACKET_SIZE
+#endif
#define MSC_MEDIA_PACKET (2048) // was 8192; how low can it go whilst still working?
#define HID_DATA_FS_MAX_PACKET_SIZE (64) // endpoint IN & OUT packet size
@@ -19,26 +43,18 @@
#define MSC_IN_EP (0x81)
#define MSC_OUT_EP (0x01)
-// Need to define here for usbd_cdc_interface.c (it needs CDC_IN_EP)
-#define CDC_IN_EP (0x83)
-#define CDC_OUT_EP (0x03)
-#define CDC_CMD_EP (0x82)
-
-typedef struct {
- uint32_t bitrate;
- uint8_t format;
- uint8_t paritytype;
- uint8_t datatype;
-} USBD_CDC_LineCodingTypeDef;
+struct _usbd_cdc_msc_hid_state_t;
typedef struct {
- uint32_t data[CDC_DATA_FS_MAX_PACKET_SIZE/4]; /* Force 32bits alignment */
- uint8_t CmdOpCode;
- uint8_t CmdLength;
-
- __IO uint32_t TxState;
- __IO uint32_t RxState;
-} USBD_CDC_HandleTypeDef;
+ struct _usbd_cdc_msc_hid_state_t *usbd; // The parent USB device
+ uint32_t ctl_packet_buf[CDC_DATA_MAX_PACKET_SIZE / 4]; // Force 32-bit alignment
+ uint8_t iface_num;
+ uint8_t in_ep;
+ uint8_t out_ep;
+ uint8_t cur_request;
+ uint8_t cur_length;
+ volatile uint8_t tx_in_progress;
+} usbd_cdc_state_t;
typedef struct _USBD_STORAGE {
int8_t (* Init) (uint8_t lun);
@@ -83,35 +99,36 @@ typedef enum {
} HID_StateTypeDef;
typedef struct {
- uint32_t Protocol;
- uint32_t IdleState;
- uint32_t AltSetting;
- HID_StateTypeDef state;
-} USBD_HID_HandleTypeDef;
+ struct _usbd_cdc_msc_hid_state_t *usbd; // The parent USB device
+ uint8_t iface_num;
+ uint8_t in_ep;
+ uint8_t out_ep;
+ uint8_t state;
+ uint8_t ctl_protocol;
+ uint8_t ctl_idle_state;
+ uint8_t ctl_alt_setting;
+ uint8_t *desc;
+ const uint8_t *report_desc;
+} usbd_hid_state_t;
typedef struct _usbd_cdc_msc_hid_state_t {
USBD_HandleTypeDef *pdev;
uint8_t usbd_mode;
- uint8_t cdc_iface_num;
- uint8_t hid_in_ep;
- uint8_t hid_out_ep;
- uint8_t hid_iface_num;
uint8_t usbd_config_desc_size;
- uint8_t *hid_desc;
- const uint8_t *hid_report_desc;
- USBD_CDC_HandleTypeDef CDC_ClassData;
USBD_MSC_BOT_HandleTypeDef MSC_BOT_ClassData;
- USBD_HID_HandleTypeDef HID_ClassData;
// RAM to hold the current descriptors, which we configure on the fly
__ALIGN_BEGIN uint8_t usbd_device_desc[USB_LEN_DEV_DESC] __ALIGN_END;
__ALIGN_BEGIN uint8_t usbd_str_desc[USBD_MAX_STR_DESC_SIZ] __ALIGN_END;
__ALIGN_BEGIN uint8_t usbd_config_desc[MAX_TEMPLATE_CONFIG_DESC_SIZE] __ALIGN_END;
- void *cdc;
- void *hid;
+ usbd_cdc_state_t *cdc;
+ #if MICROPY_HW_USB_ENABLE_CDC2
+ usbd_cdc_state_t *cdc2;
+ #endif
+ usbd_hid_state_t *hid;
} usbd_cdc_msc_hid_state_t;
#define USBD_HID_MOUSE_MAX_PACKET (4)
@@ -126,33 +143,53 @@ extern const uint8_t USBD_HID_KEYBOARD_ReportDesc[USBD_HID_KEYBOARD_REPORT_DESC_
extern const USBD_ClassTypeDef USBD_CDC_MSC_HID;
+static inline uint32_t usbd_msc_max_packet(USBD_HandleTypeDef *pdev) {
+ #if USBD_SUPPORT_HS_MODE
+ if (pdev->dev_speed == USBD_SPEED_HIGH) {
+ return MSC_HS_MAX_PACKET;
+ } else
+ #endif
+ {
+ return MSC_FS_MAX_PACKET;
+ }
+}
+
+static inline uint32_t usbd_cdc_max_packet(USBD_HandleTypeDef *pdev) {
+ #if USBD_SUPPORT_HS_MODE
+ if (pdev->dev_speed == USBD_SPEED_HIGH) {
+ return CDC_DATA_HS_MAX_PACKET_SIZE;
+ } else
+ #endif
+ {
+ return CDC_DATA_FS_MAX_PACKET_SIZE;
+ }
+}
+
// returns 0 on success, -1 on failure
int USBD_SelectMode(usbd_cdc_msc_hid_state_t *usbd, uint32_t mode, USBD_HID_ModeInfoTypeDef *hid_info);
// returns the current usb mode
uint8_t USBD_GetMode(usbd_cdc_msc_hid_state_t *usbd);
-uint8_t USBD_CDC_ReceivePacket(usbd_cdc_msc_hid_state_t *usbd, uint8_t *buf);
-uint8_t USBD_CDC_TransmitPacket(usbd_cdc_msc_hid_state_t *usbd, size_t len, const uint8_t *buf);
+uint8_t USBD_CDC_ReceivePacket(usbd_cdc_state_t *cdc, uint8_t *buf);
+uint8_t USBD_CDC_TransmitPacket(usbd_cdc_state_t *cdc, size_t len, const uint8_t *buf);
static inline void USBD_MSC_RegisterStorage(usbd_cdc_msc_hid_state_t *usbd, USBD_StorageTypeDef *fops) {
usbd->MSC_BOT_ClassData.bdev_ops = fops;
}
-uint8_t USBD_HID_ReceivePacket(usbd_cdc_msc_hid_state_t *usbd, uint8_t *buf);
-int USBD_HID_CanSendReport(usbd_cdc_msc_hid_state_t *usbd);
-uint8_t USBD_HID_SendReport(usbd_cdc_msc_hid_state_t *usbd, uint8_t *report, uint16_t len);
-uint8_t USBD_HID_SetNAK(usbd_cdc_msc_hid_state_t *usbd);
-uint8_t USBD_HID_ClearNAK(usbd_cdc_msc_hid_state_t *usbd);
+uint8_t USBD_HID_ReceivePacket(usbd_hid_state_t *usbd, uint8_t *buf);
+int USBD_HID_CanSendReport(usbd_hid_state_t *usbd);
+uint8_t USBD_HID_SendReport(usbd_hid_state_t *usbd, uint8_t *report, uint16_t len);
+uint8_t USBD_HID_SetNAK(usbd_hid_state_t *usbd);
+uint8_t USBD_HID_ClearNAK(usbd_hid_state_t *usbd);
// These are provided externally to implement the CDC interface
-struct _usbd_cdc_itf_t;
-uint8_t *usbd_cdc_init(struct _usbd_cdc_itf_t *cdc, usbd_cdc_msc_hid_state_t *usbd);
-int8_t usbd_cdc_control(struct _usbd_cdc_itf_t *cdc, uint8_t cmd, uint8_t* pbuf, uint16_t length);
-int8_t usbd_cdc_receive(struct _usbd_cdc_itf_t *cdc, size_t len);
+uint8_t *usbd_cdc_init(usbd_cdc_state_t *cdc);
+int8_t usbd_cdc_control(usbd_cdc_state_t *cdc, uint8_t cmd, uint8_t* pbuf, uint16_t length);
+int8_t usbd_cdc_receive(usbd_cdc_state_t *cdc, size_t len);
// These are provided externally to implement the HID interface
-struct _usbd_hid_itf_t;
-uint8_t *usbd_hid_init(struct _usbd_hid_itf_t *hid, usbd_cdc_msc_hid_state_t *usbd);
-int8_t usbd_hid_receive(struct _usbd_hid_itf_t *hid, size_t len);
+uint8_t *usbd_hid_init(usbd_hid_state_t *hid);
+int8_t usbd_hid_receive(usbd_hid_state_t *hid, size_t len);
#endif // _USB_CDC_MSC_CORE_H_
diff --git a/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid0.h b/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid0.h
index 08882bb1a..c876dcf29 100644
--- a/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid0.h
+++ b/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid0.h
@@ -23,8 +23,8 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
-#ifndef MICROPY_INCLUDED_STMHAL_USBDEV_CLASS_INC_USBD_CDC_MSC_HID0_H
-#define MICROPY_INCLUDED_STMHAL_USBDEV_CLASS_INC_USBD_CDC_MSC_HID0_H
+#ifndef MICROPY_INCLUDED_STM32_USBDEV_CLASS_INC_USBD_CDC_MSC_HID0_H
+#define MICROPY_INCLUDED_STM32_USBDEV_CLASS_INC_USBD_CDC_MSC_HID0_H
// these are exports for the CDC/MSC/HID interface that are independent
// from any other definitions/declarations
@@ -34,9 +34,12 @@ typedef enum {
USBD_MODE_CDC = 0x01,
USBD_MODE_MSC = 0x02,
USBD_MODE_HID = 0x04,
- USBD_MODE_CDC_MSC = 0x03,
- USBD_MODE_CDC_HID = 0x05,
- USBD_MODE_MSC_HID = 0x06,
+ USBD_MODE_CDC2 = 0x08,
+ USBD_MODE_CDC_MSC = USBD_MODE_CDC | USBD_MODE_MSC,
+ USBD_MODE_CDC_HID = USBD_MODE_CDC | USBD_MODE_HID,
+ USBD_MODE_MSC_HID = USBD_MODE_MSC | USBD_MODE_HID,
+ USBD_MODE_CDC2_MSC = USBD_MODE_CDC | USBD_MODE_MSC | USBD_MODE_CDC2,
+ USBD_MODE_HIGH_SPEED = 0x80, // or with one of the above
} usb_device_mode_t;
typedef struct _USBD_HID_ModeInfoTypeDef {
@@ -48,4 +51,4 @@ typedef struct _USBD_HID_ModeInfoTypeDef {
const uint8_t *report_desc;
} USBD_HID_ModeInfoTypeDef;
-#endif // MICROPY_INCLUDED_STMHAL_USBDEV_CLASS_INC_USBD_CDC_MSC_HID0_H
+#endif // MICROPY_INCLUDED_STM32_USBDEV_CLASS_INC_USBD_CDC_MSC_HID0_H
diff --git a/ports/stm32/usbdev/class/inc/usbd_msc_bot.h b/ports/stm32/usbdev/class/inc/usbd_msc_bot.h
index 41f8ab5a5..4edc912fe 100644
--- a/ports/stm32/usbdev/class/inc/usbd_msc_bot.h
+++ b/ports/stm32/usbdev/class/inc/usbd_msc_bot.h
@@ -1,151 +1,151 @@
-/**
- ******************************************************************************
- * @file usbd_msc_bot.h
- * @author MCD Application Team
- * @version V2.0.0
- * @date 18-February-2014
- * @brief header for the usbd_msc_bot.c file
- ******************************************************************************
- * @attention
- *
- * <h2><center>&copy; COPYRIGHT 2014 STMicroelectronics</center></h2>
- *
- * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
- * You may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.st.com/software_license_agreement_liberty_v2
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- ******************************************************************************
- */
-
-/* Define to prevent recursive inclusion -------------------------------------*/
-
-#include "usbd_core.h"
-
-/* Define to prevent recursive inclusion -------------------------------------*/
-#ifndef __USBD_MSC_BOT_H
-#define __USBD_MSC_BOT_H
-
-/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY
- * @{
- */
-
-/** @defgroup MSC_BOT
- * @brief This file is the Header file for usbd_bot.c
- * @{
- */
-
-
-/** @defgroup USBD_CORE_Exported_Defines
- * @{
- */
-#define USBD_BOT_IDLE 0 /* Idle state */
-#define USBD_BOT_DATA_OUT 1 /* Data Out state */
-#define USBD_BOT_DATA_IN 2 /* Data In state */
-#define USBD_BOT_LAST_DATA_IN 3 /* Last Data In Last */
-#define USBD_BOT_SEND_DATA 4 /* Send Immediate data */
-#define USBD_BOT_NO_DATA 5 /* No data Stage */
-
-#define USBD_BOT_CBW_SIGNATURE 0x43425355
-#define USBD_BOT_CSW_SIGNATURE 0x53425355
-#define USBD_BOT_CBW_LENGTH 31
-#define USBD_BOT_CSW_LENGTH 13
-#define USBD_BOT_MAX_DATA 256
-
-/* CSW Status Definitions */
-#define USBD_CSW_CMD_PASSED 0x00
-#define USBD_CSW_CMD_FAILED 0x01
-#define USBD_CSW_PHASE_ERROR 0x02
-
-/* BOT Status */
-#define USBD_BOT_STATUS_NORMAL 0
-#define USBD_BOT_STATUS_RECOVERY 1
-#define USBD_BOT_STATUS_ERROR 2
-
-
-#define USBD_DIR_IN 0
-#define USBD_DIR_OUT 1
-#define USBD_BOTH_DIR 2
-
-/**
- * @}
- */
-
-/** @defgroup MSC_CORE_Private_TypesDefinitions
- * @{
- */
-
-typedef struct
-{
- uint32_t dSignature;
- uint32_t dTag;
- uint32_t dDataLength;
- uint8_t bmFlags;
- uint8_t bLUN;
- uint8_t bCBLength;
- uint8_t CB[16];
- uint8_t ReservedForAlign;
-}
-USBD_MSC_BOT_CBWTypeDef;
-
-
-typedef struct
-{
- uint32_t dSignature;
- uint32_t dTag;
- uint32_t dDataResidue;
- uint8_t bStatus;
- uint8_t ReservedForAlign[3];
-}
-USBD_MSC_BOT_CSWTypeDef;
-
-/**
- * @}
- */
-
-
-/** @defgroup USBD_CORE_Exported_Types
- * @{
- */
-
-/**
- * @}
- */
-/** @defgroup USBD_CORE_Exported_FunctionsPrototypes
- * @{
- */
-void MSC_BOT_Init (USBD_HandleTypeDef *pdev);
-void MSC_BOT_Reset (USBD_HandleTypeDef *pdev);
-void MSC_BOT_DeInit (USBD_HandleTypeDef *pdev);
-void MSC_BOT_DataIn (USBD_HandleTypeDef *pdev,
- uint8_t epnum);
-
-void MSC_BOT_DataOut (USBD_HandleTypeDef *pdev,
- uint8_t epnum);
-
-void MSC_BOT_SendCSW (USBD_HandleTypeDef *pdev,
- uint8_t CSW_Status);
-
-void MSC_BOT_CplClrFeature (USBD_HandleTypeDef *pdev,
- uint8_t epnum);
-/**
- * @}
- */
-
-#endif /* __USBD_MSC_BOT_H */
-/**
- * @}
- */
-
-/**
-* @}
-*/
-/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
-
+/**
+ ******************************************************************************
+ * @file usbd_msc_bot.h
+ * @author MCD Application Team
+ * @version V2.0.0
+ * @date 18-February-2014
+ * @brief header for the usbd_msc_bot.c file
+ ******************************************************************************
+ * @attention
+ *
+ * <h2><center>&copy; COPYRIGHT 2014 STMicroelectronics</center></h2>
+ *
+ * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
+ * You may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.st.com/software_license_agreement_liberty_v2
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************
+ */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+
+#include "usbd_core.h"
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __USBD_MSC_BOT_H
+#define __USBD_MSC_BOT_H
+
+/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY
+ * @{
+ */
+
+/** @defgroup MSC_BOT
+ * @brief This file is the Header file for usbd_bot.c
+ * @{
+ */
+
+
+/** @defgroup USBD_CORE_Exported_Defines
+ * @{
+ */
+#define USBD_BOT_IDLE 0 /* Idle state */
+#define USBD_BOT_DATA_OUT 1 /* Data Out state */
+#define USBD_BOT_DATA_IN 2 /* Data In state */
+#define USBD_BOT_LAST_DATA_IN 3 /* Last Data In Last */
+#define USBD_BOT_SEND_DATA 4 /* Send Immediate data */
+#define USBD_BOT_NO_DATA 5 /* No data Stage */
+
+#define USBD_BOT_CBW_SIGNATURE 0x43425355
+#define USBD_BOT_CSW_SIGNATURE 0x53425355
+#define USBD_BOT_CBW_LENGTH 31
+#define USBD_BOT_CSW_LENGTH 13
+#define USBD_BOT_MAX_DATA 256
+
+/* CSW Status Definitions */
+#define USBD_CSW_CMD_PASSED 0x00
+#define USBD_CSW_CMD_FAILED 0x01
+#define USBD_CSW_PHASE_ERROR 0x02
+
+/* BOT Status */
+#define USBD_BOT_STATUS_NORMAL 0
+#define USBD_BOT_STATUS_RECOVERY 1
+#define USBD_BOT_STATUS_ERROR 2
+
+
+#define USBD_DIR_IN 0
+#define USBD_DIR_OUT 1
+#define USBD_BOTH_DIR 2
+
+/**
+ * @}
+ */
+
+/** @defgroup MSC_CORE_Private_TypesDefinitions
+ * @{
+ */
+
+typedef struct
+{
+ uint32_t dSignature;
+ uint32_t dTag;
+ uint32_t dDataLength;
+ uint8_t bmFlags;
+ uint8_t bLUN;
+ uint8_t bCBLength;
+ uint8_t CB[16];
+ uint8_t ReservedForAlign;
+}
+USBD_MSC_BOT_CBWTypeDef;
+
+
+typedef struct
+{
+ uint32_t dSignature;
+ uint32_t dTag;
+ uint32_t dDataResidue;
+ uint8_t bStatus;
+ uint8_t ReservedForAlign[3];
+}
+USBD_MSC_BOT_CSWTypeDef;
+
+/**
+ * @}
+ */
+
+
+/** @defgroup USBD_CORE_Exported_Types
+ * @{
+ */
+
+/**
+ * @}
+ */
+/** @defgroup USBD_CORE_Exported_FunctionsPrototypes
+ * @{
+ */
+void MSC_BOT_Init (USBD_HandleTypeDef *pdev);
+void MSC_BOT_Reset (USBD_HandleTypeDef *pdev);
+void MSC_BOT_DeInit (USBD_HandleTypeDef *pdev);
+void MSC_BOT_DataIn (USBD_HandleTypeDef *pdev,
+ uint8_t epnum);
+
+void MSC_BOT_DataOut (USBD_HandleTypeDef *pdev,
+ uint8_t epnum);
+
+void MSC_BOT_SendCSW (USBD_HandleTypeDef *pdev,
+ uint8_t CSW_Status);
+
+void MSC_BOT_CplClrFeature (USBD_HandleTypeDef *pdev,
+ uint8_t epnum);
+/**
+ * @}
+ */
+
+#endif /* __USBD_MSC_BOT_H */
+/**
+ * @}
+ */
+
+/**
+* @}
+*/
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
+
diff --git a/ports/stm32/usbdev/class/inc/usbd_msc_data.h b/ports/stm32/usbdev/class/inc/usbd_msc_data.h
index f468267f4..afd39e4f0 100644
--- a/ports/stm32/usbdev/class/inc/usbd_msc_data.h
+++ b/ports/stm32/usbdev/class/inc/usbd_msc_data.h
@@ -1,104 +1,104 @@
-/**
- ******************************************************************************
- * @file usbd_msc_data.h
- * @author MCD Application Team
- * @version V2.0.0
- * @date 18-February-2014
- * @brief header for the usbd_msc_data.c file
- ******************************************************************************
- * @attention
- *
- * <h2><center>&copy; COPYRIGHT 2014 STMicroelectronics</center></h2>
- *
- * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
- * You may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.st.com/software_license_agreement_liberty_v2
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- ******************************************************************************
- */
-
-/* Define to prevent recursive inclusion -------------------------------------*/
-
-#ifndef _USBD_MSC_DATA_H_
-#define _USBD_MSC_DATA_H_
-
-/* Includes ------------------------------------------------------------------*/
-#include "usbd_conf.h"
-
-/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY
- * @{
- */
-
-/** @defgroup USB_INFO
- * @brief general defines for the usb device library file
- * @{
- */
-
-/** @defgroup USB_INFO_Exported_Defines
- * @{
- */
-#define MODE_SENSE6_LEN 8
-#define MODE_SENSE10_LEN 8
-#define LENGTH_INQUIRY_PAGE00 7
-#define LENGTH_FORMAT_CAPACITIES 20
-
-/**
- * @}
- */
-
-
-/** @defgroup USBD_INFO_Exported_TypesDefinitions
- * @{
- */
-/**
- * @}
- */
-
-
-
-/** @defgroup USBD_INFO_Exported_Macros
- * @{
- */
-
-/**
- * @}
- */
-
-/** @defgroup USBD_INFO_Exported_Variables
- * @{
- */
-extern const uint8_t MSC_Page00_Inquiry_Data[];
-extern const uint8_t MSC_Mode_Sense6_data[];
-extern const uint8_t MSC_Mode_Sense10_data[] ;
-
-/**
- * @}
- */
-
-/** @defgroup USBD_INFO_Exported_FunctionsPrototype
- * @{
- */
-
-/**
- * @}
- */
-
-#endif /* _USBD_MSC_DATA_H_ */
-
-/**
- * @}
- */
-
-/**
-* @}
-*/
-
-/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
+/**
+ ******************************************************************************
+ * @file usbd_msc_data.h
+ * @author MCD Application Team
+ * @version V2.0.0
+ * @date 18-February-2014
+ * @brief header for the usbd_msc_data.c file
+ ******************************************************************************
+ * @attention
+ *
+ * <h2><center>&copy; COPYRIGHT 2014 STMicroelectronics</center></h2>
+ *
+ * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
+ * You may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.st.com/software_license_agreement_liberty_v2
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************
+ */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+
+#ifndef _USBD_MSC_DATA_H_
+#define _USBD_MSC_DATA_H_
+
+/* Includes ------------------------------------------------------------------*/
+#include "usbd_conf.h"
+
+/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY
+ * @{
+ */
+
+/** @defgroup USB_INFO
+ * @brief general defines for the usb device library file
+ * @{
+ */
+
+/** @defgroup USB_INFO_Exported_Defines
+ * @{
+ */
+#define MODE_SENSE6_LEN 8
+#define MODE_SENSE10_LEN 8
+#define LENGTH_INQUIRY_PAGE00 7
+#define LENGTH_FORMAT_CAPACITIES 20
+
+/**
+ * @}
+ */
+
+
+/** @defgroup USBD_INFO_Exported_TypesDefinitions
+ * @{
+ */
+/**
+ * @}
+ */
+
+
+
+/** @defgroup USBD_INFO_Exported_Macros
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+/** @defgroup USBD_INFO_Exported_Variables
+ * @{
+ */
+extern const uint8_t MSC_Page00_Inquiry_Data[];
+extern const uint8_t MSC_Mode_Sense6_data[];
+extern const uint8_t MSC_Mode_Sense10_data[] ;
+
+/**
+ * @}
+ */
+
+/** @defgroup USBD_INFO_Exported_FunctionsPrototype
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+#endif /* _USBD_MSC_DATA_H_ */
+
+/**
+ * @}
+ */
+
+/**
+* @}
+*/
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/ports/stm32/usbdev/class/inc/usbd_msc_scsi.h b/ports/stm32/usbdev/class/inc/usbd_msc_scsi.h
index 34f059ee5..b657cead0 100644
--- a/ports/stm32/usbdev/class/inc/usbd_msc_scsi.h
+++ b/ports/stm32/usbdev/class/inc/usbd_msc_scsi.h
@@ -1,195 +1,195 @@
-/**
- ******************************************************************************
- * @file usbd_msc_scsi.h
- * @author MCD Application Team
- * @version V2.0.0
- * @date 18-February-2014
- * @brief header for the usbd_msc_scsi.c file
- ******************************************************************************
- * @attention
- *
- * <h2><center>&copy; COPYRIGHT 2014 STMicroelectronics</center></h2>
- *
- * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
- * You may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.st.com/software_license_agreement_liberty_v2
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- ******************************************************************************
- */
-
-/* Define to prevent recursive inclusion -------------------------------------*/
-#ifndef __USBD_MSC_SCSI_H
-#define __USBD_MSC_SCSI_H
-
-/* Includes ------------------------------------------------------------------*/
-#include "usbd_def.h"
-
-/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY
- * @{
- */
-
-/** @defgroup USBD_SCSI
- * @brief header file for the storage disk file
- * @{
- */
-
-/** @defgroup USBD_SCSI_Exported_Defines
- * @{
- */
-
-#define SENSE_LIST_DEEPTH 4
-
-/* SCSI Commands */
-#define SCSI_FORMAT_UNIT 0x04
-#define SCSI_INQUIRY 0x12
-#define SCSI_MODE_SELECT6 0x15
-#define SCSI_MODE_SELECT10 0x55
-#define SCSI_MODE_SENSE6 0x1A
-#define SCSI_MODE_SENSE10 0x5A
-#define SCSI_ALLOW_MEDIUM_REMOVAL 0x1E
-#define SCSI_SYNCHRONIZE_CACHE10 0x35
-#define SCSI_SYNCHRONIZE_CACHE16 0x91
-#define SCSI_READ6 0x08
-#define SCSI_READ10 0x28
-#define SCSI_READ12 0xA8
-#define SCSI_READ16 0x88
-
-#define SCSI_READ_CAPACITY10 0x25
-#define SCSI_READ_CAPACITY16 0x9E
-
-#define SCSI_REQUEST_SENSE 0x03
-#define SCSI_START_STOP_UNIT 0x1B
-#define SCSI_TEST_UNIT_READY 0x00
-#define SCSI_WRITE6 0x0A
-#define SCSI_WRITE10 0x2A
-#define SCSI_WRITE12 0xAA
-#define SCSI_WRITE16 0x8A
-
-#define SCSI_VERIFY10 0x2F
-#define SCSI_VERIFY12 0xAF
-#define SCSI_VERIFY16 0x8F
-
-#define SCSI_SEND_DIAGNOSTIC 0x1D
-#define SCSI_READ_FORMAT_CAPACITIES 0x23
-
-#define NO_SENSE 0
-#define RECOVERED_ERROR 1
-#define NOT_READY 2
-#define MEDIUM_ERROR 3
-#define HARDWARE_ERROR 4
-#define ILLEGAL_REQUEST 5
-#define UNIT_ATTENTION 6
-#define DATA_PROTECT 7
-#define BLANK_CHECK 8
-#define VENDOR_SPECIFIC 9
-#define COPY_ABORTED 10
-#define ABORTED_COMMAND 11
-#define VOLUME_OVERFLOW 13
-#define MISCOMPARE 14
-
-
-#define INVALID_CDB 0x20
-#define INVALID_FIELED_IN_COMMAND 0x24
-#define PARAMETER_LIST_LENGTH_ERROR 0x1A
-#define INVALID_FIELD_IN_PARAMETER_LIST 0x26
-#define ADDRESS_OUT_OF_RANGE 0x21
-#define MEDIUM_NOT_PRESENT 0x3A
-#define MEDIUM_HAVE_CHANGED 0x28
-#define WRITE_PROTECTED 0x27
-#define UNRECOVERED_READ_ERROR 0x11
-#define WRITE_FAULT 0x03
-
-#define READ_FORMAT_CAPACITY_DATA_LEN 0x0C
-#define READ_CAPACITY10_DATA_LEN 0x08
-#define MODE_SENSE10_DATA_LEN 0x08
-#define MODE_SENSE6_DATA_LEN 0x04
-#define REQUEST_SENSE_DATA_LEN 0x12
-#define STANDARD_INQUIRY_DATA_LEN 0x24
-#define BLKVFY 0x04
-
-extern uint8_t Page00_Inquiry_Data[];
-extern uint8_t Standard_Inquiry_Data[];
-extern uint8_t Standard_Inquiry_Data2[];
-extern uint8_t Mode_Sense6_data[];
-extern uint8_t Mode_Sense10_data[];
-extern uint8_t Scsi_Sense_Data[];
-extern uint8_t ReadCapacity10_Data[];
-extern uint8_t ReadFormatCapacity_Data [];
-/**
- * @}
- */
-
-
-/** @defgroup USBD_SCSI_Exported_TypesDefinitions
- * @{
- */
-
-typedef struct _SENSE_ITEM {
- char Skey;
- union {
- struct _ASCs {
- char ASC;
- char ASCQ;
- }b;
- unsigned int ASC;
- char *pData;
- } w;
-} USBD_SCSI_SenseTypeDef;
-/**
- * @}
- */
-
-/** @defgroup USBD_SCSI_Exported_Macros
- * @{
- */
-
-/**
- * @}
- */
-
-/** @defgroup USBD_SCSI_Exported_Variables
- * @{
- */
-
-/**
- * @}
- */
-/** @defgroup USBD_SCSI_Exported_FunctionsPrototype
- * @{
- */
-int8_t SCSI_ProcessCmd(USBD_HandleTypeDef *pdev,
- uint8_t lun,
- uint8_t *cmd);
-
-void SCSI_SenseCode(USBD_HandleTypeDef *pdev,
- uint8_t lun,
- uint8_t sKey,
- uint8_t ASC);
-
-/**
- * @}
- */
-
-#endif /* __USBD_MSC_SCSI_H */
-/**
- * @}
- */
-
-/**
- * @}
- */
-
-/**
-* @}
-*/
-
-/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
-
+/**
+ ******************************************************************************
+ * @file usbd_msc_scsi.h
+ * @author MCD Application Team
+ * @version V2.0.0
+ * @date 18-February-2014
+ * @brief header for the usbd_msc_scsi.c file
+ ******************************************************************************
+ * @attention
+ *
+ * <h2><center>&copy; COPYRIGHT 2014 STMicroelectronics</center></h2>
+ *
+ * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
+ * You may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.st.com/software_license_agreement_liberty_v2
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************
+ */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __USBD_MSC_SCSI_H
+#define __USBD_MSC_SCSI_H
+
+/* Includes ------------------------------------------------------------------*/
+#include "usbd_def.h"
+
+/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY
+ * @{
+ */
+
+/** @defgroup USBD_SCSI
+ * @brief header file for the storage disk file
+ * @{
+ */
+
+/** @defgroup USBD_SCSI_Exported_Defines
+ * @{
+ */
+
+#define SENSE_LIST_DEEPTH 4
+
+/* SCSI Commands */
+#define SCSI_FORMAT_UNIT 0x04
+#define SCSI_INQUIRY 0x12
+#define SCSI_MODE_SELECT6 0x15
+#define SCSI_MODE_SELECT10 0x55
+#define SCSI_MODE_SENSE6 0x1A
+#define SCSI_MODE_SENSE10 0x5A
+#define SCSI_ALLOW_MEDIUM_REMOVAL 0x1E
+#define SCSI_SYNCHRONIZE_CACHE10 0x35
+#define SCSI_SYNCHRONIZE_CACHE16 0x91
+#define SCSI_READ6 0x08
+#define SCSI_READ10 0x28
+#define SCSI_READ12 0xA8
+#define SCSI_READ16 0x88
+
+#define SCSI_READ_CAPACITY10 0x25
+#define SCSI_READ_CAPACITY16 0x9E
+
+#define SCSI_REQUEST_SENSE 0x03
+#define SCSI_START_STOP_UNIT 0x1B
+#define SCSI_TEST_UNIT_READY 0x00
+#define SCSI_WRITE6 0x0A
+#define SCSI_WRITE10 0x2A
+#define SCSI_WRITE12 0xAA
+#define SCSI_WRITE16 0x8A
+
+#define SCSI_VERIFY10 0x2F
+#define SCSI_VERIFY12 0xAF
+#define SCSI_VERIFY16 0x8F
+
+#define SCSI_SEND_DIAGNOSTIC 0x1D
+#define SCSI_READ_FORMAT_CAPACITIES 0x23
+
+#define NO_SENSE 0
+#define RECOVERED_ERROR 1
+#define NOT_READY 2
+#define MEDIUM_ERROR 3
+#define HARDWARE_ERROR 4
+#define ILLEGAL_REQUEST 5
+#define UNIT_ATTENTION 6
+#define DATA_PROTECT 7
+#define BLANK_CHECK 8
+#define VENDOR_SPECIFIC 9
+#define COPY_ABORTED 10
+#define ABORTED_COMMAND 11
+#define VOLUME_OVERFLOW 13
+#define MISCOMPARE 14
+
+
+#define INVALID_CDB 0x20
+#define INVALID_FIELED_IN_COMMAND 0x24
+#define PARAMETER_LIST_LENGTH_ERROR 0x1A
+#define INVALID_FIELD_IN_PARAMETER_LIST 0x26
+#define ADDRESS_OUT_OF_RANGE 0x21
+#define MEDIUM_NOT_PRESENT 0x3A
+#define MEDIUM_HAVE_CHANGED 0x28
+#define WRITE_PROTECTED 0x27
+#define UNRECOVERED_READ_ERROR 0x11
+#define WRITE_FAULT 0x03
+
+#define READ_FORMAT_CAPACITY_DATA_LEN 0x0C
+#define READ_CAPACITY10_DATA_LEN 0x08
+#define MODE_SENSE10_DATA_LEN 0x08
+#define MODE_SENSE6_DATA_LEN 0x04
+#define REQUEST_SENSE_DATA_LEN 0x12
+#define STANDARD_INQUIRY_DATA_LEN 0x24
+#define BLKVFY 0x04
+
+extern uint8_t Page00_Inquiry_Data[];
+extern uint8_t Standard_Inquiry_Data[];
+extern uint8_t Standard_Inquiry_Data2[];
+extern uint8_t Mode_Sense6_data[];
+extern uint8_t Mode_Sense10_data[];
+extern uint8_t Scsi_Sense_Data[];
+extern uint8_t ReadCapacity10_Data[];
+extern uint8_t ReadFormatCapacity_Data [];
+/**
+ * @}
+ */
+
+
+/** @defgroup USBD_SCSI_Exported_TypesDefinitions
+ * @{
+ */
+
+typedef struct _SENSE_ITEM {
+ char Skey;
+ union {
+ struct _ASCs {
+ char ASC;
+ char ASCQ;
+ }b;
+ unsigned int ASC;
+ char *pData;
+ } w;
+} USBD_SCSI_SenseTypeDef;
+/**
+ * @}
+ */
+
+/** @defgroup USBD_SCSI_Exported_Macros
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+/** @defgroup USBD_SCSI_Exported_Variables
+ * @{
+ */
+
+/**
+ * @}
+ */
+/** @defgroup USBD_SCSI_Exported_FunctionsPrototype
+ * @{
+ */
+int8_t SCSI_ProcessCmd(USBD_HandleTypeDef *pdev,
+ uint8_t lun,
+ uint8_t *cmd);
+
+void SCSI_SenseCode(USBD_HandleTypeDef *pdev,
+ uint8_t lun,
+ uint8_t sKey,
+ uint8_t ASC);
+
+/**
+ * @}
+ */
+
+#endif /* __USBD_MSC_SCSI_H */
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+* @}
+*/
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
+
diff --git a/ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c b/ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c
index 379a8f32c..c5aac037d 100644
--- a/ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c
+++ b/ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c
@@ -24,13 +24,31 @@
* THE SOFTWARE.
*/
+#include STM32_HAL_H
#include "usbd_ioreq.h"
#include "usbd_cdc_msc_hid.h"
+#if MICROPY_HW_ENABLE_USB
+
+#define MSC_TEMPLATE_CONFIG_DESC_SIZE (32)
+#define MSC_TEMPLATE_MSC_DESC_OFFSET (9)
#define CDC_TEMPLATE_CONFIG_DESC_SIZE (67)
#define CDC_MSC_TEMPLATE_CONFIG_DESC_SIZE (98)
+#define CDC_MSC_TEMPLATE_MSC_DESC_OFFSET (9)
+#define CDC_MSC_TEMPLATE_CDC_DESC_OFFSET (40)
+#define CDC2_MSC_TEMPLATE_CONFIG_DESC_SIZE (9 + 23 + (8 + 58) + (8 + 58))
+#define CDC2_MSC_TEMPLATE_MSC_DESC_OFFSET (9)
+#define CDC2_MSC_TEMPLATE_CDC_DESC_OFFSET (9 + 23 + 8)
+#define CDC2_MSC_TEMPLATE_CDC2_DESC_OFFSET (9 + 23 + (8 + 58) + 8)
#define CDC_HID_TEMPLATE_CONFIG_DESC_SIZE (107)
#define CDC_HID_TEMPLATE_HID_DESC_OFFSET (9)
+#define CDC_HID_TEMPLATE_CDC_DESC_OFFSET (49)
+#define CDC_TEMPLATE_CDC_DESC_OFFSET (9)
+#define CDC_DESC_OFFSET_INTR_INTERVAL (34)
+#define CDC_DESC_OFFSET_OUT_MAX_PACKET_LO (48)
+#define CDC_DESC_OFFSET_OUT_MAX_PACKET_HI (49)
+#define CDC_DESC_OFFSET_IN_MAX_PACKET_LO (55)
+#define CDC_DESC_OFFSET_IN_MAX_PACKET_HI (56)
#define HID_DESC_OFFSET_SUBCLASS (6)
#define HID_DESC_OFFSET_PROTOCOL (7)
#define HID_DESC_OFFSET_SUBDESC (9)
@@ -45,10 +63,20 @@
#define CDC_IFACE_NUM_ALONE (0)
#define CDC_IFACE_NUM_WITH_MSC (1)
+#define CDC2_IFACE_NUM_WITH_MSC (3)
#define CDC_IFACE_NUM_WITH_HID (1)
#define MSC_IFACE_NUM_WITH_CDC (0)
#define HID_IFACE_NUM_WITH_CDC (0)
#define HID_IFACE_NUM_WITH_MSC (1)
+
+#define CDC_IN_EP (0x83)
+#define CDC_OUT_EP (0x03)
+#define CDC_CMD_EP (0x82)
+
+#define CDC2_IN_EP (0x85)
+#define CDC2_OUT_EP (0x05)
+#define CDC2_CMD_EP (0x84)
+
#define HID_IN_EP_WITH_CDC (0x81)
#define HID_OUT_EP_WITH_CDC (0x01)
#define HID_IN_EP_WITH_MSC (0x83)
@@ -57,10 +85,7 @@
#define USB_DESC_TYPE_ASSOCIATION (0x0b)
#define CDC_CMD_PACKET_SIZE (8) // Control Endpoint Packet size
-#define CDC_DATA_IN_PACKET_SIZE CDC_DATA_FS_MAX_PACKET_SIZE
-#define CDC_DATA_OUT_PACKET_SIZE CDC_DATA_FS_MAX_PACKET_SIZE
-#define MSC_MAX_PACKET (0x40)
#define BOT_GET_MAX_LUN (0xfe)
#define BOT_RESET (0xff)
@@ -71,8 +96,7 @@
#define HID_REQ_SET_IDLE (0x0a)
#define HID_REQ_GET_IDLE (0x02)
-/*
-// this is used only in high-speed mode, which we don't support
+#if USBD_SUPPORT_HS_MODE
// USB Standard Device Descriptor
__ALIGN_BEGIN static uint8_t USBD_CDC_MSC_HID_DeviceQualifierDesc[USB_LEN_DEV_QUALIFIER_DESC] __ALIGN_END = {
USB_LEN_DEV_QUALIFIER_DESC,
@@ -82,11 +106,59 @@ __ALIGN_BEGIN static uint8_t USBD_CDC_MSC_HID_DeviceQualifierDesc[USB_LEN_DEV_QU
0x00,
0x00,
0x00,
- 0x40, // same for CDC and MSC (latter being MSC_MAX_PACKET), HID is 0x04
+ 0x40, // same for CDC and MSC (latter being MSC_FS_MAX_PACKET), HID is 0x04
0x01,
0x00,
};
-*/
+#endif
+
+// USB MSC device Configuration Descriptor
+static const uint8_t msc_template_config_desc[MSC_TEMPLATE_CONFIG_DESC_SIZE] = {
+ //--------------------------------------------------------------------------
+ // Configuration Descriptor
+ 0x09, // bLength: Configuration Descriptor size
+ USB_DESC_TYPE_CONFIGURATION, // bDescriptorType: Configuration
+ LOBYTE(MSC_TEMPLATE_CONFIG_DESC_SIZE), // wTotalLength: no of returned bytes
+ HIBYTE(MSC_TEMPLATE_CONFIG_DESC_SIZE),
+ 0x01, // bNumInterfaces: 1 interfaces
+ 0x01, // bConfigurationValue: Configuration value
+ 0x00, // iConfiguration: Index of string descriptor describing the configuration
+ 0x80, // bmAttributes: bus powered; 0xc0 for self powered
+ 0xfa, // bMaxPower: in units of 2mA
+
+ //==========================================================================
+ // MSC only has 1 interface so doesn't need an IAD
+
+ //--------------------------------------------------------------------------
+ // Interface Descriptor
+ 0x09, // bLength: Interface Descriptor size
+ USB_DESC_TYPE_INTERFACE, // bDescriptorType: interface descriptor
+ MSC_IFACE_NUM_WITH_CDC, // bInterfaceNumber: Number of Interface
+ 0x00, // bAlternateSetting: Alternate setting
+ 0x02, // bNumEndpoints
+ 0x08, // bInterfaceClass: MSC Class
+ 0x06, // bInterfaceSubClass : SCSI transparent
+ 0x50, // nInterfaceProtocol
+ 0x00, // iInterface:
+
+ // Endpoint IN descriptor
+ 0x07, // bLength: Endpoint descriptor length
+ USB_DESC_TYPE_ENDPOINT, // bDescriptorType: Endpoint descriptor type
+ MSC_IN_EP, // bEndpointAddress: IN, address 3
+ 0x02, // bmAttributes: Bulk endpoint type
+ LOBYTE(MSC_FS_MAX_PACKET), // wMaxPacketSize
+ HIBYTE(MSC_FS_MAX_PACKET),
+ 0x00, // bInterval: ignore for Bulk transfer
+
+ // Endpoint OUT descriptor
+ 0x07, // bLength: Endpoint descriptor length
+ USB_DESC_TYPE_ENDPOINT, // bDescriptorType: Endpoint descriptor type
+ MSC_OUT_EP, // bEndpointAddress: OUT, address 3
+ 0x02, // bmAttributes: Bulk endpoint type
+ LOBYTE(MSC_FS_MAX_PACKET), // wMaxPacketSize
+ HIBYTE(MSC_FS_MAX_PACKET),
+ 0x00, // bInterval: ignore for Bulk transfer
+};
// USB CDC MSC device Configuration Descriptor
static const uint8_t cdc_msc_template_config_desc[CDC_MSC_TEMPLATE_CONFIG_DESC_SIZE] = {
@@ -122,8 +194,8 @@ static const uint8_t cdc_msc_template_config_desc[CDC_MSC_TEMPLATE_CONFIG_DESC_S
USB_DESC_TYPE_ENDPOINT, // bDescriptorType: Endpoint descriptor type
MSC_IN_EP, // bEndpointAddress: IN, address 3
0x02, // bmAttributes: Bulk endpoint type
- LOBYTE(MSC_MAX_PACKET), // wMaxPacketSize
- HIBYTE(MSC_MAX_PACKET),
+ LOBYTE(MSC_FS_MAX_PACKET), // wMaxPacketSize
+ HIBYTE(MSC_FS_MAX_PACKET),
0x00, // bInterval: ignore for Bulk transfer
// Endpoint OUT descriptor
@@ -131,8 +203,8 @@ static const uint8_t cdc_msc_template_config_desc[CDC_MSC_TEMPLATE_CONFIG_DESC_S
USB_DESC_TYPE_ENDPOINT, // bDescriptorType: Endpoint descriptor type
MSC_OUT_EP, // bEndpointAddress: OUT, address 3
0x02, // bmAttributes: Bulk endpoint type
- LOBYTE(MSC_MAX_PACKET), // wMaxPacketSize
- HIBYTE(MSC_MAX_PACKET),
+ LOBYTE(MSC_FS_MAX_PACKET), // wMaxPacketSize
+ HIBYTE(MSC_FS_MAX_PACKET),
0x00, // bInterval: ignore for Bulk transfer
//==========================================================================
@@ -553,26 +625,56 @@ int USBD_SelectMode(usbd_cdc_msc_hid_state_t *usbd, uint32_t mode, USBD_HID_Mode
// construct config desc
switch (usbd->usbd_mode) {
+ case USBD_MODE_MSC:
+ usbd->usbd_config_desc_size = sizeof(msc_template_config_desc);
+ memcpy(usbd->usbd_config_desc, msc_template_config_desc, sizeof(msc_template_config_desc));
+ break;
+
case USBD_MODE_CDC_MSC:
usbd->usbd_config_desc_size = sizeof(cdc_msc_template_config_desc);
memcpy(usbd->usbd_config_desc, cdc_msc_template_config_desc, sizeof(cdc_msc_template_config_desc));
- usbd->cdc_iface_num = CDC_IFACE_NUM_WITH_MSC;
+ usbd->cdc->iface_num = CDC_IFACE_NUM_WITH_MSC;
+ break;
+
+ #if MICROPY_HW_USB_ENABLE_CDC2
+ case USBD_MODE_CDC2_MSC: {
+ usbd->usbd_config_desc_size = CDC2_MSC_TEMPLATE_CONFIG_DESC_SIZE;
+ uint8_t *d = usbd->usbd_config_desc;
+ memcpy(d, cdc_msc_template_config_desc, sizeof(cdc_msc_template_config_desc));
+ d[2] = LOBYTE(CDC2_MSC_TEMPLATE_CONFIG_DESC_SIZE); // wTotalLength
+ d[3] = HIBYTE(CDC2_MSC_TEMPLATE_CONFIG_DESC_SIZE);
+ d[4] = 5; // bNumInterfaces
+ memcpy(d + 9 + 23 + (8 + 58), d + 9 + 23, 8 + 58);
+ d += 9 + 23 + (8 + 58);
+ d[2] = CDC2_IFACE_NUM_WITH_MSC; // bFirstInterface
+ d[10] = CDC2_IFACE_NUM_WITH_MSC; // bInterfaceNumber
+ d[26] = CDC2_IFACE_NUM_WITH_MSC + 1; // bDataInterface
+ d[34] = CDC2_IFACE_NUM_WITH_MSC + 0; // bMasterInterface
+ d[35] = CDC2_IFACE_NUM_WITH_MSC + 1; // bSlaveInterface
+ d[38] = CDC2_CMD_EP; // bEndpointAddress
+ d[45] = CDC2_IFACE_NUM_WITH_MSC + 1; // bInterfaceNumber
+ d[54] = CDC2_OUT_EP; // bEndpointAddress
+ d[61] = CDC2_IN_EP; // bEndpointAddress
+ usbd->cdc->iface_num = CDC_IFACE_NUM_WITH_MSC;
+ usbd->cdc2->iface_num = CDC2_IFACE_NUM_WITH_MSC;
break;
+ }
+ #endif
case USBD_MODE_CDC_HID:
usbd->usbd_config_desc_size = sizeof(cdc_hid_template_config_desc);
memcpy(usbd->usbd_config_desc, cdc_hid_template_config_desc, sizeof(cdc_hid_template_config_desc));
- usbd->cdc_iface_num = CDC_IFACE_NUM_WITH_HID;
- usbd->hid_in_ep = HID_IN_EP_WITH_CDC;
- usbd->hid_out_ep = HID_OUT_EP_WITH_CDC;
- usbd->hid_iface_num = HID_IFACE_NUM_WITH_CDC;
- usbd->hid_desc = usbd->usbd_config_desc + CDC_HID_TEMPLATE_HID_DESC_OFFSET;
+ usbd->cdc->iface_num = CDC_IFACE_NUM_WITH_HID;
+ usbd->hid->in_ep = HID_IN_EP_WITH_CDC;
+ usbd->hid->out_ep = HID_OUT_EP_WITH_CDC;
+ usbd->hid->iface_num = HID_IFACE_NUM_WITH_CDC;
+ usbd->hid->desc = usbd->usbd_config_desc + CDC_HID_TEMPLATE_HID_DESC_OFFSET;
break;
case USBD_MODE_CDC:
usbd->usbd_config_desc_size = sizeof(cdc_template_config_desc);
memcpy(usbd->usbd_config_desc, cdc_template_config_desc, sizeof(cdc_template_config_desc));
- usbd->cdc_iface_num = CDC_IFACE_NUM_ALONE;
+ usbd->cdc->iface_num = CDC_IFACE_NUM_ALONE;
break;
/*
@@ -589,9 +691,21 @@ int USBD_SelectMode(usbd_cdc_msc_hid_state_t *usbd, uint32_t mode, USBD_HID_Mode
return -1;
}
+ if (usbd->usbd_mode & USBD_MODE_CDC) {
+ usbd->cdc->in_ep = CDC_IN_EP;
+ usbd->cdc->out_ep = CDC_OUT_EP;
+ }
+
+ #if MICROPY_HW_USB_ENABLE_CDC2
+ if (usbd->usbd_mode & USBD_MODE_CDC2) {
+ usbd->cdc2->in_ep = CDC2_IN_EP;
+ usbd->cdc2->out_ep = CDC2_OUT_EP;
+ }
+ #endif
+
// configure the HID descriptor, if needed
if (usbd->usbd_mode & USBD_MODE_HID) {
- uint8_t *hid_desc = usbd->hid_desc;
+ uint8_t *hid_desc = usbd->hid->desc;
hid_desc[HID_DESC_OFFSET_SUBCLASS] = hid_info->subclass;
hid_desc[HID_DESC_OFFSET_PROTOCOL] = hid_info->protocol;
hid_desc[HID_DESC_OFFSET_REPORT_DESC_LEN] = hid_info->report_desc_len;
@@ -601,66 +715,70 @@ int USBD_SelectMode(usbd_cdc_msc_hid_state_t *usbd, uint32_t mode, USBD_HID_Mode
hid_desc[HID_DESC_OFFSET_MAX_PACKET_OUT_LO] = hid_info->max_packet_len;
hid_desc[HID_DESC_OFFSET_MAX_PACKET_OUT_HI] = 0;
hid_desc[HID_DESC_OFFSET_POLLING_INTERVAL_OUT] = hid_info->polling_interval;
- usbd->hid_report_desc = hid_info->report_desc;
+ usbd->hid->report_desc = hid_info->report_desc;
}
return 0;
}
+static void usbd_cdc_state_init(USBD_HandleTypeDef *pdev, usbd_cdc_msc_hid_state_t *usbd, usbd_cdc_state_t *cdc, uint8_t cmd_ep) {
+ int mp = usbd_cdc_max_packet(pdev);
+
+ // Open endpoints
+ USBD_LL_OpenEP(pdev, cdc->in_ep, USBD_EP_TYPE_BULK, mp);
+ USBD_LL_OpenEP(pdev, cdc->out_ep, USBD_EP_TYPE_BULK, mp);
+ USBD_LL_OpenEP(pdev, cmd_ep, USBD_EP_TYPE_INTR, CDC_CMD_PACKET_SIZE);
+
+ // Init state
+ cdc->usbd = usbd;
+ cdc->cur_request = 0xff;
+ cdc->tx_in_progress = 0;
+
+ // Init interface
+ uint8_t *buf = usbd_cdc_init(cdc);
+
+ // Prepare Out endpoint to receive next packet
+ USBD_LL_PrepareReceive(pdev, cdc->out_ep, buf, mp);
+}
+
static uint8_t USBD_CDC_MSC_HID_Init(USBD_HandleTypeDef *pdev, uint8_t cfgidx) {
+ #if !USBD_SUPPORT_HS_MODE
if (pdev->dev_speed == USBD_SPEED_HIGH) {
// can't handle high speed
return 1;
}
+ #endif
usbd_cdc_msc_hid_state_t *usbd = pdev->pClassData;
if (usbd->usbd_mode & USBD_MODE_CDC) {
// CDC VCP component
+ usbd_cdc_state_init(pdev, usbd, usbd->cdc, CDC_CMD_EP);
+ }
- // Open EP IN
- USBD_LL_OpenEP(pdev,
- CDC_IN_EP,
- USBD_EP_TYPE_BULK,
- CDC_DATA_IN_PACKET_SIZE);
-
- // Open EP OUT
- USBD_LL_OpenEP(pdev,
- CDC_OUT_EP,
- USBD_EP_TYPE_BULK,
- CDC_DATA_OUT_PACKET_SIZE);
-
- // Open Command IN EP
- USBD_LL_OpenEP(pdev,
- CDC_CMD_EP,
- USBD_EP_TYPE_INTR,
- CDC_CMD_PACKET_SIZE);
-
- // Init physical Interface components
- uint8_t *buf = usbd_cdc_init(usbd->cdc, usbd);
-
- // Init Xfer states
- usbd->CDC_ClassData.TxState = 0;
- usbd->CDC_ClassData.RxState = 0;
-
- // Prepare Out endpoint to receive next packet
- USBD_LL_PrepareReceive(pdev, CDC_OUT_EP, buf, CDC_DATA_OUT_PACKET_SIZE);
+ #if MICROPY_HW_USB_ENABLE_CDC2
+ if (usbd->usbd_mode & USBD_MODE_CDC2) {
+ // CDC VCP #2 component
+ usbd_cdc_state_init(pdev, usbd, usbd->cdc2, CDC2_CMD_EP);
}
+ #endif
if (usbd->usbd_mode & USBD_MODE_MSC) {
// MSC component
+ int mp = usbd_msc_max_packet(pdev);
+
// Open EP OUT
USBD_LL_OpenEP(pdev,
MSC_OUT_EP,
USBD_EP_TYPE_BULK,
- MSC_MAX_PACKET);
+ mp);
// Open EP IN
USBD_LL_OpenEP(pdev,
MSC_IN_EP,
USBD_EP_TYPE_BULK,
- MSC_MAX_PACKET);
+ mp);
// Init the BOT layer
MSC_BOT_Init(pdev);
@@ -671,30 +789,26 @@ static uint8_t USBD_CDC_MSC_HID_Init(USBD_HandleTypeDef *pdev, uint8_t cfgidx) {
// get max packet lengths from descriptor
uint16_t mps_in =
- usbd->hid_desc[HID_DESC_OFFSET_MAX_PACKET_LO]
- | (usbd->hid_desc[HID_DESC_OFFSET_MAX_PACKET_HI] << 8);
+ usbd->hid->desc[HID_DESC_OFFSET_MAX_PACKET_LO]
+ | (usbd->hid->desc[HID_DESC_OFFSET_MAX_PACKET_HI] << 8);
uint16_t mps_out =
- usbd->hid_desc[HID_DESC_OFFSET_MAX_PACKET_OUT_LO]
- | (usbd->hid_desc[HID_DESC_OFFSET_MAX_PACKET_OUT_HI] << 8);
+ usbd->hid->desc[HID_DESC_OFFSET_MAX_PACKET_OUT_LO]
+ | (usbd->hid->desc[HID_DESC_OFFSET_MAX_PACKET_OUT_HI] << 8);
// Open EP IN
- USBD_LL_OpenEP(pdev,
- usbd->hid_in_ep,
- USBD_EP_TYPE_INTR,
- mps_in);
+ USBD_LL_OpenEP(pdev, usbd->hid->in_ep, USBD_EP_TYPE_INTR, mps_in);
// Open EP OUT
- USBD_LL_OpenEP(pdev,
- usbd->hid_out_ep,
- USBD_EP_TYPE_INTR,
- mps_out);
+ USBD_LL_OpenEP(pdev, usbd->hid->out_ep, USBD_EP_TYPE_INTR, mps_out);
- uint8_t *buf = usbd_hid_init(usbd->hid, usbd);
+
+ usbd->hid->usbd = usbd;
+ uint8_t *buf = usbd_hid_init(usbd->hid);
// Prepare Out endpoint to receive next packet
- USBD_LL_PrepareReceive(pdev, usbd->hid_out_ep, buf, mps_out);
+ USBD_LL_PrepareReceive(pdev, usbd->hid->out_ep, buf, mps_out);
- usbd->HID_ClassData.state = HID_IDLE;
+ usbd->hid->state = HID_IDLE;
}
return 0;
@@ -712,6 +826,17 @@ static uint8_t USBD_CDC_MSC_HID_DeInit(USBD_HandleTypeDef *pdev, uint8_t cfgidx)
USBD_LL_CloseEP(pdev, CDC_CMD_EP);
}
+ #if MICROPY_HW_USB_ENABLE_CDC2
+ if ((usbd->usbd_mode & USBD_MODE_CDC2) && usbd->cdc2) {
+ // CDC VCP #2 component
+
+ // close endpoints
+ USBD_LL_CloseEP(pdev, CDC2_IN_EP);
+ USBD_LL_CloseEP(pdev, CDC2_OUT_EP);
+ USBD_LL_CloseEP(pdev, CDC2_CMD_EP);
+ }
+ #endif
+
if (usbd->usbd_mode & USBD_MODE_MSC) {
// MSC component
@@ -727,8 +852,8 @@ static uint8_t USBD_CDC_MSC_HID_DeInit(USBD_HandleTypeDef *pdev, uint8_t cfgidx)
// HID component
// close endpoints
- USBD_LL_CloseEP(pdev, usbd->hid_in_ep);
- USBD_LL_CloseEP(pdev, usbd->hid_out_ep);
+ USBD_LL_CloseEP(pdev, usbd->hid->in_ep);
+ USBD_LL_CloseEP(pdev, usbd->hid->out_ep);
}
return 0;
@@ -754,31 +879,75 @@ static uint8_t USBD_CDC_MSC_HID_Setup(USBD_HandleTypeDef *pdev, USBD_SetupReqTyp
usbd_cdc_msc_hid_state_t *usbd = pdev->pClassData;
+ // Work out the recipient of the setup request
+ uint8_t mode = usbd->usbd_mode;
+ uint8_t recipient = 0;
+ usbd_cdc_state_t *cdc = NULL;
+ switch (req->bmRequest & USB_REQ_RECIPIENT_MASK) {
+ case USB_REQ_RECIPIENT_INTERFACE: {
+ uint16_t iface = req->wIndex;
+ if ((mode & USBD_MODE_CDC) && iface == usbd->cdc->iface_num) {
+ recipient = USBD_MODE_CDC;
+ cdc = usbd->cdc;
+ #if MICROPY_HW_USB_ENABLE_CDC2
+ } else if ((mode & USBD_MODE_CDC2) && iface == usbd->cdc2->iface_num) {
+ recipient = USBD_MODE_CDC;
+ cdc = usbd->cdc2;
+ #endif
+ } else if ((mode & USBD_MODE_MSC) && iface == MSC_IFACE_NUM_WITH_CDC) {
+ recipient = USBD_MODE_MSC;
+ } else if ((mode & USBD_MODE_HID) && iface == usbd->hid->iface_num) {
+ recipient = USBD_MODE_HID;
+ }
+ break;
+ }
+ case USB_REQ_RECIPIENT_ENDPOINT: {
+ uint8_t ep = req->wIndex & 0x7f;
+ if ((mode & USBD_MODE_CDC) && (ep == CDC_OUT_EP || ep == (CDC_CMD_EP & 0x7f))) {
+ recipient = USBD_MODE_CDC;
+ cdc = usbd->cdc;
+ #if MICROPY_HW_USB_ENABLE_CDC2
+ } else if ((mode & USBD_MODE_CDC2) && (ep == CDC2_OUT_EP || ep == (CDC2_CMD_EP & 0x7f))) {
+ recipient = USBD_MODE_CDC;
+ cdc = usbd->cdc2;
+ #endif
+ } else if ((mode & USBD_MODE_MSC) && ep == MSC_OUT_EP) {
+ recipient = USBD_MODE_MSC;
+ } else if ((mode & USBD_MODE_HID) && ep == usbd->hid->out_ep) {
+ recipient = USBD_MODE_HID;
+ }
+ break;
+ }
+ }
+
+ // Fail the request if we didn't have a valid recipient
+ if (recipient == 0) {
+ USBD_CtlError(pdev, req);
+ return USBD_FAIL;
+ }
+
switch (req->bmRequest & USB_REQ_TYPE_MASK) {
// Class request
case USB_REQ_TYPE_CLASS:
- // req->wIndex is the recipient interface number
- if ((usbd->usbd_mode & USBD_MODE_CDC) && req->wIndex == usbd->cdc_iface_num) {
- // CDC component
+ if (recipient == USBD_MODE_CDC) {
if (req->wLength) {
if (req->bmRequest & 0x80) {
// device-to-host request
- usbd_cdc_control(usbd->cdc, req->bRequest, (uint8_t*)usbd->CDC_ClassData.data, req->wLength);
- USBD_CtlSendData(pdev, (uint8_t*)usbd->CDC_ClassData.data, req->wLength);
+ usbd_cdc_control(cdc, req->bRequest, (uint8_t*)cdc->ctl_packet_buf, req->wLength);
+ USBD_CtlSendData(pdev, (uint8_t*)cdc->ctl_packet_buf, req->wLength);
} else {
// host-to-device request
- usbd->CDC_ClassData.CmdOpCode = req->bRequest;
- usbd->CDC_ClassData.CmdLength = req->wLength;
- USBD_CtlPrepareRx(pdev, (uint8_t*)usbd->CDC_ClassData.data, req->wLength);
+ cdc->cur_request = req->bRequest;
+ cdc->cur_length = req->wLength;
+ USBD_CtlPrepareRx(pdev, (uint8_t*)cdc->ctl_packet_buf, req->wLength);
}
} else {
// Not a Data request
// Transfer the command to the interface layer
- return usbd_cdc_control(usbd->cdc, req->bRequest, NULL, req->wValue);
+ return usbd_cdc_control(cdc, req->bRequest, NULL, req->wValue);
}
- } else if ((usbd->usbd_mode & USBD_MODE_MSC) && req->wIndex == MSC_IFACE_NUM_WITH_CDC) {
- // MSC component
+ } else if (recipient == USBD_MODE_MSC) {
switch (req->bRequest) {
case BOT_GET_MAX_LUN:
if ((req->wValue == 0) && (req->wLength == 1) && ((req->bmRequest & 0x80) == 0x80)) {
@@ -803,22 +972,22 @@ static uint8_t USBD_CDC_MSC_HID_Setup(USBD_HandleTypeDef *pdev, USBD_SetupReqTyp
USBD_CtlError(pdev, req);
return USBD_FAIL;
}
- } else if ((usbd->usbd_mode & USBD_MODE_HID) && req->wIndex == usbd->hid_iface_num) {
+ } else if (recipient == USBD_MODE_HID) {
switch (req->bRequest) {
case HID_REQ_SET_PROTOCOL:
- usbd->HID_ClassData.Protocol = (uint8_t)(req->wValue);
+ usbd->hid->ctl_protocol = (uint8_t)(req->wValue);
break;
case HID_REQ_GET_PROTOCOL:
- USBD_CtlSendData(pdev, (uint8_t *)&usbd->HID_ClassData.Protocol, 1);
+ USBD_CtlSendData(pdev, &usbd->hid->ctl_protocol, 1);
break;
case HID_REQ_SET_IDLE:
- usbd->HID_ClassData.IdleState = (uint8_t)(req->wValue >> 8);
+ usbd->hid->ctl_idle_state = (uint8_t)(req->wValue >> 8);
break;
case HID_REQ_GET_IDLE:
- USBD_CtlSendData(pdev, (uint8_t *)&usbd->HID_ClassData.IdleState, 1);
+ USBD_CtlSendData(pdev, &usbd->hid->ctl_idle_state, 1);
break;
default:
@@ -828,9 +997,8 @@ static uint8_t USBD_CDC_MSC_HID_Setup(USBD_HandleTypeDef *pdev, USBD_SetupReqTyp
}
break;
- // Interface & Endpoint request
case USB_REQ_TYPE_STANDARD:
- if ((usbd->usbd_mode & USBD_MODE_MSC) && req->wIndex == MSC_IFACE_NUM_WITH_CDC) {
+ if (recipient == USBD_MODE_MSC) {
switch (req->bRequest) {
case USB_REQ_GET_INTERFACE :
USBD_CtlSendData(pdev, (uint8_t *)&usbd->MSC_BOT_ClassData.interface, 1);
@@ -848,38 +1016,38 @@ static uint8_t USBD_CDC_MSC_HID_Setup(USBD_HandleTypeDef *pdev, USBD_SetupReqTyp
USBD_LL_CloseEP(pdev, (uint8_t)req->wIndex);
if((((uint8_t)req->wIndex) & 0x80) == 0x80) {
// Open EP IN
- USBD_LL_OpenEP(pdev, MSC_IN_EP, USBD_EP_TYPE_BULK, MSC_MAX_PACKET);
+ USBD_LL_OpenEP(pdev, MSC_IN_EP, USBD_EP_TYPE_BULK, usbd_msc_max_packet(pdev));
} else {
// Open EP OUT
- USBD_LL_OpenEP(pdev, MSC_OUT_EP, USBD_EP_TYPE_BULK, MSC_MAX_PACKET);
+ USBD_LL_OpenEP(pdev, MSC_OUT_EP, USBD_EP_TYPE_BULK, usbd_msc_max_packet(pdev));
}
// Handle BOT error
MSC_BOT_CplClrFeature(pdev, (uint8_t)req->wIndex);
break;
}
- } else if ((usbd->usbd_mode & USBD_MODE_HID) && req->wIndex == usbd->hid_iface_num) {
+ } else if (recipient == USBD_MODE_HID) {
switch (req->bRequest) {
case USB_REQ_GET_DESCRIPTOR: {
uint16_t len = 0;
const uint8_t *pbuf = NULL;
if (req->wValue >> 8 == HID_REPORT_DESC) {
- len = usbd->hid_desc[HID_DESC_OFFSET_REPORT_DESC_LEN];
+ len = usbd->hid->desc[HID_DESC_OFFSET_REPORT_DESC_LEN];
len = MIN(len, req->wLength);
- pbuf = usbd->hid_report_desc;
+ pbuf = usbd->hid->report_desc;
} else if (req->wValue >> 8 == HID_DESCRIPTOR_TYPE) {
len = MIN(HID_SUBDESC_LEN, req->wLength);
- pbuf = usbd->hid_desc + HID_DESC_OFFSET_SUBDESC;
+ pbuf = usbd->hid->desc + HID_DESC_OFFSET_SUBDESC;
}
USBD_CtlSendData(pdev, (uint8_t*)pbuf, len);
break;
}
case USB_REQ_GET_INTERFACE:
- USBD_CtlSendData(pdev, (uint8_t *)&usbd->HID_ClassData.AltSetting, 1);
+ USBD_CtlSendData(pdev, &usbd->hid->ctl_alt_setting, 1);
break;
case USB_REQ_SET_INTERFACE:
- usbd->HID_ClassData.AltSetting = (uint8_t)(req->wValue);
+ usbd->hid->ctl_alt_setting = (uint8_t)(req->wValue);
break;
}
}
@@ -895,10 +1063,16 @@ static uint8_t EP0_TxSent(USBD_HandleTypeDef *pdev) {
static uint8_t USBD_CDC_MSC_HID_EP0_RxReady(USBD_HandleTypeDef *pdev) {
usbd_cdc_msc_hid_state_t *usbd = pdev->pClassData;
- if (usbd->cdc != NULL && usbd->CDC_ClassData.CmdOpCode != 0xff) {
- usbd_cdc_control(usbd->cdc, usbd->CDC_ClassData.CmdOpCode, (uint8_t*)usbd->CDC_ClassData.data, usbd->CDC_ClassData.CmdLength);
- usbd->CDC_ClassData.CmdOpCode = 0xff;
+ if (usbd->cdc != NULL && usbd->cdc->cur_request != 0xff) {
+ usbd_cdc_control(usbd->cdc, usbd->cdc->cur_request, (uint8_t*)usbd->cdc->ctl_packet_buf, usbd->cdc->cur_length);
+ usbd->cdc->cur_request = 0xff;
}
+ #if MICROPY_HW_USB_ENABLE_CDC2
+ if (usbd->cdc2 != NULL && usbd->cdc2->cur_request != 0xff) {
+ usbd_cdc_control(usbd->cdc2, usbd->cdc2->cur_request, (uint8_t*)usbd->cdc2->ctl_packet_buf, usbd->cdc2->cur_length);
+ usbd->cdc2->cur_request = 0xff;
+ }
+ #endif
return USBD_OK;
}
@@ -906,15 +1080,20 @@ static uint8_t USBD_CDC_MSC_HID_EP0_RxReady(USBD_HandleTypeDef *pdev) {
static uint8_t USBD_CDC_MSC_HID_DataIn(USBD_HandleTypeDef *pdev, uint8_t epnum) {
usbd_cdc_msc_hid_state_t *usbd = pdev->pClassData;
if ((usbd->usbd_mode & USBD_MODE_CDC) && (epnum == (CDC_IN_EP & 0x7f) || epnum == (CDC_CMD_EP & 0x7f))) {
- usbd->CDC_ClassData.TxState = 0;
+ usbd->cdc->tx_in_progress = 0;
+ return USBD_OK;
+ #if MICROPY_HW_USB_ENABLE_CDC2
+ } else if ((usbd->usbd_mode & USBD_MODE_CDC2) && (epnum == (CDC2_IN_EP & 0x7f) || epnum == (CDC2_CMD_EP & 0x7f))) {
+ usbd->cdc2->tx_in_progress = 0;
return USBD_OK;
+ #endif
} else if ((usbd->usbd_mode & USBD_MODE_MSC) && epnum == (MSC_IN_EP & 0x7f)) {
MSC_BOT_DataIn(pdev, epnum);
return USBD_OK;
- } else if ((usbd->usbd_mode & USBD_MODE_HID) && epnum == (usbd->hid_in_ep & 0x7f)) {
+ } else if ((usbd->usbd_mode & USBD_MODE_HID) && epnum == (usbd->hid->in_ep & 0x7f)) {
/* Ensure that the FIFO is empty before a new transfer, this condition could
be caused by a new transfer before the end of the previous transfer */
- usbd->HID_ClassData.state = HID_IDLE;
+ usbd->hid->state = HID_IDLE;
return USBD_OK;
}
@@ -932,10 +1111,16 @@ static uint8_t USBD_CDC_MSC_HID_DataOut(USBD_HandleTypeDef *pdev, uint8_t epnum)
usbd_cdc_receive(usbd->cdc, len);
return USBD_OK;
+ #if MICROPY_HW_USB_ENABLE_CDC2
+ } else if ((usbd->usbd_mode & USBD_MODE_CDC2) && epnum == (CDC2_OUT_EP & 0x7f)) {
+ size_t len = USBD_LL_GetRxDataSize(pdev, epnum);
+ usbd_cdc_receive(usbd->cdc2, len);
+ return USBD_OK;
+ #endif
} else if ((usbd->usbd_mode & USBD_MODE_MSC) && epnum == (MSC_OUT_EP & 0x7f)) {
MSC_BOT_DataOut(pdev, epnum);
return USBD_OK;
- } else if ((usbd->usbd_mode & USBD_MODE_HID) && epnum == (usbd->hid_out_ep & 0x7f)) {
+ } else if ((usbd->usbd_mode & USBD_MODE_HID) && epnum == (usbd->hid->out_ep & 0x7f)) {
size_t len = USBD_LL_GetRxDataSize(pdev, epnum);
usbd_hid_receive(usbd->hid, len);
}
@@ -943,30 +1128,101 @@ static uint8_t USBD_CDC_MSC_HID_DataOut(USBD_HandleTypeDef *pdev, uint8_t epnum)
return USBD_OK;
}
+#if USBD_SUPPORT_HS_MODE
+static void usbd_cdc_desc_config_max_packet(USBD_HandleTypeDef *pdev, uint8_t *cdc_desc) {
+ uint32_t mp = usbd_cdc_max_packet(pdev);
+ cdc_desc[CDC_DESC_OFFSET_OUT_MAX_PACKET_LO] = LOBYTE(mp);
+ cdc_desc[CDC_DESC_OFFSET_OUT_MAX_PACKET_HI] = HIBYTE(mp);
+ cdc_desc[CDC_DESC_OFFSET_IN_MAX_PACKET_LO] = LOBYTE(mp);
+ cdc_desc[CDC_DESC_OFFSET_IN_MAX_PACKET_HI] = HIBYTE(mp);
+ uint8_t interval; // polling interval in frames of 1ms
+ if (pdev->dev_speed == USBD_SPEED_HIGH) {
+ interval = 0x09;
+ } else {
+ interval = 0x20;
+ }
+ cdc_desc[CDC_DESC_OFFSET_INTR_INTERVAL] = interval;
+}
+#endif
+
static uint8_t *USBD_CDC_MSC_HID_GetCfgDesc(USBD_HandleTypeDef *pdev, uint16_t *length) {
usbd_cdc_msc_hid_state_t *usbd = pdev->pClassData;
+
+ #if USBD_SUPPORT_HS_MODE
+ uint8_t *cdc_desc = NULL;
+ #if MICROPY_HW_USB_ENABLE_CDC2
+ uint8_t *cdc2_desc = NULL;
+ #endif
+ uint8_t *msc_desc = NULL;
+ switch (usbd->usbd_mode) {
+ case USBD_MODE_MSC:
+ msc_desc = usbd->usbd_config_desc + MSC_TEMPLATE_MSC_DESC_OFFSET;
+ break;
+
+ case USBD_MODE_CDC_MSC:
+ cdc_desc = usbd->usbd_config_desc + CDC_MSC_TEMPLATE_CDC_DESC_OFFSET;
+ msc_desc = usbd->usbd_config_desc + CDC_MSC_TEMPLATE_MSC_DESC_OFFSET;
+ break;
+
+ #if MICROPY_HW_USB_ENABLE_CDC2
+ case USBD_MODE_CDC2_MSC:
+ cdc_desc = usbd->usbd_config_desc + CDC2_MSC_TEMPLATE_CDC_DESC_OFFSET;
+ cdc2_desc = usbd->usbd_config_desc + CDC2_MSC_TEMPLATE_CDC2_DESC_OFFSET;
+ msc_desc = usbd->usbd_config_desc + CDC2_MSC_TEMPLATE_MSC_DESC_OFFSET;
+ break;
+ #endif
+
+ case USBD_MODE_CDC_HID:
+ cdc_desc = usbd->usbd_config_desc + CDC_HID_TEMPLATE_CDC_DESC_OFFSET;
+ break;
+
+ case USBD_MODE_CDC:
+ cdc_desc = usbd->usbd_config_desc + CDC_TEMPLATE_CDC_DESC_OFFSET;
+ break;
+ }
+
+ // configure CDC descriptors, if needed
+ if (cdc_desc != NULL) {
+ usbd_cdc_desc_config_max_packet(pdev, cdc_desc);
+ }
+
+ #if MICROPY_HW_USB_ENABLE_CDC2
+ if (cdc2_desc != NULL) {
+ usbd_cdc_desc_config_max_packet(pdev, cdc2_desc);
+ }
+ #endif
+
+ if (msc_desc != NULL) {
+ uint32_t mp = usbd_msc_max_packet(pdev);
+ msc_desc[13] = LOBYTE(mp);
+ msc_desc[14] = HIBYTE(mp);
+ msc_desc[20] = LOBYTE(mp);
+ msc_desc[21] = HIBYTE(mp);
+ }
+ #endif
+
*length = usbd->usbd_config_desc_size;
return usbd->usbd_config_desc;
}
-// this is used only in high-speed mode, which we don't support
uint8_t *USBD_CDC_MSC_HID_GetDeviceQualifierDescriptor(USBD_HandleTypeDef *pdev, uint16_t *length) {
- /*
+ #if USBD_SUPPORT_HS_MODE
*length = sizeof(USBD_CDC_MSC_HID_DeviceQualifierDesc);
return USBD_CDC_MSC_HID_DeviceQualifierDesc;
- */
+ #else
*length = 0;
return NULL;
+ #endif
}
// data received on non-control OUT endpoint
-uint8_t USBD_CDC_TransmitPacket(usbd_cdc_msc_hid_state_t *usbd, size_t len, const uint8_t *buf) {
- if (usbd->CDC_ClassData.TxState == 0) {
+uint8_t USBD_CDC_TransmitPacket(usbd_cdc_state_t *cdc, size_t len, const uint8_t *buf) {
+ if (cdc->tx_in_progress == 0) {
// transmit next packet
- USBD_LL_Transmit(usbd->pdev, CDC_IN_EP, (uint8_t*)buf, len);
+ USBD_LL_Transmit(cdc->usbd->pdev, cdc->in_ep, (uint8_t*)buf, len);
// Tx transfer in progress
- usbd->CDC_ClassData.TxState = 1;
+ cdc->tx_in_progress = 1;
return USBD_OK;
} else {
return USBD_BUSY;
@@ -974,60 +1230,67 @@ uint8_t USBD_CDC_TransmitPacket(usbd_cdc_msc_hid_state_t *usbd, size_t len, cons
}
// prepare OUT endpoint for reception
-uint8_t USBD_CDC_ReceivePacket(usbd_cdc_msc_hid_state_t *usbd, uint8_t *buf) {
+uint8_t USBD_CDC_ReceivePacket(usbd_cdc_state_t *cdc, uint8_t *buf) {
// Suspend or Resume USB Out process
- if (usbd->pdev->dev_speed == USBD_SPEED_HIGH) {
+
+ #if !USBD_SUPPORT_HS_MODE
+ if (cdc->usbd->pdev->dev_speed == USBD_SPEED_HIGH) {
return USBD_FAIL;
}
+ #endif
// Prepare Out endpoint to receive next packet
- USBD_LL_PrepareReceive(usbd->pdev, CDC_OUT_EP, buf, CDC_DATA_OUT_PACKET_SIZE);
+ USBD_LL_PrepareReceive(cdc->usbd->pdev, cdc->out_ep, buf, usbd_cdc_max_packet(cdc->usbd->pdev));
return USBD_OK;
}
// prepare OUT endpoint for reception
-uint8_t USBD_HID_ReceivePacket(usbd_cdc_msc_hid_state_t *usbd, uint8_t *buf) {
+uint8_t USBD_HID_ReceivePacket(usbd_hid_state_t *hid, uint8_t *buf) {
// Suspend or Resume USB Out process
- if (usbd->pdev->dev_speed == USBD_SPEED_HIGH) {
+
+ #if !USBD_SUPPORT_HS_MODE
+ if (hid->usbd->pdev->dev_speed == USBD_SPEED_HIGH) {
return USBD_FAIL;
}
+ #endif
// Prepare Out endpoint to receive next packet
uint16_t mps_out =
- usbd->hid_desc[HID_DESC_OFFSET_MAX_PACKET_OUT_LO]
- | (usbd->hid_desc[HID_DESC_OFFSET_MAX_PACKET_OUT_HI] << 8);
- USBD_LL_PrepareReceive(usbd->pdev, usbd->hid_out_ep, buf, mps_out);
+ hid->desc[HID_DESC_OFFSET_MAX_PACKET_OUT_LO]
+ | (hid->desc[HID_DESC_OFFSET_MAX_PACKET_OUT_HI] << 8);
+ USBD_LL_PrepareReceive(hid->usbd->pdev, hid->out_ep, buf, mps_out);
return USBD_OK;
}
-int USBD_HID_CanSendReport(usbd_cdc_msc_hid_state_t *usbd) {
- return usbd->pdev->dev_state == USBD_STATE_CONFIGURED && usbd->HID_ClassData.state == HID_IDLE;
+int USBD_HID_CanSendReport(usbd_hid_state_t *hid) {
+ return hid->usbd->pdev->dev_state == USBD_STATE_CONFIGURED && hid->state == HID_IDLE;
}
-uint8_t USBD_HID_SendReport(usbd_cdc_msc_hid_state_t *usbd, uint8_t *report, uint16_t len) {
- if (usbd->pdev->dev_state == USBD_STATE_CONFIGURED) {
- if (usbd->HID_ClassData.state == HID_IDLE) {
- usbd->HID_ClassData.state = HID_BUSY;
- USBD_LL_Transmit(usbd->pdev, usbd->hid_in_ep, report, len);
+uint8_t USBD_HID_SendReport(usbd_hid_state_t *hid, uint8_t *report, uint16_t len) {
+ if (hid->usbd->pdev->dev_state == USBD_STATE_CONFIGURED) {
+ if (hid->state == HID_IDLE) {
+ hid->state = HID_BUSY;
+ USBD_LL_Transmit(hid->usbd->pdev, hid->in_ep, report, len);
+ return USBD_OK;
}
}
- return USBD_OK;
+ return USBD_FAIL;
}
-uint8_t USBD_HID_SetNAK(usbd_cdc_msc_hid_state_t *usbd) {
+uint8_t USBD_HID_SetNAK(usbd_hid_state_t *hid) {
// get USBx object from pdev (needed for USBx_OUTEP macro below)
- PCD_HandleTypeDef *hpcd = usbd->pdev->pData;
+ PCD_HandleTypeDef *hpcd = hid->usbd->pdev->pData;
USB_OTG_GlobalTypeDef *USBx = hpcd->Instance;
// set NAK on HID OUT endpoint
USBx_OUTEP(HID_OUT_EP_WITH_CDC)->DOEPCTL |= USB_OTG_DOEPCTL_SNAK;
return USBD_OK;
}
-uint8_t USBD_HID_ClearNAK(usbd_cdc_msc_hid_state_t *usbd) {
+uint8_t USBD_HID_ClearNAK(usbd_hid_state_t *hid) {
// get USBx object from pdev (needed for USBx_OUTEP macro below)
- PCD_HandleTypeDef *hpcd = usbd->pdev->pData;
+ PCD_HandleTypeDef *hpcd = hid->usbd->pdev->pData;
USB_OTG_GlobalTypeDef *USBx = hpcd->Instance;
// clear NAK on HID OUT endpoint
USBx_OUTEP(HID_OUT_EP_WITH_CDC)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK;
@@ -1051,3 +1314,5 @@ const USBD_ClassTypeDef USBD_CDC_MSC_HID = {
USBD_CDC_MSC_HID_GetCfgDesc,
USBD_CDC_MSC_HID_GetDeviceQualifierDescriptor,
};
+
+#endif
diff --git a/ports/stm32/usbdev/class/src/usbd_msc_bot.c b/ports/stm32/usbdev/class/src/usbd_msc_bot.c
index 2fccd9e08..d20f7a8dc 100644
--- a/ports/stm32/usbdev/class/src/usbd_msc_bot.c
+++ b/ports/stm32/usbdev/class/src/usbd_msc_bot.c
@@ -1,407 +1,407 @@
-/**
- ******************************************************************************
- * @file usbd_msc_bot.c
- * @author MCD Application Team
- * @version V2.0.0
- * @date 18-February-2014
- * @brief This file provides all the BOT protocol core functions.
- ******************************************************************************
- * @attention
- *
- * <h2><center>&copy; COPYRIGHT 2014 STMicroelectronics</center></h2>
- *
- * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
- * You may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.st.com/software_license_agreement_liberty_v2
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- ******************************************************************************
- */
-
-/* Includes ------------------------------------------------------------------*/
-#include "usbd_msc_bot.h"
-#include "usbd_msc_scsi.h"
-#include "usbd_cdc_msc_hid.h"
-#include "usbd_ioreq.h"
-
-/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY
- * @{
- */
-
-
-/** @defgroup MSC_BOT
- * @brief BOT protocol module
- * @{
- */
-
-/** @defgroup MSC_BOT_Private_TypesDefinitions
- * @{
- */
-/**
- * @}
- */
-
-
-/** @defgroup MSC_BOT_Private_Defines
- * @{
- */
-
-/**
- * @}
- */
-
-
-/** @defgroup MSC_BOT_Private_Macros
- * @{
- */
-/**
- * @}
- */
-
-
-/** @defgroup MSC_BOT_Private_Variables
- * @{
- */
-
-/**
- * @}
- */
-
-
-/** @defgroup MSC_BOT_Private_FunctionPrototypes
- * @{
- */
-static void MSC_BOT_CBW_Decode (USBD_HandleTypeDef *pdev);
-
-static void MSC_BOT_SendData (USBD_HandleTypeDef *pdev,
- uint8_t* pbuf,
- uint16_t len);
-
-static void MSC_BOT_Abort(USBD_HandleTypeDef *pdev);
-/**
- * @}
- */
-
-
-/** @defgroup MSC_BOT_Private_Functions
- * @{
- */
-
-
-
-/**
-* @brief MSC_BOT_Init
-* Initialize the BOT Process
-* @param pdev: device instance
-* @retval None
-*/
-void MSC_BOT_Init (USBD_HandleTypeDef *pdev)
-{
- USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData;
-
- hmsc->bot_state = USBD_BOT_IDLE;
- hmsc->bot_status = USBD_BOT_STATUS_NORMAL;
-
- hmsc->scsi_sense_tail = 0;
- hmsc->scsi_sense_head = 0;
-
- hmsc->bdev_ops->Init(0);
-
- USBD_LL_FlushEP(pdev, MSC_OUT_EP);
- USBD_LL_FlushEP(pdev, MSC_IN_EP);
-
- /* Prapare EP to Receive First BOT Cmd */
- USBD_LL_PrepareReceive (pdev,
- MSC_OUT_EP,
- (uint8_t *)&hmsc->cbw,
- USBD_BOT_CBW_LENGTH);
-}
-
-/**
-* @brief MSC_BOT_Reset
-* Reset the BOT Machine
-* @param pdev: device instance
-* @retval None
-*/
-void MSC_BOT_Reset (USBD_HandleTypeDef *pdev)
-{
- USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData;
-
- hmsc->bot_state = USBD_BOT_IDLE;
- hmsc->bot_status = USBD_BOT_STATUS_RECOVERY;
-
- /* Prapare EP to Receive First BOT Cmd */
- USBD_LL_PrepareReceive (pdev,
- MSC_OUT_EP,
- (uint8_t *)&hmsc->cbw,
- USBD_BOT_CBW_LENGTH);
-}
-
-/**
-* @brief MSC_BOT_DeInit
-* Uninitialize the BOT Machine
-* @param pdev: device instance
-* @retval None
-*/
-void MSC_BOT_DeInit (USBD_HandleTypeDef *pdev)
-{
- USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData;
- hmsc->bot_state = USBD_BOT_IDLE;
-}
-
-/**
-* @brief MSC_BOT_DataIn
-* Handle BOT IN data stage
-* @param pdev: device instance
-* @param epnum: endpoint index
-* @retval None
-*/
-void MSC_BOT_DataIn (USBD_HandleTypeDef *pdev,
- uint8_t epnum)
-{
- USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData;
-
- switch (hmsc->bot_state)
- {
- case USBD_BOT_DATA_IN:
- if(SCSI_ProcessCmd(pdev,
- hmsc->cbw.bLUN,
- &hmsc->cbw.CB[0]) < 0)
- {
- MSC_BOT_SendCSW (pdev, USBD_CSW_CMD_FAILED);
- }
- break;
-
- case USBD_BOT_SEND_DATA:
- case USBD_BOT_LAST_DATA_IN:
- MSC_BOT_SendCSW (pdev, USBD_CSW_CMD_PASSED);
-
- break;
-
- default:
- break;
- }
-}
-/**
-* @brief MSC_BOT_DataOut
-* Proccess MSC OUT data
-* @param pdev: device instance
-* @param epnum: endpoint index
-* @retval None
-*/
-void MSC_BOT_DataOut (USBD_HandleTypeDef *pdev,
- uint8_t epnum)
-{
- USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData;
-
- switch (hmsc->bot_state)
- {
- case USBD_BOT_IDLE:
- MSC_BOT_CBW_Decode(pdev);
- break;
-
- case USBD_BOT_DATA_OUT:
-
- if(SCSI_ProcessCmd(pdev,
- hmsc->cbw.bLUN,
- &hmsc->cbw.CB[0]) < 0)
- {
- MSC_BOT_SendCSW (pdev, USBD_CSW_CMD_FAILED);
- }
-
- break;
-
- default:
- break;
- }
-}
-
-/**
-* @brief MSC_BOT_CBW_Decode
-* Decode the CBW command and set the BOT state machine accordingtly
-* @param pdev: device instance
-* @retval None
-*/
-static void MSC_BOT_CBW_Decode (USBD_HandleTypeDef *pdev)
-{
- USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData;
-
- hmsc->csw.dTag = hmsc->cbw.dTag;
- hmsc->csw.dDataResidue = hmsc->cbw.dDataLength;
-
- if ((USBD_LL_GetRxDataSize (pdev ,MSC_OUT_EP) != USBD_BOT_CBW_LENGTH) ||
- (hmsc->cbw.dSignature != USBD_BOT_CBW_SIGNATURE)||
- (hmsc->cbw.bLUN > 1) ||
- (hmsc->cbw.bCBLength < 1) ||
- (hmsc->cbw.bCBLength > 16))
- {
-
- SCSI_SenseCode(pdev,
- hmsc->cbw.bLUN,
- ILLEGAL_REQUEST,
- INVALID_CDB);
-
- hmsc->bot_status = USBD_BOT_STATUS_ERROR;
- MSC_BOT_Abort(pdev);
-
- }
- else
- {
- if(SCSI_ProcessCmd(pdev,
- hmsc->cbw.bLUN,
- &hmsc->cbw.CB[0]) < 0)
- {
- if(hmsc->bot_state == USBD_BOT_NO_DATA)
- {
- MSC_BOT_SendCSW (pdev,
- USBD_CSW_CMD_FAILED);
- }
- else
- {
- MSC_BOT_Abort(pdev);
- }
- }
- /*Burst xfer handled internally*/
- else if ((hmsc->bot_state != USBD_BOT_DATA_IN) &&
- (hmsc->bot_state != USBD_BOT_DATA_OUT) &&
- (hmsc->bot_state != USBD_BOT_LAST_DATA_IN))
- {
- if (hmsc->bot_data_length > 0)
- {
- MSC_BOT_SendData(pdev,
- hmsc->bot_data,
- hmsc->bot_data_length);
- }
- else if (hmsc->bot_data_length == 0)
- {
- MSC_BOT_SendCSW (pdev,
- USBD_CSW_CMD_PASSED);
- }
- }
- }
-}
-
-/**
-* @brief MSC_BOT_SendData
-* Send the requested data
-* @param pdev: device instance
-* @param buf: pointer to data buffer
-* @param len: Data Length
-* @retval None
-*/
-static void MSC_BOT_SendData(USBD_HandleTypeDef *pdev,
- uint8_t* buf,
- uint16_t len)
-{
- USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData;
-
- len = MIN (hmsc->cbw.dDataLength, len);
- hmsc->csw.dDataResidue -= len;
- hmsc->csw.bStatus = USBD_CSW_CMD_PASSED;
- hmsc->bot_state = USBD_BOT_SEND_DATA;
-
- USBD_LL_Transmit (pdev, MSC_IN_EP, buf, len);
-}
-
-/**
-* @brief MSC_BOT_SendCSW
-* Send the Command Status Wrapper
-* @param pdev: device instance
-* @param status : CSW status
-* @retval None
-*/
-void MSC_BOT_SendCSW (USBD_HandleTypeDef *pdev,
- uint8_t CSW_Status)
-{
- USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData;
-
- hmsc->csw.dSignature = USBD_BOT_CSW_SIGNATURE;
- hmsc->csw.bStatus = CSW_Status;
- hmsc->bot_state = USBD_BOT_IDLE;
-
- USBD_LL_Transmit (pdev,
- MSC_IN_EP,
- (uint8_t *)&hmsc->csw,
- USBD_BOT_CSW_LENGTH);
-
- /* Prapare EP to Receive next Cmd */
- USBD_LL_PrepareReceive (pdev,
- MSC_OUT_EP,
- (uint8_t *)&hmsc->cbw,
- USBD_BOT_CBW_LENGTH);
-
-}
-
-/**
-* @brief MSC_BOT_Abort
-* Abort the current transfer
-* @param pdev: device instance
-* @retval status
-*/
-
-static void MSC_BOT_Abort (USBD_HandleTypeDef *pdev)
-{
- USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData;
-
- if ((hmsc->cbw.bmFlags == 0) &&
- (hmsc->cbw.dDataLength != 0) &&
- (hmsc->bot_status == USBD_BOT_STATUS_NORMAL) )
- {
- USBD_LL_StallEP(pdev, MSC_OUT_EP );
- }
- USBD_LL_StallEP(pdev, MSC_IN_EP);
-
- if(hmsc->bot_status == USBD_BOT_STATUS_ERROR)
- {
- USBD_LL_PrepareReceive (pdev,
- MSC_OUT_EP,
- (uint8_t *)&hmsc->cbw,
- USBD_BOT_CBW_LENGTH);
- }
-}
-
-/**
-* @brief MSC_BOT_CplClrFeature
-* Complete the clear feature request
-* @param pdev: device instance
-* @param epnum: endpoint index
-* @retval None
-*/
-
-void MSC_BOT_CplClrFeature (USBD_HandleTypeDef *pdev, uint8_t epnum)
-{
- USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData;
-
- if(hmsc->bot_status == USBD_BOT_STATUS_ERROR )/* Bad CBW Signature */
- {
- USBD_LL_StallEP(pdev, MSC_IN_EP);
- hmsc->bot_status = USBD_BOT_STATUS_NORMAL;
- }
- else if(((epnum & 0x80) == 0x80) && ( hmsc->bot_status != USBD_BOT_STATUS_RECOVERY))
- {
- MSC_BOT_SendCSW (pdev, USBD_CSW_CMD_FAILED);
- }
-
-}
-/**
- * @}
- */
-
-
-/**
- * @}
- */
-
-
-/**
- * @}
- */
-
-/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
+/**
+ ******************************************************************************
+ * @file usbd_msc_bot.c
+ * @author MCD Application Team
+ * @version V2.0.0
+ * @date 18-February-2014
+ * @brief This file provides all the BOT protocol core functions.
+ ******************************************************************************
+ * @attention
+ *
+ * <h2><center>&copy; COPYRIGHT 2014 STMicroelectronics</center></h2>
+ *
+ * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
+ * You may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.st.com/software_license_agreement_liberty_v2
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************
+ */
+
+/* Includes ------------------------------------------------------------------*/
+#include "usbd_msc_bot.h"
+#include "usbd_msc_scsi.h"
+#include "usbd_cdc_msc_hid.h"
+#include "usbd_ioreq.h"
+
+/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY
+ * @{
+ */
+
+
+/** @defgroup MSC_BOT
+ * @brief BOT protocol module
+ * @{
+ */
+
+/** @defgroup MSC_BOT_Private_TypesDefinitions
+ * @{
+ */
+/**
+ * @}
+ */
+
+
+/** @defgroup MSC_BOT_Private_Defines
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+
+/** @defgroup MSC_BOT_Private_Macros
+ * @{
+ */
+/**
+ * @}
+ */
+
+
+/** @defgroup MSC_BOT_Private_Variables
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+
+/** @defgroup MSC_BOT_Private_FunctionPrototypes
+ * @{
+ */
+static void MSC_BOT_CBW_Decode (USBD_HandleTypeDef *pdev);
+
+static void MSC_BOT_SendData (USBD_HandleTypeDef *pdev,
+ uint8_t* pbuf,
+ uint16_t len);
+
+static void MSC_BOT_Abort(USBD_HandleTypeDef *pdev);
+/**
+ * @}
+ */
+
+
+/** @defgroup MSC_BOT_Private_Functions
+ * @{
+ */
+
+
+
+/**
+* @brief MSC_BOT_Init
+* Initialize the BOT Process
+* @param pdev: device instance
+* @retval None
+*/
+void MSC_BOT_Init (USBD_HandleTypeDef *pdev)
+{
+ USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData;
+
+ hmsc->bot_state = USBD_BOT_IDLE;
+ hmsc->bot_status = USBD_BOT_STATUS_NORMAL;
+
+ hmsc->scsi_sense_tail = 0;
+ hmsc->scsi_sense_head = 0;
+
+ hmsc->bdev_ops->Init(0);
+
+ USBD_LL_FlushEP(pdev, MSC_OUT_EP);
+ USBD_LL_FlushEP(pdev, MSC_IN_EP);
+
+ /* Prapare EP to Receive First BOT Cmd */
+ USBD_LL_PrepareReceive (pdev,
+ MSC_OUT_EP,
+ (uint8_t *)&hmsc->cbw,
+ USBD_BOT_CBW_LENGTH);
+}
+
+/**
+* @brief MSC_BOT_Reset
+* Reset the BOT Machine
+* @param pdev: device instance
+* @retval None
+*/
+void MSC_BOT_Reset (USBD_HandleTypeDef *pdev)
+{
+ USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData;
+
+ hmsc->bot_state = USBD_BOT_IDLE;
+ hmsc->bot_status = USBD_BOT_STATUS_RECOVERY;
+
+ /* Prapare EP to Receive First BOT Cmd */
+ USBD_LL_PrepareReceive (pdev,
+ MSC_OUT_EP,
+ (uint8_t *)&hmsc->cbw,
+ USBD_BOT_CBW_LENGTH);
+}
+
+/**
+* @brief MSC_BOT_DeInit
+* Uninitialize the BOT Machine
+* @param pdev: device instance
+* @retval None
+*/
+void MSC_BOT_DeInit (USBD_HandleTypeDef *pdev)
+{
+ USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData;
+ hmsc->bot_state = USBD_BOT_IDLE;
+}
+
+/**
+* @brief MSC_BOT_DataIn
+* Handle BOT IN data stage
+* @param pdev: device instance
+* @param epnum: endpoint index
+* @retval None
+*/
+void MSC_BOT_DataIn (USBD_HandleTypeDef *pdev,
+ uint8_t epnum)
+{
+ USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData;
+
+ switch (hmsc->bot_state)
+ {
+ case USBD_BOT_DATA_IN:
+ if(SCSI_ProcessCmd(pdev,
+ hmsc->cbw.bLUN,
+ &hmsc->cbw.CB[0]) < 0)
+ {
+ MSC_BOT_SendCSW (pdev, USBD_CSW_CMD_FAILED);
+ }
+ break;
+
+ case USBD_BOT_SEND_DATA:
+ case USBD_BOT_LAST_DATA_IN:
+ MSC_BOT_SendCSW (pdev, USBD_CSW_CMD_PASSED);
+
+ break;
+
+ default:
+ break;
+ }
+}
+/**
+* @brief MSC_BOT_DataOut
+* Proccess MSC OUT data
+* @param pdev: device instance
+* @param epnum: endpoint index
+* @retval None
+*/
+void MSC_BOT_DataOut (USBD_HandleTypeDef *pdev,
+ uint8_t epnum)
+{
+ USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData;
+
+ switch (hmsc->bot_state)
+ {
+ case USBD_BOT_IDLE:
+ MSC_BOT_CBW_Decode(pdev);
+ break;
+
+ case USBD_BOT_DATA_OUT:
+
+ if(SCSI_ProcessCmd(pdev,
+ hmsc->cbw.bLUN,
+ &hmsc->cbw.CB[0]) < 0)
+ {
+ MSC_BOT_SendCSW (pdev, USBD_CSW_CMD_FAILED);
+ }
+
+ break;
+
+ default:
+ break;
+ }
+}
+
+/**
+* @brief MSC_BOT_CBW_Decode
+* Decode the CBW command and set the BOT state machine accordingtly
+* @param pdev: device instance
+* @retval None
+*/
+static void MSC_BOT_CBW_Decode (USBD_HandleTypeDef *pdev)
+{
+ USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData;
+
+ hmsc->csw.dTag = hmsc->cbw.dTag;
+ hmsc->csw.dDataResidue = hmsc->cbw.dDataLength;
+
+ if ((USBD_LL_GetRxDataSize (pdev ,MSC_OUT_EP) != USBD_BOT_CBW_LENGTH) ||
+ (hmsc->cbw.dSignature != USBD_BOT_CBW_SIGNATURE)||
+ (hmsc->cbw.bLUN > 1) ||
+ (hmsc->cbw.bCBLength < 1) ||
+ (hmsc->cbw.bCBLength > 16))
+ {
+
+ SCSI_SenseCode(pdev,
+ hmsc->cbw.bLUN,
+ ILLEGAL_REQUEST,
+ INVALID_CDB);
+
+ hmsc->bot_status = USBD_BOT_STATUS_ERROR;
+ MSC_BOT_Abort(pdev);
+
+ }
+ else
+ {
+ if(SCSI_ProcessCmd(pdev,
+ hmsc->cbw.bLUN,
+ &hmsc->cbw.CB[0]) < 0)
+ {
+ if(hmsc->bot_state == USBD_BOT_NO_DATA)
+ {
+ MSC_BOT_SendCSW (pdev,
+ USBD_CSW_CMD_FAILED);
+ }
+ else
+ {
+ MSC_BOT_Abort(pdev);
+ }
+ }
+ /*Burst xfer handled internally*/
+ else if ((hmsc->bot_state != USBD_BOT_DATA_IN) &&
+ (hmsc->bot_state != USBD_BOT_DATA_OUT) &&
+ (hmsc->bot_state != USBD_BOT_LAST_DATA_IN))
+ {
+ if (hmsc->bot_data_length > 0)
+ {
+ MSC_BOT_SendData(pdev,
+ hmsc->bot_data,
+ hmsc->bot_data_length);
+ }
+ else if (hmsc->bot_data_length == 0)
+ {
+ MSC_BOT_SendCSW (pdev,
+ USBD_CSW_CMD_PASSED);
+ }
+ }
+ }
+}
+
+/**
+* @brief MSC_BOT_SendData
+* Send the requested data
+* @param pdev: device instance
+* @param buf: pointer to data buffer
+* @param len: Data Length
+* @retval None
+*/
+static void MSC_BOT_SendData(USBD_HandleTypeDef *pdev,
+ uint8_t* buf,
+ uint16_t len)
+{
+ USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData;
+
+ len = MIN (hmsc->cbw.dDataLength, len);
+ hmsc->csw.dDataResidue -= len;
+ hmsc->csw.bStatus = USBD_CSW_CMD_PASSED;
+ hmsc->bot_state = USBD_BOT_SEND_DATA;
+
+ USBD_LL_Transmit (pdev, MSC_IN_EP, buf, len);
+}
+
+/**
+* @brief MSC_BOT_SendCSW
+* Send the Command Status Wrapper
+* @param pdev: device instance
+* @param status : CSW status
+* @retval None
+*/
+void MSC_BOT_SendCSW (USBD_HandleTypeDef *pdev,
+ uint8_t CSW_Status)
+{
+ USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData;
+
+ hmsc->csw.dSignature = USBD_BOT_CSW_SIGNATURE;
+ hmsc->csw.bStatus = CSW_Status;
+ hmsc->bot_state = USBD_BOT_IDLE;
+
+ USBD_LL_Transmit (pdev,
+ MSC_IN_EP,
+ (uint8_t *)&hmsc->csw,
+ USBD_BOT_CSW_LENGTH);
+
+ /* Prapare EP to Receive next Cmd */
+ USBD_LL_PrepareReceive (pdev,
+ MSC_OUT_EP,
+ (uint8_t *)&hmsc->cbw,
+ USBD_BOT_CBW_LENGTH);
+
+}
+
+/**
+* @brief MSC_BOT_Abort
+* Abort the current transfer
+* @param pdev: device instance
+* @retval status
+*/
+
+static void MSC_BOT_Abort (USBD_HandleTypeDef *pdev)
+{
+ USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData;
+
+ if ((hmsc->cbw.bmFlags == 0) &&
+ (hmsc->cbw.dDataLength != 0) &&
+ (hmsc->bot_status == USBD_BOT_STATUS_NORMAL) )
+ {
+ USBD_LL_StallEP(pdev, MSC_OUT_EP );
+ }
+ USBD_LL_StallEP(pdev, MSC_IN_EP);
+
+ if(hmsc->bot_status == USBD_BOT_STATUS_ERROR)
+ {
+ USBD_LL_PrepareReceive (pdev,
+ MSC_OUT_EP,
+ (uint8_t *)&hmsc->cbw,
+ USBD_BOT_CBW_LENGTH);
+ }
+}
+
+/**
+* @brief MSC_BOT_CplClrFeature
+* Complete the clear feature request
+* @param pdev: device instance
+* @param epnum: endpoint index
+* @retval None
+*/
+
+void MSC_BOT_CplClrFeature (USBD_HandleTypeDef *pdev, uint8_t epnum)
+{
+ USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData;
+
+ if(hmsc->bot_status == USBD_BOT_STATUS_ERROR )/* Bad CBW Signature */
+ {
+ USBD_LL_StallEP(pdev, MSC_IN_EP);
+ hmsc->bot_status = USBD_BOT_STATUS_NORMAL;
+ }
+ else if(((epnum & 0x80) == 0x80) && ( hmsc->bot_status != USBD_BOT_STATUS_RECOVERY))
+ {
+ MSC_BOT_SendCSW (pdev, USBD_CSW_CMD_FAILED);
+ }
+
+}
+/**
+ * @}
+ */
+
+
+/**
+ * @}
+ */
+
+
+/**
+ * @}
+ */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/ports/stm32/usbdev/class/src/usbd_msc_data.c b/ports/stm32/usbdev/class/src/usbd_msc_data.c
index 4d72bd5fc..96740a3a4 100644
--- a/ports/stm32/usbdev/class/src/usbd_msc_data.c
+++ b/ports/stm32/usbdev/class/src/usbd_msc_data.c
@@ -1,134 +1,134 @@
-/**
- ******************************************************************************
- * @file usbd_msc_data.c
- * @author MCD Application Team
- * @version V2.0.0
- * @date 18-February-2014
- * @brief This file provides all the vital inquiry pages and sense data.
- ******************************************************************************
- * @attention
- *
- * <h2><center>&copy; COPYRIGHT 2014 STMicroelectronics</center></h2>
- *
- * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
- * You may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.st.com/software_license_agreement_liberty_v2
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- ******************************************************************************
- */
-
-/* Includes ------------------------------------------------------------------*/
-#include "usbd_msc_data.h"
-
-
-/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY
- * @{
- */
-
-
-/** @defgroup MSC_DATA
- * @brief Mass storage info/data module
- * @{
- */
-
-/** @defgroup MSC_DATA_Private_TypesDefinitions
- * @{
- */
-/**
- * @}
- */
-
-
-/** @defgroup MSC_DATA_Private_Defines
- * @{
- */
-/**
- * @}
- */
-
-
-/** @defgroup MSC_DATA_Private_Macros
- * @{
- */
-/**
- * @}
- */
-
-
-/** @defgroup MSC_DATA_Private_Variables
- * @{
- */
-
-
-/* USB Mass storage Page 0 Inquiry Data */
-const uint8_t MSC_Page00_Inquiry_Data[] = {//7
- 0x00,
- 0x00,
- 0x00,
- (LENGTH_INQUIRY_PAGE00 - 4),
- 0x00,
- 0x80,
- 0x83
-};
-/* USB Mass storage sense 6 Data */
-const uint8_t MSC_Mode_Sense6_data[] = {
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x00
-};
-/* USB Mass storage sense 10 Data */
-const uint8_t MSC_Mode_Sense10_data[] = {
- 0x00,
- 0x06,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x00
-};
-/**
- * @}
- */
-
-
-/** @defgroup MSC_DATA_Private_FunctionPrototypes
- * @{
- */
-/**
- * @}
- */
-
-
-/** @defgroup MSC_DATA_Private_Functions
- * @{
- */
-
-/**
- * @}
- */
-
-
-/**
- * @}
- */
-
-
-/**
- * @}
- */
-
-/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
+/**
+ ******************************************************************************
+ * @file usbd_msc_data.c
+ * @author MCD Application Team
+ * @version V2.0.0
+ * @date 18-February-2014
+ * @brief This file provides all the vital inquiry pages and sense data.
+ ******************************************************************************
+ * @attention
+ *
+ * <h2><center>&copy; COPYRIGHT 2014 STMicroelectronics</center></h2>
+ *
+ * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
+ * You may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.st.com/software_license_agreement_liberty_v2
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************
+ */
+
+/* Includes ------------------------------------------------------------------*/
+#include "usbd_msc_data.h"
+
+
+/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY
+ * @{
+ */
+
+
+/** @defgroup MSC_DATA
+ * @brief Mass storage info/data module
+ * @{
+ */
+
+/** @defgroup MSC_DATA_Private_TypesDefinitions
+ * @{
+ */
+/**
+ * @}
+ */
+
+
+/** @defgroup MSC_DATA_Private_Defines
+ * @{
+ */
+/**
+ * @}
+ */
+
+
+/** @defgroup MSC_DATA_Private_Macros
+ * @{
+ */
+/**
+ * @}
+ */
+
+
+/** @defgroup MSC_DATA_Private_Variables
+ * @{
+ */
+
+
+/* USB Mass storage Page 0 Inquiry Data */
+const uint8_t MSC_Page00_Inquiry_Data[] = {//7
+ 0x00,
+ 0x00,
+ 0x00,
+ (LENGTH_INQUIRY_PAGE00 - 4),
+ 0x00,
+ 0x80,
+ 0x83
+};
+/* USB Mass storage sense 6 Data */
+const uint8_t MSC_Mode_Sense6_data[] = {
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00
+};
+/* USB Mass storage sense 10 Data */
+const uint8_t MSC_Mode_Sense10_data[] = {
+ 0x00,
+ 0x06,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00
+};
+/**
+ * @}
+ */
+
+
+/** @defgroup MSC_DATA_Private_FunctionPrototypes
+ * @{
+ */
+/**
+ * @}
+ */
+
+
+/** @defgroup MSC_DATA_Private_Functions
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+
+/**
+ * @}
+ */
+
+
+/**
+ * @}
+ */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/ports/stm32/usbdev/class/src/usbd_msc_scsi.c b/ports/stm32/usbdev/class/src/usbd_msc_scsi.c
index 50cd5b971..9da903377 100644
--- a/ports/stm32/usbdev/class/src/usbd_msc_scsi.c
+++ b/ports/stm32/usbdev/class/src/usbd_msc_scsi.c
@@ -1,811 +1,811 @@
-/**
- ******************************************************************************
- * @file usbd_msc_scsi.c
- * @author MCD Application Team
- * @version V2.0.0
- * @date 18-February-2014
- * @brief This file provides all the USBD SCSI layer functions.
- ******************************************************************************
- * @attention
- *
- * <h2><center>&copy; COPYRIGHT 2014 STMicroelectronics</center></h2>
- *
- * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
- * You may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.st.com/software_license_agreement_liberty_v2
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- ******************************************************************************
- */
-
-/* Includes ------------------------------------------------------------------*/
-#include "usbd_msc_bot.h"
-#include "usbd_msc_scsi.h"
-#include "usbd_msc_data.h"
-#include "usbd_cdc_msc_hid.h"
-
-
-
-/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY
- * @{
- */
-
-
-/** @defgroup MSC_SCSI
- * @brief Mass storage SCSI layer module
- * @{
- */
-
-/** @defgroup MSC_SCSI_Private_TypesDefinitions
- * @{
- */
-/**
- * @}
- */
-
-
-/** @defgroup MSC_SCSI_Private_Defines
- * @{
- */
-
-/**
- * @}
- */
-
-
-/** @defgroup MSC_SCSI_Private_Macros
- * @{
- */
-/**
- * @}
- */
-
-
-/** @defgroup MSC_SCSI_Private_Variables
- * @{
- */
-
-/**
- * @}
- */
-
-
-/** @defgroup MSC_SCSI_Private_FunctionPrototypes
- * @{
- */
-static int8_t SCSI_TestUnitReady(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params);
-static int8_t SCSI_Inquiry(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params);
-static int8_t SCSI_ReadFormatCapacity(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params);
-static int8_t SCSI_ReadCapacity10(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params);
-static int8_t SCSI_RequestSense (USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params);
-static int8_t SCSI_StartStopUnit(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params);
-static int8_t SCSI_AllowMediumRemoval(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params);
-static int8_t SCSI_ModeSense6 (USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params);
-static int8_t SCSI_ModeSense10 (USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params);
-static int8_t SCSI_SynchronizeCache(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params);
-static int8_t SCSI_Write10(USBD_HandleTypeDef *pdev, uint8_t lun , uint8_t *params);
-static int8_t SCSI_Read10(USBD_HandleTypeDef *pdev, uint8_t lun , uint8_t *params);
-static int8_t SCSI_Verify10(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params);
-static int8_t SCSI_CheckAddressRange (USBD_HandleTypeDef *pdev,
- uint8_t lun ,
- uint32_t blk_offset ,
- uint16_t blk_nbr);
-static int8_t SCSI_ProcessRead (USBD_HandleTypeDef *pdev,
- uint8_t lun);
-
-static int8_t SCSI_ProcessWrite (USBD_HandleTypeDef *pdev,
- uint8_t lun);
-/**
- * @}
- */
-
-
-/** @defgroup MSC_SCSI_Private_Functions
- * @{
- */
-
-
-/**
-* @brief SCSI_ProcessCmd
-* Process SCSI commands
-* @param pdev: device instance
-* @param lun: Logical unit number
-* @param params: Command parameters
-* @retval status
-*/
-int8_t SCSI_ProcessCmd(USBD_HandleTypeDef *pdev,
- uint8_t lun,
- uint8_t *params)
-{
- /*
- if (params[0] != SCSI_READ10 && params[0] != SCSI_WRITE10) {
- printf("SCSI_ProcessCmd(lun=%d, params=%x, %x)\n", lun, params[0], params[1]);
- }
- */
-
- switch (params[0])
- {
- case SCSI_TEST_UNIT_READY:
- return SCSI_TestUnitReady(pdev, lun, params);
-
- case SCSI_REQUEST_SENSE:
- return SCSI_RequestSense (pdev, lun, params);
- case SCSI_INQUIRY:
- return SCSI_Inquiry(pdev, lun, params);
-
- case SCSI_START_STOP_UNIT:
- return SCSI_StartStopUnit(pdev, lun, params);
-
- case SCSI_ALLOW_MEDIUM_REMOVAL:
- return SCSI_AllowMediumRemoval(pdev, lun, params);
-
- case SCSI_MODE_SENSE6:
- return SCSI_ModeSense6 (pdev, lun, params);
-
- case SCSI_MODE_SENSE10:
- return SCSI_ModeSense10 (pdev, lun, params);
-
- case SCSI_SYNCHRONIZE_CACHE10:
- case SCSI_SYNCHRONIZE_CACHE16:
- return SCSI_SynchronizeCache(pdev, lun, params);
-
- case SCSI_READ_FORMAT_CAPACITIES:
- return SCSI_ReadFormatCapacity(pdev, lun, params);
-
- case SCSI_READ_CAPACITY10:
- return SCSI_ReadCapacity10(pdev, lun, params);
-
- case SCSI_READ10:
- return SCSI_Read10(pdev, lun, params);
-
- case SCSI_WRITE10:
- return SCSI_Write10(pdev, lun, params);
-
- case SCSI_VERIFY10:
- return SCSI_Verify10(pdev, lun, params);
-
- default:
- SCSI_SenseCode(pdev,
- lun,
- ILLEGAL_REQUEST,
- INVALID_CDB);
- return -1;
- }
-}
-
-
-/**
-* @brief SCSI_TestUnitReady
-* Process SCSI Test Unit Ready Command
-* @param lun: Logical unit number
-* @param params: Command parameters
-* @retval status
-*/
-static int8_t SCSI_TestUnitReady(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params)
-{
- USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData;
-
- /* case 9 : Hi > D0 */
- if (hmsc->cbw.dDataLength != 0)
- {
- SCSI_SenseCode(pdev,
- hmsc->cbw.bLUN,
- ILLEGAL_REQUEST,
- INVALID_CDB);
- return -1;
- }
-
- if(hmsc->bdev_ops->IsReady(lun) !=0 )
- {
- SCSI_SenseCode(pdev,
- lun,
- NOT_READY,
- MEDIUM_NOT_PRESENT);
-
- hmsc->bot_state = USBD_BOT_NO_DATA;
- return -1;
- }
- hmsc->bot_data_length = 0;
- return 0;
-}
-
-/**
-* @brief SCSI_Inquiry
-* Process Inquiry command
-* @param lun: Logical unit number
-* @param params: Command parameters
-* @retval status
-*/
-static int8_t SCSI_Inquiry(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params)
-{
- uint8_t* pPage;
- uint16_t len;
- USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData;
-
- if (params[1] & 0x01)/*Evpd is set*/
- {
- pPage = (uint8_t *)MSC_Page00_Inquiry_Data;
- len = LENGTH_INQUIRY_PAGE00;
- }
- else
- {
-
- pPage = (uint8_t *)&hmsc->bdev_ops->pInquiry[lun * STANDARD_INQUIRY_DATA_LEN];
- len = pPage[4] + 5;
-
- if (params[4] <= len)
- {
- len = params[4];
- }
- }
- hmsc->bot_data_length = len;
-
- while (len)
- {
- len--;
- hmsc->bot_data[len] = pPage[len];
- }
- return 0;
-}
-
-/**
-* @brief SCSI_ReadCapacity10
-* Process Read Capacity 10 command
-* @param lun: Logical unit number
-* @param params: Command parameters
-* @retval status
-*/
-static int8_t SCSI_ReadCapacity10(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params)
-{
- USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData;
-
- if(hmsc->bdev_ops->GetCapacity(lun, &hmsc->scsi_blk_nbr, &hmsc->scsi_blk_size) != 0)
- {
- SCSI_SenseCode(pdev,
- lun,
- NOT_READY,
- MEDIUM_NOT_PRESENT);
- return -1;
- }
- else
- {
-
- hmsc->bot_data[0] = (uint8_t)((hmsc->scsi_blk_nbr - 1) >> 24);
- hmsc->bot_data[1] = (uint8_t)((hmsc->scsi_blk_nbr - 1) >> 16);
- hmsc->bot_data[2] = (uint8_t)((hmsc->scsi_blk_nbr - 1) >> 8);
- hmsc->bot_data[3] = (uint8_t)(hmsc->scsi_blk_nbr - 1);
-
- hmsc->bot_data[4] = (uint8_t)(hmsc->scsi_blk_size >> 24);
- hmsc->bot_data[5] = (uint8_t)(hmsc->scsi_blk_size >> 16);
- hmsc->bot_data[6] = (uint8_t)(hmsc->scsi_blk_size >> 8);
- hmsc->bot_data[7] = (uint8_t)(hmsc->scsi_blk_size);
-
- hmsc->bot_data_length = 8;
- return 0;
- }
-}
-/**
-* @brief SCSI_ReadFormatCapacity
-* Process Read Format Capacity command
-* @param lun: Logical unit number
-* @param params: Command parameters
-* @retval status
-*/
-static int8_t SCSI_ReadFormatCapacity(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params)
-{
- USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData;
-
- uint16_t blk_size;
- uint32_t blk_nbr;
- uint16_t i;
-
- for(i=0 ; i < 12 ; i++)
- {
- hmsc->bot_data[i] = 0;
- }
-
- if(hmsc->bdev_ops->GetCapacity(lun, &blk_nbr, &blk_size) != 0)
- {
- SCSI_SenseCode(pdev,
- lun,
- NOT_READY,
- MEDIUM_NOT_PRESENT);
- return -1;
- }
- else
- {
- hmsc->bot_data[3] = 0x08;
- hmsc->bot_data[4] = (uint8_t)((blk_nbr - 1) >> 24);
- hmsc->bot_data[5] = (uint8_t)((blk_nbr - 1) >> 16);
- hmsc->bot_data[6] = (uint8_t)((blk_nbr - 1) >> 8);
- hmsc->bot_data[7] = (uint8_t)(blk_nbr - 1);
-
- hmsc->bot_data[8] = 0x02;
- hmsc->bot_data[9] = (uint8_t)(blk_size >> 16);
- hmsc->bot_data[10] = (uint8_t)(blk_size >> 8);
- hmsc->bot_data[11] = (uint8_t)(blk_size);
-
- hmsc->bot_data_length = 12;
- return 0;
- }
-}
-/**
-* @brief SCSI_ModeSense6
-* Process Mode Sense6 command
-* @param lun: Logical unit number
-* @param params: Command parameters
-* @retval status
-*/
-static int8_t SCSI_ModeSense6 (USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params)
-{
- USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData;
- uint16_t len = 8 ;
- hmsc->bot_data_length = len;
-
- while (len)
- {
- len--;
- hmsc->bot_data[len] = MSC_Mode_Sense6_data[len];
- }
- return 0;
-}
-
-/**
-* @brief SCSI_ModeSense10
-* Process Mode Sense10 command
-* @param lun: Logical unit number
-* @param params: Command parameters
-* @retval status
-*/
-static int8_t SCSI_ModeSense10 (USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params)
-{
- uint16_t len = 8;
- USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData;
-
- hmsc->bot_data_length = len;
-
- while (len)
- {
- len--;
- hmsc->bot_data[len] = MSC_Mode_Sense10_data[len];
- }
- return 0;
-}
-
-static int8_t SCSI_SynchronizeCache(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params) {
- // nothing to synchronize, so just return "success"
- USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData;
- hmsc->bot_data_length = 0;
- return 0;
-}
-
-/**
-* @brief SCSI_RequestSense
-* Process Request Sense command
-* @param lun: Logical unit number
-* @param params: Command parameters
-* @retval status
-*/
-
-static int8_t SCSI_RequestSense (USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params)
-{
- uint8_t i;
- USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData;
-
- for(i=0 ; i < REQUEST_SENSE_DATA_LEN ; i++)
- {
- hmsc->bot_data[i] = 0;
- }
-
- hmsc->bot_data[0] = 0x70;
- hmsc->bot_data[7] = REQUEST_SENSE_DATA_LEN - 6;
-
- if((hmsc->scsi_sense_head != hmsc->scsi_sense_tail)) {
-
- hmsc->bot_data[2] = hmsc->scsi_sense[hmsc->scsi_sense_head].Skey;
- hmsc->bot_data[12] = hmsc->scsi_sense[hmsc->scsi_sense_head].w.b.ASCQ;
- hmsc->bot_data[13] = hmsc->scsi_sense[hmsc->scsi_sense_head].w.b.ASC;
- hmsc->scsi_sense_head++;
-
- if (hmsc->scsi_sense_head == SENSE_LIST_DEEPTH)
- {
- hmsc->scsi_sense_head = 0;
- }
- }
- hmsc->bot_data_length = REQUEST_SENSE_DATA_LEN;
-
- if (params[4] <= REQUEST_SENSE_DATA_LEN)
- {
- hmsc->bot_data_length = params[4];
- }
- return 0;
-}
-
-/**
-* @brief SCSI_SenseCode
-* Load the last error code in the error list
-* @param lun: Logical unit number
-* @param sKey: Sense Key
-* @param ASC: Additional Sense Key
-* @retval none
-
-*/
-void SCSI_SenseCode(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t sKey, uint8_t ASC)
-{
- USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData;
-
- hmsc->scsi_sense[hmsc->scsi_sense_tail].Skey = sKey;
- hmsc->scsi_sense[hmsc->scsi_sense_tail].w.ASC = ASC << 8;
- hmsc->scsi_sense_tail++;
- if (hmsc->scsi_sense_tail == SENSE_LIST_DEEPTH)
- {
- hmsc->scsi_sense_tail = 0;
- }
-}
-/**
-* @brief SCSI_StartStopUnit
-* Process Start Stop Unit command
-* @param lun: Logical unit number
-* @param params: Command parameters
-* @retval status
-*/
-static int8_t SCSI_StartStopUnit(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params)
-{
- USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData;
- hmsc->bot_data_length = 0;
-
- // On Mac OS X, when the device is ejected a SCSI_START_STOP_UNIT command is sent.
- // Bit 0 of params[4] is the START bit.
- // If we get a stop, we must really stop the device so that the Mac does not
- // automatically remount it.
- hmsc->bdev_ops->StartStopUnit(lun, params[4] & 1);
-
- return 0;
-}
-
-/**
-* @brief SCSI_AllowMediumRemoval
-* Process Allow Medium Removal command
-* @param lun: Logical unit number
-* @param params: Command parameters
-* @retval status
-*/
-static int8_t SCSI_AllowMediumRemoval(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params)
-{
- USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData;
- hmsc->bot_data_length = 0;
- hmsc->bdev_ops->PreventAllowMediumRemoval(lun, params[0]);
- return 0;
-}
-
-/**
-* @brief SCSI_Read10
-* Process Read10 command
-* @param lun: Logical unit number
-* @param params: Command parameters
-* @retval status
-*/
-static int8_t SCSI_Read10(USBD_HandleTypeDef *pdev, uint8_t lun , uint8_t *params)
-{
- USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData;
-
- if(hmsc->bot_state == USBD_BOT_IDLE) /* Idle */
- {
-
- /* case 10 : Ho <> Di */
-
- if ((hmsc->cbw.bmFlags & 0x80) != 0x80)
- {
- SCSI_SenseCode(pdev,
- hmsc->cbw.bLUN,
- ILLEGAL_REQUEST,
- INVALID_CDB);
- return -1;
- }
-
- if(hmsc->bdev_ops->IsReady(lun) !=0 )
- {
- SCSI_SenseCode(pdev,
- lun,
- NOT_READY,
- MEDIUM_NOT_PRESENT);
- return -1;
- }
-
- hmsc->scsi_blk_addr_in_blks = (params[2] << 24) | \
- (params[3] << 16) | \
- (params[4] << 8) | \
- params[5];
-
- hmsc->scsi_blk_len = (params[7] << 8) | \
- params[8];
-
-
-
- if( SCSI_CheckAddressRange(pdev, lun, hmsc->scsi_blk_addr_in_blks, hmsc->scsi_blk_len) < 0)
- {
- return -1; /* error */
- }
-
- hmsc->bot_state = USBD_BOT_DATA_IN;
- hmsc->scsi_blk_len *= hmsc->scsi_blk_size;
-
- /* cases 4,5 : Hi <> Dn */
- if (hmsc->cbw.dDataLength != hmsc->scsi_blk_len)
- {
- SCSI_SenseCode(pdev,
- hmsc->cbw.bLUN,
- ILLEGAL_REQUEST,
- INVALID_CDB);
- return -1;
- }
- }
- hmsc->bot_data_length = MSC_MEDIA_PACKET;
-
- return SCSI_ProcessRead(pdev, lun);
-}
-
-/**
-* @brief SCSI_Write10
-* Process Write10 command
-* @param lun: Logical unit number
-* @param params: Command parameters
-* @retval status
-*/
-
-static int8_t SCSI_Write10 (USBD_HandleTypeDef *pdev, uint8_t lun , uint8_t *params)
-{
- USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData;
-
- if (hmsc->bot_state == USBD_BOT_IDLE) /* Idle */
- {
-
- /* case 8 : Hi <> Do */
-
- if ((hmsc->cbw.bmFlags & 0x80) == 0x80)
- {
- SCSI_SenseCode(pdev,
- hmsc->cbw.bLUN,
- ILLEGAL_REQUEST,
- INVALID_CDB);
- return -1;
- }
-
- /* Check whether Media is ready */
- if(hmsc->bdev_ops->IsReady(lun) !=0 )
- {
- SCSI_SenseCode(pdev,
- lun,
- NOT_READY,
- MEDIUM_NOT_PRESENT);
- return -1;
- }
-
- /* Check If media is write-protected */
- if(hmsc->bdev_ops->IsWriteProtected(lun) !=0 )
- {
- SCSI_SenseCode(pdev,
- lun,
- NOT_READY,
- WRITE_PROTECTED);
- return -1;
- }
-
-
- hmsc->scsi_blk_addr_in_blks = (params[2] << 24) | \
- (params[3] << 16) | \
- (params[4] << 8) | \
- params[5];
- hmsc->scsi_blk_len = (params[7] << 8) | \
- params[8];
-
- /* check if LBA address is in the right range */
- if(SCSI_CheckAddressRange(pdev,
- lun,
- hmsc->scsi_blk_addr_in_blks,
- hmsc->scsi_blk_len) < 0)
- {
- return -1; /* error */
- }
-
- hmsc->scsi_blk_len *= hmsc->scsi_blk_size;
-
- /* cases 3,11,13 : Hn,Ho <> D0 */
- if (hmsc->cbw.dDataLength != hmsc->scsi_blk_len)
- {
- SCSI_SenseCode(pdev,
- hmsc->cbw.bLUN,
- ILLEGAL_REQUEST,
- INVALID_CDB);
- return -1;
- }
-
- /* Prepare EP to receive first data packet */
- hmsc->bot_state = USBD_BOT_DATA_OUT;
- USBD_LL_PrepareReceive (pdev,
- MSC_OUT_EP,
- hmsc->bot_data,
- MIN (hmsc->scsi_blk_len, MSC_MEDIA_PACKET));
- }
- else /* Write Process ongoing */
- {
- return SCSI_ProcessWrite(pdev, lun);
- }
- return 0;
-}
-
-
-/**
-* @brief SCSI_Verify10
-* Process Verify10 command
-* @param lun: Logical unit number
-* @param params: Command parameters
-* @retval status
-*/
-
-static int8_t SCSI_Verify10(USBD_HandleTypeDef *pdev, uint8_t lun , uint8_t *params)
-{
- USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData;
-
- if ((params[1]& 0x02) == 0x02)
- {
- SCSI_SenseCode (pdev,
- lun,
- ILLEGAL_REQUEST,
- INVALID_FIELED_IN_COMMAND);
- return -1; /* Error, Verify Mode Not supported*/
- }
-
- hmsc->scsi_blk_addr_in_blks = (params[2] << 24) | (params[3] << 16) | (params[4] << 8) | params[5];
- hmsc->scsi_blk_len = (params[7] << 8) | params[8];
-
- if(SCSI_CheckAddressRange(pdev,
- lun,
- hmsc->scsi_blk_addr_in_blks,
- hmsc->scsi_blk_len) < 0)
- {
- return -1; /* error */
- }
- hmsc->bot_data_length = 0;
- return 0;
-}
-
-/**
-* @brief SCSI_CheckAddressRange
-* Check address range
-* @param lun: Logical unit number
-* @param blk_offset: first block address
-* @param blk_nbr: number of block to be processed
-* @retval status
-*/
-static int8_t SCSI_CheckAddressRange (USBD_HandleTypeDef *pdev, uint8_t lun , uint32_t blk_offset , uint16_t blk_nbr)
-{
- USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData;
-
- if ((blk_offset + blk_nbr) > hmsc->scsi_blk_nbr )
- {
- SCSI_SenseCode(pdev,
- lun,
- ILLEGAL_REQUEST,
- ADDRESS_OUT_OF_RANGE);
- return -1;
- }
- return 0;
-}
-
-/**
-* @brief SCSI_ProcessRead
-* Handle Read Process
-* @param lun: Logical unit number
-* @retval status
-*/
-static int8_t SCSI_ProcessRead (USBD_HandleTypeDef *pdev, uint8_t lun)
-{
- USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData;
- uint32_t len;
-
- len = MIN(hmsc->scsi_blk_len , MSC_MEDIA_PACKET);
-
- if( hmsc->bdev_ops->Read(lun ,
- hmsc->bot_data,
- hmsc->scsi_blk_addr_in_blks,
- len / hmsc->scsi_blk_size) < 0)
- {
-
- SCSI_SenseCode(pdev,
- lun,
- HARDWARE_ERROR,
- UNRECOVERED_READ_ERROR);
- return -1;
- }
-
-
- USBD_LL_Transmit (pdev,
- MSC_IN_EP,
- hmsc->bot_data,
- len);
-
-
- hmsc->scsi_blk_addr_in_blks += len / hmsc->scsi_blk_size;
- hmsc->scsi_blk_len -= len;
-
- /* case 6 : Hi = Di */
- hmsc->csw.dDataResidue -= len;
-
- if (hmsc->scsi_blk_len == 0)
- {
- hmsc->bot_state = USBD_BOT_LAST_DATA_IN;
- }
- return 0;
-}
-
-/**
-* @brief SCSI_ProcessWrite
-* Handle Write Process
-* @param lun: Logical unit number
-* @retval status
-*/
-
-static int8_t SCSI_ProcessWrite (USBD_HandleTypeDef *pdev, uint8_t lun)
-{
- uint32_t len;
- USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData;
-
- len = MIN(hmsc->scsi_blk_len , MSC_MEDIA_PACKET);
-
- if(hmsc->bdev_ops->Write(lun ,
- hmsc->bot_data,
- hmsc->scsi_blk_addr_in_blks,
- len / hmsc->scsi_blk_size) < 0)
- {
- SCSI_SenseCode(pdev,
- lun,
- HARDWARE_ERROR,
- WRITE_FAULT);
- return -1;
- }
-
-
- hmsc->scsi_blk_addr_in_blks += len / hmsc->scsi_blk_size;
- hmsc->scsi_blk_len -= len;
-
- /* case 12 : Ho = Do */
- hmsc->csw.dDataResidue -= len;
-
- if (hmsc->scsi_blk_len == 0)
- {
- MSC_BOT_SendCSW (pdev, USBD_CSW_CMD_PASSED);
- }
- else
- {
- /* Prapare EP to Receive next packet */
- USBD_LL_PrepareReceive (pdev,
- MSC_OUT_EP,
- hmsc->bot_data,
- MIN (hmsc->scsi_blk_len, MSC_MEDIA_PACKET));
- }
-
- return 0;
-}
-/**
- * @}
- */
-
-
-/**
- * @}
- */
-
-
-/**
- * @}
- */
-
-/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
+/**
+ ******************************************************************************
+ * @file usbd_msc_scsi.c
+ * @author MCD Application Team
+ * @version V2.0.0
+ * @date 18-February-2014
+ * @brief This file provides all the USBD SCSI layer functions.
+ ******************************************************************************
+ * @attention
+ *
+ * <h2><center>&copy; COPYRIGHT 2014 STMicroelectronics</center></h2>
+ *
+ * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
+ * You may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.st.com/software_license_agreement_liberty_v2
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************
+ */
+
+/* Includes ------------------------------------------------------------------*/
+#include "usbd_msc_bot.h"
+#include "usbd_msc_scsi.h"
+#include "usbd_msc_data.h"
+#include "usbd_cdc_msc_hid.h"
+
+
+
+/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY
+ * @{
+ */
+
+
+/** @defgroup MSC_SCSI
+ * @brief Mass storage SCSI layer module
+ * @{
+ */
+
+/** @defgroup MSC_SCSI_Private_TypesDefinitions
+ * @{
+ */
+/**
+ * @}
+ */
+
+
+/** @defgroup MSC_SCSI_Private_Defines
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+
+/** @defgroup MSC_SCSI_Private_Macros
+ * @{
+ */
+/**
+ * @}
+ */
+
+
+/** @defgroup MSC_SCSI_Private_Variables
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+
+/** @defgroup MSC_SCSI_Private_FunctionPrototypes
+ * @{
+ */
+static int8_t SCSI_TestUnitReady(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params);
+static int8_t SCSI_Inquiry(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params);
+static int8_t SCSI_ReadFormatCapacity(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params);
+static int8_t SCSI_ReadCapacity10(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params);
+static int8_t SCSI_RequestSense (USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params);
+static int8_t SCSI_StartStopUnit(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params);
+static int8_t SCSI_AllowMediumRemoval(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params);
+static int8_t SCSI_ModeSense6 (USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params);
+static int8_t SCSI_ModeSense10 (USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params);
+static int8_t SCSI_SynchronizeCache(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params);
+static int8_t SCSI_Write10(USBD_HandleTypeDef *pdev, uint8_t lun , uint8_t *params);
+static int8_t SCSI_Read10(USBD_HandleTypeDef *pdev, uint8_t lun , uint8_t *params);
+static int8_t SCSI_Verify10(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params);
+static int8_t SCSI_CheckAddressRange (USBD_HandleTypeDef *pdev,
+ uint8_t lun ,
+ uint32_t blk_offset ,
+ uint16_t blk_nbr);
+static int8_t SCSI_ProcessRead (USBD_HandleTypeDef *pdev,
+ uint8_t lun);
+
+static int8_t SCSI_ProcessWrite (USBD_HandleTypeDef *pdev,
+ uint8_t lun);
+/**
+ * @}
+ */
+
+
+/** @defgroup MSC_SCSI_Private_Functions
+ * @{
+ */
+
+
+/**
+* @brief SCSI_ProcessCmd
+* Process SCSI commands
+* @param pdev: device instance
+* @param lun: Logical unit number
+* @param params: Command parameters
+* @retval status
+*/
+int8_t SCSI_ProcessCmd(USBD_HandleTypeDef *pdev,
+ uint8_t lun,
+ uint8_t *params)
+{
+ /*
+ if (params[0] != SCSI_READ10 && params[0] != SCSI_WRITE10) {
+ printf("SCSI_ProcessCmd(lun=%d, params=%x, %x)\n", lun, params[0], params[1]);
+ }
+ */
+
+ switch (params[0])
+ {
+ case SCSI_TEST_UNIT_READY:
+ return SCSI_TestUnitReady(pdev, lun, params);
+
+ case SCSI_REQUEST_SENSE:
+ return SCSI_RequestSense (pdev, lun, params);
+ case SCSI_INQUIRY:
+ return SCSI_Inquiry(pdev, lun, params);
+
+ case SCSI_START_STOP_UNIT:
+ return SCSI_StartStopUnit(pdev, lun, params);
+
+ case SCSI_ALLOW_MEDIUM_REMOVAL:
+ return SCSI_AllowMediumRemoval(pdev, lun, params);
+
+ case SCSI_MODE_SENSE6:
+ return SCSI_ModeSense6 (pdev, lun, params);
+
+ case SCSI_MODE_SENSE10:
+ return SCSI_ModeSense10 (pdev, lun, params);
+
+ case SCSI_SYNCHRONIZE_CACHE10:
+ case SCSI_SYNCHRONIZE_CACHE16:
+ return SCSI_SynchronizeCache(pdev, lun, params);
+
+ case SCSI_READ_FORMAT_CAPACITIES:
+ return SCSI_ReadFormatCapacity(pdev, lun, params);
+
+ case SCSI_READ_CAPACITY10:
+ return SCSI_ReadCapacity10(pdev, lun, params);
+
+ case SCSI_READ10:
+ return SCSI_Read10(pdev, lun, params);
+
+ case SCSI_WRITE10:
+ return SCSI_Write10(pdev, lun, params);
+
+ case SCSI_VERIFY10:
+ return SCSI_Verify10(pdev, lun, params);
+
+ default:
+ SCSI_SenseCode(pdev,
+ lun,
+ ILLEGAL_REQUEST,
+ INVALID_CDB);
+ return -1;
+ }
+}
+
+
+/**
+* @brief SCSI_TestUnitReady
+* Process SCSI Test Unit Ready Command
+* @param lun: Logical unit number
+* @param params: Command parameters
+* @retval status
+*/
+static int8_t SCSI_TestUnitReady(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params)
+{
+ USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData;
+
+ /* case 9 : Hi > D0 */
+ if (hmsc->cbw.dDataLength != 0)
+ {
+ SCSI_SenseCode(pdev,
+ hmsc->cbw.bLUN,
+ ILLEGAL_REQUEST,
+ INVALID_CDB);
+ return -1;
+ }
+
+ if(hmsc->bdev_ops->IsReady(lun) !=0 )
+ {
+ SCSI_SenseCode(pdev,
+ lun,
+ NOT_READY,
+ MEDIUM_NOT_PRESENT);
+
+ hmsc->bot_state = USBD_BOT_NO_DATA;
+ return -1;
+ }
+ hmsc->bot_data_length = 0;
+ return 0;
+}
+
+/**
+* @brief SCSI_Inquiry
+* Process Inquiry command
+* @param lun: Logical unit number
+* @param params: Command parameters
+* @retval status
+*/
+static int8_t SCSI_Inquiry(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params)
+{
+ uint8_t* pPage;
+ uint16_t len;
+ USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData;
+
+ if (params[1] & 0x01)/*Evpd is set*/
+ {
+ pPage = (uint8_t *)MSC_Page00_Inquiry_Data;
+ len = LENGTH_INQUIRY_PAGE00;
+ }
+ else
+ {
+
+ pPage = (uint8_t *)&hmsc->bdev_ops->pInquiry[lun * STANDARD_INQUIRY_DATA_LEN];
+ len = pPage[4] + 5;
+
+ if (params[4] <= len)
+ {
+ len = params[4];
+ }
+ }
+ hmsc->bot_data_length = len;
+
+ while (len)
+ {
+ len--;
+ hmsc->bot_data[len] = pPage[len];
+ }
+ return 0;
+}
+
+/**
+* @brief SCSI_ReadCapacity10
+* Process Read Capacity 10 command
+* @param lun: Logical unit number
+* @param params: Command parameters
+* @retval status
+*/
+static int8_t SCSI_ReadCapacity10(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params)
+{
+ USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData;
+
+ if(hmsc->bdev_ops->GetCapacity(lun, &hmsc->scsi_blk_nbr, &hmsc->scsi_blk_size) != 0)
+ {
+ SCSI_SenseCode(pdev,
+ lun,
+ NOT_READY,
+ MEDIUM_NOT_PRESENT);
+ return -1;
+ }
+ else
+ {
+
+ hmsc->bot_data[0] = (uint8_t)((hmsc->scsi_blk_nbr - 1) >> 24);
+ hmsc->bot_data[1] = (uint8_t)((hmsc->scsi_blk_nbr - 1) >> 16);
+ hmsc->bot_data[2] = (uint8_t)((hmsc->scsi_blk_nbr - 1) >> 8);
+ hmsc->bot_data[3] = (uint8_t)(hmsc->scsi_blk_nbr - 1);
+
+ hmsc->bot_data[4] = (uint8_t)(hmsc->scsi_blk_size >> 24);
+ hmsc->bot_data[5] = (uint8_t)(hmsc->scsi_blk_size >> 16);
+ hmsc->bot_data[6] = (uint8_t)(hmsc->scsi_blk_size >> 8);
+ hmsc->bot_data[7] = (uint8_t)(hmsc->scsi_blk_size);
+
+ hmsc->bot_data_length = 8;
+ return 0;
+ }
+}
+/**
+* @brief SCSI_ReadFormatCapacity
+* Process Read Format Capacity command
+* @param lun: Logical unit number
+* @param params: Command parameters
+* @retval status
+*/
+static int8_t SCSI_ReadFormatCapacity(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params)
+{
+ USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData;
+
+ uint16_t blk_size;
+ uint32_t blk_nbr;
+ uint16_t i;
+
+ for(i=0 ; i < 12 ; i++)
+ {
+ hmsc->bot_data[i] = 0;
+ }
+
+ if(hmsc->bdev_ops->GetCapacity(lun, &blk_nbr, &blk_size) != 0)
+ {
+ SCSI_SenseCode(pdev,
+ lun,
+ NOT_READY,
+ MEDIUM_NOT_PRESENT);
+ return -1;
+ }
+ else
+ {
+ hmsc->bot_data[3] = 0x08;
+ hmsc->bot_data[4] = (uint8_t)((blk_nbr - 1) >> 24);
+ hmsc->bot_data[5] = (uint8_t)((blk_nbr - 1) >> 16);
+ hmsc->bot_data[6] = (uint8_t)((blk_nbr - 1) >> 8);
+ hmsc->bot_data[7] = (uint8_t)(blk_nbr - 1);
+
+ hmsc->bot_data[8] = 0x02;
+ hmsc->bot_data[9] = (uint8_t)(blk_size >> 16);
+ hmsc->bot_data[10] = (uint8_t)(blk_size >> 8);
+ hmsc->bot_data[11] = (uint8_t)(blk_size);
+
+ hmsc->bot_data_length = 12;
+ return 0;
+ }
+}
+/**
+* @brief SCSI_ModeSense6
+* Process Mode Sense6 command
+* @param lun: Logical unit number
+* @param params: Command parameters
+* @retval status
+*/
+static int8_t SCSI_ModeSense6 (USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params)
+{
+ USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData;
+ uint16_t len = 8 ;
+ hmsc->bot_data_length = len;
+
+ while (len)
+ {
+ len--;
+ hmsc->bot_data[len] = MSC_Mode_Sense6_data[len];
+ }
+ return 0;
+}
+
+/**
+* @brief SCSI_ModeSense10
+* Process Mode Sense10 command
+* @param lun: Logical unit number
+* @param params: Command parameters
+* @retval status
+*/
+static int8_t SCSI_ModeSense10 (USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params)
+{
+ uint16_t len = 8;
+ USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData;
+
+ hmsc->bot_data_length = len;
+
+ while (len)
+ {
+ len--;
+ hmsc->bot_data[len] = MSC_Mode_Sense10_data[len];
+ }
+ return 0;
+}
+
+static int8_t SCSI_SynchronizeCache(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params) {
+ // nothing to synchronize, so just return "success"
+ USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData;
+ hmsc->bot_data_length = 0;
+ return 0;
+}
+
+/**
+* @brief SCSI_RequestSense
+* Process Request Sense command
+* @param lun: Logical unit number
+* @param params: Command parameters
+* @retval status
+*/
+
+static int8_t SCSI_RequestSense (USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params)
+{
+ uint8_t i;
+ USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData;
+
+ for(i=0 ; i < REQUEST_SENSE_DATA_LEN ; i++)
+ {
+ hmsc->bot_data[i] = 0;
+ }
+
+ hmsc->bot_data[0] = 0x70;
+ hmsc->bot_data[7] = REQUEST_SENSE_DATA_LEN - 6;
+
+ if((hmsc->scsi_sense_head != hmsc->scsi_sense_tail)) {
+
+ hmsc->bot_data[2] = hmsc->scsi_sense[hmsc->scsi_sense_head].Skey;
+ hmsc->bot_data[12] = hmsc->scsi_sense[hmsc->scsi_sense_head].w.b.ASCQ;
+ hmsc->bot_data[13] = hmsc->scsi_sense[hmsc->scsi_sense_head].w.b.ASC;
+ hmsc->scsi_sense_head++;
+
+ if (hmsc->scsi_sense_head == SENSE_LIST_DEEPTH)
+ {
+ hmsc->scsi_sense_head = 0;
+ }
+ }
+ hmsc->bot_data_length = REQUEST_SENSE_DATA_LEN;
+
+ if (params[4] <= REQUEST_SENSE_DATA_LEN)
+ {
+ hmsc->bot_data_length = params[4];
+ }
+ return 0;
+}
+
+/**
+* @brief SCSI_SenseCode
+* Load the last error code in the error list
+* @param lun: Logical unit number
+* @param sKey: Sense Key
+* @param ASC: Additional Sense Key
+* @retval none
+
+*/
+void SCSI_SenseCode(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t sKey, uint8_t ASC)
+{
+ USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData;
+
+ hmsc->scsi_sense[hmsc->scsi_sense_tail].Skey = sKey;
+ hmsc->scsi_sense[hmsc->scsi_sense_tail].w.ASC = ASC << 8;
+ hmsc->scsi_sense_tail++;
+ if (hmsc->scsi_sense_tail == SENSE_LIST_DEEPTH)
+ {
+ hmsc->scsi_sense_tail = 0;
+ }
+}
+/**
+* @brief SCSI_StartStopUnit
+* Process Start Stop Unit command
+* @param lun: Logical unit number
+* @param params: Command parameters
+* @retval status
+*/
+static int8_t SCSI_StartStopUnit(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params)
+{
+ USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData;
+ hmsc->bot_data_length = 0;
+
+ // On Mac OS X, when the device is ejected a SCSI_START_STOP_UNIT command is sent.
+ // Bit 0 of params[4] is the START bit.
+ // If we get a stop, we must really stop the device so that the Mac does not
+ // automatically remount it.
+ hmsc->bdev_ops->StartStopUnit(lun, params[4] & 1);
+
+ return 0;
+}
+
+/**
+* @brief SCSI_AllowMediumRemoval
+* Process Allow Medium Removal command
+* @param lun: Logical unit number
+* @param params: Command parameters
+* @retval status
+*/
+static int8_t SCSI_AllowMediumRemoval(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params)
+{
+ USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData;
+ hmsc->bot_data_length = 0;
+ hmsc->bdev_ops->PreventAllowMediumRemoval(lun, params[4]);
+ return 0;
+}
+
+/**
+* @brief SCSI_Read10
+* Process Read10 command
+* @param lun: Logical unit number
+* @param params: Command parameters
+* @retval status
+*/
+static int8_t SCSI_Read10(USBD_HandleTypeDef *pdev, uint8_t lun , uint8_t *params)
+{
+ USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData;
+
+ if(hmsc->bot_state == USBD_BOT_IDLE) /* Idle */
+ {
+
+ /* case 10 : Ho <> Di */
+
+ if ((hmsc->cbw.bmFlags & 0x80) != 0x80)
+ {
+ SCSI_SenseCode(pdev,
+ hmsc->cbw.bLUN,
+ ILLEGAL_REQUEST,
+ INVALID_CDB);
+ return -1;
+ }
+
+ if(hmsc->bdev_ops->IsReady(lun) !=0 )
+ {
+ SCSI_SenseCode(pdev,
+ lun,
+ NOT_READY,
+ MEDIUM_NOT_PRESENT);
+ return -1;
+ }
+
+ hmsc->scsi_blk_addr_in_blks = (params[2] << 24) | \
+ (params[3] << 16) | \
+ (params[4] << 8) | \
+ params[5];
+
+ hmsc->scsi_blk_len = (params[7] << 8) | \
+ params[8];
+
+
+
+ if( SCSI_CheckAddressRange(pdev, lun, hmsc->scsi_blk_addr_in_blks, hmsc->scsi_blk_len) < 0)
+ {
+ return -1; /* error */
+ }
+
+ hmsc->bot_state = USBD_BOT_DATA_IN;
+ hmsc->scsi_blk_len *= hmsc->scsi_blk_size;
+
+ /* cases 4,5 : Hi <> Dn */
+ if (hmsc->cbw.dDataLength != hmsc->scsi_blk_len)
+ {
+ SCSI_SenseCode(pdev,
+ hmsc->cbw.bLUN,
+ ILLEGAL_REQUEST,
+ INVALID_CDB);
+ return -1;
+ }
+ }
+ hmsc->bot_data_length = MSC_MEDIA_PACKET;
+
+ return SCSI_ProcessRead(pdev, lun);
+}
+
+/**
+* @brief SCSI_Write10
+* Process Write10 command
+* @param lun: Logical unit number
+* @param params: Command parameters
+* @retval status
+*/
+
+static int8_t SCSI_Write10 (USBD_HandleTypeDef *pdev, uint8_t lun , uint8_t *params)
+{
+ USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData;
+
+ if (hmsc->bot_state == USBD_BOT_IDLE) /* Idle */
+ {
+
+ /* case 8 : Hi <> Do */
+
+ if ((hmsc->cbw.bmFlags & 0x80) == 0x80)
+ {
+ SCSI_SenseCode(pdev,
+ hmsc->cbw.bLUN,
+ ILLEGAL_REQUEST,
+ INVALID_CDB);
+ return -1;
+ }
+
+ /* Check whether Media is ready */
+ if(hmsc->bdev_ops->IsReady(lun) !=0 )
+ {
+ SCSI_SenseCode(pdev,
+ lun,
+ NOT_READY,
+ MEDIUM_NOT_PRESENT);
+ return -1;
+ }
+
+ /* Check If media is write-protected */
+ if(hmsc->bdev_ops->IsWriteProtected(lun) !=0 )
+ {
+ SCSI_SenseCode(pdev,
+ lun,
+ NOT_READY,
+ WRITE_PROTECTED);
+ return -1;
+ }
+
+
+ hmsc->scsi_blk_addr_in_blks = (params[2] << 24) | \
+ (params[3] << 16) | \
+ (params[4] << 8) | \
+ params[5];
+ hmsc->scsi_blk_len = (params[7] << 8) | \
+ params[8];
+
+ /* check if LBA address is in the right range */
+ if(SCSI_CheckAddressRange(pdev,
+ lun,
+ hmsc->scsi_blk_addr_in_blks,
+ hmsc->scsi_blk_len) < 0)
+ {
+ return -1; /* error */
+ }
+
+ hmsc->scsi_blk_len *= hmsc->scsi_blk_size;
+
+ /* cases 3,11,13 : Hn,Ho <> D0 */
+ if (hmsc->cbw.dDataLength != hmsc->scsi_blk_len)
+ {
+ SCSI_SenseCode(pdev,
+ hmsc->cbw.bLUN,
+ ILLEGAL_REQUEST,
+ INVALID_CDB);
+ return -1;
+ }
+
+ /* Prepare EP to receive first data packet */
+ hmsc->bot_state = USBD_BOT_DATA_OUT;
+ USBD_LL_PrepareReceive (pdev,
+ MSC_OUT_EP,
+ hmsc->bot_data,
+ MIN (hmsc->scsi_blk_len, MSC_MEDIA_PACKET));
+ }
+ else /* Write Process ongoing */
+ {
+ return SCSI_ProcessWrite(pdev, lun);
+ }
+ return 0;
+}
+
+
+/**
+* @brief SCSI_Verify10
+* Process Verify10 command
+* @param lun: Logical unit number
+* @param params: Command parameters
+* @retval status
+*/
+
+static int8_t SCSI_Verify10(USBD_HandleTypeDef *pdev, uint8_t lun , uint8_t *params)
+{
+ USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData;
+
+ if ((params[1]& 0x02) == 0x02)
+ {
+ SCSI_SenseCode (pdev,
+ lun,
+ ILLEGAL_REQUEST,
+ INVALID_FIELED_IN_COMMAND);
+ return -1; /* Error, Verify Mode Not supported*/
+ }
+
+ hmsc->scsi_blk_addr_in_blks = (params[2] << 24) | (params[3] << 16) | (params[4] << 8) | params[5];
+ hmsc->scsi_blk_len = (params[7] << 8) | params[8];
+
+ if(SCSI_CheckAddressRange(pdev,
+ lun,
+ hmsc->scsi_blk_addr_in_blks,
+ hmsc->scsi_blk_len) < 0)
+ {
+ return -1; /* error */
+ }
+ hmsc->bot_data_length = 0;
+ return 0;
+}
+
+/**
+* @brief SCSI_CheckAddressRange
+* Check address range
+* @param lun: Logical unit number
+* @param blk_offset: first block address
+* @param blk_nbr: number of block to be processed
+* @retval status
+*/
+static int8_t SCSI_CheckAddressRange (USBD_HandleTypeDef *pdev, uint8_t lun , uint32_t blk_offset , uint16_t blk_nbr)
+{
+ USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData;
+
+ if ((blk_offset + blk_nbr) > hmsc->scsi_blk_nbr )
+ {
+ SCSI_SenseCode(pdev,
+ lun,
+ ILLEGAL_REQUEST,
+ ADDRESS_OUT_OF_RANGE);
+ return -1;
+ }
+ return 0;
+}
+
+/**
+* @brief SCSI_ProcessRead
+* Handle Read Process
+* @param lun: Logical unit number
+* @retval status
+*/
+static int8_t SCSI_ProcessRead (USBD_HandleTypeDef *pdev, uint8_t lun)
+{
+ USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData;
+ uint32_t len;
+
+ len = MIN(hmsc->scsi_blk_len , MSC_MEDIA_PACKET);
+
+ if( hmsc->bdev_ops->Read(lun ,
+ hmsc->bot_data,
+ hmsc->scsi_blk_addr_in_blks,
+ len / hmsc->scsi_blk_size) < 0)
+ {
+
+ SCSI_SenseCode(pdev,
+ lun,
+ HARDWARE_ERROR,
+ UNRECOVERED_READ_ERROR);
+ return -1;
+ }
+
+
+ USBD_LL_Transmit (pdev,
+ MSC_IN_EP,
+ hmsc->bot_data,
+ len);
+
+
+ hmsc->scsi_blk_addr_in_blks += len / hmsc->scsi_blk_size;
+ hmsc->scsi_blk_len -= len;
+
+ /* case 6 : Hi = Di */
+ hmsc->csw.dDataResidue -= len;
+
+ if (hmsc->scsi_blk_len == 0)
+ {
+ hmsc->bot_state = USBD_BOT_LAST_DATA_IN;
+ }
+ return 0;
+}
+
+/**
+* @brief SCSI_ProcessWrite
+* Handle Write Process
+* @param lun: Logical unit number
+* @retval status
+*/
+
+static int8_t SCSI_ProcessWrite (USBD_HandleTypeDef *pdev, uint8_t lun)
+{
+ uint32_t len;
+ USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData;
+
+ len = MIN(hmsc->scsi_blk_len , MSC_MEDIA_PACKET);
+
+ if(hmsc->bdev_ops->Write(lun ,
+ hmsc->bot_data,
+ hmsc->scsi_blk_addr_in_blks,
+ len / hmsc->scsi_blk_size) < 0)
+ {
+ SCSI_SenseCode(pdev,
+ lun,
+ HARDWARE_ERROR,
+ WRITE_FAULT);
+ return -1;
+ }
+
+
+ hmsc->scsi_blk_addr_in_blks += len / hmsc->scsi_blk_size;
+ hmsc->scsi_blk_len -= len;
+
+ /* case 12 : Ho = Do */
+ hmsc->csw.dDataResidue -= len;
+
+ if (hmsc->scsi_blk_len == 0)
+ {
+ MSC_BOT_SendCSW (pdev, USBD_CSW_CMD_PASSED);
+ }
+ else
+ {
+ /* Prapare EP to Receive next packet */
+ USBD_LL_PrepareReceive (pdev,
+ MSC_OUT_EP,
+ hmsc->bot_data,
+ MIN (hmsc->scsi_blk_len, MSC_MEDIA_PACKET));
+ }
+
+ return 0;
+}
+/**
+ * @}
+ */
+
+
+/**
+ * @}
+ */
+
+
+/**
+ * @}
+ */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/ports/stm32/usbdev/core/inc/usbd_core.h b/ports/stm32/usbdev/core/inc/usbd_core.h
index 3178d4a4b..5494be3a2 100644
--- a/ports/stm32/usbdev/core/inc/usbd_core.h
+++ b/ports/stm32/usbdev/core/inc/usbd_core.h
@@ -1,159 +1,159 @@
-/**
- ******************************************************************************
- * @file usbd_core.h
- * @author MCD Application Team
- * @version V2.0.0
- * @date 18-February-2014
- * @brief Header file for usbd_core.c
- ******************************************************************************
- * @attention
- *
- * <h2><center>&copy; COPYRIGHT 2014 STMicroelectronics</center></h2>
- *
- * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
- * You may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.st.com/software_license_agreement_liberty_v2
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- ******************************************************************************
- */
-
-/* Define to prevent recursive inclusion -------------------------------------*/
-#ifndef __USBD_CORE_H
-#define __USBD_CORE_H
-
-/* Includes ------------------------------------------------------------------*/
-#include "usbd_conf.h"
-#include "usbd_def.h"
-#include "usbd_ioreq.h"
-#include "usbd_ctlreq.h"
-
-/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY
- * @{
- */
-
-/** @defgroup USBD_CORE
- * @brief This file is the Header file for usbd_core.c file
- * @{
- */
-
-
-/** @defgroup USBD_CORE_Exported_Defines
- * @{
- */
-
-/**
- * @}
- */
-
-
-/** @defgroup USBD_CORE_Exported_TypesDefinitions
- * @{
- */
-
-
-/**
- * @}
- */
-
-
-
-/** @defgroup USBD_CORE_Exported_Macros
- * @{
- */
-
-/**
- * @}
- */
-
-/** @defgroup USBD_CORE_Exported_Variables
- * @{
- */
-#define USBD_SOF USBD_LL_SOF
-/**
- * @}
- */
-
-/** @defgroup USBD_CORE_Exported_FunctionsPrototype
- * @{
- */
-USBD_StatusTypeDef USBD_Init(USBD_HandleTypeDef *pdev, USBD_DescriptorsTypeDef *pdesc, uint8_t id);
-USBD_StatusTypeDef USBD_DeInit(USBD_HandleTypeDef *pdev);
-USBD_StatusTypeDef USBD_Start (USBD_HandleTypeDef *pdev);
-USBD_StatusTypeDef USBD_Stop (USBD_HandleTypeDef *pdev);
-USBD_StatusTypeDef USBD_RegisterClass(USBD_HandleTypeDef *pdev, const USBD_ClassTypeDef *pclass);
-
-USBD_StatusTypeDef USBD_RunTestMode (USBD_HandleTypeDef *pdev);
-USBD_StatusTypeDef USBD_SetClassConfig(USBD_HandleTypeDef *pdev, uint8_t cfgidx);
-USBD_StatusTypeDef USBD_ClrClassConfig(USBD_HandleTypeDef *pdev, uint8_t cfgidx);
-
-USBD_StatusTypeDef USBD_LL_SetupStage(USBD_HandleTypeDef *pdev, uint8_t *psetup);
-USBD_StatusTypeDef USBD_LL_DataOutStage(USBD_HandleTypeDef *pdev , uint8_t epnum, uint8_t *pdata);
-USBD_StatusTypeDef USBD_LL_DataInStage(USBD_HandleTypeDef *pdev , uint8_t epnum, uint8_t *pdata);
-
-USBD_StatusTypeDef USBD_LL_Reset(USBD_HandleTypeDef *pdev);
-USBD_StatusTypeDef USBD_LL_SetSpeed(USBD_HandleTypeDef *pdev, USBD_SpeedTypeDef speed);
-USBD_StatusTypeDef USBD_LL_Suspend(USBD_HandleTypeDef *pdev);
-USBD_StatusTypeDef USBD_LL_Resume(USBD_HandleTypeDef *pdev);
-
-USBD_StatusTypeDef USBD_LL_SOF(USBD_HandleTypeDef *pdev);
-USBD_StatusTypeDef USBD_LL_IsoINIncomplete(USBD_HandleTypeDef *pdev, uint8_t epnum);
-USBD_StatusTypeDef USBD_LL_IsoOUTIncomplete(USBD_HandleTypeDef *pdev, uint8_t epnum);
-
-USBD_StatusTypeDef USBD_LL_DevConnected(USBD_HandleTypeDef *pdev);
-USBD_StatusTypeDef USBD_LL_DevDisconnected(USBD_HandleTypeDef *pdev);
-
-/* USBD Low Level Driver */
-USBD_StatusTypeDef USBD_LL_Init (USBD_HandleTypeDef *pdev);
-USBD_StatusTypeDef USBD_LL_DeInit (USBD_HandleTypeDef *pdev);
-USBD_StatusTypeDef USBD_LL_Start(USBD_HandleTypeDef *pdev);
-USBD_StatusTypeDef USBD_LL_Stop (USBD_HandleTypeDef *pdev);
-USBD_StatusTypeDef USBD_LL_OpenEP (USBD_HandleTypeDef *pdev,
- uint8_t ep_addr,
- uint8_t ep_type,
- uint16_t ep_mps);
-
-USBD_StatusTypeDef USBD_LL_CloseEP (USBD_HandleTypeDef *pdev, uint8_t ep_addr);
-USBD_StatusTypeDef USBD_LL_FlushEP (USBD_HandleTypeDef *pdev, uint8_t ep_addr);
-USBD_StatusTypeDef USBD_LL_StallEP (USBD_HandleTypeDef *pdev, uint8_t ep_addr);
-USBD_StatusTypeDef USBD_LL_ClearStallEP (USBD_HandleTypeDef *pdev, uint8_t ep_addr);
-uint8_t USBD_LL_IsStallEP (USBD_HandleTypeDef *pdev, uint8_t ep_addr);
-USBD_StatusTypeDef USBD_LL_SetUSBAddress (USBD_HandleTypeDef *pdev, uint8_t dev_addr);
-USBD_StatusTypeDef USBD_LL_Transmit (USBD_HandleTypeDef *pdev,
- uint8_t ep_addr,
- uint8_t *pbuf,
- uint16_t size);
-
-USBD_StatusTypeDef USBD_LL_PrepareReceive(USBD_HandleTypeDef *pdev,
- uint8_t ep_addr,
- uint8_t *pbuf,
- uint16_t size);
-
-uint32_t USBD_LL_GetRxDataSize (USBD_HandleTypeDef *pdev, uint8_t ep_addr);
-void USBD_LL_Delay (uint32_t Delay);
-
-/**
- * @}
- */
-
-#endif /* __USBD_CORE_H */
-
-/**
- * @}
- */
-
-/**
-* @}
-*/
-
-/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
-
-
-
+/**
+ ******************************************************************************
+ * @file usbd_core.h
+ * @author MCD Application Team
+ * @version V2.0.0
+ * @date 18-February-2014
+ * @brief Header file for usbd_core.c
+ ******************************************************************************
+ * @attention
+ *
+ * <h2><center>&copy; COPYRIGHT 2014 STMicroelectronics</center></h2>
+ *
+ * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
+ * You may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.st.com/software_license_agreement_liberty_v2
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************
+ */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __USBD_CORE_H
+#define __USBD_CORE_H
+
+/* Includes ------------------------------------------------------------------*/
+#include "usbd_conf.h"
+#include "usbd_def.h"
+#include "usbd_ioreq.h"
+#include "usbd_ctlreq.h"
+
+/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY
+ * @{
+ */
+
+/** @defgroup USBD_CORE
+ * @brief This file is the Header file for usbd_core.c file
+ * @{
+ */
+
+
+/** @defgroup USBD_CORE_Exported_Defines
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+
+/** @defgroup USBD_CORE_Exported_TypesDefinitions
+ * @{
+ */
+
+
+/**
+ * @}
+ */
+
+
+
+/** @defgroup USBD_CORE_Exported_Macros
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+/** @defgroup USBD_CORE_Exported_Variables
+ * @{
+ */
+#define USBD_SOF USBD_LL_SOF
+/**
+ * @}
+ */
+
+/** @defgroup USBD_CORE_Exported_FunctionsPrototype
+ * @{
+ */
+USBD_StatusTypeDef USBD_Init(USBD_HandleTypeDef *pdev, USBD_DescriptorsTypeDef *pdesc, uint8_t id);
+USBD_StatusTypeDef USBD_DeInit(USBD_HandleTypeDef *pdev);
+USBD_StatusTypeDef USBD_Start (USBD_HandleTypeDef *pdev);
+USBD_StatusTypeDef USBD_Stop (USBD_HandleTypeDef *pdev);
+USBD_StatusTypeDef USBD_RegisterClass(USBD_HandleTypeDef *pdev, const USBD_ClassTypeDef *pclass);
+
+USBD_StatusTypeDef USBD_RunTestMode (USBD_HandleTypeDef *pdev);
+USBD_StatusTypeDef USBD_SetClassConfig(USBD_HandleTypeDef *pdev, uint8_t cfgidx);
+USBD_StatusTypeDef USBD_ClrClassConfig(USBD_HandleTypeDef *pdev, uint8_t cfgidx);
+
+USBD_StatusTypeDef USBD_LL_SetupStage(USBD_HandleTypeDef *pdev, uint8_t *psetup);
+USBD_StatusTypeDef USBD_LL_DataOutStage(USBD_HandleTypeDef *pdev , uint8_t epnum, uint8_t *pdata);
+USBD_StatusTypeDef USBD_LL_DataInStage(USBD_HandleTypeDef *pdev , uint8_t epnum, uint8_t *pdata);
+
+USBD_StatusTypeDef USBD_LL_Reset(USBD_HandleTypeDef *pdev);
+USBD_StatusTypeDef USBD_LL_SetSpeed(USBD_HandleTypeDef *pdev, USBD_SpeedTypeDef speed);
+USBD_StatusTypeDef USBD_LL_Suspend(USBD_HandleTypeDef *pdev);
+USBD_StatusTypeDef USBD_LL_Resume(USBD_HandleTypeDef *pdev);
+
+USBD_StatusTypeDef USBD_LL_SOF(USBD_HandleTypeDef *pdev);
+USBD_StatusTypeDef USBD_LL_IsoINIncomplete(USBD_HandleTypeDef *pdev, uint8_t epnum);
+USBD_StatusTypeDef USBD_LL_IsoOUTIncomplete(USBD_HandleTypeDef *pdev, uint8_t epnum);
+
+USBD_StatusTypeDef USBD_LL_DevConnected(USBD_HandleTypeDef *pdev);
+USBD_StatusTypeDef USBD_LL_DevDisconnected(USBD_HandleTypeDef *pdev);
+
+/* USBD Low Level Driver */
+USBD_StatusTypeDef USBD_LL_Init (USBD_HandleTypeDef *pdev, int high_speed);
+USBD_StatusTypeDef USBD_LL_DeInit (USBD_HandleTypeDef *pdev);
+USBD_StatusTypeDef USBD_LL_Start(USBD_HandleTypeDef *pdev);
+USBD_StatusTypeDef USBD_LL_Stop (USBD_HandleTypeDef *pdev);
+USBD_StatusTypeDef USBD_LL_OpenEP (USBD_HandleTypeDef *pdev,
+ uint8_t ep_addr,
+ uint8_t ep_type,
+ uint16_t ep_mps);
+
+USBD_StatusTypeDef USBD_LL_CloseEP (USBD_HandleTypeDef *pdev, uint8_t ep_addr);
+USBD_StatusTypeDef USBD_LL_FlushEP (USBD_HandleTypeDef *pdev, uint8_t ep_addr);
+USBD_StatusTypeDef USBD_LL_StallEP (USBD_HandleTypeDef *pdev, uint8_t ep_addr);
+USBD_StatusTypeDef USBD_LL_ClearStallEP (USBD_HandleTypeDef *pdev, uint8_t ep_addr);
+uint8_t USBD_LL_IsStallEP (USBD_HandleTypeDef *pdev, uint8_t ep_addr);
+USBD_StatusTypeDef USBD_LL_SetUSBAddress (USBD_HandleTypeDef *pdev, uint8_t dev_addr);
+USBD_StatusTypeDef USBD_LL_Transmit (USBD_HandleTypeDef *pdev,
+ uint8_t ep_addr,
+ uint8_t *pbuf,
+ uint16_t size);
+
+USBD_StatusTypeDef USBD_LL_PrepareReceive(USBD_HandleTypeDef *pdev,
+ uint8_t ep_addr,
+ uint8_t *pbuf,
+ uint16_t size);
+
+uint32_t USBD_LL_GetRxDataSize (USBD_HandleTypeDef *pdev, uint8_t ep_addr);
+void USBD_LL_Delay (uint32_t Delay);
+
+/**
+ * @}
+ */
+
+#endif /* __USBD_CORE_H */
+
+/**
+ * @}
+ */
+
+/**
+* @}
+*/
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
+
+
+
diff --git a/ports/stm32/usbdev/core/inc/usbd_ctlreq.h b/ports/stm32/usbdev/core/inc/usbd_ctlreq.h
index 9edf07924..8c26884e6 100644
--- a/ports/stm32/usbdev/core/inc/usbd_ctlreq.h
+++ b/ports/stm32/usbdev/core/inc/usbd_ctlreq.h
@@ -1,106 +1,106 @@
-/**
- ******************************************************************************
- * @file usbd_req.h
- * @author MCD Application Team
- * @version V2.0.0
- * @date 18-February-2014
- * @brief header file for the usbd_req.c file
- ******************************************************************************
- * @attention
- *
- * <h2><center>&copy; COPYRIGHT 2014 STMicroelectronics</center></h2>
- *
- * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
- * You may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.st.com/software_license_agreement_liberty_v2
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- ******************************************************************************
- */
-
-/* Define to prevent recursive inclusion -------------------------------------*/
-
-#ifndef __USB_REQUEST_H_
-#define __USB_REQUEST_H_
-
-/* Includes ------------------------------------------------------------------*/
-#include "usbd_def.h"
-
-
-/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY
- * @{
- */
-
-/** @defgroup USBD_REQ
- * @brief header file for the usbd_ioreq.c file
- * @{
- */
-
-/** @defgroup USBD_REQ_Exported_Defines
- * @{
- */
-/**
- * @}
- */
-
-
-/** @defgroup USBD_REQ_Exported_Types
- * @{
- */
-/**
- * @}
- */
-
-
-
-/** @defgroup USBD_REQ_Exported_Macros
- * @{
- */
-/**
- * @}
- */
-
-/** @defgroup USBD_REQ_Exported_Variables
- * @{
- */
-/**
- * @}
- */
-
-/** @defgroup USBD_REQ_Exported_FunctionsPrototype
- * @{
- */
-
-USBD_StatusTypeDef USBD_StdDevReq (USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req);
-USBD_StatusTypeDef USBD_StdItfReq (USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req);
-USBD_StatusTypeDef USBD_StdEPReq (USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req);
-
-
-void USBD_CtlError (USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req);
-
-void USBD_ParseSetupRequest (USBD_SetupReqTypedef *req, uint8_t *pdata);
-
-void USBD_GetString (uint8_t *desc, uint8_t *unicode, uint16_t *len);
-/**
- * @}
- */
-
-#endif /* __USB_REQUEST_H_ */
-
-/**
- * @}
- */
-
-/**
-* @}
-*/
-
-
-/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
+/**
+ ******************************************************************************
+ * @file usbd_req.h
+ * @author MCD Application Team
+ * @version V2.0.0
+ * @date 18-February-2014
+ * @brief header file for the usbd_req.c file
+ ******************************************************************************
+ * @attention
+ *
+ * <h2><center>&copy; COPYRIGHT 2014 STMicroelectronics</center></h2>
+ *
+ * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
+ * You may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.st.com/software_license_agreement_liberty_v2
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************
+ */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+
+#ifndef __USB_REQUEST_H_
+#define __USB_REQUEST_H_
+
+/* Includes ------------------------------------------------------------------*/
+#include "usbd_def.h"
+
+
+/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY
+ * @{
+ */
+
+/** @defgroup USBD_REQ
+ * @brief header file for the usbd_ioreq.c file
+ * @{
+ */
+
+/** @defgroup USBD_REQ_Exported_Defines
+ * @{
+ */
+/**
+ * @}
+ */
+
+
+/** @defgroup USBD_REQ_Exported_Types
+ * @{
+ */
+/**
+ * @}
+ */
+
+
+
+/** @defgroup USBD_REQ_Exported_Macros
+ * @{
+ */
+/**
+ * @}
+ */
+
+/** @defgroup USBD_REQ_Exported_Variables
+ * @{
+ */
+/**
+ * @}
+ */
+
+/** @defgroup USBD_REQ_Exported_FunctionsPrototype
+ * @{
+ */
+
+USBD_StatusTypeDef USBD_StdDevReq (USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req);
+USBD_StatusTypeDef USBD_StdItfReq (USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req);
+USBD_StatusTypeDef USBD_StdEPReq (USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req);
+
+
+void USBD_CtlError (USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req);
+
+void USBD_ParseSetupRequest (USBD_SetupReqTypedef *req, uint8_t *pdata);
+
+void USBD_GetString (uint8_t *desc, uint8_t *unicode, uint16_t *len);
+/**
+ * @}
+ */
+
+#endif /* __USB_REQUEST_H_ */
+
+/**
+ * @}
+ */
+
+/**
+* @}
+*/
+
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/ports/stm32/usbdev/core/inc/usbd_def.h b/ports/stm32/usbdev/core/inc/usbd_def.h
index 888d426ef..e0d1c3762 100644
--- a/ports/stm32/usbdev/core/inc/usbd_def.h
+++ b/ports/stm32/usbdev/core/inc/usbd_def.h
@@ -1,321 +1,313 @@
-/**
- ******************************************************************************
- * @file usbd_def.h
- * @author MCD Application Team
- * @version V2.0.0
- * @date 18-February-2014
- * @brief general defines for the usb device library
- ******************************************************************************
- * @attention
- *
- * <h2><center>&copy; COPYRIGHT 2014 STMicroelectronics</center></h2>
- *
- * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
- * You may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.st.com/software_license_agreement_liberty_v2
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- ******************************************************************************
- */
-
-/* Define to prevent recursive inclusion -------------------------------------*/
-
-#ifndef __USBD_DEF_H
-#define __USBD_DEF_H
-
-/* Includes ------------------------------------------------------------------*/
-#include "usbd_conf.h"
-
-/** @addtogroup STM32_USBD_DEVICE_LIBRARY
- * @{
- */
-
-/** @defgroup USB_DEF
- * @brief general defines for the usb device library file
- * @{
- */
-
-/** @defgroup USB_DEF_Exported_Defines
- * @{
- */
-
-#ifndef NULL
-#define NULL ((void *)0)
-#endif
-
-
-#define USB_LEN_DEV_QUALIFIER_DESC 0x0A
-#define USB_LEN_DEV_DESC 0x12
-#define USB_LEN_CFG_DESC 0x09
-#define USB_LEN_IF_DESC 0x09
-#define USB_LEN_EP_DESC 0x07
-#define USB_LEN_OTG_DESC 0x03
-#define USB_LEN_LANGID_STR_DESC 0x04
-#define USB_LEN_OTHER_SPEED_DESC_SIZ 0x09
-
-#define USBD_IDX_LANGID_STR 0x00
-#define USBD_IDX_MFC_STR 0x01
-#define USBD_IDX_PRODUCT_STR 0x02
-#define USBD_IDX_SERIAL_STR 0x03
-#define USBD_IDX_CONFIG_STR 0x04
-#define USBD_IDX_INTERFACE_STR 0x05
-
-#define USB_REQ_TYPE_STANDARD 0x00
-#define USB_REQ_TYPE_CLASS 0x20
-#define USB_REQ_TYPE_VENDOR 0x40
-#define USB_REQ_TYPE_MASK 0x60
-
-#define USB_REQ_RECIPIENT_DEVICE 0x00
-#define USB_REQ_RECIPIENT_INTERFACE 0x01
-#define USB_REQ_RECIPIENT_ENDPOINT 0x02
-#define USB_REQ_RECIPIENT_MASK 0x03
-
-#define USB_REQ_GET_STATUS 0x00
-#define USB_REQ_CLEAR_FEATURE 0x01
-#define USB_REQ_SET_FEATURE 0x03
-#define USB_REQ_SET_ADDRESS 0x05
-#define USB_REQ_GET_DESCRIPTOR 0x06
-#define USB_REQ_SET_DESCRIPTOR 0x07
-#define USB_REQ_GET_CONFIGURATION 0x08
-#define USB_REQ_SET_CONFIGURATION 0x09
-#define USB_REQ_GET_INTERFACE 0x0A
-#define USB_REQ_SET_INTERFACE 0x0B
-#define USB_REQ_SYNCH_FRAME 0x0C
-
-#define USB_DESC_TYPE_DEVICE 1
-#define USB_DESC_TYPE_CONFIGURATION 2
-#define USB_DESC_TYPE_STRING 3
-#define USB_DESC_TYPE_INTERFACE 4
-#define USB_DESC_TYPE_ENDPOINT 5
-#define USB_DESC_TYPE_DEVICE_QUALIFIER 6
-#define USB_DESC_TYPE_OTHER_SPEED_CONFIGURATION 7
-
-
-#define USB_CONFIG_REMOTE_WAKEUP 2
-#define USB_CONFIG_SELF_POWERED 1
-
-#define USB_FEATURE_EP_HALT 0
-#define USB_FEATURE_REMOTE_WAKEUP 1
-#define USB_FEATURE_TEST_MODE 2
-
-
-#define USB_HS_MAX_PACKET_SIZE 512
-#define USB_FS_MAX_PACKET_SIZE 64
-#define USB_MAX_EP0_SIZE 64
-
-/* Device Status */
-#define USBD_STATE_DEFAULT 1
-#define USBD_STATE_ADDRESSED 2
-#define USBD_STATE_CONFIGURED 3
-#define USBD_STATE_SUSPENDED 4
-
-
-/* EP0 State */
-#define USBD_EP0_IDLE 0
-#define USBD_EP0_SETUP 1
-#define USBD_EP0_DATA_IN 2
-#define USBD_EP0_DATA_OUT 3
-#define USBD_EP0_STATUS_IN 4
-#define USBD_EP0_STATUS_OUT 5
-#define USBD_EP0_STALL 6
-
-#define USBD_EP_TYPE_CTRL 0
-#define USBD_EP_TYPE_ISOC 1
-#define USBD_EP_TYPE_BULK 2
-#define USBD_EP_TYPE_INTR 3
-
-
-/**
- * @}
- */
-
-
-/** @defgroup USBD_DEF_Exported_TypesDefinitions
- * @{
- */
-
-typedef struct usb_setup_req
-{
-
- uint8_t bmRequest;
- uint8_t bRequest;
- uint16_t wValue;
- uint16_t wIndex;
- uint16_t wLength;
-}USBD_SetupReqTypedef;
-
-struct _USBD_HandleTypeDef;
-
-typedef struct _Device_cb
-{
- uint8_t (*Init) (struct _USBD_HandleTypeDef *pdev , uint8_t cfgidx);
- uint8_t (*DeInit) (struct _USBD_HandleTypeDef *pdev , uint8_t cfgidx);
- /* Control Endpoints*/
- uint8_t (*Setup) (struct _USBD_HandleTypeDef *pdev , USBD_SetupReqTypedef *req);
- uint8_t (*EP0_TxSent) (struct _USBD_HandleTypeDef *pdev );
- uint8_t (*EP0_RxReady) (struct _USBD_HandleTypeDef *pdev );
- /* Class Specific Endpoints*/
- uint8_t (*DataIn) (struct _USBD_HandleTypeDef *pdev , uint8_t epnum);
- uint8_t (*DataOut) (struct _USBD_HandleTypeDef *pdev , uint8_t epnum);
- uint8_t (*SOF) (struct _USBD_HandleTypeDef *pdev);
- uint8_t (*IsoINIncomplete) (struct _USBD_HandleTypeDef *pdev , uint8_t epnum);
- uint8_t (*IsoOUTIncomplete) (struct _USBD_HandleTypeDef *pdev , uint8_t epnum);
-
- uint8_t *(*GetHSConfigDescriptor)(struct _USBD_HandleTypeDef *pdev, uint16_t *length);
- uint8_t *(*GetFSConfigDescriptor)(struct _USBD_HandleTypeDef *pdev, uint16_t *length);
- uint8_t *(*GetOtherSpeedConfigDescriptor)(struct _USBD_HandleTypeDef *pdev, uint16_t *length);
- uint8_t *(*GetDeviceQualifierDescriptor)(struct _USBD_HandleTypeDef *pdev, uint16_t *length);
-#if (USBD_SUPPORT_USER_STRING == 1)
- uint8_t *(*GetUsrStrDescriptor)(struct _USBD_HandleTypeDef *pdev ,uint8_t index, uint16_t *length);
-#endif
-
-} USBD_ClassTypeDef;
-
-/* Following USB Device Speed */
-typedef enum
-{
- USBD_SPEED_HIGH = 0,
- USBD_SPEED_FULL = 1,
- USBD_SPEED_LOW = 2,
-}USBD_SpeedTypeDef;
-
-/* Following USB Device status */
-typedef enum {
- USBD_OK = 0,
- USBD_BUSY,
- USBD_FAIL,
-}USBD_StatusTypeDef;
-
-struct _USBD_HandleTypeDef;
-
-/* USB Device descriptors structure */
-typedef struct
-{
- uint8_t *(*GetDeviceDescriptor)(struct _USBD_HandleTypeDef *pdev, uint16_t *length);
- uint8_t *(*GetLangIDStrDescriptor)(struct _USBD_HandleTypeDef *pdev, uint16_t *length);
- uint8_t *(*GetManufacturerStrDescriptor)(struct _USBD_HandleTypeDef *pdev, uint16_t *length);
- uint8_t *(*GetProductStrDescriptor)(struct _USBD_HandleTypeDef *pdev, uint16_t *length);
- uint8_t *(*GetSerialStrDescriptor)(struct _USBD_HandleTypeDef *pdev, uint16_t *length);
- uint8_t *(*GetConfigurationStrDescriptor)(struct _USBD_HandleTypeDef *pdev, uint16_t *length);
- uint8_t *(*GetInterfaceStrDescriptor)(struct _USBD_HandleTypeDef *pdev, uint16_t *length);
-} USBD_DescriptorsTypeDef;
-
-/* USB Device handle structure */
-typedef struct
-{
- uint32_t status;
- uint32_t total_length;
- uint32_t rem_length;
- uint32_t maxpacket;
-} USBD_EndpointTypeDef;
-
-/* USB Device handle structure */
-typedef struct _USBD_HandleTypeDef
-{
- uint8_t id;
- uint32_t dev_config;
- uint32_t dev_default_config;
- uint32_t dev_config_status;
- USBD_SpeedTypeDef dev_speed;
- USBD_EndpointTypeDef ep_in[15];
- USBD_EndpointTypeDef ep_out[15];
- uint32_t ep0_state;
- uint32_t ep0_data_len;
- uint8_t dev_state;
- uint8_t dev_old_state;
- uint8_t dev_address;
- uint8_t dev_connection_status;
- uint8_t dev_test_mode;
- uint32_t dev_remote_wakeup;
-
- USBD_SetupReqTypedef request;
- USBD_DescriptorsTypeDef *pDesc;
- const USBD_ClassTypeDef *pClass;
- void *pClassData;
- void *pUserData;
- void *pData;
-} USBD_HandleTypeDef;
-
-/**
- * @}
- */
-
-
-
-/** @defgroup USBD_DEF_Exported_Macros
- * @{
- */
-#define SWAPBYTE(addr) (((uint16_t)(*((uint8_t *)(addr)))) + \
- (((uint16_t)(*(((uint8_t *)(addr)) + 1))) << 8))
-
-#define LOBYTE(x) ((uint8_t)(x & 0x00FF))
-#define HIBYTE(x) ((uint8_t)((x & 0xFF00) >>8))
-#define MIN(a, b) (((a) < (b)) ? (a) : (b))
-#define MAX(a, b) (((a) > (b)) ? (a) : (b))
-
-
-#if defined ( __GNUC__ )
- #ifndef __weak
- #define __weak __attribute__((weak))
- #endif /* __weak */
- #ifndef __packed
- #define __packed __attribute__((__packed__))
- #endif /* __packed */
-#endif /* __GNUC__ */
-
-
-/* In HS mode and when the DMA is used, all variables and data structures dealing
- with the DMA during the transaction process should be 4-bytes aligned */
-
-#if defined (__GNUC__) /* GNU Compiler */
- #define __ALIGN_END __attribute__ ((aligned (4)))
- #define __ALIGN_BEGIN
-#else
- #define __ALIGN_END
- #if defined (__CC_ARM) /* ARM Compiler */
- #define __ALIGN_BEGIN __align(4)
- #elif defined (__ICCARM__) /* IAR Compiler */
- #define __ALIGN_BEGIN
- #elif defined (__TASKING__) /* TASKING Compiler */
- #define __ALIGN_BEGIN __align(4)
- #endif /* __CC_ARM */
-#endif /* __GNUC__ */
-
-
-/**
- * @}
- */
-
-/** @defgroup USBD_DEF_Exported_Variables
- * @{
- */
-
-/**
- * @}
- */
-
-/** @defgroup USBD_DEF_Exported_FunctionsPrototype
- * @{
- */
-
-/**
- * @}
- */
-
-#endif /* __USBD_DEF_H */
-
-/**
- * @}
- */
-
-/**
-* @}
-*/
-/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
+/**
+ ******************************************************************************
+ * @file usbd_def.h
+ * @author MCD Application Team
+ * @version V2.0.0
+ * @date 18-February-2014
+ * @brief general defines for the usb device library
+ ******************************************************************************
+ * @attention
+ *
+ * <h2><center>&copy; COPYRIGHT 2014 STMicroelectronics</center></h2>
+ *
+ * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
+ * You may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.st.com/software_license_agreement_liberty_v2
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************
+ */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+
+#ifndef __USBD_DEF_H
+#define __USBD_DEF_H
+
+/* Includes ------------------------------------------------------------------*/
+#include "usbd_conf.h"
+
+/** @addtogroup STM32_USBD_DEVICE_LIBRARY
+ * @{
+ */
+
+/** @defgroup USB_DEF
+ * @brief general defines for the usb device library file
+ * @{
+ */
+
+/** @defgroup USB_DEF_Exported_Defines
+ * @{
+ */
+
+#ifndef NULL
+#define NULL ((void *)0)
+#endif
+
+
+#define USB_LEN_DEV_QUALIFIER_DESC 0x0A
+#define USB_LEN_DEV_DESC 0x12
+#define USB_LEN_CFG_DESC 0x09
+#define USB_LEN_IF_DESC 0x09
+#define USB_LEN_EP_DESC 0x07
+#define USB_LEN_OTG_DESC 0x03
+#define USB_LEN_LANGID_STR_DESC 0x04
+#define USB_LEN_OTHER_SPEED_DESC_SIZ 0x09
+
+#define USBD_IDX_LANGID_STR 0x00
+#define USBD_IDX_MFC_STR 0x01
+#define USBD_IDX_PRODUCT_STR 0x02
+#define USBD_IDX_SERIAL_STR 0x03
+#define USBD_IDX_CONFIG_STR 0x04
+#define USBD_IDX_INTERFACE_STR 0x05
+
+#define USB_REQ_TYPE_STANDARD 0x00
+#define USB_REQ_TYPE_CLASS 0x20
+#define USB_REQ_TYPE_VENDOR 0x40
+#define USB_REQ_TYPE_MASK 0x60
+
+#define USB_REQ_RECIPIENT_DEVICE 0x00
+#define USB_REQ_RECIPIENT_INTERFACE 0x01
+#define USB_REQ_RECIPIENT_ENDPOINT 0x02
+#define USB_REQ_RECIPIENT_MASK 0x03
+
+#define USB_REQ_GET_STATUS 0x00
+#define USB_REQ_CLEAR_FEATURE 0x01
+#define USB_REQ_SET_FEATURE 0x03
+#define USB_REQ_SET_ADDRESS 0x05
+#define USB_REQ_GET_DESCRIPTOR 0x06
+#define USB_REQ_SET_DESCRIPTOR 0x07
+#define USB_REQ_GET_CONFIGURATION 0x08
+#define USB_REQ_SET_CONFIGURATION 0x09
+#define USB_REQ_GET_INTERFACE 0x0A
+#define USB_REQ_SET_INTERFACE 0x0B
+#define USB_REQ_SYNCH_FRAME 0x0C
+
+#define USB_DESC_TYPE_DEVICE 1
+#define USB_DESC_TYPE_CONFIGURATION 2
+#define USB_DESC_TYPE_STRING 3
+#define USB_DESC_TYPE_INTERFACE 4
+#define USB_DESC_TYPE_ENDPOINT 5
+#define USB_DESC_TYPE_DEVICE_QUALIFIER 6
+#define USB_DESC_TYPE_OTHER_SPEED_CONFIGURATION 7
+
+
+#define USB_CONFIG_REMOTE_WAKEUP 2
+#define USB_CONFIG_SELF_POWERED 1
+
+#define USB_FEATURE_EP_HALT 0
+#define USB_FEATURE_REMOTE_WAKEUP 1
+#define USB_FEATURE_TEST_MODE 2
+
+
+#define USB_HS_MAX_PACKET_SIZE 512
+#define USB_FS_MAX_PACKET_SIZE 64
+#define USB_MAX_EP0_SIZE 64
+
+/* Device Status */
+#define USBD_STATE_DEFAULT 1
+#define USBD_STATE_ADDRESSED 2
+#define USBD_STATE_CONFIGURED 3
+#define USBD_STATE_SUSPENDED 4
+
+
+/* EP0 State */
+#define USBD_EP0_IDLE 0
+#define USBD_EP0_SETUP 1
+#define USBD_EP0_DATA_IN 2
+#define USBD_EP0_DATA_OUT 3
+#define USBD_EP0_STATUS_IN 4
+#define USBD_EP0_STATUS_OUT 5
+#define USBD_EP0_STALL 6
+
+#define USBD_EP_TYPE_CTRL 0
+#define USBD_EP_TYPE_ISOC 1
+#define USBD_EP_TYPE_BULK 2
+#define USBD_EP_TYPE_INTR 3
+
+
+/**
+ * @}
+ */
+
+
+/** @defgroup USBD_DEF_Exported_TypesDefinitions
+ * @{
+ */
+
+typedef struct usb_setup_req
+{
+
+ uint8_t bmRequest;
+ uint8_t bRequest;
+ uint16_t wValue;
+ uint16_t wIndex;
+ uint16_t wLength;
+}USBD_SetupReqTypedef;
+
+struct _USBD_HandleTypeDef;
+
+typedef struct _Device_cb
+{
+ uint8_t (*Init) (struct _USBD_HandleTypeDef *pdev , uint8_t cfgidx);
+ uint8_t (*DeInit) (struct _USBD_HandleTypeDef *pdev , uint8_t cfgidx);
+ /* Control Endpoints*/
+ uint8_t (*Setup) (struct _USBD_HandleTypeDef *pdev , USBD_SetupReqTypedef *req);
+ uint8_t (*EP0_TxSent) (struct _USBD_HandleTypeDef *pdev );
+ uint8_t (*EP0_RxReady) (struct _USBD_HandleTypeDef *pdev );
+ /* Class Specific Endpoints*/
+ uint8_t (*DataIn) (struct _USBD_HandleTypeDef *pdev , uint8_t epnum);
+ uint8_t (*DataOut) (struct _USBD_HandleTypeDef *pdev , uint8_t epnum);
+ uint8_t (*SOF) (struct _USBD_HandleTypeDef *pdev);
+ uint8_t (*IsoINIncomplete) (struct _USBD_HandleTypeDef *pdev , uint8_t epnum);
+ uint8_t (*IsoOUTIncomplete) (struct _USBD_HandleTypeDef *pdev , uint8_t epnum);
+
+ uint8_t *(*GetHSConfigDescriptor)(struct _USBD_HandleTypeDef *pdev, uint16_t *length);
+ uint8_t *(*GetFSConfigDescriptor)(struct _USBD_HandleTypeDef *pdev, uint16_t *length);
+ uint8_t *(*GetOtherSpeedConfigDescriptor)(struct _USBD_HandleTypeDef *pdev, uint16_t *length);
+ uint8_t *(*GetDeviceQualifierDescriptor)(struct _USBD_HandleTypeDef *pdev, uint16_t *length);
+
+} USBD_ClassTypeDef;
+
+/* Following USB Device Speed */
+typedef enum
+{
+ USBD_SPEED_HIGH = 0,
+ USBD_SPEED_FULL = 1,
+ USBD_SPEED_LOW = 2,
+}USBD_SpeedTypeDef;
+
+/* Following USB Device status */
+typedef enum {
+ USBD_OK = 0,
+ USBD_BUSY,
+ USBD_FAIL,
+}USBD_StatusTypeDef;
+
+struct _USBD_HandleTypeDef;
+
+/* USB Device descriptors structure */
+typedef struct
+{
+ uint8_t *(*GetDeviceDescriptor)(struct _USBD_HandleTypeDef *pdev, uint16_t *length);
+ uint8_t *(*GetStrDescriptor)(struct _USBD_HandleTypeDef *pdev, uint8_t idx, uint16_t *length);
+} USBD_DescriptorsTypeDef;
+
+/* USB Device handle structure */
+typedef struct
+{
+ uint32_t status;
+ uint32_t total_length;
+ uint32_t rem_length;
+ uint32_t maxpacket;
+} USBD_EndpointTypeDef;
+
+/* USB Device handle structure */
+typedef struct _USBD_HandleTypeDef
+{
+ uint8_t id;
+ uint32_t dev_config;
+ uint32_t dev_default_config;
+ uint32_t dev_config_status;
+ USBD_SpeedTypeDef dev_speed;
+ USBD_EndpointTypeDef ep_in[15];
+ USBD_EndpointTypeDef ep_out[15];
+ uint32_t ep0_state;
+ uint32_t ep0_data_len;
+ uint8_t dev_state;
+ uint8_t dev_old_state;
+ uint8_t dev_address;
+ uint8_t dev_connection_status;
+ uint8_t dev_test_mode;
+ uint32_t dev_remote_wakeup;
+
+ USBD_SetupReqTypedef request;
+ USBD_DescriptorsTypeDef *pDesc;
+ const USBD_ClassTypeDef *pClass;
+ void *pClassData;
+ void *pUserData;
+ void *pData;
+} USBD_HandleTypeDef;
+
+/**
+ * @}
+ */
+
+
+
+/** @defgroup USBD_DEF_Exported_Macros
+ * @{
+ */
+#define SWAPBYTE(addr) (((uint16_t)(*((uint8_t *)(addr)))) + \
+ (((uint16_t)(*(((uint8_t *)(addr)) + 1))) << 8))
+
+#define LOBYTE(x) ((uint8_t)(x & 0x00FF))
+#define HIBYTE(x) ((uint8_t)((x & 0xFF00) >>8))
+#define MIN(a, b) (((a) < (b)) ? (a) : (b))
+#define MAX(a, b) (((a) > (b)) ? (a) : (b))
+
+
+#if defined ( __GNUC__ )
+ #ifndef __weak
+ #define __weak __attribute__((weak))
+ #endif /* __weak */
+ #ifndef __packed
+ #define __packed __attribute__((__packed__))
+ #endif /* __packed */
+#endif /* __GNUC__ */
+
+
+/* In HS mode and when the DMA is used, all variables and data structures dealing
+ with the DMA during the transaction process should be 4-bytes aligned */
+
+#if defined (__GNUC__) /* GNU Compiler */
+ #define __ALIGN_END __attribute__ ((aligned (4)))
+ #define __ALIGN_BEGIN
+#else
+ #define __ALIGN_END
+ #if defined (__CC_ARM) /* ARM Compiler */
+ #define __ALIGN_BEGIN __align(4)
+ #elif defined (__ICCARM__) /* IAR Compiler */
+ #define __ALIGN_BEGIN
+ #elif defined (__TASKING__) /* TASKING Compiler */
+ #define __ALIGN_BEGIN __align(4)
+ #endif /* __CC_ARM */
+#endif /* __GNUC__ */
+
+
+/**
+ * @}
+ */
+
+/** @defgroup USBD_DEF_Exported_Variables
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+/** @defgroup USBD_DEF_Exported_FunctionsPrototype
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+#endif /* __USBD_DEF_H */
+
+/**
+ * @}
+ */
+
+/**
+* @}
+*/
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/ports/stm32/usbdev/core/inc/usbd_ioreq.h b/ports/stm32/usbdev/core/inc/usbd_ioreq.h
index 04e01b854..c964f0ad5 100644
--- a/ports/stm32/usbdev/core/inc/usbd_ioreq.h
+++ b/ports/stm32/usbdev/core/inc/usbd_ioreq.h
@@ -1,121 +1,121 @@
-/**
- ******************************************************************************
- * @file usbd_ioreq.h
- * @author MCD Application Team
- * @version V2.0.0
- * @date 18-February-2014
- * @brief header file for the usbd_ioreq.c file
- ******************************************************************************
- * @attention
- *
- * <h2><center>&copy; COPYRIGHT 2014 STMicroelectronics</center></h2>
- *
- * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
- * You may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.st.com/software_license_agreement_liberty_v2
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- ******************************************************************************
- */
-
-/* Define to prevent recursive inclusion -------------------------------------*/
-
-#ifndef __USBD_IOREQ_H_
-#define __USBD_IOREQ_H_
-
-/* Includes ------------------------------------------------------------------*/
-#include "usbd_def.h"
-#include "usbd_core.h"
-
-/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY
- * @{
- */
-
-/** @defgroup USBD_IOREQ
- * @brief header file for the usbd_ioreq.c file
- * @{
- */
-
-/** @defgroup USBD_IOREQ_Exported_Defines
- * @{
- */
-/**
- * @}
- */
-
-
-/** @defgroup USBD_IOREQ_Exported_Types
- * @{
- */
-
-
-/**
- * @}
- */
-
-
-
-/** @defgroup USBD_IOREQ_Exported_Macros
- * @{
- */
-
-/**
- * @}
- */
-
-/** @defgroup USBD_IOREQ_Exported_Variables
- * @{
- */
-
-/**
- * @}
- */
-
-/** @defgroup USBD_IOREQ_Exported_FunctionsPrototype
- * @{
- */
-
-USBD_StatusTypeDef USBD_CtlSendData (USBD_HandleTypeDef *pdev,
- uint8_t *buf,
- uint16_t len);
-
-USBD_StatusTypeDef USBD_CtlContinueSendData (USBD_HandleTypeDef *pdev,
- uint8_t *pbuf,
- uint16_t len);
-
-USBD_StatusTypeDef USBD_CtlPrepareRx (USBD_HandleTypeDef *pdev,
- uint8_t *pbuf,
- uint16_t len);
-
-USBD_StatusTypeDef USBD_CtlContinueRx (USBD_HandleTypeDef *pdev,
- uint8_t *pbuf,
- uint16_t len);
-
-USBD_StatusTypeDef USBD_CtlSendStatus (USBD_HandleTypeDef *pdev);
-
-USBD_StatusTypeDef USBD_CtlReceiveStatus (USBD_HandleTypeDef *pdev);
-
-uint16_t USBD_GetRxCount (USBD_HandleTypeDef *pdev ,
- uint8_t epnum);
-
-/**
- * @}
- */
-
-#endif /* __USBD_IOREQ_H_ */
-
-/**
- * @}
- */
-
-/**
-* @}
-*/
-/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
+/**
+ ******************************************************************************
+ * @file usbd_ioreq.h
+ * @author MCD Application Team
+ * @version V2.0.0
+ * @date 18-February-2014
+ * @brief header file for the usbd_ioreq.c file
+ ******************************************************************************
+ * @attention
+ *
+ * <h2><center>&copy; COPYRIGHT 2014 STMicroelectronics</center></h2>
+ *
+ * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
+ * You may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.st.com/software_license_agreement_liberty_v2
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************
+ */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+
+#ifndef __USBD_IOREQ_H_
+#define __USBD_IOREQ_H_
+
+/* Includes ------------------------------------------------------------------*/
+#include "usbd_def.h"
+#include "usbd_core.h"
+
+/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY
+ * @{
+ */
+
+/** @defgroup USBD_IOREQ
+ * @brief header file for the usbd_ioreq.c file
+ * @{
+ */
+
+/** @defgroup USBD_IOREQ_Exported_Defines
+ * @{
+ */
+/**
+ * @}
+ */
+
+
+/** @defgroup USBD_IOREQ_Exported_Types
+ * @{
+ */
+
+
+/**
+ * @}
+ */
+
+
+
+/** @defgroup USBD_IOREQ_Exported_Macros
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+/** @defgroup USBD_IOREQ_Exported_Variables
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+/** @defgroup USBD_IOREQ_Exported_FunctionsPrototype
+ * @{
+ */
+
+USBD_StatusTypeDef USBD_CtlSendData (USBD_HandleTypeDef *pdev,
+ uint8_t *buf,
+ uint16_t len);
+
+USBD_StatusTypeDef USBD_CtlContinueSendData (USBD_HandleTypeDef *pdev,
+ uint8_t *pbuf,
+ uint16_t len);
+
+USBD_StatusTypeDef USBD_CtlPrepareRx (USBD_HandleTypeDef *pdev,
+ uint8_t *pbuf,
+ uint16_t len);
+
+USBD_StatusTypeDef USBD_CtlContinueRx (USBD_HandleTypeDef *pdev,
+ uint8_t *pbuf,
+ uint16_t len);
+
+USBD_StatusTypeDef USBD_CtlSendStatus (USBD_HandleTypeDef *pdev);
+
+USBD_StatusTypeDef USBD_CtlReceiveStatus (USBD_HandleTypeDef *pdev);
+
+uint16_t USBD_GetRxCount (USBD_HandleTypeDef *pdev ,
+ uint8_t epnum);
+
+/**
+ * @}
+ */
+
+#endif /* __USBD_IOREQ_H_ */
+
+/**
+ * @}
+ */
+
+/**
+* @}
+*/
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/ports/stm32/usbdev/core/src/usbd_core.c b/ports/stm32/usbdev/core/src/usbd_core.c
index ae5b99626..f235b24ee 100644
--- a/ports/stm32/usbdev/core/src/usbd_core.c
+++ b/ports/stm32/usbdev/core/src/usbd_core.c
@@ -1,554 +1,552 @@
-/**
- ******************************************************************************
- * @file usbd_core.c
- * @author MCD Application Team
- * @version V2.0.0
- * @date 18-February-2014
- * @brief This file provides all the USBD core functions.
- ******************************************************************************
- * @attention
- *
- * <h2><center>&copy; COPYRIGHT 2014 STMicroelectronics</center></h2>
- *
- * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
- * You may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.st.com/software_license_agreement_liberty_v2
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- ******************************************************************************
- */
-
-/* Includes ------------------------------------------------------------------*/
-#include "usbd_core.h"
-
-/** @addtogroup STM32_USBD_DEVICE_LIBRARY
-* @{
-*/
-
-
-/** @defgroup USBD_CORE
-* @brief usbd core module
-* @{
-*/
-
-/** @defgroup USBD_CORE_Private_TypesDefinitions
-* @{
-*/
-/**
-* @}
-*/
-
-
-/** @defgroup USBD_CORE_Private_Defines
-* @{
-*/
-
-/**
-* @}
-*/
-
-
-/** @defgroup USBD_CORE_Private_Macros
-* @{
-*/
-/**
-* @}
-*/
-
-
-
-
-/** @defgroup USBD_CORE_Private_FunctionPrototypes
-* @{
-*/
-
-/**
-* @}
-*/
-
-/** @defgroup USBD_CORE_Private_Variables
-* @{
-*/
-
-/**
-* @}
-*/
-
-/** @defgroup USBD_CORE_Private_Functions
-* @{
-*/
-
-/**
-* @brief USBD_Init
-* Initailizes the device stack and load the class driver
-* @param pdev: device instance
-* @param core_address: USB OTG core ID
-* @param pdesc: Descriptor structure address
-* @param id: Low level core index
-* @retval None
-*/
-USBD_StatusTypeDef USBD_Init(USBD_HandleTypeDef *pdev, USBD_DescriptorsTypeDef *pdesc, uint8_t id)
-{
- /* Check whether the USB Host handle is valid */
- if(pdev == NULL)
- {
- USBD_ErrLog("Invalid Device handle");
- return USBD_FAIL;
- }
-
- /* Unlink previous class*/
- if(pdev->pClass != NULL)
- {
- pdev->pClass = NULL;
- }
-
- /* Assign USBD Descriptors */
- if(pdesc != NULL)
- {
- pdev->pDesc = pdesc;
- }
-
- /* Set Device initial State */
- pdev->dev_state = USBD_STATE_DEFAULT;
- pdev->id = id;
- /* Initialize low level driver */
- USBD_LL_Init(pdev);
-
- return USBD_OK;
-}
-
-/**
-* @brief USBD_DeInit
-* Re-Initialize th device library
-* @param pdev: device instance
-* @retval status: status
-*/
-USBD_StatusTypeDef USBD_DeInit(USBD_HandleTypeDef *pdev)
-{
- /* Set Default State */
- pdev->dev_state = USBD_STATE_DEFAULT;
-
- /* Free Class Resources */
- pdev->pClass->DeInit(pdev, pdev->dev_config);
-
- /* Stop the low level driver */
- USBD_LL_Stop(pdev);
-
- /* Initialize low level driver */
- USBD_LL_DeInit(pdev);
-
- return USBD_OK;
-}
-
-
-/**
- * @brief USBD_RegisterClass
- * Link class driver to Device Core.
- * @param pDevice : Device Handle
- * @param pclass: Class handle
- * @retval USBD Status
- */
-USBD_StatusTypeDef USBD_RegisterClass(USBD_HandleTypeDef *pdev, const USBD_ClassTypeDef *pclass)
-{
- USBD_StatusTypeDef status = USBD_OK;
- if(pclass != 0)
- {
- /* link the class tgo the USB Device handle */
- pdev->pClass = pclass;
- status = USBD_OK;
- }
- else
- {
- USBD_ErrLog("Invalid Class handle");
- status = USBD_FAIL;
- }
-
- return status;
-}
-
-/**
- * @brief USBD_Start
- * Start the USB Device Core.
- * @param pdev: Device Handle
- * @retval USBD Status
- */
-USBD_StatusTypeDef USBD_Start (USBD_HandleTypeDef *pdev)
-{
-
- /* Start the low level driver */
- USBD_LL_Start(pdev);
-
- return USBD_OK;
-}
-
-/**
- * @brief USBD_Stop
- * Stop the USB Device Core.
- * @param pdev: Device Handle
- * @retval USBD Status
- */
-USBD_StatusTypeDef USBD_Stop (USBD_HandleTypeDef *pdev)
-{
- /* Free Class Resources */
- pdev->pClass->DeInit(pdev, pdev->dev_config);
-
- /* Stop the low level driver */
- USBD_LL_Stop(pdev);
-
- return USBD_OK;
-}
-
-/**
-* @brief USBD_RunTestMode
-* Launch test mode process
-* @param pdev: device instance
-* @retval status
-*/
-USBD_StatusTypeDef USBD_RunTestMode (USBD_HandleTypeDef *pdev)
-{
- return USBD_OK;
-}
-
-
-/**
-* @brief USBD_SetClassConfig
-* Configure device and start the interface
-* @param pdev: device instance
-* @param cfgidx: configuration index
-* @retval status
-*/
-
-USBD_StatusTypeDef USBD_SetClassConfig(USBD_HandleTypeDef *pdev, uint8_t cfgidx)
-{
- USBD_StatusTypeDef ret = USBD_FAIL;
-
- if(pdev->pClass != NULL)
- {
- /* Set configuration and Start the Class*/
- if(pdev->pClass->Init(pdev, cfgidx) == 0)
- {
- ret = USBD_OK;
- }
- }
- return ret;
-}
-
-/**
-* @brief USBD_ClrClassConfig
-* Clear current configuration
-* @param pdev: device instance
-* @param cfgidx: configuration index
-* @retval status: USBD_StatusTypeDef
-*/
-USBD_StatusTypeDef USBD_ClrClassConfig(USBD_HandleTypeDef *pdev, uint8_t cfgidx)
-{
- /* Clear configuration and Deinitialize the Class process*/
- pdev->pClass->DeInit(pdev, cfgidx);
- return USBD_OK;
-}
-
-
-/**
-* @brief USBD_SetupStage
-* Handle the setup stage
-* @param pdev: device instance
-* @retval status
-*/
-USBD_StatusTypeDef USBD_LL_SetupStage(USBD_HandleTypeDef *pdev, uint8_t *psetup)
-{
-
- USBD_ParseSetupRequest(&pdev->request, psetup);
-
- pdev->ep0_state = USBD_EP0_SETUP;
- pdev->ep0_data_len = pdev->request.wLength;
-
- switch (pdev->request.bmRequest & 0x1F)
- {
- case USB_REQ_RECIPIENT_DEVICE:
- USBD_StdDevReq (pdev, &pdev->request);
- break;
-
- case USB_REQ_RECIPIENT_INTERFACE:
- USBD_StdItfReq(pdev, &pdev->request);
- break;
-
- case USB_REQ_RECIPIENT_ENDPOINT:
- USBD_StdEPReq(pdev, &pdev->request);
- break;
-
- default:
- USBD_LL_StallEP(pdev , pdev->request.bmRequest & 0x80);
- break;
- }
- return USBD_OK;
-}
-
-/**
-* @brief USBD_DataOutStage
-* Handle data OUT stage
-* @param pdev: device instance
-* @param epnum: endpoint index
-* @retval status
-*/
-USBD_StatusTypeDef USBD_LL_DataOutStage(USBD_HandleTypeDef *pdev , uint8_t epnum, uint8_t *pdata)
-{
- USBD_EndpointTypeDef *pep;
-
- if(epnum == 0)
- {
- pep = &pdev->ep_out[0];
-
- if ( pdev->ep0_state == USBD_EP0_DATA_OUT)
- {
- if(pep->rem_length > pep->maxpacket)
- {
- pep->rem_length -= pep->maxpacket;
-
- USBD_CtlContinueRx (pdev,
- pdata,
- MIN(pep->rem_length ,pep->maxpacket));
- }
- else
- {
- if((pdev->pClass->EP0_RxReady != NULL)&&
- (pdev->dev_state == USBD_STATE_CONFIGURED))
- {
- pdev->pClass->EP0_RxReady(pdev);
- }
- USBD_CtlSendStatus(pdev);
- }
- }
- }
- else if((pdev->pClass->DataOut != NULL)&&
- (pdev->dev_state == USBD_STATE_CONFIGURED))
- {
- pdev->pClass->DataOut(pdev, epnum);
- }
- return USBD_OK;
-}
-
-/**
-* @brief USBD_DataInStage
-* Handle data in stage
-* @param pdev: device instance
-* @param epnum: endpoint index
-* @retval status
-*/
-USBD_StatusTypeDef USBD_LL_DataInStage(USBD_HandleTypeDef *pdev ,uint8_t epnum, uint8_t *pdata)
-{
- USBD_EndpointTypeDef *pep;
-
- if(epnum == 0)
- {
- pep = &pdev->ep_in[0];
-
- if ( pdev->ep0_state == USBD_EP0_DATA_IN)
- {
- if(pep->rem_length > pep->maxpacket)
- {
- pep->rem_length -= pep->maxpacket;
-
- USBD_CtlContinueSendData (pdev,
- pdata,
- pep->rem_length);
- }
- else
- { /* last packet is MPS multiple, so send ZLP packet */
- if((pep->total_length % pep->maxpacket == 0) &&
- (pep->total_length >= pep->maxpacket) &&
- (pep->total_length < pdev->ep0_data_len ))
- {
-
- USBD_CtlContinueSendData(pdev , NULL, 0);
- pdev->ep0_data_len = 0;
- }
- else
- {
- if((pdev->pClass->EP0_TxSent != NULL)&&
- (pdev->dev_state == USBD_STATE_CONFIGURED))
- {
- pdev->pClass->EP0_TxSent(pdev);
- }
- USBD_CtlReceiveStatus(pdev);
- }
- }
- }
- if (pdev->dev_test_mode == 1)
- {
- USBD_RunTestMode(pdev);
- pdev->dev_test_mode = 0;
- }
- }
- else if((pdev->pClass->DataIn != NULL)&&
- (pdev->dev_state == USBD_STATE_CONFIGURED))
- {
- pdev->pClass->DataIn(pdev, epnum);
- }
- return USBD_OK;
-}
-
-/**
-* @brief USBD_LL_Reset
-* Handle Reset event
-* @param pdev: device instance
-* @retval status
-*/
-
-USBD_StatusTypeDef USBD_LL_Reset(USBD_HandleTypeDef *pdev)
-{
- /* Open EP0 OUT */
- USBD_LL_OpenEP(pdev,
- 0x00,
- USBD_EP_TYPE_CTRL,
- USB_MAX_EP0_SIZE);
-
- pdev->ep_out[0].maxpacket = USB_MAX_EP0_SIZE;
-
- /* Open EP0 IN */
- USBD_LL_OpenEP(pdev,
- 0x80,
- USBD_EP_TYPE_CTRL,
- USB_MAX_EP0_SIZE);
-
- pdev->ep_in[0].maxpacket = USB_MAX_EP0_SIZE;
- /* Upon Reset call usr call back */
- pdev->dev_state = USBD_STATE_DEFAULT;
-
- if (pdev->pClassData)
- pdev->pClass->DeInit(pdev, pdev->dev_config);
-
-
- return USBD_OK;
-}
-
-
-
-
-/**
-* @brief USBD_LL_Reset
-* Handle Reset event
-* @param pdev: device instance
-* @retval status
-*/
-USBD_StatusTypeDef USBD_LL_SetSpeed(USBD_HandleTypeDef *pdev, USBD_SpeedTypeDef speed)
-{
- pdev->dev_speed = speed;
- return USBD_OK;
-}
-
-/**
-* @brief USBD_Suspend
-* Handle Suspend event
-* @param pdev: device instance
-* @retval status
-*/
-
-USBD_StatusTypeDef USBD_LL_Suspend(USBD_HandleTypeDef *pdev)
-{
- pdev->dev_old_state = pdev->dev_state;
- pdev->dev_state = USBD_STATE_SUSPENDED;
- return USBD_OK;
-}
-
-/**
-* @brief USBD_Resume
-* Handle Resume event
-* @param pdev: device instance
-* @retval status
-*/
-
-USBD_StatusTypeDef USBD_LL_Resume(USBD_HandleTypeDef *pdev)
-{
- pdev->dev_state = pdev->dev_old_state;
- return USBD_OK;
-}
-
-/**
-* @brief USBD_SOF
-* Handle SOF event
-* @param pdev: device instance
-* @retval status
-*/
-
-USBD_StatusTypeDef USBD_LL_SOF(USBD_HandleTypeDef *pdev)
-{
- if(pdev->dev_state == USBD_STATE_CONFIGURED)
- {
- if(pdev->pClass->SOF != NULL)
- {
- pdev->pClass->SOF(pdev);
- }
- }
- return USBD_OK;
-}
-
-/**
-* @brief USBD_IsoINIncomplete
-* Handle iso in incomplete event
-* @param pdev: device instance
-* @retval status
-*/
-USBD_StatusTypeDef USBD_LL_IsoINIncomplete(USBD_HandleTypeDef *pdev, uint8_t epnum)
-{
- return USBD_OK;
-}
-
-/**
-* @brief USBD_IsoOUTIncomplete
-* Handle iso out incomplete event
-* @param pdev: device instance
-* @retval status
-*/
-USBD_StatusTypeDef USBD_LL_IsoOUTIncomplete(USBD_HandleTypeDef *pdev, uint8_t epnum)
-{
- return USBD_OK;
-}
-
-/**
-* @brief USBD_DevConnected
-* Handle device connection event
-* @param pdev: device instance
-* @retval status
-*/
-USBD_StatusTypeDef USBD_LL_DevConnected(USBD_HandleTypeDef *pdev)
-{
- return USBD_OK;
-}
-
-/**
-* @brief USBD_DevDisconnected
-* Handle device disconnection event
-* @param pdev: device instance
-* @retval status
-*/
-USBD_StatusTypeDef USBD_LL_DevDisconnected(USBD_HandleTypeDef *pdev)
-{
- /* Free Class Resources */
- pdev->dev_state = USBD_STATE_DEFAULT;
- pdev->pClass->DeInit(pdev, pdev->dev_config);
-
- return USBD_OK;
-}
-/**
-* @}
-*/
-
-
-/**
-* @}
-*/
-
-
-/**
-* @}
-*/
-
-/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
-
+/**
+ ******************************************************************************
+ * @file usbd_core.c
+ * @author MCD Application Team
+ * @version V2.0.0
+ * @date 18-February-2014
+ * @brief This file provides all the USBD core functions.
+ ******************************************************************************
+ * @attention
+ *
+ * <h2><center>&copy; COPYRIGHT 2014 STMicroelectronics</center></h2>
+ *
+ * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
+ * You may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.st.com/software_license_agreement_liberty_v2
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************
+ */
+
+/* Includes ------------------------------------------------------------------*/
+#include "usbd_core.h"
+
+/** @addtogroup STM32_USBD_DEVICE_LIBRARY
+* @{
+*/
+
+
+/** @defgroup USBD_CORE
+* @brief usbd core module
+* @{
+*/
+
+/** @defgroup USBD_CORE_Private_TypesDefinitions
+* @{
+*/
+/**
+* @}
+*/
+
+
+/** @defgroup USBD_CORE_Private_Defines
+* @{
+*/
+
+/**
+* @}
+*/
+
+
+/** @defgroup USBD_CORE_Private_Macros
+* @{
+*/
+/**
+* @}
+*/
+
+
+
+
+/** @defgroup USBD_CORE_Private_FunctionPrototypes
+* @{
+*/
+
+/**
+* @}
+*/
+
+/** @defgroup USBD_CORE_Private_Variables
+* @{
+*/
+
+/**
+* @}
+*/
+
+/** @defgroup USBD_CORE_Private_Functions
+* @{
+*/
+
+/**
+* @brief USBD_Init
+* Initailizes the device stack and load the class driver
+* @param pdev: device instance
+* @param core_address: USB OTG core ID
+* @param pdesc: Descriptor structure address
+* @param id: Low level core index
+* @retval None
+*/
+USBD_StatusTypeDef USBD_Init(USBD_HandleTypeDef *pdev, USBD_DescriptorsTypeDef *pdesc, uint8_t id)
+{
+ /* Check whether the USB Host handle is valid */
+ if(pdev == NULL)
+ {
+ return USBD_FAIL;
+ }
+
+ /* Unlink previous class*/
+ if(pdev->pClass != NULL)
+ {
+ pdev->pClass = NULL;
+ }
+
+ /* Assign USBD Descriptors */
+ if(pdesc != NULL)
+ {
+ pdev->pDesc = pdesc;
+ }
+
+ /* Set Device initial State */
+ pdev->dev_state = USBD_STATE_DEFAULT;
+ pdev->id = id;
+ /* Initialize low level driver */
+ USBD_LL_Init(pdev, 0);
+
+ return USBD_OK;
+}
+
+/**
+* @brief USBD_DeInit
+* Re-Initialize th device library
+* @param pdev: device instance
+* @retval status: status
+*/
+USBD_StatusTypeDef USBD_DeInit(USBD_HandleTypeDef *pdev)
+{
+ /* Set Default State */
+ pdev->dev_state = USBD_STATE_DEFAULT;
+
+ /* Free Class Resources */
+ pdev->pClass->DeInit(pdev, pdev->dev_config);
+
+ /* Stop the low level driver */
+ USBD_LL_Stop(pdev);
+
+ /* Initialize low level driver */
+ USBD_LL_DeInit(pdev);
+
+ return USBD_OK;
+}
+
+
+/**
+ * @brief USBD_RegisterClass
+ * Link class driver to Device Core.
+ * @param pDevice : Device Handle
+ * @param pclass: Class handle
+ * @retval USBD Status
+ */
+USBD_StatusTypeDef USBD_RegisterClass(USBD_HandleTypeDef *pdev, const USBD_ClassTypeDef *pclass)
+{
+ USBD_StatusTypeDef status = USBD_OK;
+ if(pclass != 0)
+ {
+ /* link the class tgo the USB Device handle */
+ pdev->pClass = pclass;
+ status = USBD_OK;
+ }
+ else
+ {
+ status = USBD_FAIL;
+ }
+
+ return status;
+}
+
+/**
+ * @brief USBD_Start
+ * Start the USB Device Core.
+ * @param pdev: Device Handle
+ * @retval USBD Status
+ */
+USBD_StatusTypeDef USBD_Start (USBD_HandleTypeDef *pdev)
+{
+
+ /* Start the low level driver */
+ USBD_LL_Start(pdev);
+
+ return USBD_OK;
+}
+
+/**
+ * @brief USBD_Stop
+ * Stop the USB Device Core.
+ * @param pdev: Device Handle
+ * @retval USBD Status
+ */
+USBD_StatusTypeDef USBD_Stop (USBD_HandleTypeDef *pdev)
+{
+ /* Free Class Resources */
+ pdev->pClass->DeInit(pdev, pdev->dev_config);
+
+ /* Stop the low level driver */
+ USBD_LL_Stop(pdev);
+
+ return USBD_OK;
+}
+
+/**
+* @brief USBD_RunTestMode
+* Launch test mode process
+* @param pdev: device instance
+* @retval status
+*/
+USBD_StatusTypeDef USBD_RunTestMode (USBD_HandleTypeDef *pdev)
+{
+ return USBD_OK;
+}
+
+
+/**
+* @brief USBD_SetClassConfig
+* Configure device and start the interface
+* @param pdev: device instance
+* @param cfgidx: configuration index
+* @retval status
+*/
+
+USBD_StatusTypeDef USBD_SetClassConfig(USBD_HandleTypeDef *pdev, uint8_t cfgidx)
+{
+ USBD_StatusTypeDef ret = USBD_FAIL;
+
+ if(pdev->pClass != NULL)
+ {
+ /* Set configuration and Start the Class*/
+ if(pdev->pClass->Init(pdev, cfgidx) == 0)
+ {
+ ret = USBD_OK;
+ }
+ }
+ return ret;
+}
+
+/**
+* @brief USBD_ClrClassConfig
+* Clear current configuration
+* @param pdev: device instance
+* @param cfgidx: configuration index
+* @retval status: USBD_StatusTypeDef
+*/
+USBD_StatusTypeDef USBD_ClrClassConfig(USBD_HandleTypeDef *pdev, uint8_t cfgidx)
+{
+ /* Clear configuration and Deinitialize the Class process*/
+ pdev->pClass->DeInit(pdev, cfgidx);
+ return USBD_OK;
+}
+
+
+/**
+* @brief USBD_SetupStage
+* Handle the setup stage
+* @param pdev: device instance
+* @retval status
+*/
+USBD_StatusTypeDef USBD_LL_SetupStage(USBD_HandleTypeDef *pdev, uint8_t *psetup)
+{
+
+ USBD_ParseSetupRequest(&pdev->request, psetup);
+
+ pdev->ep0_state = USBD_EP0_SETUP;
+ pdev->ep0_data_len = pdev->request.wLength;
+
+ switch (pdev->request.bmRequest & 0x1F)
+ {
+ case USB_REQ_RECIPIENT_DEVICE:
+ USBD_StdDevReq (pdev, &pdev->request);
+ break;
+
+ case USB_REQ_RECIPIENT_INTERFACE:
+ USBD_StdItfReq(pdev, &pdev->request);
+ break;
+
+ case USB_REQ_RECIPIENT_ENDPOINT:
+ USBD_StdEPReq(pdev, &pdev->request);
+ break;
+
+ default:
+ USBD_LL_StallEP(pdev , pdev->request.bmRequest & 0x80);
+ break;
+ }
+ return USBD_OK;
+}
+
+/**
+* @brief USBD_DataOutStage
+* Handle data OUT stage
+* @param pdev: device instance
+* @param epnum: endpoint index
+* @retval status
+*/
+USBD_StatusTypeDef USBD_LL_DataOutStage(USBD_HandleTypeDef *pdev , uint8_t epnum, uint8_t *pdata)
+{
+ USBD_EndpointTypeDef *pep;
+
+ if(epnum == 0)
+ {
+ pep = &pdev->ep_out[0];
+
+ if ( pdev->ep0_state == USBD_EP0_DATA_OUT)
+ {
+ if(pep->rem_length > pep->maxpacket)
+ {
+ pep->rem_length -= pep->maxpacket;
+
+ USBD_CtlContinueRx (pdev,
+ pdata,
+ MIN(pep->rem_length ,pep->maxpacket));
+ }
+ else
+ {
+ if((pdev->pClass->EP0_RxReady != NULL)&&
+ (pdev->dev_state == USBD_STATE_CONFIGURED))
+ {
+ pdev->pClass->EP0_RxReady(pdev);
+ }
+ USBD_CtlSendStatus(pdev);
+ }
+ }
+ }
+ else if((pdev->pClass->DataOut != NULL)&&
+ (pdev->dev_state == USBD_STATE_CONFIGURED))
+ {
+ pdev->pClass->DataOut(pdev, epnum);
+ }
+ return USBD_OK;
+}
+
+/**
+* @brief USBD_DataInStage
+* Handle data in stage
+* @param pdev: device instance
+* @param epnum: endpoint index
+* @retval status
+*/
+USBD_StatusTypeDef USBD_LL_DataInStage(USBD_HandleTypeDef *pdev ,uint8_t epnum, uint8_t *pdata)
+{
+ USBD_EndpointTypeDef *pep;
+
+ if(epnum == 0)
+ {
+ pep = &pdev->ep_in[0];
+
+ if ( pdev->ep0_state == USBD_EP0_DATA_IN)
+ {
+ if(pep->rem_length > pep->maxpacket)
+ {
+ pep->rem_length -= pep->maxpacket;
+
+ USBD_CtlContinueSendData (pdev,
+ pdata,
+ pep->rem_length);
+ }
+ else
+ { /* last packet is MPS multiple, so send ZLP packet */
+ if((pep->total_length % pep->maxpacket == 0) &&
+ (pep->total_length >= pep->maxpacket) &&
+ (pep->total_length < pdev->ep0_data_len ))
+ {
+
+ USBD_CtlContinueSendData(pdev , NULL, 0);
+ pdev->ep0_data_len = 0;
+ }
+ else
+ {
+ if((pdev->pClass->EP0_TxSent != NULL)&&
+ (pdev->dev_state == USBD_STATE_CONFIGURED))
+ {
+ pdev->pClass->EP0_TxSent(pdev);
+ }
+ USBD_CtlReceiveStatus(pdev);
+ }
+ }
+ }
+ if (pdev->dev_test_mode == 1)
+ {
+ USBD_RunTestMode(pdev);
+ pdev->dev_test_mode = 0;
+ }
+ }
+ else if((pdev->pClass->DataIn != NULL)&&
+ (pdev->dev_state == USBD_STATE_CONFIGURED))
+ {
+ pdev->pClass->DataIn(pdev, epnum);
+ }
+ return USBD_OK;
+}
+
+/**
+* @brief USBD_LL_Reset
+* Handle Reset event
+* @param pdev: device instance
+* @retval status
+*/
+
+USBD_StatusTypeDef USBD_LL_Reset(USBD_HandleTypeDef *pdev)
+{
+ /* Open EP0 OUT */
+ USBD_LL_OpenEP(pdev,
+ 0x00,
+ USBD_EP_TYPE_CTRL,
+ USB_MAX_EP0_SIZE);
+
+ pdev->ep_out[0].maxpacket = USB_MAX_EP0_SIZE;
+
+ /* Open EP0 IN */
+ USBD_LL_OpenEP(pdev,
+ 0x80,
+ USBD_EP_TYPE_CTRL,
+ USB_MAX_EP0_SIZE);
+
+ pdev->ep_in[0].maxpacket = USB_MAX_EP0_SIZE;
+ /* Upon Reset call usr call back */
+ pdev->dev_state = USBD_STATE_DEFAULT;
+
+ if (pdev->pClassData)
+ pdev->pClass->DeInit(pdev, pdev->dev_config);
+
+
+ return USBD_OK;
+}
+
+
+
+
+/**
+* @brief USBD_LL_Reset
+* Handle Reset event
+* @param pdev: device instance
+* @retval status
+*/
+USBD_StatusTypeDef USBD_LL_SetSpeed(USBD_HandleTypeDef *pdev, USBD_SpeedTypeDef speed)
+{
+ pdev->dev_speed = speed;
+ return USBD_OK;
+}
+
+/**
+* @brief USBD_Suspend
+* Handle Suspend event
+* @param pdev: device instance
+* @retval status
+*/
+
+USBD_StatusTypeDef USBD_LL_Suspend(USBD_HandleTypeDef *pdev)
+{
+ pdev->dev_old_state = pdev->dev_state;
+ pdev->dev_state = USBD_STATE_SUSPENDED;
+ return USBD_OK;
+}
+
+/**
+* @brief USBD_Resume
+* Handle Resume event
+* @param pdev: device instance
+* @retval status
+*/
+
+USBD_StatusTypeDef USBD_LL_Resume(USBD_HandleTypeDef *pdev)
+{
+ pdev->dev_state = pdev->dev_old_state;
+ return USBD_OK;
+}
+
+/**
+* @brief USBD_SOF
+* Handle SOF event
+* @param pdev: device instance
+* @retval status
+*/
+
+USBD_StatusTypeDef USBD_LL_SOF(USBD_HandleTypeDef *pdev)
+{
+ if(pdev->dev_state == USBD_STATE_CONFIGURED)
+ {
+ if(pdev->pClass->SOF != NULL)
+ {
+ pdev->pClass->SOF(pdev);
+ }
+ }
+ return USBD_OK;
+}
+
+/**
+* @brief USBD_IsoINIncomplete
+* Handle iso in incomplete event
+* @param pdev: device instance
+* @retval status
+*/
+USBD_StatusTypeDef USBD_LL_IsoINIncomplete(USBD_HandleTypeDef *pdev, uint8_t epnum)
+{
+ return USBD_OK;
+}
+
+/**
+* @brief USBD_IsoOUTIncomplete
+* Handle iso out incomplete event
+* @param pdev: device instance
+* @retval status
+*/
+USBD_StatusTypeDef USBD_LL_IsoOUTIncomplete(USBD_HandleTypeDef *pdev, uint8_t epnum)
+{
+ return USBD_OK;
+}
+
+/**
+* @brief USBD_DevConnected
+* Handle device connection event
+* @param pdev: device instance
+* @retval status
+*/
+USBD_StatusTypeDef USBD_LL_DevConnected(USBD_HandleTypeDef *pdev)
+{
+ return USBD_OK;
+}
+
+/**
+* @brief USBD_DevDisconnected
+* Handle device disconnection event
+* @param pdev: device instance
+* @retval status
+*/
+USBD_StatusTypeDef USBD_LL_DevDisconnected(USBD_HandleTypeDef *pdev)
+{
+ /* Free Class Resources */
+ pdev->dev_state = USBD_STATE_DEFAULT;
+ pdev->pClass->DeInit(pdev, pdev->dev_config);
+
+ return USBD_OK;
+}
+/**
+* @}
+*/
+
+
+/**
+* @}
+*/
+
+
+/**
+* @}
+*/
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
+
diff --git a/ports/stm32/usbdev/core/src/usbd_ctlreq.c b/ports/stm32/usbdev/core/src/usbd_ctlreq.c
index 5fba322fa..f25f252d6 100644
--- a/ports/stm32/usbdev/core/src/usbd_ctlreq.c
+++ b/ports/stm32/usbdev/core/src/usbd_ctlreq.c
@@ -1,769 +1,740 @@
-/**
- ******************************************************************************
- * @file usbd_req.c
- * @author MCD Application Team
- * @version V2.0.0
- * @date 18-February-2014
- * @brief This file provides the standard USB requests following chapter 9.
- ******************************************************************************
- * @attention
- *
- * <h2><center>&copy; COPYRIGHT 2014 STMicroelectronics</center></h2>
- *
- * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
- * You may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.st.com/software_license_agreement_liberty_v2
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- ******************************************************************************
- */
-
-/* Includes ------------------------------------------------------------------*/
-#include "usbd_ctlreq.h"
-#include "usbd_ioreq.h"
-
-
-/** @addtogroup STM32_USBD_STATE_DEVICE_LIBRARY
- * @{
- */
-
-
-/** @defgroup USBD_REQ
- * @brief USB standard requests module
- * @{
- */
-
-/** @defgroup USBD_REQ_Private_TypesDefinitions
- * @{
- */
-/**
- * @}
- */
-
-
-/** @defgroup USBD_REQ_Private_Defines
- * @{
- */
-
-/**
- * @}
- */
-
-
-/** @defgroup USBD_REQ_Private_Macros
- * @{
- */
-/**
- * @}
- */
-
-
-/** @defgroup USBD_REQ_Private_Variables
- * @{
- */
-/**
- * @}
- */
-
-
-/** @defgroup USBD_REQ_Private_FunctionPrototypes
- * @{
- */
-static void USBD_GetDescriptor(USBD_HandleTypeDef *pdev ,
- USBD_SetupReqTypedef *req);
-
-static void USBD_SetAddress(USBD_HandleTypeDef *pdev ,
- USBD_SetupReqTypedef *req);
-
-static void USBD_SetConfig(USBD_HandleTypeDef *pdev ,
- USBD_SetupReqTypedef *req);
-
-static void USBD_GetConfig(USBD_HandleTypeDef *pdev ,
- USBD_SetupReqTypedef *req);
-
-static void USBD_GetStatus(USBD_HandleTypeDef *pdev ,
- USBD_SetupReqTypedef *req);
-
-static void USBD_SetFeature(USBD_HandleTypeDef *pdev ,
- USBD_SetupReqTypedef *req);
-
-static void USBD_ClrFeature(USBD_HandleTypeDef *pdev ,
- USBD_SetupReqTypedef *req);
-
-static uint8_t USBD_GetLen(uint8_t *buf);
-
-/**
- * @}
- */
-
-
-/** @defgroup USBD_REQ_Private_Functions
- * @{
- */
-
-
-/**
-* @brief USBD_StdDevReq
-* Handle standard usb device requests
-* @param pdev: device instance
-* @param req: usb request
-* @retval status
-*/
-USBD_StatusTypeDef USBD_StdDevReq (USBD_HandleTypeDef *pdev , USBD_SetupReqTypedef *req)
-{
- USBD_StatusTypeDef ret = USBD_OK;
-
- switch (req->bRequest)
- {
- case USB_REQ_GET_DESCRIPTOR:
-
- USBD_GetDescriptor (pdev, req) ;
- break;
-
- case USB_REQ_SET_ADDRESS:
- USBD_SetAddress(pdev, req);
- break;
-
- case USB_REQ_SET_CONFIGURATION:
- USBD_SetConfig (pdev , req);
- break;
-
- case USB_REQ_GET_CONFIGURATION:
- USBD_GetConfig (pdev , req);
- break;
-
- case USB_REQ_GET_STATUS:
- USBD_GetStatus (pdev , req);
- break;
-
-
- case USB_REQ_SET_FEATURE:
- USBD_SetFeature (pdev , req);
- break;
-
- case USB_REQ_CLEAR_FEATURE:
- USBD_ClrFeature (pdev , req);
- break;
-
- default:
- USBD_CtlError(pdev , req);
- break;
- }
-
- return ret;
-}
-
-/**
-* @brief USBD_StdItfReq
-* Handle standard usb interface requests
-* @param pdev: USB OTG device instance
-* @param req: usb request
-* @retval status
-*/
-USBD_StatusTypeDef USBD_StdItfReq (USBD_HandleTypeDef *pdev , USBD_SetupReqTypedef *req)
-{
- USBD_StatusTypeDef ret = USBD_OK;
-
- switch (pdev->dev_state)
- {
- case USBD_STATE_CONFIGURED:
-
- if (LOBYTE(req->wIndex) <= USBD_MAX_NUM_INTERFACES)
- {
- pdev->pClass->Setup (pdev, req);
-
- if((req->wLength == 0)&& (ret == USBD_OK))
- {
- USBD_CtlSendStatus(pdev);
- }
- }
- else
- {
- USBD_CtlError(pdev , req);
- }
- break;
-
- default:
- USBD_CtlError(pdev , req);
- break;
- }
- return USBD_OK;
-}
-
-/**
-* @brief USBD_StdEPReq
-* Handle standard usb endpoint requests
-* @param pdev: USB OTG device instance
-* @param req: usb request
-* @retval status
-*/
-USBD_StatusTypeDef USBD_StdEPReq (USBD_HandleTypeDef *pdev , USBD_SetupReqTypedef *req)
-{
-
- uint8_t ep_addr;
- USBD_StatusTypeDef ret = USBD_OK;
- USBD_EndpointTypeDef *pep;
- ep_addr = LOBYTE(req->wIndex);
-
- switch (req->bRequest)
- {
-
- case USB_REQ_SET_FEATURE :
-
- switch (pdev->dev_state)
- {
- case USBD_STATE_ADDRESSED:
- if ((ep_addr != 0x00) && (ep_addr != 0x80))
- {
- USBD_LL_StallEP(pdev , ep_addr);
- }
- break;
-
- case USBD_STATE_CONFIGURED:
- if (req->wValue == USB_FEATURE_EP_HALT)
- {
- if ((ep_addr != 0x00) && (ep_addr != 0x80))
- {
- USBD_LL_StallEP(pdev , ep_addr);
-
- }
- }
- pdev->pClass->Setup (pdev, req);
- USBD_CtlSendStatus(pdev);
-
- break;
-
- default:
- USBD_CtlError(pdev , req);
- break;
- }
- break;
-
- case USB_REQ_CLEAR_FEATURE :
-
- switch (pdev->dev_state)
- {
- case USBD_STATE_ADDRESSED:
- if ((ep_addr != 0x00) && (ep_addr != 0x80))
- {
- USBD_LL_StallEP(pdev , ep_addr);
- }
- break;
-
- case USBD_STATE_CONFIGURED:
- if (req->wValue == USB_FEATURE_EP_HALT)
- {
- if ((ep_addr & 0x7F) != 0x00)
- {
- USBD_LL_ClearStallEP(pdev , ep_addr);
- pdev->pClass->Setup (pdev, req);
- }
- USBD_CtlSendStatus(pdev);
- }
- break;
-
- default:
- USBD_CtlError(pdev , req);
- break;
- }
- break;
-
- case USB_REQ_GET_STATUS:
- switch (pdev->dev_state)
- {
- case USBD_STATE_ADDRESSED:
- if ((ep_addr & 0x7F) != 0x00)
- {
- USBD_LL_StallEP(pdev , ep_addr);
- }
- break;
-
- case USBD_STATE_CONFIGURED:
- pep = ((ep_addr & 0x80) == 0x80) ? &pdev->ep_in[ep_addr & 0x7F]:\
- &pdev->ep_out[ep_addr & 0x7F];
- if(USBD_LL_IsStallEP(pdev, ep_addr))
- {
- pep->status = 0x0001;
- }
- else
- {
- pep->status = 0x0000;
- }
-
- USBD_CtlSendData (pdev,
- (uint8_t *)&pep->status,
- 2);
- break;
-
- default:
- USBD_CtlError(pdev , req);
- break;
- }
- break;
-
- default:
- break;
- }
- return ret;
-}
-/**
-* @brief USBD_GetDescriptor
-* Handle Get Descriptor requests
-* @param pdev: device instance
-* @param req: usb request
-* @retval status
-*/
-static void USBD_GetDescriptor(USBD_HandleTypeDef *pdev ,
- USBD_SetupReqTypedef *req)
-{
- uint16_t len;
- uint8_t *pbuf;
-
-
- switch (req->wValue >> 8)
- {
- case USB_DESC_TYPE_DEVICE:
- pbuf = pdev->pDesc->GetDeviceDescriptor(pdev, &len);
- break;
-
- case USB_DESC_TYPE_CONFIGURATION:
- if(pdev->dev_speed == USBD_SPEED_HIGH )
- {
- pbuf = (uint8_t *)pdev->pClass->GetHSConfigDescriptor(pdev, &len);
- pbuf[1] = USB_DESC_TYPE_CONFIGURATION;
- }
- else
- {
- pbuf = (uint8_t *)pdev->pClass->GetFSConfigDescriptor(pdev, &len);
- pbuf[1] = USB_DESC_TYPE_CONFIGURATION;
- }
- break;
-
- case USB_DESC_TYPE_STRING:
- switch ((uint8_t)(req->wValue))
- {
- case USBD_IDX_LANGID_STR:
- pbuf = pdev->pDesc->GetLangIDStrDescriptor(pdev, &len);
- break;
-
- case USBD_IDX_MFC_STR:
- pbuf = pdev->pDesc->GetManufacturerStrDescriptor(pdev, &len);
- break;
-
- case USBD_IDX_PRODUCT_STR:
- pbuf = pdev->pDesc->GetProductStrDescriptor(pdev, &len);
- break;
-
- case USBD_IDX_SERIAL_STR:
- pbuf = pdev->pDesc->GetSerialStrDescriptor(pdev, &len);
- break;
-
- case USBD_IDX_CONFIG_STR:
- pbuf = pdev->pDesc->GetConfigurationStrDescriptor(pdev, &len);
- break;
-
- case USBD_IDX_INTERFACE_STR:
- pbuf = pdev->pDesc->GetInterfaceStrDescriptor(pdev, &len);
- break;
-
- default:
-#if (USBD_SUPPORT_USER_STRING == 1)
- pbuf = pdev->pClass->GetUsrStrDescriptor(pdev, (req->wValue) , &len);
- break;
-#else
- USBD_CtlError(pdev , req);
- return;
-#endif
- }
- break;
- case USB_DESC_TYPE_DEVICE_QUALIFIER:
-
- if(pdev->dev_speed == USBD_SPEED_HIGH )
- {
- pbuf = (uint8_t *)pdev->pClass->GetDeviceQualifierDescriptor(pdev, &len);
- break;
- }
- else
- {
- USBD_CtlError(pdev , req);
- return;
- }
-
- case USB_DESC_TYPE_OTHER_SPEED_CONFIGURATION:
- if(pdev->dev_speed == USBD_SPEED_HIGH )
- {
- pbuf = (uint8_t *)pdev->pClass->GetOtherSpeedConfigDescriptor(pdev, &len);
- pbuf[1] = USB_DESC_TYPE_OTHER_SPEED_CONFIGURATION;
- break;
- }
- else
- {
- USBD_CtlError(pdev , req);
- return;
- }
-
- default:
- USBD_CtlError(pdev , req);
- return;
- }
-
- if((len != 0)&& (req->wLength != 0))
- {
-
- len = MIN(len , req->wLength);
-
- USBD_CtlSendData (pdev,
- pbuf,
- len);
- }
-
-}
-
-/**
-* @brief USBD_SetAddress
-* Set device address
-* @param pdev: device instance
-* @param req: usb request
-* @retval status
-*/
-static void USBD_SetAddress(USBD_HandleTypeDef *pdev ,
- USBD_SetupReqTypedef *req)
-{
- uint8_t dev_addr;
-
- if ((req->wIndex == 0) && (req->wLength == 0))
- {
- dev_addr = (uint8_t)(req->wValue) & 0x7F;
-
- if (pdev->dev_state == USBD_STATE_CONFIGURED)
- {
- USBD_CtlError(pdev , req);
- }
- else
- {
- pdev->dev_address = dev_addr;
- USBD_LL_SetUSBAddress(pdev, dev_addr);
- USBD_CtlSendStatus(pdev);
-
- if (dev_addr != 0)
- {
- pdev->dev_state = USBD_STATE_ADDRESSED;
- }
- else
- {
- pdev->dev_state = USBD_STATE_DEFAULT;
- }
- }
- }
- else
- {
- USBD_CtlError(pdev , req);
- }
-}
-
-/**
-* @brief USBD_SetConfig
-* Handle Set device configuration request
-* @param pdev: device instance
-* @param req: usb request
-* @retval status
-*/
-static void USBD_SetConfig(USBD_HandleTypeDef *pdev ,
- USBD_SetupReqTypedef *req)
-{
-
- uint8_t cfgidx;
-
- cfgidx = (uint8_t)(req->wValue);
-
- if (cfgidx > USBD_MAX_NUM_CONFIGURATION )
- {
- USBD_CtlError(pdev , req);
- }
- else
- {
- switch (pdev->dev_state)
- {
- case USBD_STATE_ADDRESSED:
- if (cfgidx)
- {
- pdev->dev_config = cfgidx;
- pdev->dev_state = USBD_STATE_CONFIGURED;
- if(USBD_SetClassConfig(pdev , cfgidx) == USBD_FAIL)
- {
- USBD_CtlError(pdev , req);
- return;
- }
- USBD_CtlSendStatus(pdev);
- }
- else
- {
- USBD_CtlSendStatus(pdev);
- }
- break;
-
- case USBD_STATE_CONFIGURED:
- if (cfgidx == 0)
- {
- pdev->dev_state = USBD_STATE_ADDRESSED;
- pdev->dev_config = cfgidx;
- USBD_ClrClassConfig(pdev , cfgidx);
- USBD_CtlSendStatus(pdev);
-
- }
- else if (cfgidx != pdev->dev_config)
- {
- /* Clear old configuration */
- USBD_ClrClassConfig(pdev , pdev->dev_config);
-
- /* set new configuration */
- pdev->dev_config = cfgidx;
- if(USBD_SetClassConfig(pdev , cfgidx) == USBD_FAIL)
- {
- USBD_CtlError(pdev , req);
- return;
- }
- USBD_CtlSendStatus(pdev);
- }
- else
- {
- USBD_CtlSendStatus(pdev);
- }
- break;
-
- default:
- USBD_CtlError(pdev , req);
- break;
- }
- }
-}
-
-/**
-* @brief USBD_GetConfig
-* Handle Get device configuration request
-* @param pdev: device instance
-* @param req: usb request
-* @retval status
-*/
-static void USBD_GetConfig(USBD_HandleTypeDef *pdev ,
- USBD_SetupReqTypedef *req)
-{
-
- if (req->wLength != 1)
- {
- USBD_CtlError(pdev , req);
- }
- else
- {
- switch (pdev->dev_state )
- {
- case USBD_STATE_ADDRESSED:
- pdev->dev_default_config = 0;
- USBD_CtlSendData (pdev,
- (uint8_t *)&pdev->dev_default_config,
- 1);
- break;
-
- case USBD_STATE_CONFIGURED:
-
- USBD_CtlSendData (pdev,
- (uint8_t *)&pdev->dev_config,
- 1);
- break;
-
- default:
- USBD_CtlError(pdev , req);
- break;
- }
- }
-}
-
-/**
-* @brief USBD_GetStatus
-* Handle Get Status request
-* @param pdev: device instance
-* @param req: usb request
-* @retval status
-*/
-static void USBD_GetStatus(USBD_HandleTypeDef *pdev ,
- USBD_SetupReqTypedef *req)
-{
-
-
- switch (pdev->dev_state)
- {
- case USBD_STATE_ADDRESSED:
- case USBD_STATE_CONFIGURED:
-
-#if ( USBD_SELF_POWERED == 1)
- pdev->dev_config_status = USB_CONFIG_SELF_POWERED;
-#else
- pdev->dev_config_status = 0;
-#endif
-
- if (pdev->dev_remote_wakeup)
- {
- pdev->dev_config_status |= USB_CONFIG_REMOTE_WAKEUP;
- }
-
- USBD_CtlSendData (pdev,
- (uint8_t *)& pdev->dev_config_status,
- 2);
- break;
-
- default :
- USBD_CtlError(pdev , req);
- break;
- }
-}
-
-
-/**
-* @brief USBD_SetFeature
-* Handle Set device feature request
-* @param pdev: device instance
-* @param req: usb request
-* @retval status
-*/
-static void USBD_SetFeature(USBD_HandleTypeDef *pdev ,
- USBD_SetupReqTypedef *req)
-{
-
- if (req->wValue == USB_FEATURE_REMOTE_WAKEUP)
- {
- pdev->dev_remote_wakeup = 1;
- pdev->pClass->Setup (pdev, req);
- USBD_CtlSendStatus(pdev);
- }
-
-}
-
-
-/**
-* @brief USBD_ClrFeature
-* Handle clear device feature request
-* @param pdev: device instance
-* @param req: usb request
-* @retval status
-*/
-static void USBD_ClrFeature(USBD_HandleTypeDef *pdev ,
- USBD_SetupReqTypedef *req)
-{
- switch (pdev->dev_state)
- {
- case USBD_STATE_ADDRESSED:
- case USBD_STATE_CONFIGURED:
- if (req->wValue == USB_FEATURE_REMOTE_WAKEUP)
- {
- pdev->dev_remote_wakeup = 0;
- pdev->pClass->Setup (pdev, req);
- USBD_CtlSendStatus(pdev);
- }
- break;
-
- default :
- USBD_CtlError(pdev , req);
- break;
- }
-}
-
-/**
-* @brief USBD_ParseSetupRequest
-* Copy buffer into setup structure
-* @param pdev: device instance
-* @param req: usb request
-* @retval None
-*/
-
-void USBD_ParseSetupRequest(USBD_SetupReqTypedef *req, uint8_t *pdata)
-{
- req->bmRequest = *(uint8_t *) (pdata);
- req->bRequest = *(uint8_t *) (pdata + 1);
- req->wValue = SWAPBYTE (pdata + 2);
- req->wIndex = SWAPBYTE (pdata + 4);
- req->wLength = SWAPBYTE (pdata + 6);
-
-}
-
-/**
-* @brief USBD_CtlError
-* Handle USB low level Error
-* @param pdev: device instance
-* @param req: usb request
-* @retval None
-*/
-
-void USBD_CtlError( USBD_HandleTypeDef *pdev ,
- USBD_SetupReqTypedef *req)
-{
- USBD_LL_StallEP(pdev , 0x80);
- USBD_LL_StallEP(pdev , 0);
-}
-
-
-/**
- * @brief USBD_GetString
- * Convert Ascii string into unicode one
- * @param desc : descriptor buffer
- * @param unicode : Formatted string buffer (unicode)
- * @param len : descriptor length
- * @retval None
- */
-void USBD_GetString(uint8_t *desc, uint8_t *unicode, uint16_t *len)
-{
- uint8_t idx = 0;
-
- if (desc != NULL)
- {
- *len = USBD_GetLen(desc) * 2 + 2;
- unicode[idx++] = *len;
- unicode[idx++] = USB_DESC_TYPE_STRING;
-
- while (*desc != '\0')
- {
- unicode[idx++] = *desc++;
- unicode[idx++] = 0x00;
- }
- }
-}
-
-/**
- * @brief USBD_GetLen
- * return the string length
- * @param buf : pointer to the ascii string buffer
- * @retval string length
- */
-static uint8_t USBD_GetLen(uint8_t *buf)
-{
- uint8_t len = 0;
-
- while (*buf != '\0')
- {
- len++;
- buf++;
- }
-
- return len;
-}
-/**
- * @}
- */
-
-
-/**
- * @}
- */
-
-
-/**
- * @}
- */
-
-/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
+/**
+ ******************************************************************************
+ * @file usbd_req.c
+ * @author MCD Application Team
+ * @version V2.0.0
+ * @date 18-February-2014
+ * @brief This file provides the standard USB requests following chapter 9.
+ ******************************************************************************
+ * @attention
+ *
+ * <h2><center>&copy; COPYRIGHT 2014 STMicroelectronics</center></h2>
+ *
+ * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
+ * You may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.st.com/software_license_agreement_liberty_v2
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************
+ */
+
+/* Includes ------------------------------------------------------------------*/
+#include "usbd_ctlreq.h"
+#include "usbd_ioreq.h"
+
+
+/** @addtogroup STM32_USBD_STATE_DEVICE_LIBRARY
+ * @{
+ */
+
+
+/** @defgroup USBD_REQ
+ * @brief USB standard requests module
+ * @{
+ */
+
+/** @defgroup USBD_REQ_Private_TypesDefinitions
+ * @{
+ */
+/**
+ * @}
+ */
+
+
+/** @defgroup USBD_REQ_Private_Defines
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+
+/** @defgroup USBD_REQ_Private_Macros
+ * @{
+ */
+/**
+ * @}
+ */
+
+
+/** @defgroup USBD_REQ_Private_Variables
+ * @{
+ */
+/**
+ * @}
+ */
+
+
+/** @defgroup USBD_REQ_Private_FunctionPrototypes
+ * @{
+ */
+static void USBD_GetDescriptor(USBD_HandleTypeDef *pdev ,
+ USBD_SetupReqTypedef *req);
+
+static void USBD_SetAddress(USBD_HandleTypeDef *pdev ,
+ USBD_SetupReqTypedef *req);
+
+static void USBD_SetConfig(USBD_HandleTypeDef *pdev ,
+ USBD_SetupReqTypedef *req);
+
+static void USBD_GetConfig(USBD_HandleTypeDef *pdev ,
+ USBD_SetupReqTypedef *req);
+
+static void USBD_GetStatus(USBD_HandleTypeDef *pdev ,
+ USBD_SetupReqTypedef *req);
+
+static void USBD_SetFeature(USBD_HandleTypeDef *pdev ,
+ USBD_SetupReqTypedef *req);
+
+static void USBD_ClrFeature(USBD_HandleTypeDef *pdev ,
+ USBD_SetupReqTypedef *req);
+
+static uint8_t USBD_GetLen(uint8_t *buf);
+
+/**
+ * @}
+ */
+
+
+/** @defgroup USBD_REQ_Private_Functions
+ * @{
+ */
+
+
+/**
+* @brief USBD_StdDevReq
+* Handle standard usb device requests
+* @param pdev: device instance
+* @param req: usb request
+* @retval status
+*/
+USBD_StatusTypeDef USBD_StdDevReq (USBD_HandleTypeDef *pdev , USBD_SetupReqTypedef *req)
+{
+ USBD_StatusTypeDef ret = USBD_OK;
+
+ switch (req->bRequest)
+ {
+ case USB_REQ_GET_DESCRIPTOR:
+
+ USBD_GetDescriptor (pdev, req) ;
+ break;
+
+ case USB_REQ_SET_ADDRESS:
+ USBD_SetAddress(pdev, req);
+ break;
+
+ case USB_REQ_SET_CONFIGURATION:
+ USBD_SetConfig (pdev , req);
+ break;
+
+ case USB_REQ_GET_CONFIGURATION:
+ USBD_GetConfig (pdev , req);
+ break;
+
+ case USB_REQ_GET_STATUS:
+ USBD_GetStatus (pdev , req);
+ break;
+
+
+ case USB_REQ_SET_FEATURE:
+ USBD_SetFeature (pdev , req);
+ break;
+
+ case USB_REQ_CLEAR_FEATURE:
+ USBD_ClrFeature (pdev , req);
+ break;
+
+ default:
+ USBD_CtlError(pdev , req);
+ break;
+ }
+
+ return ret;
+}
+
+/**
+* @brief USBD_StdItfReq
+* Handle standard usb interface requests
+* @param pdev: USB OTG device instance
+* @param req: usb request
+* @retval status
+*/
+USBD_StatusTypeDef USBD_StdItfReq (USBD_HandleTypeDef *pdev , USBD_SetupReqTypedef *req)
+{
+ USBD_StatusTypeDef ret = USBD_OK;
+
+ switch (pdev->dev_state)
+ {
+ case USBD_STATE_CONFIGURED:
+
+ if (LOBYTE(req->wIndex) <= USBD_MAX_NUM_INTERFACES)
+ {
+ pdev->pClass->Setup (pdev, req);
+
+ if((req->wLength == 0)&& (ret == USBD_OK))
+ {
+ USBD_CtlSendStatus(pdev);
+ }
+ }
+ else
+ {
+ USBD_CtlError(pdev , req);
+ }
+ break;
+
+ default:
+ USBD_CtlError(pdev , req);
+ break;
+ }
+ return USBD_OK;
+}
+
+/**
+* @brief USBD_StdEPReq
+* Handle standard usb endpoint requests
+* @param pdev: USB OTG device instance
+* @param req: usb request
+* @retval status
+*/
+USBD_StatusTypeDef USBD_StdEPReq (USBD_HandleTypeDef *pdev , USBD_SetupReqTypedef *req)
+{
+
+ uint8_t ep_addr;
+ USBD_StatusTypeDef ret = USBD_OK;
+ USBD_EndpointTypeDef *pep;
+ ep_addr = LOBYTE(req->wIndex);
+
+ switch (req->bRequest)
+ {
+
+ case USB_REQ_SET_FEATURE :
+
+ switch (pdev->dev_state)
+ {
+ case USBD_STATE_ADDRESSED:
+ if ((ep_addr != 0x00) && (ep_addr != 0x80))
+ {
+ USBD_LL_StallEP(pdev , ep_addr);
+ }
+ break;
+
+ case USBD_STATE_CONFIGURED:
+ if (req->wValue == USB_FEATURE_EP_HALT)
+ {
+ if ((ep_addr != 0x00) && (ep_addr != 0x80))
+ {
+ USBD_LL_StallEP(pdev , ep_addr);
+
+ }
+ }
+ pdev->pClass->Setup (pdev, req);
+ USBD_CtlSendStatus(pdev);
+
+ break;
+
+ default:
+ USBD_CtlError(pdev , req);
+ break;
+ }
+ break;
+
+ case USB_REQ_CLEAR_FEATURE :
+
+ switch (pdev->dev_state)
+ {
+ case USBD_STATE_ADDRESSED:
+ if ((ep_addr != 0x00) && (ep_addr != 0x80))
+ {
+ USBD_LL_StallEP(pdev , ep_addr);
+ }
+ break;
+
+ case USBD_STATE_CONFIGURED:
+ if (req->wValue == USB_FEATURE_EP_HALT)
+ {
+ if ((ep_addr & 0x7F) != 0x00)
+ {
+ USBD_LL_ClearStallEP(pdev , ep_addr);
+ pdev->pClass->Setup (pdev, req);
+ }
+ USBD_CtlSendStatus(pdev);
+ }
+ break;
+
+ default:
+ USBD_CtlError(pdev , req);
+ break;
+ }
+ break;
+
+ case USB_REQ_GET_STATUS:
+ switch (pdev->dev_state)
+ {
+ case USBD_STATE_ADDRESSED:
+ if ((ep_addr & 0x7F) != 0x00)
+ {
+ USBD_LL_StallEP(pdev , ep_addr);
+ }
+ break;
+
+ case USBD_STATE_CONFIGURED:
+ pep = ((ep_addr & 0x80) == 0x80) ? &pdev->ep_in[ep_addr & 0x7F]:\
+ &pdev->ep_out[ep_addr & 0x7F];
+ if(USBD_LL_IsStallEP(pdev, ep_addr))
+ {
+ pep->status = 0x0001;
+ }
+ else
+ {
+ pep->status = 0x0000;
+ }
+
+ USBD_CtlSendData (pdev,
+ (uint8_t *)&pep->status,
+ 2);
+ break;
+
+ default:
+ USBD_CtlError(pdev , req);
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+ return ret;
+}
+/**
+* @brief USBD_GetDescriptor
+* Handle Get Descriptor requests
+* @param pdev: device instance
+* @param req: usb request
+* @retval status
+*/
+static void USBD_GetDescriptor(USBD_HandleTypeDef *pdev ,
+ USBD_SetupReqTypedef *req)
+{
+ uint16_t len;
+ uint8_t *pbuf;
+
+
+ switch (req->wValue >> 8)
+ {
+ case USB_DESC_TYPE_DEVICE:
+ pbuf = pdev->pDesc->GetDeviceDescriptor(pdev, &len);
+ break;
+
+ case USB_DESC_TYPE_CONFIGURATION:
+ if(pdev->dev_speed == USBD_SPEED_HIGH )
+ {
+ pbuf = (uint8_t *)pdev->pClass->GetHSConfigDescriptor(pdev, &len);
+ pbuf[1] = USB_DESC_TYPE_CONFIGURATION;
+ }
+ else
+ {
+ pbuf = (uint8_t *)pdev->pClass->GetFSConfigDescriptor(pdev, &len);
+ pbuf[1] = USB_DESC_TYPE_CONFIGURATION;
+ }
+ break;
+
+ case USB_DESC_TYPE_STRING:
+ pbuf = pdev->pDesc->GetStrDescriptor(pdev, req->wValue & 0xff, &len);
+ if (pbuf == NULL) {
+ USBD_CtlError(pdev, req);
+ return;
+ }
+ break;
+
+ case USB_DESC_TYPE_DEVICE_QUALIFIER:
+
+ if(pdev->dev_speed == USBD_SPEED_HIGH )
+ {
+ pbuf = (uint8_t *)pdev->pClass->GetDeviceQualifierDescriptor(pdev, &len);
+ break;
+ }
+ else
+ {
+ USBD_CtlError(pdev , req);
+ return;
+ }
+
+ case USB_DESC_TYPE_OTHER_SPEED_CONFIGURATION:
+ if(pdev->dev_speed == USBD_SPEED_HIGH )
+ {
+ pbuf = (uint8_t *)pdev->pClass->GetOtherSpeedConfigDescriptor(pdev, &len);
+ pbuf[1] = USB_DESC_TYPE_OTHER_SPEED_CONFIGURATION;
+ break;
+ }
+ else
+ {
+ USBD_CtlError(pdev , req);
+ return;
+ }
+
+ default:
+ USBD_CtlError(pdev , req);
+ return;
+ }
+
+ if((len != 0)&& (req->wLength != 0))
+ {
+
+ len = MIN(len , req->wLength);
+
+ USBD_CtlSendData (pdev,
+ pbuf,
+ len);
+ }
+
+}
+
+/**
+* @brief USBD_SetAddress
+* Set device address
+* @param pdev: device instance
+* @param req: usb request
+* @retval status
+*/
+static void USBD_SetAddress(USBD_HandleTypeDef *pdev ,
+ USBD_SetupReqTypedef *req)
+{
+ uint8_t dev_addr;
+
+ if ((req->wIndex == 0) && (req->wLength == 0))
+ {
+ dev_addr = (uint8_t)(req->wValue) & 0x7F;
+
+ if (pdev->dev_state == USBD_STATE_CONFIGURED)
+ {
+ USBD_CtlError(pdev , req);
+ }
+ else
+ {
+ pdev->dev_address = dev_addr;
+ USBD_LL_SetUSBAddress(pdev, dev_addr);
+ USBD_CtlSendStatus(pdev);
+
+ if (dev_addr != 0)
+ {
+ pdev->dev_state = USBD_STATE_ADDRESSED;
+ }
+ else
+ {
+ pdev->dev_state = USBD_STATE_DEFAULT;
+ }
+ }
+ }
+ else
+ {
+ USBD_CtlError(pdev , req);
+ }
+}
+
+/**
+* @brief USBD_SetConfig
+* Handle Set device configuration request
+* @param pdev: device instance
+* @param req: usb request
+* @retval status
+*/
+static void USBD_SetConfig(USBD_HandleTypeDef *pdev ,
+ USBD_SetupReqTypedef *req)
+{
+
+ uint8_t cfgidx;
+
+ cfgidx = (uint8_t)(req->wValue);
+
+ if (cfgidx > USBD_MAX_NUM_CONFIGURATION )
+ {
+ USBD_CtlError(pdev , req);
+ }
+ else
+ {
+ switch (pdev->dev_state)
+ {
+ case USBD_STATE_ADDRESSED:
+ if (cfgidx)
+ {
+ pdev->dev_config = cfgidx;
+ pdev->dev_state = USBD_STATE_CONFIGURED;
+ if(USBD_SetClassConfig(pdev , cfgidx) == USBD_FAIL)
+ {
+ USBD_CtlError(pdev , req);
+ return;
+ }
+ USBD_CtlSendStatus(pdev);
+ }
+ else
+ {
+ USBD_CtlSendStatus(pdev);
+ }
+ break;
+
+ case USBD_STATE_CONFIGURED:
+ if (cfgidx == 0)
+ {
+ pdev->dev_state = USBD_STATE_ADDRESSED;
+ pdev->dev_config = cfgidx;
+ USBD_ClrClassConfig(pdev , cfgidx);
+ USBD_CtlSendStatus(pdev);
+
+ }
+ else if (cfgidx != pdev->dev_config)
+ {
+ /* Clear old configuration */
+ USBD_ClrClassConfig(pdev , pdev->dev_config);
+
+ /* set new configuration */
+ pdev->dev_config = cfgidx;
+ if(USBD_SetClassConfig(pdev , cfgidx) == USBD_FAIL)
+ {
+ USBD_CtlError(pdev , req);
+ return;
+ }
+ USBD_CtlSendStatus(pdev);
+ }
+ else
+ {
+ USBD_CtlSendStatus(pdev);
+ }
+ break;
+
+ default:
+ USBD_CtlError(pdev , req);
+ break;
+ }
+ }
+}
+
+/**
+* @brief USBD_GetConfig
+* Handle Get device configuration request
+* @param pdev: device instance
+* @param req: usb request
+* @retval status
+*/
+static void USBD_GetConfig(USBD_HandleTypeDef *pdev ,
+ USBD_SetupReqTypedef *req)
+{
+
+ if (req->wLength != 1)
+ {
+ USBD_CtlError(pdev , req);
+ }
+ else
+ {
+ switch (pdev->dev_state )
+ {
+ case USBD_STATE_ADDRESSED:
+ pdev->dev_default_config = 0;
+ USBD_CtlSendData (pdev,
+ (uint8_t *)&pdev->dev_default_config,
+ 1);
+ break;
+
+ case USBD_STATE_CONFIGURED:
+
+ USBD_CtlSendData (pdev,
+ (uint8_t *)&pdev->dev_config,
+ 1);
+ break;
+
+ default:
+ USBD_CtlError(pdev , req);
+ break;
+ }
+ }
+}
+
+/**
+* @brief USBD_GetStatus
+* Handle Get Status request
+* @param pdev: device instance
+* @param req: usb request
+* @retval status
+*/
+static void USBD_GetStatus(USBD_HandleTypeDef *pdev ,
+ USBD_SetupReqTypedef *req)
+{
+
+
+ switch (pdev->dev_state)
+ {
+ case USBD_STATE_ADDRESSED:
+ case USBD_STATE_CONFIGURED:
+
+#if ( USBD_SELF_POWERED == 1)
+ pdev->dev_config_status = USB_CONFIG_SELF_POWERED;
+#else
+ pdev->dev_config_status = 0;
+#endif
+
+ if (pdev->dev_remote_wakeup)
+ {
+ pdev->dev_config_status |= USB_CONFIG_REMOTE_WAKEUP;
+ }
+
+ USBD_CtlSendData (pdev,
+ (uint8_t *)& pdev->dev_config_status,
+ 2);
+ break;
+
+ default :
+ USBD_CtlError(pdev , req);
+ break;
+ }
+}
+
+
+/**
+* @brief USBD_SetFeature
+* Handle Set device feature request
+* @param pdev: device instance
+* @param req: usb request
+* @retval status
+*/
+static void USBD_SetFeature(USBD_HandleTypeDef *pdev ,
+ USBD_SetupReqTypedef *req)
+{
+
+ if (req->wValue == USB_FEATURE_REMOTE_WAKEUP)
+ {
+ pdev->dev_remote_wakeup = 1;
+ pdev->pClass->Setup (pdev, req);
+ USBD_CtlSendStatus(pdev);
+ }
+
+}
+
+
+/**
+* @brief USBD_ClrFeature
+* Handle clear device feature request
+* @param pdev: device instance
+* @param req: usb request
+* @retval status
+*/
+static void USBD_ClrFeature(USBD_HandleTypeDef *pdev ,
+ USBD_SetupReqTypedef *req)
+{
+ switch (pdev->dev_state)
+ {
+ case USBD_STATE_ADDRESSED:
+ case USBD_STATE_CONFIGURED:
+ if (req->wValue == USB_FEATURE_REMOTE_WAKEUP)
+ {
+ pdev->dev_remote_wakeup = 0;
+ pdev->pClass->Setup (pdev, req);
+ USBD_CtlSendStatus(pdev);
+ }
+ break;
+
+ default :
+ USBD_CtlError(pdev , req);
+ break;
+ }
+}
+
+/**
+* @brief USBD_ParseSetupRequest
+* Copy buffer into setup structure
+* @param pdev: device instance
+* @param req: usb request
+* @retval None
+*/
+
+void USBD_ParseSetupRequest(USBD_SetupReqTypedef *req, uint8_t *pdata)
+{
+ req->bmRequest = *(uint8_t *) (pdata);
+ req->bRequest = *(uint8_t *) (pdata + 1);
+ req->wValue = SWAPBYTE (pdata + 2);
+ req->wIndex = SWAPBYTE (pdata + 4);
+ req->wLength = SWAPBYTE (pdata + 6);
+
+}
+
+/**
+* @brief USBD_CtlError
+* Handle USB low level Error
+* @param pdev: device instance
+* @param req: usb request
+* @retval None
+*/
+
+void USBD_CtlError( USBD_HandleTypeDef *pdev ,
+ USBD_SetupReqTypedef *req)
+{
+ USBD_LL_StallEP(pdev , 0x80);
+ USBD_LL_StallEP(pdev , 0);
+}
+
+
+/**
+ * @brief USBD_GetString
+ * Convert Ascii string into unicode one
+ * @param desc : descriptor buffer
+ * @param unicode : Formatted string buffer (unicode)
+ * @param len : descriptor length
+ * @retval None
+ */
+void USBD_GetString(uint8_t *desc, uint8_t *unicode, uint16_t *len)
+{
+ uint8_t idx = 0;
+
+ if (desc != NULL)
+ {
+ *len = USBD_GetLen(desc) * 2 + 2;
+ unicode[idx++] = *len;
+ unicode[idx++] = USB_DESC_TYPE_STRING;
+
+ while (*desc != '\0')
+ {
+ unicode[idx++] = *desc++;
+ unicode[idx++] = 0x00;
+ }
+ }
+}
+
+/**
+ * @brief USBD_GetLen
+ * return the string length
+ * @param buf : pointer to the ascii string buffer
+ * @retval string length
+ */
+static uint8_t USBD_GetLen(uint8_t *buf)
+{
+ uint8_t len = 0;
+
+ while (*buf != '\0')
+ {
+ len++;
+ buf++;
+ }
+
+ return len;
+}
+/**
+ * @}
+ */
+
+
+/**
+ * @}
+ */
+
+
+/**
+ * @}
+ */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/ports/stm32/usbdev/core/src/usbd_ioreq.c b/ports/stm32/usbdev/core/src/usbd_ioreq.c
index 9e396ba56..aab59fcef 100644
--- a/ports/stm32/usbdev/core/src/usbd_ioreq.c
+++ b/ports/stm32/usbdev/core/src/usbd_ioreq.c
@@ -1,236 +1,236 @@
-/**
- ******************************************************************************
- * @file usbd_ioreq.c
- * @author MCD Application Team
- * @version V2.0.0
- * @date 18-February-2014
- * @brief This file provides the IO requests APIs for control endpoints.
- ******************************************************************************
- * @attention
- *
- * <h2><center>&copy; COPYRIGHT 2014 STMicroelectronics</center></h2>
- *
- * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
- * You may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.st.com/software_license_agreement_liberty_v2
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- ******************************************************************************
- */
-
-/* Includes ------------------------------------------------------------------*/
-#include "usbd_ioreq.h"
-
-/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY
- * @{
- */
-
-
-/** @defgroup USBD_IOREQ
- * @brief control I/O requests module
- * @{
- */
-
-/** @defgroup USBD_IOREQ_Private_TypesDefinitions
- * @{
- */
-/**
- * @}
- */
-
-
-/** @defgroup USBD_IOREQ_Private_Defines
- * @{
- */
-
-/**
- * @}
- */
-
-
-/** @defgroup USBD_IOREQ_Private_Macros
- * @{
- */
-/**
- * @}
- */
-
-
-/** @defgroup USBD_IOREQ_Private_Variables
- * @{
- */
-
-/**
- * @}
- */
-
-
-/** @defgroup USBD_IOREQ_Private_FunctionPrototypes
- * @{
- */
-/**
- * @}
- */
-
-
-/** @defgroup USBD_IOREQ_Private_Functions
- * @{
- */
-
-/**
-* @brief USBD_CtlSendData
-* send data on the ctl pipe
-* @param pdev: device instance
-* @param buff: pointer to data buffer
-* @param len: length of data to be sent
-* @retval status
-*/
-USBD_StatusTypeDef USBD_CtlSendData (USBD_HandleTypeDef *pdev,
- uint8_t *pbuf,
- uint16_t len)
-{
- /* Set EP0 State */
- pdev->ep0_state = USBD_EP0_DATA_IN;
- pdev->ep_in[0].total_length = len;
- pdev->ep_in[0].rem_length = len;
- /* Start the transfer */
- USBD_LL_Transmit (pdev, 0x00, pbuf, len);
-
- return USBD_OK;
-}
-
-/**
-* @brief USBD_CtlContinueSendData
-* continue sending data on the ctl pipe
-* @param pdev: device instance
-* @param buff: pointer to data buffer
-* @param len: length of data to be sent
-* @retval status
-*/
-USBD_StatusTypeDef USBD_CtlContinueSendData (USBD_HandleTypeDef *pdev,
- uint8_t *pbuf,
- uint16_t len)
-{
- /* Start the next transfer */
- USBD_LL_Transmit (pdev, 0x00, pbuf, len);
-
- return USBD_OK;
-}
-
-/**
-* @brief USBD_CtlPrepareRx
-* receive data on the ctl pipe
-* @param pdev: USB OTG device instance
-* @param buff: pointer to data buffer
-* @param len: length of data to be received
-* @retval status
-*/
-USBD_StatusTypeDef USBD_CtlPrepareRx (USBD_HandleTypeDef *pdev,
- uint8_t *pbuf,
- uint16_t len)
-{
- /* Set EP0 State */
- pdev->ep0_state = USBD_EP0_DATA_OUT;
- pdev->ep_out[0].total_length = len;
- pdev->ep_out[0].rem_length = len;
- /* Start the transfer */
- USBD_LL_PrepareReceive (pdev,
- 0,
- pbuf,
- len);
-
- return USBD_OK;
-}
-
-/**
-* @brief USBD_CtlContinueRx
-* continue receive data on the ctl pipe
-* @param pdev: USB OTG device instance
-* @param buff: pointer to data buffer
-* @param len: length of data to be received
-* @retval status
-*/
-USBD_StatusTypeDef USBD_CtlContinueRx (USBD_HandleTypeDef *pdev,
- uint8_t *pbuf,
- uint16_t len)
-{
-
- USBD_LL_PrepareReceive (pdev,
- 0,
- pbuf,
- len);
- return USBD_OK;
-}
-/**
-* @brief USBD_CtlSendStatus
-* send zero lzngth packet on the ctl pipe
-* @param pdev: USB OTG device instance
-* @retval status
-*/
-USBD_StatusTypeDef USBD_CtlSendStatus (USBD_HandleTypeDef *pdev)
-{
-
- /* Set EP0 State */
- pdev->ep0_state = USBD_EP0_STATUS_IN;
-
- /* Start the transfer */
- USBD_LL_Transmit (pdev, 0x00, NULL, 0);
-
- return USBD_OK;
-}
-
-/**
-* @brief USBD_CtlReceiveStatus
-* receive zero lzngth packet on the ctl pipe
-* @param pdev: USB OTG device instance
-* @retval status
-*/
-USBD_StatusTypeDef USBD_CtlReceiveStatus (USBD_HandleTypeDef *pdev)
-{
- /* Set EP0 State */
- pdev->ep0_state = USBD_EP0_STATUS_OUT;
-
- /* Start the transfer */
- USBD_LL_PrepareReceive ( pdev,
- 0,
- NULL,
- 0);
-
- return USBD_OK;
-}
-
-
-/**
-* @brief USBD_GetRxCount
-* returns the received data length
-* @param pdev: USB OTG device instance
-* epnum: endpoint index
-* @retval Rx Data blength
-*/
-uint16_t USBD_GetRxCount (USBD_HandleTypeDef *pdev , uint8_t ep_addr)
-{
- return USBD_LL_GetRxDataSize(pdev, ep_addr);
-}
-
-/**
- * @}
- */
-
-
-/**
- * @}
- */
-
-
-/**
- * @}
- */
-
-/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
+/**
+ ******************************************************************************
+ * @file usbd_ioreq.c
+ * @author MCD Application Team
+ * @version V2.0.0
+ * @date 18-February-2014
+ * @brief This file provides the IO requests APIs for control endpoints.
+ ******************************************************************************
+ * @attention
+ *
+ * <h2><center>&copy; COPYRIGHT 2014 STMicroelectronics</center></h2>
+ *
+ * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
+ * You may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.st.com/software_license_agreement_liberty_v2
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************
+ */
+
+/* Includes ------------------------------------------------------------------*/
+#include "usbd_ioreq.h"
+
+/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY
+ * @{
+ */
+
+
+/** @defgroup USBD_IOREQ
+ * @brief control I/O requests module
+ * @{
+ */
+
+/** @defgroup USBD_IOREQ_Private_TypesDefinitions
+ * @{
+ */
+/**
+ * @}
+ */
+
+
+/** @defgroup USBD_IOREQ_Private_Defines
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+
+/** @defgroup USBD_IOREQ_Private_Macros
+ * @{
+ */
+/**
+ * @}
+ */
+
+
+/** @defgroup USBD_IOREQ_Private_Variables
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+
+/** @defgroup USBD_IOREQ_Private_FunctionPrototypes
+ * @{
+ */
+/**
+ * @}
+ */
+
+
+/** @defgroup USBD_IOREQ_Private_Functions
+ * @{
+ */
+
+/**
+* @brief USBD_CtlSendData
+* send data on the ctl pipe
+* @param pdev: device instance
+* @param buff: pointer to data buffer
+* @param len: length of data to be sent
+* @retval status
+*/
+USBD_StatusTypeDef USBD_CtlSendData (USBD_HandleTypeDef *pdev,
+ uint8_t *pbuf,
+ uint16_t len)
+{
+ /* Set EP0 State */
+ pdev->ep0_state = USBD_EP0_DATA_IN;
+ pdev->ep_in[0].total_length = len;
+ pdev->ep_in[0].rem_length = len;
+ /* Start the transfer */
+ USBD_LL_Transmit (pdev, 0x00, pbuf, len);
+
+ return USBD_OK;
+}
+
+/**
+* @brief USBD_CtlContinueSendData
+* continue sending data on the ctl pipe
+* @param pdev: device instance
+* @param buff: pointer to data buffer
+* @param len: length of data to be sent
+* @retval status
+*/
+USBD_StatusTypeDef USBD_CtlContinueSendData (USBD_HandleTypeDef *pdev,
+ uint8_t *pbuf,
+ uint16_t len)
+{
+ /* Start the next transfer */
+ USBD_LL_Transmit (pdev, 0x00, pbuf, len);
+
+ return USBD_OK;
+}
+
+/**
+* @brief USBD_CtlPrepareRx
+* receive data on the ctl pipe
+* @param pdev: USB OTG device instance
+* @param buff: pointer to data buffer
+* @param len: length of data to be received
+* @retval status
+*/
+USBD_StatusTypeDef USBD_CtlPrepareRx (USBD_HandleTypeDef *pdev,
+ uint8_t *pbuf,
+ uint16_t len)
+{
+ /* Set EP0 State */
+ pdev->ep0_state = USBD_EP0_DATA_OUT;
+ pdev->ep_out[0].total_length = len;
+ pdev->ep_out[0].rem_length = len;
+ /* Start the transfer */
+ USBD_LL_PrepareReceive (pdev,
+ 0,
+ pbuf,
+ len);
+
+ return USBD_OK;
+}
+
+/**
+* @brief USBD_CtlContinueRx
+* continue receive data on the ctl pipe
+* @param pdev: USB OTG device instance
+* @param buff: pointer to data buffer
+* @param len: length of data to be received
+* @retval status
+*/
+USBD_StatusTypeDef USBD_CtlContinueRx (USBD_HandleTypeDef *pdev,
+ uint8_t *pbuf,
+ uint16_t len)
+{
+
+ USBD_LL_PrepareReceive (pdev,
+ 0,
+ pbuf,
+ len);
+ return USBD_OK;
+}
+/**
+* @brief USBD_CtlSendStatus
+* send zero lzngth packet on the ctl pipe
+* @param pdev: USB OTG device instance
+* @retval status
+*/
+USBD_StatusTypeDef USBD_CtlSendStatus (USBD_HandleTypeDef *pdev)
+{
+
+ /* Set EP0 State */
+ pdev->ep0_state = USBD_EP0_STATUS_IN;
+
+ /* Start the transfer */
+ USBD_LL_Transmit (pdev, 0x00, NULL, 0);
+
+ return USBD_OK;
+}
+
+/**
+* @brief USBD_CtlReceiveStatus
+* receive zero lzngth packet on the ctl pipe
+* @param pdev: USB OTG device instance
+* @retval status
+*/
+USBD_StatusTypeDef USBD_CtlReceiveStatus (USBD_HandleTypeDef *pdev)
+{
+ /* Set EP0 State */
+ pdev->ep0_state = USBD_EP0_STATUS_OUT;
+
+ /* Start the transfer */
+ USBD_LL_PrepareReceive ( pdev,
+ 0,
+ NULL,
+ 0);
+
+ return USBD_OK;
+}
+
+
+/**
+* @brief USBD_GetRxCount
+* returns the received data length
+* @param pdev: USB OTG device instance
+* epnum: endpoint index
+* @retval Rx Data blength
+*/
+uint16_t USBD_GetRxCount (USBD_HandleTypeDef *pdev , uint8_t ep_addr)
+{
+ return USBD_LL_GetRxDataSize(pdev, ep_addr);
+}
+
+/**
+ * @}
+ */
+
+
+/**
+ * @}
+ */
+
+
+/**
+ * @}
+ */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/ports/stm32/usbhost/Release_Notes.html b/ports/stm32/usbhost/Release_Notes.html
deleted file mode 100644
index cbb723ee9..000000000
--- a/ports/stm32/usbhost/Release_Notes.html
+++ /dev/null
@@ -1,973 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
-<html xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:w="urn:schemas-microsoft-com:office:word" xmlns:m="http://schemas.microsoft.com/office/2004/12/omml" xmlns="http://www.w3.org/TR/REC-html40"><head>
-
-
-
-
-<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
-<link rel="File-List" href="Release_Notes_for_STM32F2xx_StdPeriph_Driver_files/filelist.xml">
-<link rel="Edit-Time-Data" href="Release_Notes_for_STM32F2xx_StdPeriph_Driver_files/editdata.mso"><!--[if !mso]>
-<style>
-v\:* {behavior:url(#default#VML);}
-o\:* {behavior:url(#default#VML);}
-w\:* {behavior:url(#default#VML);}
-.shape {behavior:url(#default#VML);}
-</style>
-<![endif]--><title>Release Notes for STM32 USB Host Library</title><!--[if gte mso 9]><xml>
- <o:DocumentProperties>
- <o:Author>STMicroelectronics</o:Author>
- <o:LastAuthor>Raouf Hosni</o:LastAuthor>
- <o:Revision>39</o:Revision>
- <o:TotalTime>137</o:TotalTime>
- <o:Created>2009-02-27T19:26:00Z</o:Created>
- <o:LastSaved>2010-10-15T11:07:00Z</o:LastSaved>
- <o:Pages>3</o:Pages>
- <o:Words>973</o:Words>
- <o:Characters>5548</o:Characters>
- <o:Company>STMicroelectronics</o:Company>
- <o:Lines>46</o:Lines>
- <o:Paragraphs>13</o:Paragraphs>
- <o:CharactersWithSpaces>6508</o:CharactersWithSpaces>
- <o:Version>12.00</o:Version>
- </o:DocumentProperties>
-</xml><![endif]-->
-
-
-
-<link rel="themeData" href="Release_Notes_for_STM32F2xx_StdPeriph_Driver_files/themedata.thmx">
-<link rel="colorSchemeMapping" href="Release_Notes_for_STM32F2xx_StdPeriph_Driver_files/colorschememapping.xml"><!--[if gte mso 9]><xml>
- <w:WordDocument>
- <w:Zoom>110</w:Zoom>
- <w:TrackMoves>false</w:TrackMoves>
- <w:TrackFormatting/>
- <w:ValidateAgainstSchemas/>
- <w:SaveIfXMLInvalid>false</w:SaveIfXMLInvalid>
- <w:IgnoreMixedContent>false</w:IgnoreMixedContent>
- <w:AlwaysShowPlaceholderText>false</w:AlwaysShowPlaceholderText>
- <w:DoNotPromoteQF/>
- <w:LidThemeOther>EN-US</w:LidThemeOther>
- <w:LidThemeAsian>X-NONE</w:LidThemeAsian>
- <w:LidThemeComplexScript>X-NONE</w:LidThemeComplexScript>
- <w:Compatibility>
- <w:BreakWrappedTables/>
- <w:SnapToGridInCell/>
- <w:WrapTextWithPunct/>
- <w:UseAsianBreakRules/>
- <w:DontGrowAutofit/>
- <w:SplitPgBreakAndParaMark/>
- <w:DontVertAlignCellWithSp/>
- <w:DontBreakConstrainedForcedTables/>
- <w:DontVertAlignInTxbx/>
- <w:Word11KerningPairs/>
- <w:CachedColBalance/>
- </w:Compatibility>
- <w:BrowserLevel>MicrosoftInternetExplorer4</w:BrowserLevel>
- <m:mathPr>
- <m:mathFont m:val="Cambria Math"/>
- <m:brkBin m:val="before"/>
- <m:brkBinSub m:val="&#45;-"/>
- <m:smallFrac m:val="off"/>
- <m:dispDef/>
- <m:lMargin m:val="0"/>
- <m:rMargin m:val="0"/>
- <m:defJc m:val="centerGroup"/>
- <m:wrapIndent m:val="1440"/>
- <m:intLim m:val="subSup"/>
- <m:naryLim m:val="undOvr"/>
- </m:mathPr></w:WordDocument>
-</xml><![endif]--><!--[if gte mso 9]><xml>
- <w:LatentStyles DefLockedState="false" DefUnhideWhenUsed="false"
- DefSemiHidden="false" DefQFormat="false" LatentStyleCount="267">
- <w:LsdException Locked="false" QFormat="true" Name="Normal"/>
- <w:LsdException Locked="false" QFormat="true" Name="heading 1"/>
- <w:LsdException Locked="false" QFormat="true" Name="heading 2"/>
- <w:LsdException Locked="false" QFormat="true" Name="heading 3"/>
- <w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
- QFormat="true" Name="heading 4"/>
- <w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
- QFormat="true" Name="heading 5"/>
- <w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
- QFormat="true" Name="heading 6"/>
- <w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
- QFormat="true" Name="heading 7"/>
- <w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
- QFormat="true" Name="heading 8"/>
- <w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
- QFormat="true" Name="heading 9"/>
- <w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
- QFormat="true" Name="caption"/>
- <w:LsdException Locked="false" QFormat="true" Name="Title"/>
- <w:LsdException Locked="false" Priority="1" Name="Default Paragraph Font"/>
- <w:LsdException Locked="false" QFormat="true" Name="Subtitle"/>
- <w:LsdException Locked="false" QFormat="true" Name="Strong"/>
- <w:LsdException Locked="false" QFormat="true" Name="Emphasis"/>
- <w:LsdException Locked="false" Priority="99" Name="No List"/>
- <w:LsdException Locked="false" Priority="99" SemiHidden="true"
- Name="Placeholder Text"/>
- <w:LsdException Locked="false" Priority="1" QFormat="true" Name="No Spacing"/>
- <w:LsdException Locked="false" Priority="60" Name="Light Shading"/>
- <w:LsdException Locked="false" Priority="61" Name="Light List"/>
- <w:LsdException Locked="false" Priority="62" Name="Light Grid"/>
- <w:LsdException Locked="false" Priority="63" Name="Medium Shading 1"/>
- <w:LsdException Locked="false" Priority="64" Name="Medium Shading 2"/>
- <w:LsdException Locked="false" Priority="65" Name="Medium List 1"/>
- <w:LsdException Locked="false" Priority="66" Name="Medium List 2"/>
- <w:LsdException Locked="false" Priority="67" Name="Medium Grid 1"/>
- <w:LsdException Locked="false" Priority="68" Name="Medium Grid 2"/>
- <w:LsdException Locked="false" Priority="69" Name="Medium Grid 3"/>
- <w:LsdException Locked="false" Priority="70" Name="Dark List"/>
- <w:LsdException Locked="false" Priority="71" Name="Colorful Shading"/>
- <w:LsdException Locked="false" Priority="72" Name="Colorful List"/>
- <w:LsdException Locked="false" Priority="73" Name="Colorful Grid"/>
- <w:LsdException Locked="false" Priority="60" Name="Light Shading Accent 1"/>
- <w:LsdException Locked="false" Priority="61" Name="Light List Accent 1"/>
- <w:LsdException Locked="false" Priority="62" Name="Light Grid Accent 1"/>
- <w:LsdException Locked="false" Priority="63" Name="Medium Shading 1 Accent 1"/>
- <w:LsdException Locked="false" Priority="64" Name="Medium Shading 2 Accent 1"/>
- <w:LsdException Locked="false" Priority="65" Name="Medium List 1 Accent 1"/>
- <w:LsdException Locked="false" Priority="99" SemiHidden="true" Name="Revision"/>
- <w:LsdException Locked="false" Priority="34" QFormat="true"
- Name="List Paragraph"/>
- <w:LsdException Locked="false" Priority="29" QFormat="true" Name="Quote"/>
- <w:LsdException Locked="false" Priority="30" QFormat="true"
- Name="Intense Quote"/>
- <w:LsdException Locked="false" Priority="66" Name="Medium List 2 Accent 1"/>
- <w:LsdException Locked="false" Priority="67" Name="Medium Grid 1 Accent 1"/>
- <w:LsdException Locked="false" Priority="68" Name="Medium Grid 2 Accent 1"/>
- <w:LsdException Locked="false" Priority="69" Name="Medium Grid 3 Accent 1"/>
- <w:LsdException Locked="false" Priority="70" Name="Dark List Accent 1"/>
- <w:LsdException Locked="false" Priority="71" Name="Colorful Shading Accent 1"/>
- <w:LsdException Locked="false" Priority="72" Name="Colorful List Accent 1"/>
- <w:LsdException Locked="false" Priority="73" Name="Colorful Grid Accent 1"/>
- <w:LsdException Locked="false" Priority="60" Name="Light Shading Accent 2"/>
- <w:LsdException Locked="false" Priority="61" Name="Light List Accent 2"/>
- <w:LsdException Locked="false" Priority="62" Name="Light Grid Accent 2"/>
- <w:LsdException Locked="false" Priority="63" Name="Medium Shading 1 Accent 2"/>
- <w:LsdException Locked="false" Priority="64" Name="Medium Shading 2 Accent 2"/>
- <w:LsdException Locked="false" Priority="65" Name="Medium List 1 Accent 2"/>
- <w:LsdException Locked="false" Priority="66" Name="Medium List 2 Accent 2"/>
- <w:LsdException Locked="false" Priority="67" Name="Medium Grid 1 Accent 2"/>
- <w:LsdException Locked="false" Priority="68" Name="Medium Grid 2 Accent 2"/>
- <w:LsdException Locked="false" Priority="69" Name="Medium Grid 3 Accent 2"/>
- <w:LsdException Locked="false" Priority="70" Name="Dark List Accent 2"/>
- <w:LsdException Locked="false" Priority="71" Name="Colorful Shading Accent 2"/>
- <w:LsdException Locked="false" Priority="72" Name="Colorful List Accent 2"/>
- <w:LsdException Locked="false" Priority="73" Name="Colorful Grid Accent 2"/>
- <w:LsdException Locked="false" Priority="60" Name="Light Shading Accent 3"/>
- <w:LsdException Locked="false" Priority="61" Name="Light List Accent 3"/>
- <w:LsdException Locked="false" Priority="62" Name="Light Grid Accent 3"/>
- <w:LsdException Locked="false" Priority="63" Name="Medium Shading 1 Accent 3"/>
- <w:LsdException Locked="false" Priority="64" Name="Medium Shading 2 Accent 3"/>
- <w:LsdException Locked="false" Priority="65" Name="Medium List 1 Accent 3"/>
- <w:LsdException Locked="false" Priority="66" Name="Medium List 2 Accent 3"/>
- <w:LsdException Locked="false" Priority="67" Name="Medium Grid 1 Accent 3"/>
- <w:LsdException Locked="false" Priority="68" Name="Medium Grid 2 Accent 3"/>
- <w:LsdException Locked="false" Priority="69" Name="Medium Grid 3 Accent 3"/>
- <w:LsdException Locked="false" Priority="70" Name="Dark List Accent 3"/>
- <w:LsdException Locked="false" Priority="71" Name="Colorful Shading Accent 3"/>
- <w:LsdException Locked="false" Priority="72" Name="Colorful List Accent 3"/>
- <w:LsdException Locked="false" Priority="73" Name="Colorful Grid Accent 3"/>
- <w:LsdException Locked="false" Priority="60" Name="Light Shading Accent 4"/>
- <w:LsdException Locked="false" Priority="61" Name="Light List Accent 4"/>
- <w:LsdException Locked="false" Priority="62" Name="Light Grid Accent 4"/>
- <w:LsdException Locked="false" Priority="63" Name="Medium Shading 1 Accent 4"/>
- <w:LsdException Locked="false" Priority="64" Name="Medium Shading 2 Accent 4"/>
- <w:LsdException Locked="false" Priority="65" Name="Medium List 1 Accent 4"/>
- <w:LsdException Locked="false" Priority="66" Name="Medium List 2 Accent 4"/>
- <w:LsdException Locked="false" Priority="67" Name="Medium Grid 1 Accent 4"/>
- <w:LsdException Locked="false" Priority="68" Name="Medium Grid 2 Accent 4"/>
- <w:LsdException Locked="false" Priority="69" Name="Medium Grid 3 Accent 4"/>
- <w:LsdException Locked="false" Priority="70" Name="Dark List Accent 4"/>
- <w:LsdException Locked="false" Priority="71" Name="Colorful Shading Accent 4"/>
- <w:LsdException Locked="false" Priority="72" Name="Colorful List Accent 4"/>
- <w:LsdException Locked="false" Priority="73" Name="Colorful Grid Accent 4"/>
- <w:LsdException Locked="false" Priority="60" Name="Light Shading Accent 5"/>
- <w:LsdException Locked="false" Priority="61" Name="Light List Accent 5"/>
- <w:LsdException Locked="false" Priority="62" Name="Light Grid Accent 5"/>
- <w:LsdException Locked="false" Priority="63" Name="Medium Shading 1 Accent 5"/>
- <w:LsdException Locked="false" Priority="64" Name="Medium Shading 2 Accent 5"/>
- <w:LsdException Locked="false" Priority="65" Name="Medium List 1 Accent 5"/>
- <w:LsdException Locked="false" Priority="66" Name="Medium List 2 Accent 5"/>
- <w:LsdException Locked="false" Priority="67" Name="Medium Grid 1 Accent 5"/>
- <w:LsdException Locked="false" Priority="68" Name="Medium Grid 2 Accent 5"/>
- <w:LsdException Locked="false" Priority="69" Name="Medium Grid 3 Accent 5"/>
- <w:LsdException Locked="false" Priority="70" Name="Dark List Accent 5"/>
- <w:LsdException Locked="false" Priority="71" Name="Colorful Shading Accent 5"/>
- <w:LsdException Locked="false" Priority="72" Name="Colorful List Accent 5"/>
- <w:LsdException Locked="false" Priority="73" Name="Colorful Grid Accent 5"/>
- <w:LsdException Locked="false" Priority="60" Name="Light Shading Accent 6"/>
- <w:LsdException Locked="false" Priority="61" Name="Light List Accent 6"/>
- <w:LsdException Locked="false" Priority="62" Name="Light Grid Accent 6"/>
- <w:LsdException Locked="false" Priority="63" Name="Medium Shading 1 Accent 6"/>
- <w:LsdException Locked="false" Priority="64" Name="Medium Shading 2 Accent 6"/>
- <w:LsdException Locked="false" Priority="65" Name="Medium List 1 Accent 6"/>
- <w:LsdException Locked="false" Priority="66" Name="Medium List 2 Accent 6"/>
- <w:LsdException Locked="false" Priority="67" Name="Medium Grid 1 Accent 6"/>
- <w:LsdException Locked="false" Priority="68" Name="Medium Grid 2 Accent 6"/>
- <w:LsdException Locked="false" Priority="69" Name="Medium Grid 3 Accent 6"/>
- <w:LsdException Locked="false" Priority="70" Name="Dark List Accent 6"/>
- <w:LsdException Locked="false" Priority="71" Name="Colorful Shading Accent 6"/>
- <w:LsdException Locked="false" Priority="72" Name="Colorful List Accent 6"/>
- <w:LsdException Locked="false" Priority="73" Name="Colorful Grid Accent 6"/>
- <w:LsdException Locked="false" Priority="19" QFormat="true"
- Name="Subtle Emphasis"/>
- <w:LsdException Locked="false" Priority="21" QFormat="true"
- Name="Intense Emphasis"/>
- <w:LsdException Locked="false" Priority="31" QFormat="true"
- Name="Subtle Reference"/>
- <w:LsdException Locked="false" Priority="32" QFormat="true"
- Name="Intense Reference"/>
- <w:LsdException Locked="false" Priority="33" QFormat="true" Name="Book Title"/>
- <w:LsdException Locked="false" Priority="37" SemiHidden="true"
- UnhideWhenUsed="true" Name="Bibliography"/>
- <w:LsdException Locked="false" Priority="39" SemiHidden="true"
- UnhideWhenUsed="true" QFormat="true" Name="TOC Heading"/>
- </w:LatentStyles>
-</xml><![endif]-->
-
-<style>
-<!--
- /* Font Definitions */
- @font-face
- {font-family:"Cambria Math";
- panose-1:2 4 5 3 5 4 6 3 2 4;
- mso-font-charset:1;
- mso-generic-font-family:roman;
- mso-font-format:other;
- mso-font-pitch:variable;
- mso-font-signature:0 0 0 0 0 0;}
-@font-face
- {font-family:Calibri;
- panose-1:2 15 5 2 2 2 4 3 2 4;
- mso-font-charset:0;
- mso-generic-font-family:swiss;
- mso-font-pitch:variable;
- mso-font-signature:-1610611985 1073750139 0 0 159 0;}
-@font-face
- {font-family:Tahoma;
- panose-1:2 11 6 4 3 5 4 4 2 4;
- mso-font-charset:0;
- mso-generic-font-family:swiss;
- mso-font-pitch:variable;
- mso-font-signature:1627400839 -2147483648 8 0 66047 0;}
-@font-face
- {font-family:Verdana;
- panose-1:2 11 6 4 3 5 4 4 2 4;
- mso-font-charset:0;
- mso-generic-font-family:swiss;
- mso-font-pitch:variable;
- mso-font-signature:536871559 0 0 0 415 0;}
- /* Style Definitions */
- p.MsoNormal, li.MsoNormal, div.MsoNormal
- {mso-style-unhide:no;
- mso-style-qformat:yes;
- mso-style-parent:"";
- margin:0in;
- margin-bottom:.0001pt;
- mso-pagination:widow-orphan;
- font-size:12.0pt;
- font-family:"Times New Roman","serif";
- mso-fareast-font-family:"Times New Roman";}
-h1
- {mso-style-unhide:no;
- mso-style-qformat:yes;
- mso-style-link:"Heading 1 Char";
- mso-margin-top-alt:auto;
- margin-right:0in;
- mso-margin-bottom-alt:auto;
- margin-left:0in;
- mso-pagination:widow-orphan;
- mso-outline-level:1;
- font-size:24.0pt;
- font-family:"Times New Roman","serif";
- mso-fareast-font-family:"Times New Roman";
- mso-fareast-theme-font:minor-fareast;
- font-weight:bold;}
-h2
- {mso-style-unhide:no;
- mso-style-qformat:yes;
- mso-style-link:"Heading 2 Char";
- mso-style-next:Normal;
- margin-top:12.0pt;
- margin-right:0in;
- margin-bottom:3.0pt;
- margin-left:0in;
- mso-pagination:widow-orphan;
- page-break-after:avoid;
- mso-outline-level:2;
- font-size:14.0pt;
- font-family:"Arial","sans-serif";
- mso-fareast-font-family:"Times New Roman";
- mso-fareast-theme-font:minor-fareast;
- font-weight:bold;
- font-style:italic;}
-h3
- {mso-style-unhide:no;
- mso-style-qformat:yes;
- mso-style-link:"Heading 3 Char";
- mso-margin-top-alt:auto;
- margin-right:0in;
- mso-margin-bottom-alt:auto;
- margin-left:0in;
- mso-pagination:widow-orphan;
- mso-outline-level:3;
- font-size:13.5pt;
- font-family:"Times New Roman","serif";
- mso-fareast-font-family:"Times New Roman";
- mso-fareast-theme-font:minor-fareast;
- font-weight:bold;}
-a:link, span.MsoHyperlink
- {mso-style-unhide:no;
- color:blue;
- text-decoration:underline;
- text-underline:single;}
-a:visited, span.MsoHyperlinkFollowed
- {mso-style-unhide:no;
- color:blue;
- text-decoration:underline;
- text-underline:single;}
-p
- {mso-style-unhide:no;
- mso-margin-top-alt:auto;
- margin-right:0in;
- mso-margin-bottom-alt:auto;
- margin-left:0in;
- mso-pagination:widow-orphan;
- font-size:12.0pt;
- font-family:"Times New Roman","serif";
- mso-fareast-font-family:"Times New Roman";}
-p.MsoAcetate, li.MsoAcetate, div.MsoAcetate
- {mso-style-unhide:no;
- mso-style-link:"Balloon Text Char";
- margin:0in;
- margin-bottom:.0001pt;
- mso-pagination:widow-orphan;
- font-size:8.0pt;
- font-family:"Tahoma","sans-serif";
- mso-fareast-font-family:"Times New Roman";}
-span.Heading1Char
- {mso-style-name:"Heading 1 Char";
- mso-style-unhide:no;
- mso-style-locked:yes;
- mso-style-link:"Heading 1";
- mso-ansi-font-size:14.0pt;
- mso-bidi-font-size:14.0pt;
- font-family:"Cambria","serif";
- mso-ascii-font-family:Cambria;
- mso-ascii-theme-font:major-latin;
- mso-fareast-font-family:"Times New Roman";
- mso-fareast-theme-font:major-fareast;
- mso-hansi-font-family:Cambria;
- mso-hansi-theme-font:major-latin;
- mso-bidi-font-family:"Times New Roman";
- mso-bidi-theme-font:major-bidi;
- color:#365F91;
- mso-themecolor:accent1;
- mso-themeshade:191;
- font-weight:bold;}
-span.Heading2Char
- {mso-style-name:"Heading 2 Char";
- mso-style-unhide:no;
- mso-style-locked:yes;
- mso-style-link:"Heading 2";
- mso-ansi-font-size:13.0pt;
- mso-bidi-font-size:13.0pt;
- font-family:"Cambria","serif";
- mso-ascii-font-family:Cambria;
- mso-ascii-theme-font:major-latin;
- mso-fareast-font-family:"Times New Roman";
- mso-fareast-theme-font:major-fareast;
- mso-hansi-font-family:Cambria;
- mso-hansi-theme-font:major-latin;
- mso-bidi-font-family:"Times New Roman";
- mso-bidi-theme-font:major-bidi;
- color:#4F81BD;
- mso-themecolor:accent1;
- font-weight:bold;}
-span.Heading3Char
- {mso-style-name:"Heading 3 Char";
- mso-style-unhide:no;
- mso-style-locked:yes;
- mso-style-link:"Heading 3";
- mso-ansi-font-size:12.0pt;
- mso-bidi-font-size:12.0pt;
- font-family:"Cambria","serif";
- mso-ascii-font-family:Cambria;
- mso-ascii-theme-font:major-latin;
- mso-fareast-font-family:"Times New Roman";
- mso-fareast-theme-font:major-fareast;
- mso-hansi-font-family:Cambria;
- mso-hansi-theme-font:major-latin;
- mso-bidi-font-family:"Times New Roman";
- mso-bidi-theme-font:major-bidi;
- color:#4F81BD;
- mso-themecolor:accent1;
- font-weight:bold;}
-span.BalloonTextChar
- {mso-style-name:"Balloon Text Char";
- mso-style-unhide:no;
- mso-style-locked:yes;
- mso-style-link:"Balloon Text";
- mso-ansi-font-size:8.0pt;
- mso-bidi-font-size:8.0pt;
- font-family:"Tahoma","sans-serif";
- mso-ascii-font-family:Tahoma;
- mso-hansi-font-family:Tahoma;
- mso-bidi-font-family:Tahoma;}
-.MsoChpDefault
- {mso-style-type:export-only;
- mso-default-props:yes;
- font-size:10.0pt;
- mso-ansi-font-size:10.0pt;
- mso-bidi-font-size:10.0pt;}
-@page WordSection1
- {size:8.5in 11.0in;
- margin:1.0in 1.25in 1.0in 1.25in;
- mso-header-margin:.5in;
- mso-footer-margin:.5in;
- mso-paper-source:0;}
-div.WordSection1
- {page:WordSection1;}
- /* List Definitions */
- @list l0
- {mso-list-id:62067358;
- mso-list-template-ids:-174943062;}
-@list l0:level1
- {mso-level-number-format:bullet;
- mso-level-text:\F0B7;
- mso-level-tab-stop:.5in;
- mso-level-number-position:left;
- text-indent:-.25in;
- mso-ansi-font-size:10.0pt;
- font-family:Symbol;}
-@list l0:level2
- {mso-level-tab-stop:1.0in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l0:level3
- {mso-level-tab-stop:1.5in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l0:level4
- {mso-level-tab-stop:2.0in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l0:level5
- {mso-level-tab-stop:2.5in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l0:level6
- {mso-level-tab-stop:3.0in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l0:level7
- {mso-level-tab-stop:3.5in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l0:level8
- {mso-level-tab-stop:4.0in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l0:level9
- {mso-level-tab-stop:4.5in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l1
- {mso-list-id:128015942;
- mso-list-template-ids:-90681214;}
-@list l1:level1
- {mso-level-tab-stop:.5in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l1:level2
- {mso-level-tab-stop:1.0in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l1:level3
- {mso-level-tab-stop:1.5in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l1:level4
- {mso-level-tab-stop:2.0in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l1:level5
- {mso-level-tab-stop:2.5in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l1:level6
- {mso-level-tab-stop:3.0in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l1:level7
- {mso-level-tab-stop:3.5in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l1:level8
- {mso-level-tab-stop:4.0in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l1:level9
- {mso-level-tab-stop:4.5in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l2
- {mso-list-id:216556000;
- mso-list-template-ids:925924412;}
-@list l2:level1
- {mso-level-number-format:bullet;
- mso-level-text:\F0B7;
- mso-level-tab-stop:.5in;
- mso-level-number-position:left;
- text-indent:-.25in;
- mso-ansi-font-size:10.0pt;
- font-family:Symbol;}
-@list l2:level2
- {mso-level-number-format:bullet;
- mso-level-text:\F0B7;
- mso-level-tab-stop:1.0in;
- mso-level-number-position:left;
- text-indent:-.25in;
- mso-ansi-font-size:10.0pt;
- font-family:Symbol;}
-@list l2:level3
- {mso-level-tab-stop:1.5in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l2:level4
- {mso-level-tab-stop:2.0in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l2:level5
- {mso-level-tab-stop:2.5in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l2:level6
- {mso-level-tab-stop:3.0in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l2:level7
- {mso-level-tab-stop:3.5in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l2:level8
- {mso-level-tab-stop:4.0in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l2:level9
- {mso-level-tab-stop:4.5in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l3
- {mso-list-id:562446694;
- mso-list-template-ids:913898366;}
-@list l3:level1
- {mso-level-number-format:bullet;
- mso-level-text:\F0B7;
- mso-level-tab-stop:.5in;
- mso-level-number-position:left;
- text-indent:-.25in;
- mso-ansi-font-size:10.0pt;
- font-family:Symbol;}
-@list l3:level2
- {mso-level-tab-stop:1.0in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l3:level3
- {mso-level-tab-stop:1.5in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l3:level4
- {mso-level-tab-stop:2.0in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l3:level5
- {mso-level-tab-stop:2.5in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l3:level6
- {mso-level-tab-stop:3.0in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l3:level7
- {mso-level-tab-stop:3.5in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l3:level8
- {mso-level-tab-stop:4.0in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l3:level9
- {mso-level-tab-stop:4.5in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l4
- {mso-list-id:797802132;
- mso-list-template-ids:-1971191336;}
-@list l4:level1
- {mso-level-tab-stop:.5in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l4:level2
- {mso-level-tab-stop:1.0in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l4:level3
- {mso-level-tab-stop:1.5in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l4:level4
- {mso-level-tab-stop:2.0in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l4:level5
- {mso-level-tab-stop:2.5in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l4:level6
- {mso-level-tab-stop:3.0in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l4:level7
- {mso-level-tab-stop:3.5in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l4:level8
- {mso-level-tab-stop:4.0in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l4:level9
- {mso-level-tab-stop:4.5in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l5
- {mso-list-id:907304066;
- mso-list-template-ids:1969781532;}
-@list l5:level1
- {mso-level-tab-stop:.5in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l5:level2
- {mso-level-tab-stop:1.0in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l5:level3
- {mso-level-tab-stop:1.5in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l5:level4
- {mso-level-tab-stop:2.0in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l5:level5
- {mso-level-tab-stop:2.5in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l5:level6
- {mso-level-tab-stop:3.0in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l5:level7
- {mso-level-tab-stop:3.5in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l5:level8
- {mso-level-tab-stop:4.0in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l5:level9
- {mso-level-tab-stop:4.5in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l6
- {mso-list-id:1050613616;
- mso-list-template-ids:-1009886748;}
-@list l6:level1
- {mso-level-number-format:bullet;
- mso-level-text:\F0B7;
- mso-level-tab-stop:.5in;
- mso-level-number-position:left;
- text-indent:-.25in;
- mso-ansi-font-size:10.0pt;
- font-family:Symbol;}
-@list l6:level2
- {mso-level-number-format:bullet;
- mso-level-text:\F0B7;
- mso-level-tab-stop:1.0in;
- mso-level-number-position:left;
- text-indent:-.25in;
- mso-ansi-font-size:10.0pt;
- font-family:Symbol;}
-@list l6:level3
- {mso-level-tab-stop:1.5in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l6:level4
- {mso-level-tab-stop:2.0in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l6:level5
- {mso-level-tab-stop:2.5in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l6:level6
- {mso-level-tab-stop:3.0in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l6:level7
- {mso-level-tab-stop:3.5in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l6:level8
- {mso-level-tab-stop:4.0in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l6:level9
- {mso-level-tab-stop:4.5in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l7
- {mso-list-id:1234970193;
- mso-list-template-ids:2055904002;}
-@list l7:level1
- {mso-level-number-format:bullet;
- mso-level-text:\F0B7;
- mso-level-tab-stop:.5in;
- mso-level-number-position:left;
- text-indent:-.25in;
- mso-ansi-font-size:10.0pt;
- font-family:Symbol;}
-@list l7:level2
- {mso-level-number-format:bullet;
- mso-level-text:\F0B7;
- mso-level-tab-stop:1.0in;
- mso-level-number-position:left;
- text-indent:-.25in;
- mso-ansi-font-size:10.0pt;
- font-family:Symbol;}
-@list l7:level3
- {mso-level-tab-stop:1.5in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l7:level4
- {mso-level-tab-stop:2.0in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l7:level5
- {mso-level-tab-stop:2.5in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l7:level6
- {mso-level-tab-stop:3.0in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l7:level7
- {mso-level-tab-stop:3.5in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l7:level8
- {mso-level-tab-stop:4.0in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l7:level9
- {mso-level-tab-stop:4.5in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l8
- {mso-list-id:1846092290;
- mso-list-template-ids:-768590846;}
-@list l8:level1
- {mso-level-start-at:2;
- mso-level-tab-stop:.5in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l8:level2
- {mso-level-tab-stop:1.0in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l8:level3
- {mso-level-tab-stop:1.5in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l8:level4
- {mso-level-tab-stop:2.0in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l8:level5
- {mso-level-tab-stop:2.5in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l8:level6
- {mso-level-tab-stop:3.0in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l8:level7
- {mso-level-tab-stop:3.5in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l8:level8
- {mso-level-tab-stop:4.0in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l8:level9
- {mso-level-tab-stop:4.5in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l9
- {mso-list-id:1894656566;
- mso-list-template-ids:1199983812;}
-@list l9:level1
- {mso-level-start-at:2;
- mso-level-tab-stop:.5in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l9:level2
- {mso-level-tab-stop:1.0in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l9:level3
- {mso-level-tab-stop:1.5in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l9:level4
- {mso-level-tab-stop:2.0in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l9:level5
- {mso-level-tab-stop:2.5in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l9:level6
- {mso-level-tab-stop:3.0in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l9:level7
- {mso-level-tab-stop:3.5in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l9:level8
- {mso-level-tab-stop:4.0in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-@list l9:level9
- {mso-level-tab-stop:4.5in;
- mso-level-number-position:left;
- text-indent:-.25in;}
-ol
- {margin-bottom:0in;}
-ul
- {margin-bottom:0in;}
--->
-</style><!--[if gte mso 10]>
-<style>
- /* Style Definitions */
- table.MsoNormalTable
- {mso-style-name:"Table Normal";
- mso-tstyle-rowband-size:0;
- mso-tstyle-colband-size:0;
- mso-style-noshow:yes;
- mso-style-priority:99;
- mso-style-qformat:yes;
- mso-style-parent:"";
- mso-padding-alt:0in 5.4pt 0in 5.4pt;
- mso-para-margin:0in;
- mso-para-margin-bottom:.0001pt;
- mso-pagination:widow-orphan;
- font-size:10.0pt;
- font-family:"Times New Roman","serif";}
-</style>
-<![endif]--><!--[if gte mso 9]><xml>
- <o:shapedefaults v:ext="edit" spidmax="7170"/>
-</xml><![endif]--><!--[if gte mso 9]><xml>
- <o:shapelayout v:ext="edit">
- <o:idmap v:ext="edit" data="1"/>
- </o:shapelayout></xml><![endif]--><meta content="MCD Application Team" name="author"></head><body style="" link="blue" vlink="blue">
-
-<div class="WordSection1">
-
-<p class="MsoNormal"><span style="font-family: &quot;Arial&quot;,&quot;sans-serif&quot;;"><o:p>&nbsp;</o:p></span></p>
-
-<div align="center">
-
-<table class="MsoNormalTable" style="width: 675pt;" border="0" cellpadding="0" cellspacing="0" width="900">
- <tbody><tr style="">
- <td style="padding: 0in;" valign="top">
- <table class="MsoNormalTable" style="width: 675pt;" border="0" cellpadding="0" cellspacing="0" width="900">
- <tbody><tr style="">
- <td style="padding: 0in 5.4pt;" valign="top">
- <p class="MsoNormal"><span style="font-size: 8pt; font-family: &quot;Arial&quot;,&quot;sans-serif&quot;; color: blue;"><a href="../../../Release_Notes.html">Back to Release page</a></span><span style="font-size: 10pt;"><o:p></o:p></span></p>
- </td>
- </tr>
- <tr style="">
- <td style="padding: 1.5pt;">
- <h1 style="margin-bottom: 0.25in; text-align: center;" align="center"><span style="font-size: 20pt; font-family: &quot;Verdana&quot;,&quot;sans-serif&quot;; color: rgb(51, 102, 255);">Release Notes for STM32 USB Host Library</span><span style="font-size: 20pt; font-family: &quot;Verdana&quot;,&quot;sans-serif&quot;;"><o:p></o:p></span></h1>
- <p class="MsoNormal" style="text-align: center;" align="center"><span style="font-size: 10pt; font-family: &quot;Arial&quot;,&quot;sans-serif&quot;; color: black;">Copyright
- 2014 STMicroelectronics</span><span style="color: black;"><u1:p></u1:p><o:p></o:p></span></p>
- <p class="MsoNormal" style="text-align: center;" align="center"><span style="font-size: 10pt; font-family: &quot;Arial&quot;,&quot;sans-serif&quot;; color: black;"><img style="border: 0px solid ; width: 86px; height: 65px;" alt="" id="_x0000_i1026" src="../../../_htmresc/st_logo.png"></span><span style="font-size: 10pt;"><o:p></o:p></span></p>
- </td>
- </tr>
- </tbody></table>
- <p class="MsoNormal"><span style="font-family: &quot;Arial&quot;,&quot;sans-serif&quot;; display: none;"><o:p>&nbsp;</o:p></span></p>
- <table class="MsoNormalTable" style="width: 675pt;" border="0" cellpadding="0" width="900">
- <tbody><tr style="">
- <td style="padding: 0in;" valign="top">
- <h2 style="background: rgb(51, 102, 255) none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;"><a name="History"></a><span style="font-size: 12pt; color: white;">Update History</span></h2>
-
- <h3 style="background: rgb(51, 102, 255) none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-right: 500pt; width: 180px;"><span style="font-size: 10pt; font-family: Arial; color: white;">V3.0.0 / 18-February-2014</span></h3>
-
-
-
- <p class="MsoNormal" style="margin: 4.5pt 0cm 4.5pt 18pt;"><b style=""><u><span style="font-size: 10pt; font-family: Verdana; color: black;">Main
-Changes</span></u></b><u><span style="font-size: 10pt; font-family: Verdana; color: black;"><o:p></o:p></span></u></p>
-
-
-
-
-
-
-
- <ul style="margin-top: 0cm;" type="square">
- <li><span style="font-size: 10pt; font-family: Verdana;">Major update
-based on STM32Cube specification: Library Core, Classes architecture and APIs
-modified vs. V2.1.0, and thus the 2 versions are not compatible.<br>
-</span></li>
- <li style="font-weight: bold;"><span style="font-size: 10pt; font-family: Verdana;">This version has to be used only with </span><span style="font-size: 10pt; font-family: Verdana;">STM32Cube</span><span style="font-size: 10pt; font-family: Verdana;"> based development</span></li>
-</ul>
-<h3 style="background: rgb(51, 102, 255) none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-right: 500pt; width: 200px;"><span style="font-size: 10pt; font-family: Arial; color: white;">V2.1.0 / 19-March-2012<o:p></o:p></span></h3>
- <p class="MsoNormal" style="margin: 4.5pt 0cm 4.5pt 18pt;"><b style=""><u><span style="font-size: 10pt; font-family: Verdana; color: black;">Main
-Changes<o:p></o:p></span></u></b></p>
-
- <ul style="margin-top: 0cm;" type="square"><li class="MsoNormal" style="color: black; margin-top: 4.5pt; margin-bottom: 4.5pt;"><span style="font-size: 10pt; font-family: Verdana;">Official support of </span><span style="font-size: 10pt; font-family: Verdana;"><span style="font-weight: bold; font-style: italic;">STM32F4xx</span> devices</span></li><li class="MsoNormal" style="color: black; margin-top: 4.5pt; margin-bottom: 4.5pt;"><span style="font-size: 10pt; font-family: Verdana;">All source files: license disclaimer text update and add link to the License file on ST Internet</span></li><li class="MsoNormal" style="color: black; margin-top: 4.5pt; margin-bottom: 4.5pt;"><span style="font-size: 10pt; font-family: Verdana;">Add ISR structure to link the low level driver to the Host library</span></li><li class="MsoNormal" style="color: black; margin-top: 4.5pt; margin-bottom: 4.5pt;"><span style="font-size: 10pt; font-family: Verdana;">Change length parameter in the I/O operations to handle large amount of data</span></li><li class="MsoNormal" style="color: black; margin-top: 4.5pt; margin-bottom: 4.5pt;"><span style="font-size: 10pt; font-family: Verdana;">Enhance the configuration descriptor parsing method to take into account multi interface devices</span></li><li class="MsoNormal" style="color: black; margin-top: 4.5pt; margin-bottom: 4.5pt;"><span style="font-size: 10pt; font-family: Verdana;">HID class</span></li><ul><li class="MsoNormal" style="color: black; margin-top: 4.5pt; margin-bottom: 4.5pt;"><span style="font-size: 10pt; font-family: Verdana;">Remove blocking even frame synchronization loop</span></li></ul><li class="MsoNormal" style="color: black; margin-top: 4.5pt; margin-bottom: 4.5pt;"><span style="font-size: 10pt; font-family: Verdana;">MSC class</span></li><ul><li class="MsoNormal" style="color: black; margin-top: 4.5pt; margin-bottom: 4.5pt;"><span style="font-size: 10pt; font-family: Verdana;">Handle correctly the BOT transfer with length &lt; max length</span></li></ul><ul><li class="MsoNormal" style="color: black; margin-top: 4.5pt; margin-bottom: 4.5pt;"><span style="font-size: 10pt; font-family: Verdana;">Handle multi sector length data in the FAT FS interface</span></li></ul><li class="MsoNormal" style="color: black; margin-top: 4.5pt; margin-bottom: 4.5pt;"><span style="font-size: 10pt; font-family: Verdana;">Miscellaneous bug fix<br></span></li></ul><h3 style="background: rgb(51, 102, 255) none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-right: 500pt; width: 171px;"><span style="font-size: 10pt; font-family: Arial; color: white;">V2.0.0 / 22-July-2011 <o:p></o:p></span></h3><p class="MsoNormal" style="margin: 4.5pt 0cm 4.5pt 18pt;"><b style=""><u><span style="font-size: 10pt; font-family: Verdana; color: black;">Main
-Changes<o:p></o:p></span></u></b></p>
-<ul style="margin-top: 0cm;" type="square"><li class="MsoNormal" style="color: black; margin-top: 4.5pt; margin-bottom: 4.5pt;"><span style="font-size: 10pt; font-family: Verdana;">Second official version supporting STM32F105/7 and STM32F2xx devices</span></li><li class="MsoNormal" style="color: black; margin-top: 4.5pt; margin-bottom: 4.5pt;"><span style="font-size: 10pt; font-family: Verdana;">Add support for <span style="font-weight: bold; font-style: italic;">STM32F2xx</span> devices</span><span style="font-size: 10pt; font-family: Verdana;"></span></li><li class="MsoNormal" style="color: black; margin-top: 4.5pt; margin-bottom: 4.5pt;"><span style="font-size: 10pt; font-family: Verdana;">Add multi interface feature</span><span style="font-size: 10pt; font-family: Verdana;"></span></li><li class="MsoNormal" style="color: black; margin-top: 4.5pt; margin-bottom: 4.5pt;"><span style="font-size: 10pt; font-family: Verdana;">Add dynamic configuration parsing</span></li><li class="MsoNormal" style="color: black; margin-top: 4.5pt; margin-bottom: 4.5pt;"><span style="font-size: 10pt; font-family: Verdana;">Add
-USBH_DeAllocate_AllChannel function in the Host channel management
-layer to clean up channels allocation table when de-initializing the
-library</span></li><li class="MsoNormal" style="color: black; margin-top: 4.5pt; margin-bottom: 4.5pt;"><span style="font-size: 10pt; font-family: Verdana;">Change the core layer to stop correctly the host core and free all allocated channels</span></li><li class="MsoNormal" style="color: black; margin-top: 4.5pt; margin-bottom: 4.5pt;"><span style="font-size: 10pt; font-family: Verdana;">Add usbh_conf.h file in the application layer to customize some user parameters</span></li></ul><span style="font-size: 10pt; font-family: Verdana;"><br></span><h3 style="background: rgb(51, 102, 255) none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-right: 500pt; width: 171px;"><span style="font-size: 10pt; font-family: Arial; color: white;">V1.0.0&nbsp;- 11/29/2010<o:p></o:p></span></h3>
-<ul style="margin-top: 0cm;" type="square"><li class="MsoNormal" style="color: black; margin-top: 4.5pt; margin-bottom: 4.5pt;"><span style="font-size: 10pt; font-family: Verdana;">Created&nbsp;</span></li></ul><h2 style="background: rgb(51, 102, 255) none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;"><a name="License"></a><span style="font-size: 12pt; color: white;">License<o:p></o:p></span></h2>
- <p class="MsoNormal"><span style="font-size: 10pt; font-family: &quot;Verdana&quot;,&quot;sans-serif&quot;; color: black;">Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); You may not use this&nbsp;</span><span style="font-size: 10pt; font-family: &quot;Verdana&quot;,&quot;sans-serif&quot;; color: black;">package</span><span style="font-size: 10pt; font-family: &quot;Verdana&quot;,&quot;sans-serif&quot;; color: black;"> except in compliance with the License. You may obtain a copy of the License at:<br><br></span></p><div style="text-align: center;"><span style="font-size: 10pt; font-family: &quot;Verdana&quot;,&quot;sans-serif&quot;; color: black;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <a target="_blank" href="http://www.st.com/software_license_agreement_liberty_v2">http://www.st.com/software_license_agreement_liberty_v2</a></span><br><span style="font-size: 10pt; font-family: &quot;Verdana&quot;,&quot;sans-serif&quot;; color: black;"></span></div><span style="font-size: 10pt; font-family: &quot;Verdana&quot;,&quot;sans-serif&quot;; color: black;"><br>Unless
-required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS, <br>WITHOUT
-WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See
-the License for the specific language governing permissions and
-limitations under the License.</span>
- <div class="MsoNormal" style="text-align: center;" align="center"><span style="color: black;">
- <hr align="center" size="2" width="100%">
- </span></div>
- <p class="MsoNormal" style="margin: 4.5pt 0in 4.5pt 0.25in; text-align: center;" align="center"><span style="font-size: 10pt; font-family: &quot;Verdana&quot;,&quot;sans-serif&quot;; color: black;">For
- complete documentation on </span><span style="font-size: 10pt; font-family: &quot;Verdana&quot;,&quot;sans-serif&quot;;">STM32<span style="color: black;">
- Microcontrollers visit </span><u><span style="color: blue;"><a href="http://www.st.com/internet/mcu/family/141.jsp" target="_blank">www.st.com/STM32</a></span></u></span><span style="font-size: 10pt; font-family: &quot;Verdana&quot;,&quot;sans-serif&quot;;"><u><span style="color: blue;"><a href="http://www.st.com/stm32" target="_blank"></a></span></u></span><span style="color: black;"><o:p></o:p></span></p>
- </td>
- </tr>
- </tbody></table>
- <p class="MsoNormal"><span style="font-size: 10pt;"><o:p></o:p></span></p>
- </td>
- </tr>
-</tbody></table>
-
-</div>
-
-<p class="MsoNormal"><o:p>&nbsp;</o:p></p>
-
-</div>
-
-</body></html> \ No newline at end of file
diff --git a/ports/stm32/usrsw.c b/ports/stm32/usrsw.c
index a7721ad77..ded0b6864 100644
--- a/ports/stm32/usrsw.c
+++ b/ports/stm32/usrsw.c
@@ -30,7 +30,6 @@
#include "py/mphal.h"
#include "extint.h"
#include "pin.h"
-#include "genhdr/pins.h"
#include "usrsw.h"
#if MICROPY_HW_HAS_SWITCH
@@ -54,11 +53,11 @@
// this function inits the switch GPIO so that it can be used
void switch_init0(void) {
- mp_hal_pin_config(&MICROPY_HW_USRSW_PIN, MP_HAL_PIN_MODE_INPUT, MICROPY_HW_USRSW_PULL, 0);
+ mp_hal_pin_config(MICROPY_HW_USRSW_PIN, MP_HAL_PIN_MODE_INPUT, MICROPY_HW_USRSW_PULL, 0);
}
int switch_get(void) {
- int val = ((MICROPY_HW_USRSW_PIN.gpio->IDR & MICROPY_HW_USRSW_PIN.pin_mask) != 0);
+ int val = ((MICROPY_HW_USRSW_PIN->gpio->IDR & MICROPY_HW_USRSW_PIN->pin_mask) != 0);
return val == MICROPY_HW_USRSW_PRESSED;
}
@@ -119,7 +118,7 @@ mp_obj_t pyb_switch_callback(mp_obj_t self_in, mp_obj_t callback) {
// Init the EXTI each time this function is called, since the EXTI
// may have been disabled by an exception in the interrupt, or the
// user disabling the line explicitly.
- extint_register((mp_obj_t)&MICROPY_HW_USRSW_PIN,
+ extint_register((mp_obj_t)MICROPY_HW_USRSW_PIN,
MICROPY_HW_USRSW_EXTI_MODE,
MICROPY_HW_USRSW_PULL,
callback == mp_const_none ? mp_const_none : (mp_obj_t)&switch_callback_obj,
diff --git a/ports/stm32/usrsw.h b/ports/stm32/usrsw.h
index d96e3c281..a8a087db2 100644
--- a/ports/stm32/usrsw.h
+++ b/ports/stm32/usrsw.h
@@ -23,12 +23,12 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
-#ifndef MICROPY_INCLUDED_STMHAL_USRSW_H
-#define MICROPY_INCLUDED_STMHAL_USRSW_H
+#ifndef MICROPY_INCLUDED_STM32_USRSW_H
+#define MICROPY_INCLUDED_STM32_USRSW_H
void switch_init0(void);
int switch_get(void);
extern const mp_obj_type_t pyb_switch_type;
-#endif // MICROPY_INCLUDED_STMHAL_USRSW_H
+#endif // MICROPY_INCLUDED_STM32_USRSW_H
diff --git a/ports/stm32/wdt.c b/ports/stm32/wdt.c
index 2b4967a43..8df7b4768 100644
--- a/ports/stm32/wdt.c
+++ b/ports/stm32/wdt.c
@@ -29,6 +29,10 @@
#include "py/runtime.h"
#include "wdt.h"
+#if defined(STM32H7)
+#define IWDG (IWDG1)
+#endif
+
typedef struct _pyb_wdt_obj_t {
mp_obj_base_t base;
} pyb_wdt_obj_t;
diff --git a/ports/stm32/wdt.h b/ports/stm32/wdt.h
index 0a486f704..d60bb7e9e 100644
--- a/ports/stm32/wdt.h
+++ b/ports/stm32/wdt.h
@@ -23,9 +23,9 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
-#ifndef MICROPY_INCLUDED_STMHAL_WDT_H
-#define MICROPY_INCLUDED_STMHAL_WDT_H
+#ifndef MICROPY_INCLUDED_STM32_WDT_H
+#define MICROPY_INCLUDED_STM32_WDT_H
extern const mp_obj_type_t pyb_wdt_type;
-#endif // MICROPY_INCLUDED_STMHAL_WDT_H
+#endif // MICROPY_INCLUDED_STM32_WDT_H
diff --git a/ports/teensy/hal_gpio.c b/ports/teensy/hal_gpio.c
index e65d03410..f9e137602 100644
--- a/ports/teensy/hal_gpio.c
+++ b/ports/teensy/hal_gpio.c
@@ -52,7 +52,7 @@ void HAL_GPIO_Init(GPIO_TypeDef *GPIOx, GPIO_InitTypeDef *GPIO_Init)
*port_pcr |= PORT_PCR_DSE;
/* Configure the IO Speed */
- if (GPIO_Init->Speed > GPIO_SPEED_MEDIUM) {
+ if (GPIO_Init->Speed > GPIO_SPEED_FREQ_MEDIUM) {
*port_pcr &= ~PORT_PCR_SRE;
} else {
*port_pcr |= PORT_PCR_SRE;
diff --git a/ports/teensy/led.c b/ports/teensy/led.c
index add052fad..cf59dbd0a 100644
--- a/ports/teensy/led.c
+++ b/ports/teensy/led.c
@@ -33,7 +33,7 @@ void led_init(void) {
GPIO_InitTypeDef GPIO_InitStructure;
/* Configure I/O speed, mode, output type and pull */
- GPIO_InitStructure.Speed = GPIO_SPEED_LOW;
+ GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStructure.Mode = MICROPY_HW_LED_OTYPE;
GPIO_InitStructure.Pull = GPIO_NOPULL;
diff --git a/ports/teensy/mk20dx256_prefix.c b/ports/teensy/mk20dx256_prefix.c
index d8e7480b5..58ab07d6e 100644
--- a/ports/teensy/mk20dx256_prefix.c
+++ b/ports/teensy/mk20dx256_prefix.c
@@ -15,7 +15,7 @@
.fn = AF_FN_ ## af_fn, \
.unit = (af_unit), \
.type = AF_PIN_TYPE_ ## af_fn ## _ ## af_type, \
- .af_fn = (af_ptr) \
+ .reg = (af_ptr) \
}
#define PIN(p_port, p_pin, p_num_af, p_af, p_adc_num, p_adc_channel) \
diff --git a/ports/teensy/pin_defs_teensy.h b/ports/teensy/pin_defs_teensy.h
index 54a6055f1..d3a700be2 100644
--- a/ports/teensy/pin_defs_teensy.h
+++ b/ports/teensy/pin_defs_teensy.h
@@ -40,10 +40,4 @@ enum {
AF_PIN_TYPE_UART_RTS,
};
-#define PIN_DEFS_PORT_AF_UNION \
- FTM_TypeDef *FTM; \
- I2C_TypeDef *I2C; \
- UART_TypeDef *UART; \
- SPI_TypeDef *SPI;
-
typedef GPIO_TypeDef pin_gpio_t;
diff --git a/ports/teensy/teensy_hal.h b/ports/teensy/teensy_hal.h
index 162effa85..aef38a2ad 100644
--- a/ports/teensy/teensy_hal.h
+++ b/ports/teensy/teensy_hal.h
@@ -74,10 +74,10 @@ typedef struct {
#define IS_GPIO_PULL(PULL) (((PULL) == GPIO_NOPULL) || ((PULL) == GPIO_PULLUP) || \
((PULL) == GPIO_PULLDOWN))
-#define GPIO_SPEED_LOW ((uint32_t)0)
-#define GPIO_SPEED_MEDIUM ((uint32_t)1)
-#define GPIO_SPEED_FAST ((uint32_t)2)
-#define GPIO_SPEED_HIGH ((uint32_t)3)
+#define GPIO_SPEED_FREQ_LOW ((uint32_t)0)
+#define GPIO_SPEED_FREQ_MEDIUM ((uint32_t)1)
+#define GPIO_SPEED_FREQ_HIGH ((uint32_t)2)
+#define GPIO_SPEED_FREQ_VERY_HIGH ((uint32_t)3)
#define IS_GPIO_AF(af) ((af) >= 0 && (af) <= 7)
diff --git a/ports/unix/Makefile b/ports/unix/Makefile
index dacf68019..1136c42b6 100644
--- a/ports/unix/Makefile
+++ b/ports/unix/Makefile
@@ -165,7 +165,6 @@ LIB_SRC_C += $(addprefix lib/,\
OBJ = $(PY_O)
OBJ += $(addprefix $(BUILD)/, $(SRC_C:.c=.o))
OBJ += $(addprefix $(BUILD)/, $(LIB_SRC_C:.c=.o))
-OBJ += $(addprefix $(BUILD)/, $(STMHAL_SRC_C:.c=.o))
# List of sources for qstr extraction
SRC_QSTR += $(SRC_C) $(LIB_SRC_C)
@@ -243,7 +242,7 @@ freedos:
# build an interpreter for coverage testing and do the testing
coverage:
$(MAKE) V=2 \
- COPT="-O0" CFLAGS_EXTRA='-DMP_CONFIGFILE="\"mpconfigport_coverage.h\"" \
+ COPT="-O0" CFLAGS_EXTRA='$(CFLAGS_EXTRA) -DMP_CONFIGFILE="<mpconfigport_coverage.h>" \
-fprofile-arcs -ftest-coverage \
-Wdouble-promotion -Wformat -Wmissing-declarations -Wmissing-prototypes -Wsign-compare \
-Wold-style-definition -Wpointer-arith -Wshadow -Wuninitialized -Wunused-parameter \
@@ -258,6 +257,7 @@ coverage_test: coverage
cd $(TOP)/tests && MICROPY_MICROPYTHON=../$(DIRNAME)/micropython_coverage ./run-tests --auto-jobs -d thread
cd $(TOP)/tests && MICROPY_MICROPYTHON=../$(DIRNAME)/micropython_coverage ./run-tests --auto-jobs --emit native
cd $(TOP)/tests && MICROPY_MICROPYTHON=../$(DIRNAME)/micropython_coverage ./run-tests -j1 --via-mpy -d basics float
+ cat $(TOP)/tests/basics/0prelim.py | ./micropython_coverage | grep -q 'abc'
gcov -o build-coverage/py $(TOP)/py/*.c
gcov -o build-coverage/extmod $(TOP)/extmod/*.c
diff --git a/ports/unix/coverage.c b/ports/unix/coverage.c
index 651db0a94..7820f6d73 100644
--- a/ports/unix/coverage.c
+++ b/ports/unix/coverage.c
@@ -4,6 +4,7 @@
#include "py/obj.h"
#include "py/objstr.h"
#include "py/runtime.h"
+#include "py/gc.h"
#include "py/repl.h"
#include "py/mpz.h"
#include "py/builtin.h"
@@ -11,6 +12,7 @@
#include "py/formatfloat.h"
#include "py/stream.h"
#include "py/binary.h"
+#include "py/bc.h"
#if defined(MICROPY_UNIX_COVERAGE)
@@ -116,7 +118,6 @@ STATIC mp_uint_t stest_read2(mp_obj_t o_in, void *buf, mp_uint_t size, int *errc
STATIC const mp_rom_map_elem_t rawfile_locals_dict_table2[] = {
{ MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) },
- { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) },
};
STATIC MP_DEFINE_CONST_DICT(rawfile_locals_dict2, rawfile_locals_dict_table2);
@@ -145,11 +146,16 @@ STATIC mp_obj_t extra_coverage(void) {
mp_printf(&mp_plat_print, "%d %+d % d\n", -123, 123, 123); // sign
mp_printf(&mp_plat_print, "%05d\n", -123); // negative number with zero padding
mp_printf(&mp_plat_print, "%ld\n", 123); // long
+ mp_printf(&mp_plat_print, "%lx\n", 0x123); // long hex
mp_printf(&mp_plat_print, "%X\n", 0x1abcdef); // capital hex
mp_printf(&mp_plat_print, "%.2s %.3s\n", "abc", "abc"); // fixed string precision
mp_printf(&mp_plat_print, "%.*s\n", -1, "abc"); // negative string precision
mp_printf(&mp_plat_print, "%b %b\n", 0, 1); // bools
+ #ifndef NDEBUG
mp_printf(&mp_plat_print, "%s\n", NULL); // null string
+ #else
+ mp_printf(&mp_plat_print, "(null)\n"); // without debugging mp_printf won't check for null
+ #endif
mp_printf(&mp_plat_print, "%d\n", 0x80000000); // should print signed
mp_printf(&mp_plat_print, "%u\n", 0x80000000); // should print unsigned
mp_printf(&mp_plat_print, "%x\n", 0x80000000); // should print unsigned
@@ -157,6 +163,23 @@ STATIC mp_obj_t extra_coverage(void) {
mp_printf(&mp_plat_print, "abc\n%"); // string ends in middle of format specifier
}
+ // GC
+ {
+ mp_printf(&mp_plat_print, "# GC\n");
+
+ // calling gc_free while GC is locked
+ gc_lock();
+ gc_free(NULL);
+ gc_unlock();
+
+ // using gc_realloc to resize to 0, which means free the memory
+ void *p = gc_alloc(4, false);
+ mp_printf(&mp_plat_print, "%p\n", gc_realloc(p, 0, false));
+
+ // calling gc_nbytes with a non-heap pointer
+ mp_printf(&mp_plat_print, "%p\n", gc_nbytes(NULL));
+ }
+
// vstr
{
mp_printf(&mp_plat_print, "# vstr\n");
@@ -227,7 +250,17 @@ STATIC mp_obj_t extra_coverage(void) {
mp_printf(&mp_plat_print, "# str\n");
// intern string
- mp_printf(&mp_plat_print, "%d\n", MP_OBJ_IS_QSTR(mp_obj_str_intern(mp_obj_new_str("intern me", 9, false))));
+ mp_printf(&mp_plat_print, "%d\n", MP_OBJ_IS_QSTR(mp_obj_str_intern(mp_obj_new_str("intern me", 9))));
+ }
+
+ // bytearray
+ {
+ mp_printf(&mp_plat_print, "# bytearray\n");
+
+ // create a bytearray via mp_obj_new_bytearray
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(mp_obj_new_bytearray(4, "data"), &bufinfo, MP_BUFFER_RW);
+ mp_printf(&mp_plat_print, "%.*s\n", bufinfo.len, bufinfo.buf);
}
// mpz
@@ -251,6 +284,39 @@ STATIC mp_obj_t extra_coverage(void) {
mpz_set_from_int(&mpz, 1);
mpz_shl_inpl(&mpz, &mpz, 70);
mp_printf(&mp_plat_print, "%d\n", mpz_as_uint_checked(&mpz, &value));
+
+ // mpz_set_from_float with inf as argument
+ mpz_set_from_float(&mpz, 1.0 / 0.0);
+ mpz_as_uint_checked(&mpz, &value);
+ mp_printf(&mp_plat_print, "%d\n", (int)value);
+
+ // mpz_set_from_float with 0 as argument
+ mpz_set_from_float(&mpz, 0);
+ mpz_as_uint_checked(&mpz, &value);
+ mp_printf(&mp_plat_print, "%d\n", (int)value);
+
+ // mpz_set_from_float with 0<x<1 as argument
+ mpz_set_from_float(&mpz, 1e-10);
+ mpz_as_uint_checked(&mpz, &value);
+ mp_printf(&mp_plat_print, "%d\n", (int)value);
+
+ // mpz_set_from_float with 1<=x<2 as argument
+ mpz_set_from_float(&mpz, 1.5);
+ mpz_as_uint_checked(&mpz, &value);
+ mp_printf(&mp_plat_print, "%d\n", (int)value);
+
+ // mpz_set_from_float with 2<x as argument
+ mpz_set_from_float(&mpz, 12345);
+ mpz_as_uint_checked(&mpz, &value);
+ mp_printf(&mp_plat_print, "%d\n", (int)value);
+
+ // mpz_mul_inpl with dest==rhs, lhs!=rhs
+ mpz_t mpz2;
+ mpz_set_from_int(&mpz, 2);
+ mpz_init_from_int(&mpz2, 3);
+ mpz_mul_inpl(&mpz, &mpz2, &mpz);
+ mpz_as_uint_checked(&mpz, &value);
+ mp_printf(&mp_plat_print, "%d\n", (int)value);
}
// runtime utils
@@ -260,12 +326,12 @@ STATIC mp_obj_t extra_coverage(void) {
// call mp_call_function_1_protected
mp_call_function_1_protected(MP_OBJ_FROM_PTR(&mp_builtin_abs_obj), MP_OBJ_NEW_SMALL_INT(1));
// call mp_call_function_1_protected with invalid args
- mp_call_function_1_protected(MP_OBJ_FROM_PTR(&mp_builtin_abs_obj), mp_obj_new_str("abc", 3, false));
+ mp_call_function_1_protected(MP_OBJ_FROM_PTR(&mp_builtin_abs_obj), mp_obj_new_str("abc", 3));
// call mp_call_function_2_protected
mp_call_function_2_protected(MP_OBJ_FROM_PTR(&mp_builtin_divmod_obj), MP_OBJ_NEW_SMALL_INT(1), MP_OBJ_NEW_SMALL_INT(1));
// call mp_call_function_2_protected with invalid args
- mp_call_function_2_protected(MP_OBJ_FROM_PTR(&mp_builtin_divmod_obj), mp_obj_new_str("abc", 3, false), mp_obj_new_str("abc", 3, false));
+ mp_call_function_2_protected(MP_OBJ_FROM_PTR(&mp_builtin_divmod_obj), mp_obj_new_str("abc", 3), mp_obj_new_str("abc", 3));
}
// warning
@@ -306,6 +372,23 @@ STATIC mp_obj_t extra_coverage(void) {
mp_printf(&mp_plat_print, "%.0lf\n", dar[0]);
}
+ // VM
+ {
+ mp_printf(&mp_plat_print, "# VM\n");
+
+ // call mp_execute_bytecode with invalide bytecode (should raise NotImplementedError)
+ mp_obj_fun_bc_t fun_bc;
+ fun_bc.bytecode = (const byte*)"\x01"; // just needed for n_state
+ mp_code_state_t *code_state = m_new_obj_var(mp_code_state_t, mp_obj_t, 1);
+ code_state->fun_bc = &fun_bc;
+ code_state->ip = (const byte*)"\x00"; // just needed for an invalid opcode
+ code_state->sp = &code_state->state[0];
+ code_state->exc_sp = NULL;
+ code_state->old_globals = NULL;
+ mp_vm_return_kind_t ret = mp_execute_bytecode(code_state, MP_OBJ_NULL);
+ mp_printf(&mp_plat_print, "%d %d\n", ret, mp_obj_get_type(code_state->state[0]) == &mp_type_NotImplementedError);
+ }
+
// scheduler
{
mp_printf(&mp_plat_print, "# scheduler\n");
diff --git a/ports/unix/file.c b/ports/unix/file.c
index 84e918082..165bbd00b 100644
--- a/ports/unix/file.c
+++ b/ports/unix/file.c
@@ -37,7 +37,7 @@
#include "py/mphal.h"
#include "fdfile.h"
-#if MICROPY_PY_IO
+#if MICROPY_PY_IO && !MICROPY_VFS
#ifdef _WIN32
#define fsync _commit
@@ -118,25 +118,21 @@ STATIC mp_uint_t fdfile_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg, i
return MP_STREAM_ERROR;
}
return 0;
+ case MP_STREAM_CLOSE:
+ close(o->fd);
+ #ifdef MICROPY_CPYTHON_COMPAT
+ o->fd = -1;
+ #endif
+ return 0;
default:
*errcode = EINVAL;
return MP_STREAM_ERROR;
}
}
-STATIC mp_obj_t fdfile_close(mp_obj_t self_in) {
- mp_obj_fdfile_t *self = MP_OBJ_TO_PTR(self_in);
- close(self->fd);
-#ifdef MICROPY_CPYTHON_COMPAT
- self->fd = -1;
-#endif
- return mp_const_none;
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_1(fdfile_close_obj, fdfile_close);
-
STATIC mp_obj_t fdfile___exit__(size_t n_args, const mp_obj_t *args) {
(void)n_args;
- return fdfile_close(args[0]);
+ return mp_stream_close(args[0]);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(fdfile___exit___obj, 4, 4, fdfile___exit__);
@@ -224,7 +220,7 @@ STATIC const mp_rom_map_elem_t rawfile_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_seek), MP_ROM_PTR(&mp_stream_seek_obj) },
{ MP_ROM_QSTR(MP_QSTR_tell), MP_ROM_PTR(&mp_stream_tell_obj) },
{ MP_ROM_QSTR(MP_QSTR_flush), MP_ROM_PTR(&mp_stream_flush_obj) },
- { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&fdfile_close_obj) },
+ { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) },
{ MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&mp_identity_obj) },
{ MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&fdfile___exit___obj) },
};
@@ -281,4 +277,4 @@ const mp_obj_fdfile_t mp_sys_stdin_obj = { .base = {&mp_type_textio}, .fd = STD
const mp_obj_fdfile_t mp_sys_stdout_obj = { .base = {&mp_type_textio}, .fd = STDOUT_FILENO };
const mp_obj_fdfile_t mp_sys_stderr_obj = { .base = {&mp_type_textio}, .fd = STDERR_FILENO };
-#endif // MICROPY_PY_IO
+#endif // MICROPY_PY_IO && !MICROPY_VFS
diff --git a/ports/unix/main.c b/ports/unix/main.c
index 629e36b8b..d1187ae90 100644
--- a/ports/unix/main.c
+++ b/ports/unix/main.c
@@ -47,6 +47,8 @@
#include "py/mphal.h"
#include "py/mpthread.h"
#include "extmod/misc.h"
+#include "extmod/vfs.h"
+#include "extmod/vfs_posix.h"
#include "genhdr/mpversion.h"
#include "input.h"
@@ -441,8 +443,25 @@ MP_NOINLINE int main_(int argc, char **argv) {
gc_init(heap, heap + heap_size);
#endif
+ #if MICROPY_ENABLE_PYSTACK
+ static mp_obj_t pystack[1024];
+ mp_pystack_init(pystack, &pystack[MP_ARRAY_SIZE(pystack)]);
+ #endif
+
mp_init();
+ #if MICROPY_VFS_POSIX
+ {
+ // Mount the host FS at the root of our internal VFS
+ mp_obj_t args[2] = {
+ mp_type_vfs_posix.make_new(&mp_type_vfs_posix, 0, 0, NULL),
+ MP_OBJ_NEW_QSTR(MP_QSTR__slash_),
+ };
+ mp_vfs_mount(2, args, (mp_map_t*)&mp_const_empty_map);
+ MP_STATE_VM(vfs_cur) = MP_STATE_VM(vfs_mount_table);
+ }
+ #endif
+
char *home = getenv("HOME");
char *path = getenv("MICROPYPATH");
if (path == NULL) {
@@ -486,7 +505,7 @@ MP_NOINLINE int main_(int argc, char **argv) {
vstr_add_strn(&vstr, p + 1, p1 - p - 1);
path_items[i] = mp_obj_new_str_from_vstr(&mp_type_str, &vstr);
} else {
- path_items[i] = MP_OBJ_NEW_QSTR(qstr_from_strn(p, p1 - p));
+ path_items[i] = mp_obj_new_str_via_qstr(p, p1 - p);
}
p = p1 + 1;
}
@@ -545,7 +564,7 @@ MP_NOINLINE int main_(int argc, char **argv) {
return usage(argv);
}
mp_obj_t import_args[4];
- import_args[0] = mp_obj_new_str(argv[a + 1], strlen(argv[a + 1]), false);
+ import_args[0] = mp_obj_new_str(argv[a + 1], strlen(argv[a + 1]));
import_args[1] = import_args[2] = mp_const_none;
// Ask __import__ to handle imported module specially - set its __name__
// to __main__, and also return this leaf module, not top-level package
@@ -611,7 +630,7 @@ MP_NOINLINE int main_(int argc, char **argv) {
// Set base dir of the script as first entry in sys.path
char *p = strrchr(basedir, '/');
- path_items[0] = MP_OBJ_NEW_QSTR(qstr_from_strn(basedir, p - basedir));
+ path_items[0] = mp_obj_new_str_via_qstr(basedir, p - basedir);
free(pathbuf);
set_sys_argv(argv, argc, a);
@@ -636,6 +655,10 @@ MP_NOINLINE int main_(int argc, char **argv) {
}
#endif
+ #if defined(MICROPY_UNIX_COVERAGE)
+ gc_sweep_all();
+ #endif
+
mp_deinit();
#if MICROPY_ENABLE_GC && !defined(NDEBUG)
@@ -648,6 +671,7 @@ MP_NOINLINE int main_(int argc, char **argv) {
return ret & 0xff;
}
+#if !MICROPY_VFS
uint mp_import_stat(const char *path) {
struct stat st;
if (stat(path, &st) == 0) {
@@ -659,6 +683,7 @@ uint mp_import_stat(const char *path) {
}
return MP_IMPORT_STAT_NO_EXIST;
}
+#endif
void nlr_jump_fail(void *val) {
printf("FATAL: uncaught NLR %p\n", val);
diff --git a/ports/unix/modffi.c b/ports/unix/modffi.c
index 1c04c4def..a12c249e2 100644
--- a/ports/unix/modffi.c
+++ b/ports/unix/modffi.c
@@ -144,7 +144,7 @@ STATIC mp_obj_t return_ffi_value(ffi_arg val, char type)
if (!s) {
return mp_const_none;
}
- return mp_obj_new_str(s, strlen(s), false);
+ return mp_obj_new_str(s, strlen(s));
}
case 'v':
return mp_const_none;
diff --git a/ports/unix/modjni.c b/ports/unix/modjni.c
index f29c095cf..8ec5ae54d 100644
--- a/ports/unix/modjni.c
+++ b/ports/unix/modjni.c
@@ -337,7 +337,7 @@ STATIC mp_obj_t new_jobject(jobject jo) {
return mp_const_none;
} else if (JJ(IsInstanceOf, jo, String_class)) {
const char *s = JJ(GetStringUTFChars, jo, NULL);
- mp_obj_t ret = mp_obj_new_str(s, strlen(s), false);
+ mp_obj_t ret = mp_obj_new_str(s, strlen(s));
JJ(ReleaseStringUTFChars, jo, s);
return ret;
} else if (JJ(IsInstanceOf, jo, Class_class)) {
diff --git a/ports/unix/modos.c b/ports/unix/modos.c
index 327116a0a..d99d0d62c 100644
--- a/ports/unix/modos.c
+++ b/ports/unix/modos.c
@@ -126,16 +126,16 @@ STATIC mp_obj_t mod_os_system(mp_obj_t cmd_in) {
return MP_OBJ_NEW_SMALL_INT(r);
}
-STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_os_system_obj, mod_os_system);
+MP_DEFINE_CONST_FUN_OBJ_1(mod_os_system_obj, mod_os_system);
STATIC mp_obj_t mod_os_getenv(mp_obj_t var_in) {
const char *s = getenv(mp_obj_str_get_str(var_in));
if (s == NULL) {
return mp_const_none;
}
- return mp_obj_new_str(s, strlen(s), false);
+ return mp_obj_new_str(s, strlen(s));
}
-STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_os_getenv_obj, mod_os_getenv);
+MP_DEFINE_CONST_FUN_OBJ_1(mod_os_getenv_obj, mod_os_getenv);
STATIC mp_obj_t mod_os_mkdir(mp_obj_t path_in) {
// TODO: Accept mode param
@@ -171,7 +171,7 @@ STATIC mp_obj_t listdir_next(mp_obj_t self_in) {
}
mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(3, NULL));
- t->items[0] = mp_obj_new_str(dirent->d_name, strlen(dirent->d_name), false);
+ t->items[0] = mp_obj_new_str(dirent->d_name, strlen(dirent->d_name));
#ifdef _DIRENT_HAVE_D_TYPE
t->items[1] = MP_OBJ_NEW_SMALL_INT(dirent->d_type);
#else
@@ -207,7 +207,7 @@ STATIC mp_obj_t mod_os_errno(size_t n_args, const mp_obj_t *args) {
errno = mp_obj_get_int(args[0]);
return mp_const_none;
}
-STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_os_errno_obj, 0, 1, mod_os_errno);
+MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_os_errno_obj, 0, 1, mod_os_errno);
STATIC const mp_rom_map_elem_t mp_module_os_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_uos) },
diff --git a/ports/unix/moduos_vfs.c b/ports/unix/moduos_vfs.c
index 96defa554..e9ac8e1f8 100644
--- a/ports/unix/moduos_vfs.c
+++ b/ports/unix/moduos_vfs.c
@@ -28,17 +28,26 @@
#include <string.h>
#include "extmod/vfs.h"
+#include "extmod/vfs_posix.h"
#include "extmod/vfs_fat.h"
#if MICROPY_VFS
+// These are defined in modos.c
+MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mod_os_errno_obj);
+MP_DECLARE_CONST_FUN_OBJ_1(mod_os_getenv_obj);
+MP_DECLARE_CONST_FUN_OBJ_1(mod_os_system_obj);
+
STATIC const mp_rom_map_elem_t uos_vfs_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_uos_vfs) },
{ MP_ROM_QSTR(MP_QSTR_sep), MP_ROM_QSTR(MP_QSTR__slash_) },
+ { MP_ROM_QSTR(MP_QSTR_errno), MP_ROM_PTR(&mod_os_errno_obj) },
+ { MP_ROM_QSTR(MP_QSTR_getenv), MP_ROM_PTR(&mod_os_getenv_obj) },
+ { MP_ROM_QSTR(MP_QSTR_system), MP_ROM_PTR(&mod_os_system_obj) },
+
{ MP_ROM_QSTR(MP_QSTR_mount), MP_ROM_PTR(&mp_vfs_mount_obj) },
{ MP_ROM_QSTR(MP_QSTR_umount), MP_ROM_PTR(&mp_vfs_umount_obj) },
- { MP_ROM_QSTR(MP_QSTR_vfs_open), MP_ROM_PTR(&mp_vfs_open_obj) },
{ MP_ROM_QSTR(MP_QSTR_chdir), MP_ROM_PTR(&mp_vfs_chdir_obj) },
{ MP_ROM_QSTR(MP_QSTR_getcwd), MP_ROM_PTR(&mp_vfs_getcwd_obj) },
@@ -52,6 +61,13 @@ STATIC const mp_rom_map_elem_t uos_vfs_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR_statvfs), MP_ROM_PTR(&mp_vfs_statvfs_obj) },
{ MP_ROM_QSTR(MP_QSTR_unlink), MP_ROM_PTR(&mp_vfs_remove_obj) }, // unlink aliases to remove
+ #if MICROPY_PY_OS_DUPTERM
+ { MP_ROM_QSTR(MP_QSTR_dupterm), MP_ROM_PTR(&mp_uos_dupterm_obj) },
+ #endif
+
+ #if MICROPY_VFS_POSIX
+ { MP_ROM_QSTR(MP_QSTR_VfsPosix), MP_ROM_PTR(&mp_type_vfs_posix) },
+ #endif
#if MICROPY_VFS_FAT
{ MP_ROM_QSTR(MP_QSTR_VfsFat), MP_ROM_PTR(&mp_fat_vfs_type) },
#endif
diff --git a/ports/unix/moduselect.c b/ports/unix/moduselect.c
index ba1c195ef..1ea7dc19a 100644
--- a/ports/unix/moduselect.c
+++ b/ports/unix/moduselect.c
@@ -40,6 +40,8 @@
#include "py/mphal.h"
#include "fdfile.h"
+#define DEBUG 0
+
#if MICROPY_PY_SOCKET
extern const mp_obj_type_t mp_type_socket;
#endif
@@ -277,12 +279,34 @@ STATIC mp_obj_t poll_iternext(mp_obj_t self_in) {
return MP_OBJ_STOP_ITERATION;
}
+#if DEBUG
+STATIC mp_obj_t poll_dump(mp_obj_t self_in) {
+ mp_obj_poll_t *self = MP_OBJ_TO_PTR(self_in);
+
+ struct pollfd *entries = self->entries;
+ for (int i = self->len - 1; i >= 0; i--) {
+ printf("fd: %d ev: %x rev: %x", entries->fd, entries->events, entries->revents);
+ if (self->obj_map) {
+ printf(" obj: %p", self->obj_map[entries - self->entries]);
+ }
+ printf("\n");
+ entries++;
+ }
+
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_1(poll_dump_obj, poll_dump);
+#endif
+
STATIC const mp_rom_map_elem_t poll_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_register), MP_ROM_PTR(&poll_register_obj) },
{ MP_ROM_QSTR(MP_QSTR_unregister), MP_ROM_PTR(&poll_unregister_obj) },
{ MP_ROM_QSTR(MP_QSTR_modify), MP_ROM_PTR(&poll_modify_obj) },
{ MP_ROM_QSTR(MP_QSTR_poll), MP_ROM_PTR(&poll_poll_obj) },
{ MP_ROM_QSTR(MP_QSTR_ipoll), MP_ROM_PTR(&poll_ipoll_obj) },
+ #if DEBUG
+ { MP_ROM_QSTR(MP_QSTR_dump), MP_ROM_PTR(&poll_dump_obj) },
+ #endif
};
STATIC MP_DEFINE_CONST_DICT(poll_locals_dict, poll_locals_dict_table);
diff --git a/ports/unix/modusocket.c b/ports/unix/modusocket.c
index cfb6a9f5e..ba50e6165 100644
--- a/ports/unix/modusocket.c
+++ b/ports/unix/modusocket.c
@@ -108,19 +108,26 @@ STATIC mp_uint_t socket_write(mp_obj_t o_in, const void *buf, mp_uint_t size, in
return r;
}
-STATIC mp_obj_t socket_close(mp_obj_t self_in) {
- mp_obj_socket_t *self = MP_OBJ_TO_PTR(self_in);
- // There's a POSIX drama regarding return value of close in general,
- // and EINTR error in particular. See e.g.
- // http://lwn.net/Articles/576478/
- // http://austingroupbugs.net/view.php?id=529
- // The rationale MicroPython follows is that close() just releases
- // file descriptor. If you're interested to catch I/O errors before
- // closing fd, fsync() it.
- close(self->fd);
- return mp_const_none;
+STATIC mp_uint_t socket_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg, int *errcode) {
+ mp_obj_socket_t *self = MP_OBJ_TO_PTR(o_in);
+ (void)arg;
+ switch (request) {
+ case MP_STREAM_CLOSE:
+ // There's a POSIX drama regarding return value of close in general,
+ // and EINTR error in particular. See e.g.
+ // http://lwn.net/Articles/576478/
+ // http://austingroupbugs.net/view.php?id=529
+ // The rationale MicroPython follows is that close() just releases
+ // file descriptor. If you're interested to catch I/O errors before
+ // closing fd, fsync() it.
+ close(self->fd);
+ return 0;
+
+ default:
+ *errcode = MP_EINVAL;
+ return MP_STREAM_ERROR;
+ }
}
-STATIC MP_DEFINE_CONST_FUN_OBJ_1(socket_close_obj, socket_close);
STATIC mp_obj_t socket_fileno(mp_obj_t self_in) {
mp_obj_socket_t *self = MP_OBJ_TO_PTR(self_in);
@@ -359,7 +366,7 @@ STATIC const mp_rom_map_elem_t usocket_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_sendto), MP_ROM_PTR(&socket_sendto_obj) },
{ MP_ROM_QSTR(MP_QSTR_setsockopt), MP_ROM_PTR(&socket_setsockopt_obj) },
{ MP_ROM_QSTR(MP_QSTR_setblocking), MP_ROM_PTR(&socket_setblocking_obj) },
- { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&socket_close_obj) },
+ { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) },
};
STATIC MP_DEFINE_CONST_DICT(usocket_locals_dict, usocket_locals_dict_table);
@@ -367,6 +374,7 @@ STATIC MP_DEFINE_CONST_DICT(usocket_locals_dict, usocket_locals_dict_table);
STATIC const mp_stream_p_t usocket_stream_p = {
.read = socket_read,
.write = socket_write,
+ .ioctl = socket_ioctl,
};
const mp_obj_type_t mp_type_socket = {
diff --git a/ports/unix/mpconfigport.h b/ports/unix/mpconfigport.h
index db382e0a7..e0f9d9995 100644
--- a/ports/unix/mpconfigport.h
+++ b/ports/unix/mpconfigport.h
@@ -83,6 +83,7 @@
#define MICROPY_PY_BUILTINS_NOTIMPLEMENTED (1)
#define MICROPY_PY_BUILTINS_INPUT (1)
#define MICROPY_PY_BUILTINS_POW3 (1)
+#define MICROPY_PY_BUILTINS_ROUND_INT (1)
#define MICROPY_PY_MICROPYTHON_MEM_INFO (1)
#define MICROPY_PY_ALL_SPECIAL_METHODS (1)
#define MICROPY_PY_REVERSE_SPECIAL_METHODS (1)
@@ -97,18 +98,21 @@
#define MICROPY_PY_SYS_MAXSIZE (1)
#define MICROPY_PY_SYS_STDFILES (1)
#define MICROPY_PY_SYS_EXC_INFO (1)
+#define MICROPY_PY_COLLECTIONS_DEQUE (1)
#define MICROPY_PY_COLLECTIONS_ORDEREDDICT (1)
#ifndef MICROPY_PY_MATH_SPECIAL_FUNCTIONS
#define MICROPY_PY_MATH_SPECIAL_FUNCTIONS (1)
#endif
#define MICROPY_PY_CMATH (1)
+#define MICROPY_PY_IO_IOBASE (1)
#define MICROPY_PY_IO_FILEIO (1)
-#define MICROPY_PY_IO_RESOURCE_STREAM (1)
#define MICROPY_PY_GC_COLLECT_RETVAL (1)
#define MICROPY_MODULE_FROZEN_STR (1)
+#ifndef MICROPY_STACKLESS
#define MICROPY_STACKLESS (0)
#define MICROPY_STACKLESS_STRICT (0)
+#endif
#define MICROPY_PY_OS_STATVFS (1)
#define MICROPY_PY_UTIME (1)
@@ -121,7 +125,7 @@
#define MICROPY_PY_UHEAPQ (1)
#define MICROPY_PY_UTIMEQ (1)
#define MICROPY_PY_UHASHLIB (1)
-#if MICROPY_PY_USSL && MICROPY_SSL_AXTLS
+#if MICROPY_PY_USSL
#define MICROPY_PY_UHASHLIB_SHA1 (1)
#endif
#define MICROPY_PY_UBINASCII (1)
@@ -177,9 +181,9 @@ extern const struct _mp_obj_module_t mp_module_ffi;
extern const struct _mp_obj_module_t mp_module_jni;
#if MICROPY_PY_UOS_VFS
-#define MICROPY_PY_UOS_VFS_DEF { MP_ROM_QSTR(MP_QSTR_uos_vfs), MP_ROM_PTR(&mp_module_uos_vfs) },
+#define MICROPY_PY_UOS_DEF { MP_ROM_QSTR(MP_QSTR_uos), MP_ROM_PTR(&mp_module_uos_vfs) },
#else
-#define MICROPY_PY_UOS_VFS_DEF
+#define MICROPY_PY_UOS_DEF { MP_ROM_QSTR(MP_QSTR_uos), MP_ROM_PTR(&mp_module_os) },
#endif
#if MICROPY_PY_FFI
#define MICROPY_PY_FFI_DEF { MP_ROM_QSTR(MP_QSTR_ffi), MP_ROM_PTR(&mp_module_ffi) },
@@ -218,8 +222,7 @@ extern const struct _mp_obj_module_t mp_module_jni;
MICROPY_PY_UTIME_DEF \
MICROPY_PY_SOCKET_DEF \
{ MP_ROM_QSTR(MP_QSTR_umachine), MP_ROM_PTR(&mp_module_machine) }, \
- { MP_ROM_QSTR(MP_QSTR_uos), MP_ROM_PTR(&mp_module_os) }, \
- MICROPY_PY_UOS_VFS_DEF \
+ MICROPY_PY_UOS_DEF \
MICROPY_PY_USELECT_DEF \
MICROPY_PY_TERMIOS_DEF \
diff --git a/ports/unix/mpconfigport_coverage.h b/ports/unix/mpconfigport_coverage.h
index 86d95eb39..97c05cfee 100644
--- a/ports/unix/mpconfigport_coverage.h
+++ b/ports/unix/mpconfigport_coverage.h
@@ -34,14 +34,28 @@
#define MICROPY_FLOAT_HIGH_QUALITY_HASH (1)
#define MICROPY_ENABLE_SCHEDULER (1)
+#define MICROPY_READER_VFS (1)
#define MICROPY_PY_DELATTR_SETATTR (1)
#define MICROPY_PY_REVERSE_SPECIAL_METHODS (1)
+#define MICROPY_PY_BUILTINS_RANGE_BINOP (1)
#define MICROPY_PY_BUILTINS_HELP (1)
#define MICROPY_PY_BUILTINS_HELP_MODULES (1)
#define MICROPY_PY_SYS_GETSIZEOF (1)
#define MICROPY_PY_URANDOM_EXTRA_FUNCS (1)
#define MICROPY_PY_IO_BUFFEREDWRITER (1)
+#define MICROPY_PY_IO_RESOURCE_STREAM (1)
+#define MICROPY_VFS_POSIX (1)
#undef MICROPY_VFS_FAT
#define MICROPY_VFS_FAT (1)
#define MICROPY_FATFS_USE_LABEL (1)
#define MICROPY_PY_FRAMEBUF (1)
+#define MICROPY_PY_COLLECTIONS_NAMEDTUPLE__ASDICT (1)
+
+// TODO these should be generic, not bound to fatfs
+#define mp_type_fileio mp_type_vfs_posix_fileio
+#define mp_type_textio mp_type_vfs_posix_textio
+
+// use vfs's functions for import stat and builtin open
+#define mp_import_stat mp_vfs_import_stat
+#define mp_builtin_open mp_vfs_open
+#define mp_builtin_open_obj mp_vfs_open_obj
diff --git a/ports/unix/mpthreadport.c b/ports/unix/mpthreadport.c
index 8c636a445..baca0a2b1 100644
--- a/ports/unix/mpthreadport.c
+++ b/ports/unix/mpthreadport.c
@@ -66,6 +66,10 @@ STATIC void mp_thread_gc(int signo, siginfo_t *info, void *context) {
// that we don't need the extra information, enough is captured by the
// gc_collect_regs_and_stack function above
//gc_collect_root((void**)context, sizeof(ucontext_t) / sizeof(uintptr_t));
+ #if MICROPY_ENABLE_PYSTACK
+ void **ptrs = (void**)(void*)MP_STATE_THREAD(pystack_start);
+ gc_collect_root(ptrs, (MP_STATE_THREAD(pystack_cur) - MP_STATE_THREAD(pystack_start)) / sizeof(void*));
+ #endif
thread_signal_done = 1;
}
}
diff --git a/ports/windows/Makefile b/ports/windows/Makefile
index b6433300f..725cb686e 100644
--- a/ports/windows/Makefile
+++ b/ports/windows/Makefile
@@ -50,10 +50,6 @@ CFLAGS_MOD += -DMICROPY_USE_READLINE=2
LDFLAGS_MOD += -lreadline
endif
-ifeq ($(CROSS_COMPILE),x86_64-w64-mingw32-)
-CFLAGS_MOD += -DMICROPY_NLR_SETJMP=1
-endif
-
LIB += -lws2_32
# List of sources for qstr extraction
diff --git a/ports/windows/mpconfigport.h b/ports/windows/mpconfigport.h
index abad35282..9db6d31ce 100644
--- a/ports/windows/mpconfigport.h
+++ b/ports/windows/mpconfigport.h
@@ -41,6 +41,7 @@
#define MICROPY_COMP_RETURN_IF_EXPR (1)
#define MICROPY_ENABLE_GC (1)
#define MICROPY_ENABLE_FINALISER (1)
+#define MICROPY_ENABLE_PYSTACK (1)
#define MICROPY_STACK_CHECK (1)
#define MICROPY_MALLOC_USES_ALLOCATED_SIZE (1)
#define MICROPY_MEM_STATS (1)
@@ -56,6 +57,7 @@
#define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_DOUBLE)
#define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_MPZ)
#define MICROPY_STREAMS_NON_BLOCK (1)
+#define MICROPY_STREAMS_POSIX_API (1)
#define MICROPY_OPT_COMPUTED_GOTO (0)
#define MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE (1)
#define MICROPY_CAN_OVERRIDE_BUILTINS (1)
@@ -73,6 +75,7 @@
#define MICROPY_PY_BUILTINS_POW3 (1)
#define MICROPY_PY_MICROPYTHON_MEM_INFO (1)
#define MICROPY_PY_ALL_SPECIAL_METHODS (1)
+#define MICROPY_PY_REVERSE_SPECIAL_METHODS (1)
#define MICROPY_PY_ARRAY_SLICE_ASSIGN (1)
#define MICROPY_PY_BUILTINS_SLICE_ATTRS (1)
#define MICROPY_PY_SYS_EXIT (1)
@@ -80,6 +83,7 @@
#define MICROPY_PY_SYS_MAXSIZE (1)
#define MICROPY_PY_SYS_STDFILES (1)
#define MICROPY_PY_SYS_EXC_INFO (1)
+#define MICROPY_PY_COLLECTIONS_DEQUE (1)
#define MICROPY_PY_COLLECTIONS_ORDEREDDICT (1)
#define MICROPY_PY_MATH_SPECIAL_FUNCTIONS (1)
#define MICROPY_PY_CMATH (1)
@@ -109,9 +113,12 @@
#define MICROPY_MACHINE_MEM_GET_WRITE_ADDR mod_machine_mem_get_addr
#define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_DETAILED)
+#define MICROPY_ERROR_PRINTER (&mp_stderr_print)
#define MICROPY_WARNINGS (1)
#define MICROPY_PY_STR_BYTES_CMP_WARN (1)
+extern const struct _mp_print_t mp_stderr_print;
+
#ifdef _MSC_VER
#define MICROPY_GCREGS_SETJMP (1)
#endif
@@ -232,6 +239,7 @@ typedef __int64 ssize_t;
#define SSIZE_MAX _I32_MAX
typedef int ssize_t;
#endif
+typedef mp_off_t off_t;
// Put static/global variables in sections with a known name
diff --git a/ports/zephyr/CMakeLists.txt b/ports/zephyr/CMakeLists.txt
new file mode 100644
index 000000000..84b0e8190
--- /dev/null
+++ b/ports/zephyr/CMakeLists.txt
@@ -0,0 +1,21 @@
+include($ENV{ZEPHYR_BASE}/cmake/app/boilerplate.cmake NO_POLICY_SCOPE)
+project(NONE)
+
+target_sources(app PRIVATE src/zephyr_start.c src/zephyr_getchar.c)
+
+add_library(libmicropython STATIC IMPORTED)
+set_target_properties(libmicropython PROPERTIES IMPORTED_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/libmicropython.a)
+target_link_libraries(app libmicropython)
+
+zephyr_get_include_directories_for_lang_as_string(C includes)
+zephyr_get_system_include_directories_for_lang_as_string(C system_includes)
+zephyr_get_compile_definitions_for_lang_as_string(C definitions)
+zephyr_get_compile_options_for_lang_as_string(C options)
+
+add_custom_target(
+ outputexports
+ COMMAND echo CC="${CMAKE_C_COMPILER}"
+ COMMAND echo Z_CFLAGS=${system_includes} ${includes} ${definitions} ${options}
+ VERBATIM
+ USES_TERMINAL
+)
diff --git a/ports/zephyr/Makefile b/ports/zephyr/Makefile
index 2e6cb41b9..8cb4c12ef 100644
--- a/ports/zephyr/Makefile
+++ b/ports/zephyr/Makefile
@@ -20,15 +20,15 @@ FROZEN_DIR = scripts
# Default target
all:
+include ../../py/mkenv.mk
+include $(TOP)/py/py.mk
+
# Zephyr (generated) config files - must be defined before include below
Z_EXPORTS = outdir/$(OUTDIR_PREFIX)/Makefile.export
ifneq ($(MAKECMDGOALS), clean)
include $(Z_EXPORTS)
endif
-include ../../py/mkenv.mk
-include $(TOP)/py/py.mk
-
INC += -I.
INC += -I$(TOP)
INC += -I$(BUILD)
@@ -41,6 +41,7 @@ SRC_C = main.c \
modusocket.c \
modutime.c \
modzephyr.c \
+ modzsensor.c \
modmachine.c \
machine_pin.c \
uart_core.c \
@@ -56,19 +57,11 @@ SRC_QSTR += $(SRC_C)
OBJ = $(PY_O) $(addprefix $(BUILD)/, $(SRC_C:.c=.o))
-CFLAGS = $(KBUILD_CFLAGS) $(NOSTDINC_FLAGS) $(ZEPHYRINCLUDE) \
+CFLAGS = $(Z_CFLAGS) \
-std=gnu99 -fomit-frame-pointer -DNDEBUG -DMICROPY_HEAP_SIZE=$(MICROPY_HEAP_SIZE) $(CFLAGS_EXTRA) $(INC)
include $(TOP)/py/mkrules.mk
-# We use single target here ($(Z_EXPORTS)) for simplicity, but actually
-# number of things get generated here: 'initconfig' generates C header for
-# Kconfig configuration, 'outputexports' generates make environment with CC,
-# etc., and 'lib' generates other headers which may be included by zephyr.h,
-# e.g. DTS-related.
-$(Z_EXPORTS): $(CONF_FILE)
- $(MAKE) -f Makefile.zephyr BOARD=$(BOARD) CONF_FILE=$(CONF_FILE) initconfig outputexports lib
-
GENERIC_TARGETS = all zephyr run qemu qemugdb flash debug debugserver
KCONFIG_TARGETS = \
initconfig config nconfig menuconfig xconfig gconfig \
@@ -81,7 +74,7 @@ $(GENERIC_TARGETS): $(LIBMICROPYTHON)
$(CLEAN_TARGETS): clean
$(GENERIC_TARGETS) $(KCONFIG_TARGETS) $(CLEAN_TARGETS):
- $(MAKE) -f Makefile.zephyr BOARD=$(BOARD) CONF_FILE=$(CONF_FILE) $@
+ $(MAKE) -C outdir/$(BOARD) $@
$(LIBMICROPYTHON): | $(Z_EXPORTS)
build/genhdr/qstr.i.last: | $(Z_EXPORTS)
@@ -90,16 +83,27 @@ build/genhdr/qstr.i.last: | $(Z_EXPORTS)
LIBMICROPYTHON_EXTRA_CMD = -$(RM) -f outdir/$(OUTDIR_PREFIX)/zephyr.lnk
# MicroPython's global clean cleans everything, fast
-CLEAN_EXTRA = outdir
+CLEAN_EXTRA = outdir libmicropython.a prj_*_merged.conf
# Clean Zephyr things in Zephyr way
z_clean:
$(MAKE) -f Makefile.zephyr BOARD=$(BOARD) clean
# This rule is for prj_$(BOARD)_merged.conf, not $(CONF_FILE), which
-# can be overriden
-prj_$(BOARD)_merged.conf: prj_base.conf prj_$(BOARD).conf
+# can be overriden.
+# prj_$(BOARD).conf is optional, that's why it's resolved with $(wildcard)
+# function.
+prj_$(BOARD)_merged.conf: prj_base.conf $(wildcard prj_$(BOARD).conf)
$(PYTHON) makeprj.py prj_base.conf prj_$(BOARD).conf $@
test:
cd $(TOP)/tests && ./run-tests --target minimal --device "execpty:make -C ../ports/zephyr run BOARD=$(BOARD) QEMU_PTY=1"
+
+cmake: outdir/$(BOARD)/Makefile
+
+outdir/$(BOARD)/Makefile: $(CONF_FILE)
+ mkdir -p outdir/$(BOARD) && cmake -DBOARD=$(BOARD) -DCONF_FILE=$(CONF_FILE) -Boutdir/$(BOARD) -H.
+
+$(Z_EXPORTS): outdir/$(BOARD)/Makefile
+ make --no-print-directory -C outdir/$(BOARD) outputexports CMAKE_COMMAND=: >$@
+ make -C outdir/$(BOARD) syscall_macros_h_target syscall_list_h_target kobj_types_h_target
diff --git a/ports/zephyr/README.md b/ports/zephyr/README.md
index 018b4ce71..f7001af4b 100644
--- a/ports/zephyr/README.md
+++ b/ports/zephyr/README.md
@@ -46,7 +46,7 @@ Running
To run the resulting firmware in QEMU (for BOARDs like qemu_x86,
qemu_cortex_m3):
- make qemu
+ make run
With the default configuration, networking is now enabled, so you need to
follow instructions in https://wiki.zephyrproject.org/view/Networking-with-Qemu
@@ -110,4 +110,4 @@ To make a minimal build:
To run a minimal build in QEMU without requiring TAP networking setup
run the following after you built image with the previous command:
- ./make-minimal BOARD=<qemu_x86|qemu_cortex_m3> qemu
+ ./make-minimal BOARD=<qemu_x86_nommu|qemu_x86|qemu_cortex_m3> run
diff --git a/ports/zephyr/main.c b/ports/zephyr/main.c
index 7eb9da3e1..a28fb3792 100644
--- a/ports/zephyr/main.c
+++ b/ports/zephyr/main.c
@@ -4,7 +4,7 @@
* The MIT License (MIT)
*
* Copyright (c) 2013, 2014 Damien P. George
- * Copyright (c) 2016 Linaro Limited
+ * Copyright (c) 2016-2017 Linaro Limited
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -41,20 +41,12 @@
#include "lib/utils/pyexec.h"
#include "lib/mp-readline/readline.h"
-void do_str(const char *src, mp_parse_input_kind_t input_kind) {
- nlr_buf_t nlr;
- if (nlr_push(&nlr) == 0) {
- mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, src, strlen(src), 0);
- qstr source_name = lex->source_name;
- mp_parse_tree_t parse_tree = mp_parse(lex, input_kind);
- mp_obj_t module_fun = mp_compile(&parse_tree, source_name, MP_EMIT_OPT_NONE, true);
- mp_call_function_0(module_fun);
- nlr_pop();
- } else {
- // uncaught exception
- mp_obj_print_exception(&mp_plat_print, (mp_obj_t)nlr.ret_val);
- }
-}
+#ifdef TEST
+#include "lib/upytesthelper/upytesthelper.h"
+#include "lib/tinytest/tinytest.c"
+#include "lib/upytesthelper/upytesthelper.c"
+#include TEST
+#endif
static char *stack_top;
static char heap[MICROPY_HEAP_SIZE];
@@ -95,6 +87,13 @@ int real_main(void) {
init_zephyr();
+ #ifdef TEST
+ static const char *argv[] = {"test"};
+ upytest_set_heap(heap, heap + sizeof(heap));
+ int r = tinytest_main(1, argv, groups);
+ printf("status: %d\n", r);
+ #endif
+
soft_reset:
#if MICROPY_ENABLE_GC
gc_init(heap, heap + sizeof(heap));
diff --git a/ports/zephyr/make-bin-testsuite b/ports/zephyr/make-bin-testsuite
new file mode 100755
index 000000000..f6aeb83f8
--- /dev/null
+++ b/ports/zephyr/make-bin-testsuite
@@ -0,0 +1,20 @@
+#!/bin/sh
+#
+# This is a wrapper for make to build a binary with builtin testsuite.
+# It should be run just like make (i.e. extra vars can be passed on the
+# command line, etc.), e.g.:
+#
+# ./make-bin-testsuite BOARD=qemu_cortex_m3
+# ./make-bin-testsuite BOARD=qemu_cortex_m3 run
+#
+
+(cd ../../tests; ./run-tests --write-exp)
+(cd ../../tests; ./run-tests --list-tests --target=minimal \
+ -e async -e intbig -e int_big -e builtin_help -e memstats -e bytes_compare3 -e class_reverse_op \
+ -e /set -e frozenset -e complex -e const -e native -e viper \
+ -e 'float_divmod\.' -e float_parse_doubleprec -e float/true_value -e float/types \
+ | ../tools/tinytest-codegen.py --stdin) > bin-testsuite.c
+
+make \
+ CFLAGS_EXTRA='-DMP_CONFIGFILE="<mpconfigport_bin_testsuite.h>" -DTEST=\"bin-testsuite.c\" -DNO_FORKING' \
+ "$@"
diff --git a/ports/zephyr/modusocket.c b/ports/zephyr/modusocket.c
index e021c3a44..84d6fa729 100644
--- a/ports/zephyr/modusocket.c
+++ b/ports/zephyr/modusocket.c
@@ -91,7 +91,7 @@ STATIC mp_obj_t format_inet_addr(struct sockaddr *addr, mp_obj_t port) {
net_addr_ntop(addr->sa_family, &sockaddr_in6->sin6_addr, buf, sizeof(buf));
mp_obj_tuple_t *tuple = mp_obj_new_tuple(addr->sa_family == AF_INET ? 2 : 4, NULL);
- tuple->items[0] = mp_obj_new_str(buf, strlen(buf), false);
+ tuple->items[0] = mp_obj_new_str(buf, strlen(buf));
// We employ the fact that port offset is the same for IPv4 & IPv6
// not filled in
//tuple->items[1] = mp_obj_new_int(ntohs(((struct sockaddr_in*)addr)->sin_port));
@@ -299,20 +299,31 @@ STATIC mp_obj_t socket_makefile(size_t n_args, const mp_obj_t *args) {
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(socket_makefile_obj, 1, 3, socket_makefile);
-STATIC mp_obj_t socket_close(mp_obj_t self_in) {
- socket_obj_t *socket = self_in;
- if (socket->ctx != -1) {
- int res = zsock_close(socket->ctx);
- RAISE_SOCK_ERRNO(res);
- socket->ctx = -1;
+STATIC mp_uint_t sock_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg, int *errcode) {
+ socket_obj_t *socket = o_in;
+ (void)arg;
+ switch (request) {
+ case MP_STREAM_CLOSE:
+ if (socket->ctx != -1) {
+ int res = zsock_close(socket->ctx);
+ RAISE_SOCK_ERRNO(res);
+ if (res == -1) {
+ *errcode = errno;
+ return MP_STREAM_ERROR;
+ }
+ socket->ctx = -1;
+ }
+ return 0;
+
+ default:
+ *errcode = MP_EINVAL;
+ return MP_STREAM_ERROR;
}
- return mp_const_none;
}
-STATIC MP_DEFINE_CONST_FUN_OBJ_1(socket_close_obj, socket_close);
STATIC const mp_rom_map_elem_t socket_locals_dict_table[] = {
- { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&socket_close_obj) },
- { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&socket_close_obj) },
+ { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mp_stream_close_obj) },
+ { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) },
{ MP_ROM_QSTR(MP_QSTR_bind), MP_ROM_PTR(&socket_bind_obj) },
{ MP_ROM_QSTR(MP_QSTR_connect), MP_ROM_PTR(&socket_connect_obj) },
{ MP_ROM_QSTR(MP_QSTR_listen), MP_ROM_PTR(&socket_listen_obj) },
@@ -332,7 +343,7 @@ STATIC MP_DEFINE_CONST_DICT(socket_locals_dict, socket_locals_dict_table);
STATIC const mp_stream_p_t socket_stream_p = {
.read = sock_read,
.write = sock_write,
- //.ioctl = sock_ioctl,
+ .ioctl = sock_ioctl,
};
STATIC const mp_obj_type_t socket_type = {
diff --git a/ports/zephyr/modzsensor.c b/ports/zephyr/modzsensor.c
new file mode 100644
index 000000000..74c909d16
--- /dev/null
+++ b/ports/zephyr/modzsensor.c
@@ -0,0 +1,146 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018 Linaro Limited
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <string.h>
+
+#include "py/runtime.h"
+
+#include <zephyr.h>
+#include <sensor.h>
+
+#if MICROPY_PY_ZSENSOR
+
+typedef struct _mp_obj_sensor_t {
+ mp_obj_base_t base;
+ struct device *dev;
+} mp_obj_sensor_t;
+
+STATIC mp_obj_t sensor_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
+ mp_arg_check_num(n_args, n_kw, 1, 1, false);
+ mp_obj_sensor_t *o = m_new_obj(mp_obj_sensor_t);
+ o->base.type = type;
+ o->dev = device_get_binding(mp_obj_str_get_str(args[0]));
+ if (o->dev == NULL) {
+ mp_raise_ValueError("dev not found");
+ }
+ return MP_OBJ_FROM_PTR(o);
+}
+
+STATIC mp_obj_t sensor_measure(mp_obj_t self_in) {
+ mp_obj_sensor_t *self = MP_OBJ_TO_PTR(self_in);
+ int st = sensor_sample_fetch(self->dev);
+ if (st != 0) {
+ mp_raise_OSError(-st);
+ }
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_1(sensor_measure_obj, sensor_measure);
+
+STATIC void sensor_get_internal(mp_obj_t self_in, mp_obj_t channel_in, struct sensor_value *res) {
+ mp_obj_sensor_t *self = MP_OBJ_TO_PTR(self_in);
+
+ int st = sensor_channel_get(self->dev, mp_obj_get_int(channel_in), res);
+ if (st != 0) {
+ mp_raise_OSError(-st);
+ }
+}
+
+STATIC mp_obj_t sensor_get_float(mp_obj_t self_in, mp_obj_t channel_in) {
+ struct sensor_value val;
+ sensor_get_internal(self_in, channel_in, &val);
+ return mp_obj_new_float(val.val1 + (mp_float_t)val.val2 / 1000000);
+}
+MP_DEFINE_CONST_FUN_OBJ_2(sensor_get_float_obj, sensor_get_float);
+
+STATIC mp_obj_t sensor_get_micros(mp_obj_t self_in, mp_obj_t channel_in) {
+ struct sensor_value val;
+ sensor_get_internal(self_in, channel_in, &val);
+ return MP_OBJ_NEW_SMALL_INT(val.val1 * 1000000 + val.val2);
+}
+MP_DEFINE_CONST_FUN_OBJ_2(sensor_get_micros_obj, sensor_get_micros);
+
+STATIC mp_obj_t sensor_get_millis(mp_obj_t self_in, mp_obj_t channel_in) {
+ struct sensor_value val;
+ sensor_get_internal(self_in, channel_in, &val);
+ return MP_OBJ_NEW_SMALL_INT(val.val1 * 1000 + val.val2 / 1000);
+}
+MP_DEFINE_CONST_FUN_OBJ_2(sensor_get_millis_obj, sensor_get_millis);
+
+STATIC mp_obj_t sensor_get_int(mp_obj_t self_in, mp_obj_t channel_in) {
+ struct sensor_value val;
+ sensor_get_internal(self_in, channel_in, &val);
+ return MP_OBJ_NEW_SMALL_INT(val.val1);
+}
+MP_DEFINE_CONST_FUN_OBJ_2(sensor_get_int_obj, sensor_get_int);
+
+STATIC const mp_rom_map_elem_t sensor_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_measure), MP_ROM_PTR(&sensor_measure_obj) },
+ { MP_ROM_QSTR(MP_QSTR_get_float), MP_ROM_PTR(&sensor_get_float_obj) },
+ { MP_ROM_QSTR(MP_QSTR_get_micros), MP_ROM_PTR(&sensor_get_micros_obj) },
+ { MP_ROM_QSTR(MP_QSTR_get_millis), MP_ROM_PTR(&sensor_get_millis_obj) },
+ { MP_ROM_QSTR(MP_QSTR_get_int), MP_ROM_PTR(&sensor_get_int_obj) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(sensor_locals_dict, sensor_locals_dict_table);
+
+STATIC const mp_obj_type_t sensor_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_Sensor,
+ .make_new = sensor_make_new,
+ .locals_dict = (void*)&sensor_locals_dict,
+};
+
+STATIC const mp_rom_map_elem_t mp_module_zsensor_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_zsensor) },
+ { MP_ROM_QSTR(MP_QSTR_Sensor), MP_ROM_PTR(&sensor_type) },
+
+#define C(name) { MP_ROM_QSTR(MP_QSTR_ ## name), MP_ROM_INT(SENSOR_CHAN_ ## name) }
+ C(ACCEL_X),
+ C(ACCEL_Y),
+ C(ACCEL_Z),
+ C(GYRO_X),
+ C(GYRO_Y),
+ C(GYRO_Z),
+ C(MAGN_X),
+ C(MAGN_Y),
+ C(MAGN_Z),
+ C(TEMP),
+ C(PRESS),
+ C(PROX),
+ C(HUMIDITY),
+ C(LIGHT),
+ C(ALTITUDE),
+#undef C
+};
+
+STATIC MP_DEFINE_CONST_DICT(mp_module_zsensor_globals, mp_module_zsensor_globals_table);
+
+const mp_obj_module_t mp_module_zsensor = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t*)&mp_module_zsensor_globals,
+};
+
+#endif //MICROPY_PY_UHASHLIB
diff --git a/ports/zephyr/mpconfigport.h b/ports/zephyr/mpconfigport.h
index 7ff05f45a..1ac1c3501 100644
--- a/ports/zephyr/mpconfigport.h
+++ b/ports/zephyr/mpconfigport.h
@@ -67,9 +67,12 @@
#define MICROPY_PY_UERRNO (1)
#define MICROPY_PY_USOCKET (1)
#endif
+#define MICROPY_PY_UBINASCII (1)
+#define MICROPY_PY_UHASHLIB (1)
#define MICROPY_PY_UTIME (1)
#define MICROPY_PY_UTIME_MP_HAL (1)
#define MICROPY_PY_ZEPHYR (1)
+#define MICROPY_PY_ZSENSOR (1)
#define MICROPY_PY_SYS_MODULES (0)
#define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_LONGLONG)
#define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_FLOAT)
@@ -109,6 +112,7 @@ extern const struct _mp_obj_module_t mp_module_machine;
extern const struct _mp_obj_module_t mp_module_time;
extern const struct _mp_obj_module_t mp_module_usocket;
extern const struct _mp_obj_module_t mp_module_zephyr;
+extern const struct _mp_obj_module_t mp_module_zsensor;
#if MICROPY_PY_USOCKET
#define MICROPY_PY_USOCKET_DEF { MP_ROM_QSTR(MP_QSTR_usocket), MP_ROM_PTR(&mp_module_usocket) },
@@ -130,11 +134,18 @@ extern const struct _mp_obj_module_t mp_module_zephyr;
#define MICROPY_PY_ZEPHYR_DEF
#endif
+#if MICROPY_PY_ZSENSOR
+#define MICROPY_PY_ZSENSOR_DEF { MP_ROM_QSTR(MP_QSTR_zsensor), MP_ROM_PTR(&mp_module_zsensor) },
+#else
+#define MICROPY_PY_ZSENSOR_DEF
+#endif
+
#define MICROPY_PORT_BUILTIN_MODULES \
{ MP_ROM_QSTR(MP_QSTR_machine), MP_ROM_PTR(&mp_module_machine) }, \
MICROPY_PY_USOCKET_DEF \
MICROPY_PY_UTIME_DEF \
MICROPY_PY_ZEPHYR_DEF \
+ MICROPY_PY_ZSENSOR_DEF \
#define MICROPY_PORT_BUILTIN_MODULE_WEAK_LINKS \
{ MP_ROM_QSTR(MP_QSTR_time), MP_ROM_PTR(&mp_module_time) }, \
diff --git a/ports/zephyr/mpconfigport_bin_testsuite.h b/ports/zephyr/mpconfigport_bin_testsuite.h
new file mode 100644
index 000000000..684b4f41c
--- /dev/null
+++ b/ports/zephyr/mpconfigport_bin_testsuite.h
@@ -0,0 +1,31 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Linaro Limited
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "mpconfigport.h"
+
+#ifdef TEST
+#include "lib/upytesthelper/upytesthelper.h"
+#define MP_PLAT_PRINT_STRN(str, len) upytest_output(str, len)
+#endif
diff --git a/ports/zephyr/prj_base.conf b/ports/zephyr/prj_base.conf
index fbcedf260..c39779548 100644
--- a/ports/zephyr/prj_base.conf
+++ b/ports/zephyr/prj_base.conf
@@ -1,4 +1,4 @@
-CONFIG_LEGACY_KERNEL=n
+CONFIG_BUILD_OUTPUT_BIN=y
CONFIG_REBOOT=y
CONFIG_STDOUT_CONSOLE=y
@@ -12,7 +12,11 @@ CONFIG_CONSOLE_PUTCHAR_BUFSIZE=128
CONFIG_NEWLIB_LIBC=y
CONFIG_FLOAT=y
-CONFIG_MAIN_STACK_SIZE=4096
+CONFIG_MAIN_STACK_SIZE=4736
+
+# Enable sensor subsystem (doesn't add code if not used).
+# Specific sensors should be enabled per-board.
+CONFIG_SENSOR=y
# Networking config
CONFIG_NETWORKING=y
@@ -28,16 +32,22 @@ CONFIG_NET_APP_SETTINGS=y
CONFIG_NET_APP_INIT_TIMEOUT=3
CONFIG_NET_APP_NEED_IPV6=y
CONFIG_NET_APP_NEED_IPV4=y
-CONFIG_NET_APP_MY_IPV6_ADDR="2001:db8::1"
-CONFIG_NET_APP_MY_IPV4_ADDR="192.0.2.1"
-CONFIG_NET_APP_MY_IPV4_GW="192.0.2.2"
# DNS
CONFIG_DNS_RESOLVER=y
CONFIG_DNS_RESOLVER_ADDITIONAL_QUERIES=2
CONFIG_DNS_SERVER_IP_ADDRESSES=y
+
+# Static IP addresses
+CONFIG_NET_APP_MY_IPV6_ADDR="2001:db8::1"
+CONFIG_NET_APP_MY_IPV4_ADDR="192.0.2.1"
+CONFIG_NET_APP_MY_IPV4_GW="192.0.2.2"
CONFIG_DNS_SERVER1="192.0.2.2"
+# DHCP configuration. Until DHCP address is assigned,
+# static configuration above is used instead.
+CONFIG_NET_DHCPV4=y
+
# Diagnostics and debugging
# Required for zephyr.stack_analyze()
diff --git a/ports/zephyr/prj_disco_l475_iot1.conf b/ports/zephyr/prj_disco_l475_iot1.conf
new file mode 100644
index 000000000..36c8b99dd
--- /dev/null
+++ b/ports/zephyr/prj_disco_l475_iot1.conf
@@ -0,0 +1,5 @@
+# Sensors
+CONFIG_HTS221=y
+CONFIG_LIS3MDL=y
+CONFIG_LPS22HB=y
+CONFIG_LSM6DSL=y