aboutsummaryrefslogtreecommitdiff
path: root/ports/stm32
diff options
context:
space:
mode:
authorDamien George2017-09-06 13:40:51 +1000
committerDamien George2017-09-06 13:40:51 +1000
commit01dd7804b87d60b2deab16712eccb3b97351a9b7 (patch)
tree1aa21f38a872b8e62a3d4e4f74f68033c6f827e4 /ports/stm32
parenta9862b30068fc9df1022f08019fb35aaa5085f64 (diff)
ports: Make new ports/ sub-directory and move all ports there.
This is to keep the top-level directory clean, to make it clear what is core and what is a port, and to allow the repository to grow with new ports in a sustainable way.
Diffstat (limited to 'ports/stm32')
-rw-r--r--ports/stm32/.gitignore1
-rw-r--r--ports/stm32/Makefile480
-rw-r--r--ports/stm32/README.md115
-rw-r--r--ports/stm32/accel.c234
-rw-r--r--ports/stm32/accel.h33
-rw-r--r--ports/stm32/adc.c678
-rw-r--r--ports/stm32/adc.h32
-rwxr-xr-xports/stm32/autoflash44
-rw-r--r--ports/stm32/boards/CERB40/mpconfigboard.h67
-rw-r--r--ports/stm32/boards/CERB40/mpconfigboard.mk4
-rw-r--r--ports/stm32/boards/CERB40/pins.csv46
-rw-r--r--ports/stm32/boards/CERB40/stm32f4xx_hal_conf.h411
-rw-r--r--ports/stm32/boards/ESPRUINO_PICO/mpconfigboard.h72
-rw-r--r--ports/stm32/boards/ESPRUINO_PICO/mpconfigboard.mk7
-rw-r--r--ports/stm32/boards/ESPRUINO_PICO/pins.csv34
-rw-r--r--ports/stm32/boards/ESPRUINO_PICO/stm32f4xx_hal_conf.h411
-rw-r--r--ports/stm32/boards/HYDRABUS/mpconfigboard.h81
-rw-r--r--ports/stm32/boards/HYDRABUS/mpconfigboard.mk4
-rw-r--r--ports/stm32/boards/HYDRABUS/pins.csv52
-rw-r--r--ports/stm32/boards/HYDRABUS/stm32f4xx_hal_conf.h411
-rw-r--r--ports/stm32/boards/LIMIFROG/board_init.c154
-rw-r--r--ports/stm32/boards/LIMIFROG/mpconfigboard.h61
-rw-r--r--ports/stm32/boards/LIMIFROG/mpconfigboard.mk5
-rw-r--r--ports/stm32/boards/LIMIFROG/pins.csv114
-rw-r--r--ports/stm32/boards/LIMIFROG/stm32l4xx_hal_conf.h373
-rw-r--r--ports/stm32/boards/NETDUINO_PLUS_2/board_init.c24
-rw-r--r--ports/stm32/boards/NETDUINO_PLUS_2/mpconfigboard.h73
-rw-r--r--ports/stm32/boards/NETDUINO_PLUS_2/mpconfigboard.mk4
-rw-r--r--ports/stm32/boards/NETDUINO_PLUS_2/pins.csv35
-rw-r--r--ports/stm32/boards/NETDUINO_PLUS_2/stm32f4xx_hal_conf.h411
-rw-r--r--ports/stm32/boards/NUCLEO_F401RE/mpconfigboard.h57
-rw-r--r--ports/stm32/boards/NUCLEO_F401RE/mpconfigboard.mk4
-rw-r--r--ports/stm32/boards/NUCLEO_F401RE/pins.csv75
-rw-r--r--ports/stm32/boards/NUCLEO_F401RE/stm32f4xx_hal_conf.h413
-rw-r--r--ports/stm32/boards/NUCLEO_F411RE/mpconfigboard.h68
-rw-r--r--ports/stm32/boards/NUCLEO_F411RE/mpconfigboard.mk4
-rw-r--r--ports/stm32/boards/NUCLEO_F411RE/pins.csv75
-rw-r--r--ports/stm32/boards/NUCLEO_F411RE/stm32f4xx_hal_conf.h413
-rw-r--r--ports/stm32/boards/NUCLEO_F429ZI/mpconfigboard.h83
-rw-r--r--ports/stm32/boards/NUCLEO_F429ZI/mpconfigboard.mk4
-rw-r--r--ports/stm32/boards/NUCLEO_F429ZI/pins.csv117
-rw-r--r--ports/stm32/boards/NUCLEO_F429ZI/stm32f4xx_hal_conf.h411
-rw-r--r--ports/stm32/boards/NUCLEO_F446RE/mpconfigboard.h64
-rw-r--r--ports/stm32/boards/NUCLEO_F446RE/mpconfigboard.mk4
-rw-r--r--ports/stm32/boards/NUCLEO_F446RE/pins.csv72
-rw-r--r--ports/stm32/boards/NUCLEO_F446RE/stm32f4xx_hal_conf.h413
-rw-r--r--ports/stm32/boards/NUCLEO_F767ZI/mpconfigboard.h76
-rw-r--r--ports/stm32/boards/NUCLEO_F767ZI/mpconfigboard.mk5
-rw-r--r--ports/stm32/boards/NUCLEO_F767ZI/pins.csv68
-rw-r--r--ports/stm32/boards/NUCLEO_F767ZI/stm32f7xx_hal_conf.h429
-rw-r--r--ports/stm32/boards/NUCLEO_L476RG/mpconfigboard.h53
-rw-r--r--ports/stm32/boards/NUCLEO_L476RG/mpconfigboard.mk5
-rw-r--r--ports/stm32/boards/NUCLEO_L476RG/pins.csv76
-rwxr-xr-xports/stm32/boards/NUCLEO_L476RG/stm32l4xx_hal_conf.h373
-rw-r--r--ports/stm32/boards/OLIMEX_E407/mpconfigboard.h80
-rw-r--r--ports/stm32/boards/OLIMEX_E407/mpconfigboard.mk4
-rw-r--r--ports/stm32/boards/OLIMEX_E407/pins.csv85
-rw-r--r--ports/stm32/boards/OLIMEX_E407/stm32f4xx_hal_conf.h411
-rw-r--r--ports/stm32/boards/PYBLITEV10/mpconfigboard.h87
-rw-r--r--ports/stm32/boards/PYBLITEV10/mpconfigboard.mk4
-rw-r--r--ports/stm32/boards/PYBLITEV10/pins.csv60
-rw-r--r--ports/stm32/boards/PYBLITEV10/stm32f4xx_hal_conf.h411
-rw-r--r--ports/stm32/boards/PYBV10/mpconfigboard.h99
-rw-r--r--ports/stm32/boards/PYBV10/mpconfigboard.mk4
-rw-r--r--ports/stm32/boards/PYBV10/pins.csv59
-rw-r--r--ports/stm32/boards/PYBV10/stm32f4xx_hal_conf.h411
-rw-r--r--ports/stm32/boards/PYBV11/mpconfigboard.h99
-rw-r--r--ports/stm32/boards/PYBV11/mpconfigboard.mk4
-rw-r--r--ports/stm32/boards/PYBV11/pins.csv59
-rw-r--r--ports/stm32/boards/PYBV11/stm32f4xx_hal_conf.h411
-rw-r--r--ports/stm32/boards/PYBV3/mpconfigboard.h88
-rw-r--r--ports/stm32/boards/PYBV3/mpconfigboard.mk4
-rw-r--r--ports/stm32/boards/PYBV3/pins.csv46
-rw-r--r--ports/stm32/boards/PYBV3/stm32f4xx_hal_conf.h411
-rw-r--r--ports/stm32/boards/PYBV4/mpconfigboard.h96
-rw-r--r--ports/stm32/boards/PYBV4/mpconfigboard.mk4
-rw-r--r--ports/stm32/boards/PYBV4/pins.csv59
-rw-r--r--ports/stm32/boards/PYBV4/stm32f4xx_hal_conf.h411
-rw-r--r--ports/stm32/boards/STM32F411DISC/mpconfigboard.h70
-rw-r--r--ports/stm32/boards/STM32F411DISC/mpconfigboard.mk4
-rw-r--r--ports/stm32/boards/STM32F411DISC/pins.csv84
-rw-r--r--ports/stm32/boards/STM32F411DISC/stm32f4xx_hal_conf.h411
-rw-r--r--ports/stm32/boards/STM32F429DISC/mpconfigboard.h73
-rw-r--r--ports/stm32/boards/STM32F429DISC/mpconfigboard.mk4
-rw-r--r--ports/stm32/boards/STM32F429DISC/pins.csv117
-rw-r--r--ports/stm32/boards/STM32F429DISC/stm32f4xx_hal_conf.h412
-rw-r--r--ports/stm32/boards/STM32F439/mpconfigboard.h85
-rw-r--r--ports/stm32/boards/STM32F439/mpconfigboard.mk4
-rw-r--r--ports/stm32/boards/STM32F439/pins.csv85
-rw-r--r--ports/stm32/boards/STM32F439/stm32f4xx_hal_conf.h411
-rw-r--r--ports/stm32/boards/STM32F4DISC/mpconfigboard.h86
-rw-r--r--ports/stm32/boards/STM32F4DISC/mpconfigboard.mk4
-rw-r--r--ports/stm32/boards/STM32F4DISC/pins.csv85
-rw-r--r--ports/stm32/boards/STM32F4DISC/staccel.py98
-rw-r--r--ports/stm32/boards/STM32F4DISC/stm32f4xx_hal_conf.h411
-rw-r--r--ports/stm32/boards/STM32F769DISC/mpconfigboard.h78
-rw-r--r--ports/stm32/boards/STM32F769DISC/mpconfigboard.mk5
-rw-r--r--ports/stm32/boards/STM32F769DISC/pins.csv57
-rw-r--r--ports/stm32/boards/STM32F769DISC/stm32f7xx_hal_conf.h430
-rw-r--r--ports/stm32/boards/STM32F7DISC/board_init.c15
-rw-r--r--ports/stm32/boards/STM32F7DISC/mpconfigboard.h82
-rw-r--r--ports/stm32/boards/STM32F7DISC/mpconfigboard.mk4
-rw-r--r--ports/stm32/boards/STM32F7DISC/pins.csv53
-rw-r--r--ports/stm32/boards/STM32F7DISC/stm32f7xx_hal_conf.h429
-rw-r--r--ports/stm32/boards/STM32L476DISC/board_init.c10
-rw-r--r--ports/stm32/boards/STM32L476DISC/mpconfigboard.h68
-rw-r--r--ports/stm32/boards/STM32L476DISC/mpconfigboard.mk6
-rw-r--r--ports/stm32/boards/STM32L476DISC/pins.csv114
-rw-r--r--ports/stm32/boards/STM32L476DISC/stm32l4xx_hal_conf.h373
-rw-r--r--ports/stm32/boards/common.ld90
-rwxr-xr-xports/stm32/boards/make-pins.py468
-rw-r--r--ports/stm32/boards/openocd_stm32f4.cfg42
-rw-r--r--ports/stm32/boards/openocd_stm32f7.cfg42
-rw-r--r--ports/stm32/boards/openocd_stm32l4.cfg42
-rw-r--r--ports/stm32/boards/pllvalues.py165
-rw-r--r--ports/stm32/boards/stm32f401_af.csv83
-rw-r--r--ports/stm32/boards/stm32f401xd.ld31
-rw-r--r--ports/stm32/boards/stm32f401xe.ld31
-rw-r--r--ports/stm32/boards/stm32f405.ld32
-rw-r--r--ports/stm32/boards/stm32f405_af.csv142
-rw-r--r--ports/stm32/boards/stm32f411.ld31
-rw-r--r--ports/stm32/boards/stm32f411_af.csv84
-rw-r--r--ports/stm32/boards/stm32f429.ld31
-rw-r--r--ports/stm32/boards/stm32f429_af.csv170
-rw-r--r--ports/stm32/boards/stm32f439.ld29
-rw-r--r--ports/stm32/boards/stm32f439_af.csv170
-rw-r--r--ports/stm32/boards/stm32f4xx_prefix.c32
-rw-r--r--ports/stm32/boards/stm32f746.ld32
-rw-r--r--ports/stm32/boards/stm32f746_af.csv171
-rw-r--r--ports/stm32/boards/stm32f767.ld32
-rw-r--r--ports/stm32/boards/stm32f767_af.csv170
-rw-r--r--ports/stm32/boards/stm32f769.ld32
-rw-r--r--ports/stm32/boards/stm32l476_af.csv116
-rw-r--r--ports/stm32/boards/stm32l476xe.ld35
-rw-r--r--ports/stm32/boards/stm32l476xg.ld37
-rw-r--r--ports/stm32/bufhelper.c54
-rw-r--r--ports/stm32/bufhelper.h32
-rw-r--r--ports/stm32/can.c901
-rw-r--r--ports/stm32/can.h38
-rw-r--r--ports/stm32/dac.c506
-rw-r--r--ports/stm32/dac.h33
-rw-r--r--ports/stm32/dma.c508
-rw-r--r--ports/stm32/dma.h103
-rw-r--r--ports/stm32/extint.c508
-rw-r--r--ports/stm32/extint.h67
-rw-r--r--ports/stm32/fatfs_port.c38
-rw-r--r--ports/stm32/flash.c288
-rw-r--r--ports/stm32/flash.h33
-rw-r--r--ports/stm32/font_petme128_8x8.h128
-rw-r--r--ports/stm32/gccollect.c77
-rw-r--r--ports/stm32/gccollect.h43
-rw-r--r--ports/stm32/gchelper.s62
-rw-r--r--ports/stm32/help.c71
-rw-r--r--ports/stm32/i2c.c1039
-rw-r--r--ports/stm32/i2c.h55
-rw-r--r--ports/stm32/irq.c76
-rw-r--r--ports/stm32/irq.h152
-rw-r--r--ports/stm32/lcd.c529
-rw-r--r--ports/stm32/lcd.h31
-rw-r--r--ports/stm32/led.c378
-rw-r--r--ports/stm32/led.h54
-rw-r--r--ports/stm32/machine_i2c.c550
-rw-r--r--ports/stm32/main.c699
-rw-r--r--ports/stm32/make-stmconst.py261
-rw-r--r--ports/stm32/modmachine.c593
-rw-r--r--ports/stm32/modmachine.h43
-rw-r--r--ports/stm32/modnetwork.c94
-rw-r--r--ports/stm32/modnetwork.h83
-rw-r--r--ports/stm32/modnwcc3k.c602
-rw-r--r--ports/stm32/modnwwiznet5k.c464
-rw-r--r--ports/stm32/modpyb.c214
-rw-r--r--ports/stm32/modstm.c51
l---------ports/stm32/modules/lcd160cr.py1
l---------ports/stm32/modules/lcd160cr_test.py1
l---------ports/stm32/modules/onewire.py1
-rw-r--r--ports/stm32/moduos.c169
-rw-r--r--ports/stm32/modusocket.c452
-rw-r--r--ports/stm32/modutime.c153
-rw-r--r--ports/stm32/mpconfigport.h348
-rw-r--r--ports/stm32/mpconfigport.mk7
-rw-r--r--ports/stm32/mphalport.c156
-rw-r--r--ports/stm32/mphalport.h75
-rw-r--r--ports/stm32/mpthreadport.c94
-rw-r--r--ports/stm32/mpthreadport.h53
-rw-r--r--ports/stm32/pendsv.c152
-rw-r--r--ports/stm32/pendsv.h36
-rw-r--r--ports/stm32/pin.c675
-rw-r--r--ports/stm32/pin.h100
-rw-r--r--ports/stm32/pin_defs_stmhal.c31
-rw-r--r--ports/stm32/pin_defs_stmhal.h131
-rw-r--r--ports/stm32/pin_named_pins.c85
-rw-r--r--ports/stm32/portmodules.h43
-rw-r--r--ports/stm32/pybcdc.inf_template92
-rw-r--r--ports/stm32/pybthread.c237
-rw-r--r--ports/stm32/pybthread.h77
-rw-r--r--ports/stm32/qstrdefsport.h47
-rw-r--r--ports/stm32/rng.c67
-rw-r--r--ports/stm32/rng.h34
-rw-r--r--ports/stm32/rtc.c730
-rw-r--r--ports/stm32/rtc.h35
-rw-r--r--ports/stm32/sdcard.c547
-rw-r--r--ports/stm32/sdcard.h48
-rw-r--r--ports/stm32/servo.c334
-rw-r--r--ports/stm32/servo.h37
-rw-r--r--ports/stm32/spi.c956
-rw-r--r--ports/stm32/spi.h43
-rw-r--r--ports/stm32/startup_stm32.S822
-rw-r--r--ports/stm32/stm32_it.c799
-rw-r--r--ports/stm32/stm32_it.h86
-rw-r--r--ports/stm32/storage.c521
-rw-r--r--ports/stm32/storage.h51
-rw-r--r--ports/stm32/system_stm32.c496
-rw-r--r--ports/stm32/systick.c140
-rw-r--r--ports/stm32/systick.h32
-rw-r--r--ports/stm32/timer.c1423
-rw-r--r--ports/stm32/timer.h42
-rw-r--r--ports/stm32/uart.c1044
-rw-r--r--ports/stm32/uart.h53
-rw-r--r--ports/stm32/usb.c719
-rw-r--r--ports/stm32/usb.h73
-rw-r--r--ports/stm32/usbd_cdc_interface.c409
-rw-r--r--ports/stm32/usbd_cdc_interface.h45
-rw-r--r--ports/stm32/usbd_conf.c689
-rw-r--r--ports/stm32/usbd_conf.h93
-rw-r--r--ports/stm32/usbd_desc.c226
-rw-r--r--ports/stm32/usbd_desc.h33
-rw-r--r--ports/stm32/usbd_hid_interface.c134
-rw-r--r--ports/stm32/usbd_hid_interface.h14
-rw-r--r--ports/stm32/usbd_msc_storage.c306
-rw-r--r--ports/stm32/usbd_msc_storage.h32
-rw-r--r--ports/stm32/usbdev/Release_Notes.html974
-rw-r--r--ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid.h122
-rw-r--r--ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid0.h51
-rw-r--r--ports/stm32/usbdev/class/inc/usbd_msc_bot.h151
-rw-r--r--ports/stm32/usbdev/class/inc/usbd_msc_data.h104
-rw-r--r--ports/stm32/usbdev/class/inc/usbd_msc_scsi.h195
-rw-r--r--ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c1130
-rw-r--r--ports/stm32/usbdev/class/src/usbd_msc.c609
-rw-r--r--ports/stm32/usbdev/class/src/usbd_msc_bot.c407
-rw-r--r--ports/stm32/usbdev/class/src/usbd_msc_data.c134
-rw-r--r--ports/stm32/usbdev/class/src/usbd_msc_scsi.c811
-rw-r--r--ports/stm32/usbdev/core/inc/usbd_core.h159
-rw-r--r--ports/stm32/usbdev/core/inc/usbd_ctlreq.h106
-rw-r--r--ports/stm32/usbdev/core/inc/usbd_def.h319
-rw-r--r--ports/stm32/usbdev/core/inc/usbd_ioreq.h121
-rw-r--r--ports/stm32/usbdev/core/src/usbd_core.c554
-rw-r--r--ports/stm32/usbdev/core/src/usbd_ctlreq.c769
-rw-r--r--ports/stm32/usbdev/core/src/usbd_ioreq.c236
-rw-r--r--ports/stm32/usbhost/Class/AUDIO/Inc/usbh_audio.h581
-rw-r--r--ports/stm32/usbhost/Class/AUDIO/Src/usbh_audio.c1994
-rw-r--r--ports/stm32/usbhost/Class/CDC/Inc/usbh_cdc.h449
-rw-r--r--ports/stm32/usbhost/Class/CDC/Src/usbh_cdc.c755
-rw-r--r--ports/stm32/usbhost/Class/HID/Inc/usbh_hid.h341
-rw-r--r--ports/stm32/usbhost/Class/HID/Inc/usbh_hid_keybd.h318
-rw-r--r--ports/stm32/usbhost/Class/HID/Inc/usbh_hid_mouse.h118
-rw-r--r--ports/stm32/usbhost/Class/HID/Inc/usbh_hid_parser.h96
-rw-r--r--ports/stm32/usbhost/Class/HID/Inc/usbh_hid_usage.h191
-rw-r--r--ports/stm32/usbhost/Class/HID/Src/usbh_hid.c800
-rw-r--r--ports/stm32/usbhost/Class/HID/Src/usbh_hid_keybd.c418
-rw-r--r--ports/stm32/usbhost/Class/HID/Src/usbh_hid_mouse.c267
-rw-r--r--ports/stm32/usbhost/Class/HID/Src/usbh_hid_parser.c235
-rw-r--r--ports/stm32/usbhost/Class/MSC/Inc/usbh_msc.h222
-rw-r--r--ports/stm32/usbhost/Class/MSC/Inc/usbh_msc_bot.h233
-rw-r--r--ports/stm32/usbhost/Class/MSC/Inc/usbh_msc_scsi.h218
-rw-r--r--ports/stm32/usbhost/Class/MSC/Src/usbh_msc.c795
-rw-r--r--ports/stm32/usbhost/Class/MSC/Src/usbh_msc_bot.c633
-rw-r--r--ports/stm32/usbhost/Class/MSC/Src/usbh_msc_scsi.c458
-rw-r--r--ports/stm32/usbhost/Class/MTP/Inc/usbh_mtp.h263
-rw-r--r--ports/stm32/usbhost/Class/MTP/Inc/usbh_mtp_ptp.h1038
-rw-r--r--ports/stm32/usbhost/Class/MTP/Src/usbh_mtp.c1065
-rw-r--r--ports/stm32/usbhost/Class/MTP/Src/usbh_mtp_ptp.c1769
-rw-r--r--ports/stm32/usbhost/Class/Template/Inc/usbh_template.h122
-rw-r--r--ports/stm32/usbhost/Class/Template/Src/usbh_template.c240
-rw-r--r--ports/stm32/usbhost/Core/Inc/usbh_conf_template.h151
-rw-r--r--ports/stm32/usbhost/Core/Inc/usbh_core.h161
-rw-r--r--ports/stm32/usbhost/Core/Inc/usbh_ctlreq.h147
-rw-r--r--ports/stm32/usbhost/Core/Inc/usbh_def.h480
-rw-r--r--ports/stm32/usbhost/Core/Inc/usbh_ioreq.h159
-rw-r--r--ports/stm32/usbhost/Core/Inc/usbh_pipes.h124
-rw-r--r--ports/stm32/usbhost/Core/Src/usbh_conf_template.c270
-rw-r--r--ports/stm32/usbhost/Core/Src/usbh_core.c936
-rw-r--r--ports/stm32/usbhost/Core/Src/usbh_ctlreq.c881
-rw-r--r--ports/stm32/usbhost/Core/Src/usbh_ioreq.c358
-rw-r--r--ports/stm32/usbhost/Core/Src/usbh_pipes.c204
-rw-r--r--ports/stm32/usbhost/Release_Notes.html973
-rw-r--r--ports/stm32/usrsw.c147
-rw-r--r--ports/stm32/usrsw.h34
-rw-r--r--ports/stm32/wdt.c106
-rw-r--r--ports/stm32/wdt.h31
289 files changed, 67268 insertions, 0 deletions
diff --git a/ports/stm32/.gitignore b/ports/stm32/.gitignore
new file mode 100644
index 000000000..414487d53
--- /dev/null
+++ b/ports/stm32/.gitignore
@@ -0,0 +1 @@
+build-*/
diff --git a/ports/stm32/Makefile b/ports/stm32/Makefile
new file mode 100644
index 000000000..58a0a7c7a
--- /dev/null
+++ b/ports/stm32/Makefile
@@ -0,0 +1,480 @@
+# 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 mpconfigport.mk
+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
+
+# directory containing scripts to be frozen as bytecode
+FROZEN_MPY_DIR ?= modules
+
+# include py core make definitions
+include $(TOP)/py/py.mk
+
+LD_DIR=boards
+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
+#USBHOST_DIR=usbhost
+FATFS_DIR=lib/oofatfs
+DFU=$(TOP)/tools/dfu.py
+# may need to prefix dfu-util with sudo
+USE_PYDFU ?= 1
+PYDFU ?= $(TOP)/tools/pydfu.py
+DFU_UTIL ?= dfu-util
+DEVICE=0483:df11
+STFLASH ?= st-flash
+OPENOCD ?= openocd
+OPENOCD_CONFIG ?= boards/openocd_stm32f4.cfg
+
+CROSS_COMPILE = arm-none-eabi-
+
+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
+#INC += -I$(USBHOST_DIR)
+
+# Basic Cortex-M flags
+CFLAGS_CORTEX_M = -mthumb
+
+# Select hardware floating-point support
+ifeq ($(CMSIS_MCU),$(filter $(CMSIS_MCU),STM32F767xx STM32F769xx))
+CFLAGS_CORTEX_M += -mfpu=fpv5-d16 -mfloat-abi=hard
+else
+CFLAGS_CORTEX_M += -mfpu=fpv4-sp-d16 -mfloat-abi=hard
+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 = $(INC) -Wall -Wpointer-arith -Werror -std=gnu99 -nostdlib $(CFLAGS_MOD) $(CFLAGS_EXTRA)
+CFLAGS += -D$(CMSIS_MCU)
+CFLAGS += $(CFLAGS_MCU_$(MCU_SERIES))
+CFLAGS += $(COPT)
+CFLAGS += -Iboards/$(BOARD)
+CFLAGS += -DSTM32_HAL_H='<stm32$(MCU_SERIES)xx_hal.h>'
+
+ifeq ($(MICROPY_FLOAT_IMPL),double)
+CFLAGS += -DMICROPY_FLOAT_IMPL=MICROPY_FLOAT_IMPL_DOUBLE
+else
+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
+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 \
+ oofatfs/ff.c \
+ oofatfs/option/unicode.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_FLOAT_IMPL),double)
+SRC_LIBM = $(addprefix lib/libm_dbl/,\
+ __cos.c \
+ __expo2.c \
+ __fpclassify.c \
+ __rem_pio2.c \
+ __rem_pio2_large.c \
+ __signbit.c \
+ __sin.c \
+ __tan.c \
+ acos.c \
+ acosh.c \
+ asin.c \
+ asinh.c \
+ atan.c \
+ atan2.c \
+ atanh.c \
+ ceil.c \
+ cos.c \
+ cosh.c \
+ erf.c \
+ exp.c \
+ expm1.c \
+ floor.c \
+ fmod.c \
+ frexp.c \
+ ldexp.c \
+ lgamma.c \
+ log.c \
+ log10.c \
+ log1p.c \
+ modf.c \
+ nearbyint.c \
+ pow.c \
+ rint.c \
+ scalbn.c \
+ sin.c \
+ sinh.c \
+ sqrt.c \
+ tan.c \
+ tanh.c \
+ tgamma.c \
+ trunc.c \
+ )
+else
+SRC_LIBM = $(addprefix lib/libm/,\
+ math.c \
+ thumb_vfp_sqrtf.c \
+ acoshf.c \
+ asinfacosf.c \
+ asinhf.c \
+ atan2f.c \
+ atanf.c \
+ atanhf.c \
+ ef_rem_pio2.c \
+ erf_lgamma.c \
+ fmodf.c \
+ kf_cos.c \
+ kf_rem_pio2.c \
+ kf_sin.c \
+ kf_tan.c \
+ log1pf.c \
+ nearbyintf.c \
+ sf_cos.c \
+ sf_erf.c \
+ sf_frexp.c \
+ sf_ldexp.c \
+ sf_modf.c \
+ sf_sin.c \
+ sf_tan.c \
+ wf_lgamma.c \
+ wf_tgamma.c \
+ )
+endif
+
+EXTMOD_SRC_C = $(addprefix extmod/,\
+ modonewire.c \
+ )
+
+DRIVERS_SRC_C = $(addprefix drivers/,\
+ memory/spiflash.c \
+ )
+
+SRC_C = \
+ main.c \
+ system_stm32.c \
+ stm32_it.c \
+ usbd_conf.c \
+ usbd_desc.c \
+ usbd_cdc_interface.c \
+ usbd_hid_interface.c \
+ usbd_msc_storage.c \
+ mphalport.c \
+ mpthreadport.c \
+ irq.c \
+ pendsv.c \
+ systick.c \
+ pybthread.c \
+ timer.c \
+ led.c \
+ pin.c \
+ pin_defs_stmhal.c \
+ pin_named_pins.c \
+ bufhelper.c \
+ dma.c \
+ i2c.c \
+ spi.c \
+ uart.c \
+ can.c \
+ usb.c \
+ wdt.c \
+ gccollect.c \
+ help.c \
+ machine_i2c.c \
+ modmachine.c \
+ modpyb.c \
+ modstm.c \
+ moduos.c \
+ modutime.c \
+ modusocket.c \
+ modnetwork.c \
+ extint.c \
+ usrsw.c \
+ rng.c \
+ rtc.c \
+ flash.c \
+ storage.c \
+ sdcard.c \
+ fatfs_port.c \
+ lcd.c \
+ accel.c \
+ servo.c \
+ dac.c \
+ adc.c \
+ $(wildcard boards/$(BOARD)/*.c)
+
+SRC_O = \
+ startup_stm32.o \
+ gchelper.o \
+
+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 \
+ hal_dma.c \
+ hal_flash.c \
+ hal_flash_ex.c \
+ hal_gpio.c \
+ hal_i2c.c \
+ hal_pcd.c \
+ hal_pcd_ex.c \
+ hal_pwr.c \
+ 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 \
+ ll_sdmmc.c \
+ ll_usb.c \
+ )
+
+SRC_USBDEV = $(addprefix $(USBDEV_DIR)/,\
+ core/src/usbd_core.c \
+ core/src/usbd_ctlreq.c \
+ core/src/usbd_ioreq.c \
+ class/src/usbd_cdc_msc_hid.c \
+ class/src/usbd_msc_bot.c \
+ class/src/usbd_msc_scsi.c \
+ class/src/usbd_msc_data.c \
+ )
+
+ifeq ($(MICROPY_PY_WIZNET5K),1)
+WIZNET5K_DIR=drivers/wiznet5k
+INC += -I$(TOP)/$(WIZNET5K_DIR)
+CFLAGS_MOD += -DMICROPY_PY_WIZNET5K=1
+SRC_MOD += modnwwiznet5k.c
+SRC_MOD += $(addprefix $(WIZNET5K_DIR)/,\
+ ethernet/w5200/w5200.c \
+ ethernet/wizchip_conf.c \
+ ethernet/socket.c \
+ internet/dns/dns.c \
+ )
+endif
+
+# for CC3000 module
+ifeq ($(MICROPY_PY_CC3K),1)
+CC3000_DIR=drivers/cc3000
+INC += -I$(TOP)/$(CC3000_DIR)/inc
+CFLAGS_MOD += -DMICROPY_PY_CC3K=1
+SRC_MOD += modnwcc3k.c
+SRC_MOD += $(addprefix $(CC3000_DIR)/src/,\
+ cc3000_common.c \
+ evnt_handler.c \
+ hci.c \
+ netapp.c \
+ nvmem.c \
+ security.c \
+ socket.c \
+ wlan.c \
+ ccspi.c \
+ inet_ntop.c \
+ inet_pton.c \
+ patch.c \
+ patch_prog.c \
+ )
+endif
+
+OBJ =
+OBJ += $(PY_O)
+OBJ += $(addprefix $(BUILD)/, $(SRC_LIB:.c=.o))
+OBJ += $(addprefix $(BUILD)/, $(SRC_LIBM:.c=.o))
+OBJ += $(addprefix $(BUILD)/, $(EXTMOD_SRC_C:.c=.o))
+OBJ += $(addprefix $(BUILD)/, $(DRIVERS_SRC_C:.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))
+OBJ += $(addprefix $(BUILD)/, $(SRC_MOD:.c=.o))
+OBJ += $(BUILD)/pins_$(BOARD).o
+
+# 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)
+# and comment out the following lines.
+$(BUILD)/$(FATFS_DIR)/ff.o: COPT += -Os
+$(filter $(PY_BUILD)/../extmod/vfs_fat_%.o, $(PY_O)): COPT += -Os
+$(PY_BUILD)/formatfloat.o: COPT += -Os
+$(PY_BUILD)/parsenum.o: COPT += -Os
+$(PY_BUILD)/mpprint.o: COPT += -Os
+
+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)
+
+ifneq ($(FROZEN_DIR),)
+# To use frozen source modules, put your .py files in a subdirectory (eg scripts/)
+# and then invoke make with FROZEN_DIR=scripts (be sure to build from scratch).
+CFLAGS += -DMICROPY_MODULE_FROZEN_STR
+endif
+
+ifneq ($(FROZEN_MPY_DIR),)
+# To use frozen bytecode, put your .py files in a subdirectory (eg frozen/) and
+# then invoke make with FROZEN_MPY_DIR=frozen (be sure to build from scratch).
+CFLAGS += -DMICROPY_QSTR_EXTRA_POOL=mp_qstr_frozen_const_pool
+CFLAGS += -DMICROPY_MODULE_FROZEN_MPY
+endif
+
+.PHONY: deploy
+
+deploy: $(BUILD)/firmware.dfu
+ $(ECHO) "Writing $< to the board"
+ifeq ($(USE_PYDFU),1)
+ $(Q)$(PYTHON) $(PYDFU) -u $<
+else
+ $(Q)$(DFU_UTIL) -a 0 -d $(DEVICE) -D $<
+endif
+
+FLASH_ADDR ?= 0x08000000
+TEXT_ADDR ?= 0x08020000
+
+deploy-stlink: $(BUILD)/firmware.dfu
+ $(ECHO) "Writing $(BUILD)/firmware0.bin to the board via ST-LINK"
+ $(Q)$(STFLASH) write $(BUILD)/firmware0.bin $(FLASH_ADDR)
+ $(ECHO) "Writing $(BUILD)/firmware1.bin to the board via ST-LINK"
+ $(Q)$(STFLASH) --reset write $(BUILD)/firmware1.bin $(TEXT_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)"
+
+$(BUILD)/firmware.dfu: $(BUILD)/firmware.elf
+ $(ECHO) "Create $@"
+ $(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 $@
+
+$(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) $@
+
+PLLVALUES = boards/pllvalues.py
+MAKE_PINS = boards/make-pins.py
+BOARD_PINS = boards/$(BOARD)/pins.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
+
+INSERT_USB_IDS = $(TOP)/tools/insert-usb-ids.py
+FILE2H = $(TOP)/tools/file2h.py
+
+USB_IDS_FILE = usb.h
+CDCINF_TEMPLATE = pybcdc.inf_template
+GEN_CDCINF_FILE = $(HEADER_BUILD)/pybcdc.inf
+GEN_CDCINF_HEADER = $(HEADER_BUILD)/pybcdc_inf.h
+
+# List of sources for qstr extraction
+SRC_QSTR += $(SRC_C) $(SRC_MOD) $(SRC_LIB) $(EXTMOD_SRC_C)
+# Append any auto-generated sources that are needed by sources listed in
+# SRC_QSTR
+SRC_QSTR_AUTO_DEPS += $(GEN_CDCINF_HEADER)
+
+# 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): | $(GEN_PINS_HDR)
+
+# With conditional pins, we may need to regenerate qstrdefs.h when config
+# options change.
+$(HEADER_BUILD)/qstrdefs.generated.h: boards/$(BOARD)/mpconfigboard.h
+
+# main.c can't be even preprocessed without $(GEN_CDCINF_HEADER)
+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 $@"
+ $(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)
+
+GEN_PLLFREQTABLE_HDR = $(HEADER_BUILD)/pllfreqtable.h
+GEN_STMCONST_HDR = $(HEADER_BUILD)/modstm_const.h
+GEN_STMCONST_QSTR = $(BUILD)/modstm_qstr.h
+GEN_STMCONST_MPZ = $(HEADER_BUILD)/modstm_mpz.h
+CMSIS_MCU_LOWER = $(shell echo $(CMSIS_MCU) | tr '[:upper:]' '[:lower:]')
+CMSIS_MCU_HDR = $(CMSIS_DIR)/$(CMSIS_MCU_LOWER).h
+
+modmachine.c: $(GEN_PLLFREQTABLE_HDR)
+$(GEN_PLLFREQTABLE_HDR): $(PLLVALUES) | $(HEADER_BUILD)
+ $(ECHO) "Create $@"
+ $(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 $@"
+ $(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 $@"
+ $(Q)$(PYTHON) $(FILE2H) $< > $@
+
+$(GEN_CDCINF_FILE): $(CDCINF_TEMPLATE) $(INSERT_USB_IDS) $(USB_IDS_FILE) | $(HEADER_BUILD)
+ $(ECHO) "Create $@"
+ $(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
new file mode 100644
index 000000000..32b6d4176
--- /dev/null
+++ b/ports/stm32/README.md
@@ -0,0 +1,115 @@
+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.
+
+The officially supported boards are the line of pyboards: PYBv1.0 and PYBv1.1
+(both with STM32F405), and PYBLITEv1.0 (with STM32F411). See
+[micropython.org/pyboard](http://www.micropython.org/pyboard/) for further
+details.
+
+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.
+
+Build instructions
+------------------
+
+Before building the firmware for a given board the MicroPython cross-compiler
+must be built; it will be used to pre-compile some of the built-in scripts to
+bytecode. The cross-compiler is built and run on the host machine, using:
+```bash
+$ make -C mpy-cross
+```
+This command should be executed from the root directory of this repository.
+All other commands below should be executed from the stmhal/ directory.
+
+An ARM compiler is required for the build, along with the associated binary
+utilities. The default compiler is `arm-none-eabi-gcc`, which is available for
+Arch Linux via the package `arm-none-eabi-gcc`, for Ubuntu via instructions
+[here](https://launchpad.net/~team-gcc-arm-embedded/+archive/ubuntu/ppa), or
+see [here](https://launchpad.net/gcc-arm-embedded) for the main GCC ARM
+Embedded page. The compiler can be changed using the `CROSS_COMPILE` variable
+when invoking `make`.
+
+To build for a given board, run:
+
+ $ make BOARD=PYBV11
+
+The default board is PYBV10 but any of the names of the subdirectories in the
+`boards/` directory can be passed as the argument to `BOARD=`. The above command
+should produce binary images in the `build-PYBV11/` subdirectory (or the
+equivalent directory for the board specified).
+
+You must then get your board/microcontroller into DFU mode. On the pyboard
+connect the 3V3 pin to the P1/DFU pin with a wire (they are next to each
+other on the bottom left of the board, second row from the bottom) and then
+reset (by pressing the RST button) or power on the board. Then flash the
+firmware using the command:
+
+ $ make BOARD=PYBV11 deploy
+
+This will use the included `tools/pydfu.py` script. You can use instead the
+`dfu-util` program (available [here](http://dfu-util.sourceforge.net/)) by
+passing `USE_PYDFU=0`:
+
+ $ make BOARD=PYBV11 USE_PYDFU=0 deploy
+
+If flashing the firmware does not work it may be because you don't have the
+correct permissions. Try then:
+
+ $ sudo make BOARD=PYBV11 deploy
+
+Or using `dfu-util` directly:
+
+ $ sudo dfu-util -a 0 -d 0483:df11 -D build-PYBV11/firmware.dfu
+
+
+### Flashing the Firmware with stlink
+
+ST Discovery or Nucleo boards have a builtin programmer called ST-LINK. With
+these boards and using Linux or OS X, you have the option to upload the
+`stmhal` firmware using the `st-flash` utility from the
+[stlink](https://github.com/texane/stlink) project. To do so, connect the board
+with a mini USB cable to its ST-LINK USB port and then use the make target
+`deploy-stlink`. For example, if you have the STM32F4DISCOVERY board, you can
+run:
+
+ $ make BOARD=STM32F4DISC deploy-stlink
+
+The `st-flash` program should detect the USB connection to the board
+automatically. If not, run `lsusb` to determine its USB bus and device number
+and set the `STLINK_DEVICE` environment variable accordingly, using the format
+`<USB_BUS>:<USB_ADDR>`. Example:
+
+ $ lsusb
+ [...]
+ Bus 002 Device 035: ID 0483:3748 STMicroelectronics ST-LINK/V2
+ $ export STLINK_DEVICE="002:0035"
+ $ make BOARD=STM32F4DISC deploy-stlink
+
+
+### Flashing the Firmware with OpenOCD
+
+Another option to deploy the firmware on ST Discovery or Nucleo boards with a
+ST-LINK interface uses [OpenOCD](http://openocd.org/). Connect the board with
+a mini USB cable to its ST-LINK USB port and then use the make target
+`deploy-openocd`. For example, if you have the STM32F4DISCOVERY board:
+
+ $ make BOARD=STM32F4DISC deploy-openocd
+
+The `openocd` program, which writes the firmware to the target board's flash,
+is configured via the file `stmhal/boards/openocd_stm32f4.cfg`. This
+configuration should work for all boards based on a STM32F4xx MCU with a
+ST-LINKv2 interface. You can override the path to this configuration by setting
+`OPENOCD_CONFIG` in your Makefile or on the command line.
+
+Accessing the board
+-------------------
+
+Once built and deployed, access the MicroPython REPL (the Python prompt) via USB
+serial or UART, depending on the board. For the pyboard you can try:
+
+ $ picocom /dev/ttyACM0
diff --git a/ports/stm32/accel.c b/ports/stm32/accel.c
new file mode 100644
index 000000000..512a6e313
--- /dev/null
+++ b/ports/stm32/accel.c
@@ -0,0 +1,234 @@
+/*
+ * 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/mphal.h"
+#include "py/nlr.h"
+#include "py/runtime.h"
+#include "pin.h"
+#include "genhdr/pins.h"
+#include "i2c.h"
+#include "accel.h"
+
+#if MICROPY_HW_HAS_MMA7660
+
+/// \moduleref pyb
+/// \class Accel - accelerometer control
+///
+/// Accel is an object that controls the accelerometer. Example usage:
+///
+/// accel = pyb.Accel()
+/// for i in range(10):
+/// print(accel.x(), accel.y(), accel.z())
+///
+/// Raw values are between -32 and 31.
+
+#define MMA_ADDR (0x98)
+#define MMA_REG_X (0)
+#define MMA_REG_Y (1)
+#define MMA_REG_Z (2)
+#define MMA_REG_TILT (3)
+#define MMA_REG_MODE (7)
+#define MMA_AXIS_SIGNED_VALUE(i) (((i) & 0x3f) | ((i) & 0x20 ? (~0x1f) : 0))
+
+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);
+}
+
+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);
+
+ // turn off AVDD, wait 30ms, turn on AVDD, wait 30ms again
+ 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_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) {
+ break;
+ }
+ }
+
+ if (status != HAL_OK) {
+ 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);
+
+ // wait for MMA to become active
+ mp_hal_delay_ms(30);
+}
+
+/******************************************************************************/
+/* MicroPython bindings */
+
+#define NUM_AXIS (3)
+#define FILT_DEPTH (4)
+
+typedef struct _pyb_accel_obj_t {
+ mp_obj_base_t base;
+ int16_t buf[NUM_AXIS * FILT_DEPTH];
+} pyb_accel_obj_t;
+
+STATIC pyb_accel_obj_t pyb_accel_obj;
+
+/// \classmethod \constructor()
+/// Create and return an accelerometer object.
+///
+/// Note: if you read accelerometer values immediately after creating this object
+/// you will get 0. It takes around 20ms for the first sample to be ready, so,
+/// unless you have some other code between creating this object and reading its
+/// values, you should put a `pyb.delay(20)` after creating it. For example:
+///
+/// accel = pyb.Accel()
+/// pyb.delay(20)
+/// print(accel.x())
+STATIC mp_obj_t pyb_accel_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);
+
+ // init accel object
+ pyb_accel_obj.base.type = &pyb_accel_type;
+ accel_start();
+
+ return &pyb_accel_obj;
+}
+
+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);
+ return mp_obj_new_int(MMA_AXIS_SIGNED_VALUE(data[0]));
+}
+
+/// \method x()
+/// Get the x-axis value.
+STATIC mp_obj_t pyb_accel_x(mp_obj_t self_in) {
+ return read_axis(MMA_REG_X);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_accel_x_obj, pyb_accel_x);
+
+/// \method y()
+/// Get the y-axis value.
+STATIC mp_obj_t pyb_accel_y(mp_obj_t self_in) {
+ return read_axis(MMA_REG_Y);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_accel_y_obj, pyb_accel_y);
+
+/// \method z()
+/// Get the z-axis value.
+STATIC mp_obj_t pyb_accel_z(mp_obj_t self_in) {
+ return read_axis(MMA_REG_Z);
+}
+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);
+ return mp_obj_new_int(data[0]);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_accel_tilt_obj, pyb_accel_tilt);
+
+/// \method filtered_xyz()
+/// Get a 3-tuple of filtered x, y and z values.
+STATIC mp_obj_t pyb_accel_filtered_xyz(mp_obj_t self_in) {
+ pyb_accel_obj_t *self = 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);
+
+ mp_obj_t tuple[NUM_AXIS];
+ for (int i = 0; i < NUM_AXIS; i++) {
+ self->buf[NUM_AXIS * (FILT_DEPTH - 1) + i] = MMA_AXIS_SIGNED_VALUE(data[i]);
+ int32_t val = 0;
+ for (int j = 0; j < FILT_DEPTH; j++) {
+ val += self->buf[i + NUM_AXIS * j];
+ }
+ tuple[i] = mp_obj_new_int(val);
+ }
+
+ return mp_obj_new_tuple(3, tuple);
+}
+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);
+ 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);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_3(pyb_accel_write_obj, pyb_accel_write);
+
+STATIC const mp_rom_map_elem_t pyb_accel_locals_dict_table[] = {
+ // TODO add init, deinit, and perhaps reset methods
+ { MP_ROM_QSTR(MP_QSTR_x), MP_ROM_PTR(&pyb_accel_x_obj) },
+ { MP_ROM_QSTR(MP_QSTR_y), MP_ROM_PTR(&pyb_accel_y_obj) },
+ { MP_ROM_QSTR(MP_QSTR_z), MP_ROM_PTR(&pyb_accel_z_obj) },
+ { MP_ROM_QSTR(MP_QSTR_tilt), MP_ROM_PTR(&pyb_accel_tilt_obj) },
+ { MP_ROM_QSTR(MP_QSTR_filtered_xyz), MP_ROM_PTR(&pyb_accel_filtered_xyz_obj) },
+ { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&pyb_accel_read_obj) },
+ { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&pyb_accel_write_obj) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(pyb_accel_locals_dict, pyb_accel_locals_dict_table);
+
+const mp_obj_type_t pyb_accel_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_Accel,
+ .make_new = pyb_accel_make_new,
+ .locals_dict = (mp_obj_dict_t*)&pyb_accel_locals_dict,
+};
+
+#endif // MICROPY_HW_HAS_MMA7660
diff --git a/ports/stm32/accel.h b/ports/stm32/accel.h
new file mode 100644
index 000000000..fc35f7775
--- /dev/null
+++ b/ports/stm32/accel.h
@@ -0,0 +1,33 @@
+/*
+ * 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.
+ */
+#ifndef MICROPY_INCLUDED_STMHAL_ACCEL_H
+#define MICROPY_INCLUDED_STMHAL_ACCEL_H
+
+extern const mp_obj_type_t pyb_accel_type;
+
+void accel_init(void);
+
+#endif // MICROPY_INCLUDED_STMHAL_ACCEL_H
diff --git a/ports/stm32/adc.c b/ports/stm32/adc.c
new file mode 100644
index 000000000..dd59e29c8
--- /dev/null
+++ b/ports/stm32/adc.c
@@ -0,0 +1,678 @@
+/*
+ * 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/nlr.h"
+#include "py/runtime.h"
+#include "py/binary.h"
+#include "py/mphal.h"
+#include "adc.h"
+#include "pin.h"
+#include "genhdr/pins.h"
+#include "timer.h"
+
+/// \moduleref pyb
+/// \class ADC - analog to digital conversion: read analog values on a pin
+///
+/// Usage:
+///
+/// adc = pyb.ADC(pin) # create an analog object from a pin
+/// val = adc.read() # read an analog value
+///
+/// adc = pyb.ADCAll(resolution) # creale an ADCAll object
+/// val = adc.read_channel(channel) # read the given channel
+/// val = adc.read_core_temp() # read MCU temperature
+/// val = adc.read_core_vbat() # read MCU VBAT
+/// val = adc.read_core_vref() # read MCU VREF
+
+/* ADC defintions */
+#define ADCx (ADC1)
+#define ADCx_CLK_ENABLE __ADC1_CLK_ENABLE
+#define ADC_NUM_CHANNELS (19)
+
+#if defined(MCU_SERIES_F4)
+
+#define ADC_FIRST_GPIO_CHANNEL (0)
+#define ADC_LAST_GPIO_CHANNEL (15)
+#define ADC_CAL_ADDRESS (0x1fff7a2a)
+#define ADC_CAL1 ((uint16_t*)(ADC_CAL_ADDRESS + 2))
+#define ADC_CAL2 ((uint16_t*)(ADC_CAL_ADDRESS + 4))
+
+#elif defined(MCU_SERIES_F7)
+
+#define ADC_FIRST_GPIO_CHANNEL (0)
+#define ADC_LAST_GPIO_CHANNEL (15)
+#define ADC_CAL_ADDRESS (0x1ff0f44a)
+#define ADC_CAL1 ((uint16_t*)(ADC_CAL_ADDRESS + 2))
+#define ADC_CAL2 ((uint16_t*)(ADC_CAL_ADDRESS + 4))
+
+#elif defined(MCU_SERIES_L4)
+
+#define ADC_FIRST_GPIO_CHANNEL (1)
+#define ADC_LAST_GPIO_CHANNEL (16)
+#define ADC_CAL_ADDRESS (0x1fff75aa)
+#define ADC_CAL1 ((uint16_t*)(ADC_CAL_ADDRESS - 2))
+#define ADC_CAL2 ((uint16_t*)(ADC_CAL_ADDRESS + 0x20))
+
+#else
+
+#error Unsupported processor
+
+#endif
+
+#if 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(STM32F746xx) || defined(STM32F767xx) || \
+ defined(STM32F769xx) || defined(STM32F446xx)
+#define VBAT_DIV (4)
+#elif defined(STM32L476xx)
+#define VBAT_DIV (3)
+#else
+#error Unsupported processor
+#endif
+
+/* 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) */
+
+// scale and calibration values for VBAT and VREF
+#define ADC_SCALE (3.3f / 4095)
+#define VREFIN_CAL ((uint16_t *)ADC_CAL_ADDRESS)
+
+typedef struct _pyb_obj_adc_t {
+ mp_obj_base_t base;
+ mp_obj_t pin_name;
+ int channel;
+ ADC_HandleTypeDef handle;
+} 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)
+ // 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) {
+ channel = ADC_CHANNEL_TEMPSENSOR;
+ }
+ #endif
+ return channel;
+}
+
+STATIC bool is_adcx_channel(int channel) {
+#if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7)
+ return IS_ADC_CHANNEL(channel);
+#elif defined(MCU_SERIES_L4)
+ ADC_HandleTypeDef handle;
+ handle.Instance = ADCx;
+ return IS_ADC_CHANNEL(&handle, channel);
+#else
+ #error Unsupported processor
+#endif
+}
+
+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)
+ while ((ADCx->SR & ADC_FLAG_EOC) != ADC_FLAG_EOC) {
+#elif defined(MCU_SERIES_L4)
+ while (READ_BIT(ADCx->ISR, ADC_FLAG_EOC) != ADC_FLAG_EOC) {
+#else
+ #error Unsupported processor
+#endif
+ if (((HAL_GetTick() - tickstart ) > timeout)) {
+ break; // timeout
+ }
+ }
+}
+
+STATIC void adcx_clock_enable(void) {
+#if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7)
+ ADCx_CLK_ENABLE();
+#elif defined(MCU_SERIES_L4)
+ __HAL_RCC_ADC_CLK_ENABLE();
+#else
+ #error Unsupported processor
+#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);
+ }
+
+ 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
+
+ HAL_ADC_Init(adcHandle);
+
+#if defined(MCU_SERIES_L4)
+ ADC_MultiModeTypeDef multimode;
+ multimode.Mode = ADC_MODE_INDEPENDENT;
+ if (HAL_ADCEx_MultiModeConfigChannel(adcHandle, &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));
+ }
+#endif
+}
+
+STATIC void adc_config_channel(ADC_HandleTypeDef *adc_handle, uint32_t channel) {
+ ADC_ChannelConfTypeDef sConfig;
+
+ sConfig.Channel = channel;
+ sConfig.Rank = 1;
+#if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7)
+ sConfig.SamplingTime = ADC_SAMPLETIME_15CYCLES;
+#elif defined(MCU_SERIES_L4)
+ sConfig.SamplingTime = ADC_SAMPLETIME_12CYCLES_5;
+ sConfig.SingleDiff = ADC_SINGLE_ENDED;
+ sConfig.OffsetNumber = ADC_OFFSET_NONE;
+#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);
+ }
+ HAL_ADC_Stop(adcHandle);
+
+ return rawValue;
+}
+
+/******************************************************************************/
+/* MicroPython bindings : adc object (single channel) */
+
+STATIC void adc_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
+ 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);
+}
+
+/// \classmethod \constructor(pin)
+/// Create an ADC object associated with the given pin.
+/// This allows you to then read analog values on that pin.
+STATIC mp_obj_t adc_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
+ // check number of arguments
+ mp_arg_check_num(n_args, n_kw, 1, 1, false);
+
+ // 1st argument is the pin name
+ mp_obj_t pin_obj = args[0];
+
+ uint32_t channel;
+
+ if (MP_OBJ_IS_INT(pin_obj)) {
+ channel = adc_get_internal_channel(mp_obj_get_int(pin_obj));
+ } else {
+ const pin_obj_t *pin = pin_find(pin_obj);
+ if ((pin->adc_num & PIN_ADC1) == 0) {
+ // No ADC1 function on that pin
+ nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "pin %q does not have ADC capabilities", pin->name));
+ }
+ channel = pin->adc_channel;
+ }
+
+ if (!is_adcx_channel(channel)) {
+ nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "not a valid ADC Channel: %d", channel));
+ }
+
+
+ if (ADC_FIRST_GPIO_CHANNEL <= channel && channel <= ADC_LAST_GPIO_CHANNEL) {
+ // these channels correspond to physical GPIO ports so make sure they exist
+ if (pin_adc1[channel] == NULL) {
+ nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError,
+ "channel %d not available on this board", channel));
+ }
+ }
+
+ pyb_obj_adc_t *o = m_new_obj(pyb_obj_adc_t);
+ memset(o, 0, sizeof(*o));
+ o->base.type = &pyb_adc_type;
+ o->pin_name = pin_obj;
+ o->channel = channel;
+ adc_init_single(o);
+
+ return o;
+}
+
+/// \method read()
+/// Read the value on the analog pin and return it. The returned value
+/// 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);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(adc_read_obj, adc_read);
+
+/// \method read_timed(buf, timer)
+///
+/// Read analog values into `buf` at a rate set by the `timer` object.
+///
+/// `buf` can be bytearray or array.array for example. The ADC values have
+/// 12-bit resolution and are stored directly into `buf` if its element size is
+/// 16 bits or greater. If `buf` has only 8-bit elements (eg a bytearray) then
+/// the sample resolution will be reduced to 8 bits.
+///
+/// `timer` should be a Timer object, and a sample is read each time the timer
+/// triggers. The timer must already be initialised and running at the desired
+/// sampling frequency.
+///
+/// To support previous behaviour of this function, `timer` can also be an
+/// integer which specifies the frequency (in Hz) to sample at. In this case
+/// Timer(6) will be automatically configured to run at the given frequency.
+///
+/// Example using a Timer object (preferred way):
+///
+/// adc = pyb.ADC(pyb.Pin.board.X19) # create an ADC on pin X19
+/// tim = pyb.Timer(6, freq=10) # create a timer running at 10Hz
+/// buf = bytearray(100) # creat a buffer to store the samples
+/// adc.read_timed(buf, tim) # sample 100 values, taking 10s
+///
+/// Example using an integer for the frequency:
+///
+/// adc = pyb.ADC(pyb.Pin.board.X19) # create an ADC on pin X19
+/// buf = bytearray(100) # create a buffer of 100 bytes
+/// adc.read_timed(buf, 10) # read analog values into buf at 10Hz
+/// # this will take 10 seconds to finish
+/// for val in buf: # loop over all values
+/// print(val) # print the value out
+///
+/// This function does not allocate any memory.
+STATIC mp_obj_t adc_read_timed(mp_obj_t self_in, mp_obj_t buf_in, mp_obj_t freq_in) {
+ pyb_obj_adc_t *self = self_in;
+
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_WRITE);
+ size_t typesize = mp_binary_get_size('@', bufinfo.typecode, NULL);
+
+ TIM_HandleTypeDef *tim;
+ #if defined(TIM6)
+ if (mp_obj_is_integer(freq_in)) {
+ // freq in Hz given so init TIM6 (legacy behaviour)
+ tim = timer_tim6_init(mp_obj_get_int(freq_in));
+ HAL_TIM_Base_Start(tim);
+ } else
+ #endif
+ {
+ // use the supplied timer object as the sampling time base
+ tim = pyb_timer_get_handle(freq_in);
+ }
+
+ // configure the ADC channel
+ adc_config_channel(&self->handle, self->channel);
+
+ // This uses the timer in polling mode to do the sampling
+ // TODO use DMA
+
+ uint nelems = bufinfo.len / typesize;
+ for (uint index = 0; index < nelems; index++) {
+ // 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);
+
+ if (index == 0) {
+ // for the first sample we need to turn the ADC on
+ 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)
+ ADCx->CR2 |= (uint32_t)ADC_CR2_SWSTART;
+#elif defined(MCU_SERIES_L4)
+ SET_BIT(ADCx->CR, ADC_CR_ADSTART);
+#else
+ #error Unsupported processor
+#endif
+ }
+
+ // wait for sample to complete
+ #define READ_TIMED_TIMEOUT (10) // in ms
+ adc_wait_for_eoc_or_timeout(READ_TIMED_TIMEOUT);
+
+ // read value
+ uint value = ADCx->DR;
+
+ // store value in buffer
+ if (typesize == 1) {
+ value >>= 4;
+ }
+ mp_binary_set_val_array_from_int(bufinfo.typecode, bufinfo.buf, index, value);
+ }
+
+ // turn the ADC off
+ HAL_ADC_Stop(&self->handle);
+
+ #if defined(TIM6)
+ if (mp_obj_is_integer(freq_in)) {
+ // stop timer if we initialised TIM6 in this function (legacy behaviour)
+ HAL_TIM_Base_Stop(tim);
+ }
+ #endif
+
+ return mp_obj_new_int(bufinfo.len);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_3(adc_read_timed_obj, adc_read_timed);
+
+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) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(adc_locals_dict, adc_locals_dict_table);
+
+const mp_obj_type_t pyb_adc_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_ADC,
+ .print = adc_print,
+ .make_new = adc_make_new,
+ .locals_dict = (mp_obj_dict_t*)&adc_locals_dict,
+};
+
+/******************************************************************************/
+/* adc all object */
+
+typedef struct _pyb_adc_all_obj_t {
+ mp_obj_base_t base;
+ ADC_HandleTypeDef handle;
+} 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) {
+ case 6: resolution = ADC_RESOLUTION_6B; break;
+ case 8: resolution = ADC_RESOLUTION_8B; break;
+ case 10: resolution = ADC_RESOLUTION_10B; break;
+ case 12: resolution = ADC_RESOLUTION_12B; break;
+ default:
+ nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError,
+ "resolution %d not supported", resolution));
+ }
+
+ for (uint32_t channel = ADC_FIRST_GPIO_CHANNEL; channel <= ADC_LAST_GPIO_CHANNEL; ++channel) {
+ // only initialise those channels that are selected with the en_mask
+ if (en_mask & (1 << channel)) {
+ // Channels 0-16 correspond to real pins. Configure the GPIO pin in
+ // 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);
+ }
+ }
+ }
+
+ 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);
+}
+
+int adc_get_resolution(ADC_HandleTypeDef *adcHandle) {
+ uint32_t res_reg = __HAL_ADC_GET_RESOLUTION(adcHandle);
+
+ switch (res_reg) {
+ case ADC_RESOLUTION_6B: return 6;
+ case ADC_RESOLUTION_8B: return 8;
+ case ADC_RESOLUTION_10B: return 10;
+ }
+ return 12;
+}
+
+int adc_read_core_temp(ADC_HandleTypeDef *adcHandle) {
+ int32_t raw_value = adc_config_and_read_channel(adcHandle, ADC_CHANNEL_TEMPSENSOR);
+
+ // Note: constants assume 12-bit resolution, so we scale the raw value to
+ // be 12-bits.
+ raw_value <<= (12 - adc_get_resolution(adcHandle));
+
+ return ((raw_value - CORE_TEMP_V25) / CORE_TEMP_AVG_SLOPE) + 25;
+}
+
+#if MICROPY_PY_BUILTINS_FLOAT
+// correction factor for reference value
+STATIC volatile float adc_refcor = 1.0f;
+
+float adc_read_core_temp_float(ADC_HandleTypeDef *adcHandle) {
+ int32_t raw_value = adc_config_and_read_channel(adcHandle, ADC_CHANNEL_TEMPSENSOR);
+
+ // constants assume 12-bit resolution so we scale the raw value to 12-bits
+ raw_value <<= (12 - adc_get_resolution(adcHandle));
+
+ float core_temp_avg_slope = (*ADC_CAL2 - *ADC_CAL1) / 80.0;
+ return (((float)raw_value * adc_refcor - *ADC_CAL1) / core_temp_avg_slope) + 30.0f;
+}
+
+float adc_read_core_vbat(ADC_HandleTypeDef *adcHandle) {
+ uint32_t raw_value = adc_config_and_read_channel(adcHandle, ADC_CHANNEL_VBAT);
+
+ // Note: constants assume 12-bit resolution, so we scale the raw value to
+ // be 12-bits.
+ raw_value <<= (12 - adc_get_resolution(adcHandle));
+
+ #if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7)
+ // 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
+ // the channel, and here we disable VBATE so a subsequent call for
+ // TEMPSENSOR or VREFINT works correctly.
+ ADC->CCR &= ~ADC_CCR_VBATE;
+ #endif
+
+ return raw_value * VBAT_DIV * ADC_SCALE * adc_refcor;
+}
+
+float adc_read_core_vref(ADC_HandleTypeDef *adcHandle) {
+ uint32_t raw_value = adc_config_and_read_channel(adcHandle, ADC_CHANNEL_VREFINT);
+
+ // Note: constants assume 12-bit resolution, so we scale the raw value to
+ // be 12-bits.
+ raw_value <<= (12 - adc_get_resolution(adcHandle));
+
+ // update the reference correction factor
+ adc_refcor = ((float)(*VREFIN_CAL)) / ((float)raw_value);
+
+ return (*VREFIN_CAL) * ADC_SCALE;
+}
+#endif
+
+/******************************************************************************/
+/* MicroPython bindings : adc_all object */
+
+STATIC mp_obj_t adc_all_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
+ // check number of arguments
+ mp_arg_check_num(n_args, n_kw, 1, 2, false);
+
+ // make ADCAll object
+ pyb_adc_all_obj_t *o = m_new_obj(pyb_adc_all_obj_t);
+ o->base.type = &pyb_adc_all_type;
+ mp_int_t res = mp_obj_get_int(args[0]);
+ uint32_t en_mask = 0xffffffff;
+ if (n_args > 1) {
+ en_mask = mp_obj_get_int(args[1]);
+ }
+ adc_init_all(o, res, en_mask);
+
+ return o;
+}
+
+STATIC mp_obj_t adc_all_read_channel(mp_obj_t self_in, mp_obj_t channel) {
+ pyb_adc_all_obj_t *self = self_in;
+ uint32_t chan = adc_get_internal_channel(mp_obj_get_int(channel));
+ uint32_t data = adc_config_and_read_channel(&self->handle, chan);
+ return mp_obj_new_int(data);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(adc_all_read_channel_obj, adc_all_read_channel);
+
+STATIC mp_obj_t adc_all_read_core_temp(mp_obj_t self_in) {
+ pyb_adc_all_obj_t *self = self_in;
+ #if MICROPY_PY_BUILTINS_FLOAT
+ float data = adc_read_core_temp_float(&self->handle);
+ return mp_obj_new_float(data);
+ #else
+ int data = adc_read_core_temp(&self->handle);
+ return mp_obj_new_int(data);
+ #endif
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(adc_all_read_core_temp_obj, adc_all_read_core_temp);
+
+#if MICROPY_PY_BUILTINS_FLOAT
+STATIC mp_obj_t adc_all_read_core_vbat(mp_obj_t self_in) {
+ pyb_adc_all_obj_t *self = self_in;
+ float data = adc_read_core_vbat(&self->handle);
+ return mp_obj_new_float(data);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(adc_all_read_core_vbat_obj, adc_all_read_core_vbat);
+
+STATIC mp_obj_t adc_all_read_core_vref(mp_obj_t self_in) {
+ pyb_adc_all_obj_t *self = self_in;
+ float data = adc_read_core_vref(&self->handle);
+ return mp_obj_new_float(data);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(adc_all_read_core_vref_obj, adc_all_read_core_vref);
+
+STATIC mp_obj_t adc_all_read_vref(mp_obj_t self_in) {
+ pyb_adc_all_obj_t *self = self_in;
+ adc_read_core_vref(&self->handle);
+ return mp_obj_new_float(3.3 * adc_refcor);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(adc_all_read_vref_obj, adc_all_read_vref);
+#endif
+
+STATIC const mp_rom_map_elem_t adc_all_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_read_channel), MP_ROM_PTR(&adc_all_read_channel_obj) },
+ { MP_ROM_QSTR(MP_QSTR_read_core_temp), MP_ROM_PTR(&adc_all_read_core_temp_obj) },
+#if MICROPY_PY_BUILTINS_FLOAT
+ { MP_ROM_QSTR(MP_QSTR_read_core_vbat), MP_ROM_PTR(&adc_all_read_core_vbat_obj) },
+ { MP_ROM_QSTR(MP_QSTR_read_core_vref), MP_ROM_PTR(&adc_all_read_core_vref_obj) },
+ { MP_ROM_QSTR(MP_QSTR_read_vref), MP_ROM_PTR(&adc_all_read_vref_obj) },
+#endif
+};
+
+STATIC MP_DEFINE_CONST_DICT(adc_all_locals_dict, adc_all_locals_dict_table);
+
+const mp_obj_type_t pyb_adc_all_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_ADCAll,
+ .make_new = adc_all_make_new,
+ .locals_dict = (mp_obj_dict_t*)&adc_all_locals_dict,
+};
diff --git a/ports/stm32/adc.h b/ports/stm32/adc.h
new file mode 100644
index 000000000..c90e6b343
--- /dev/null
+++ b/ports/stm32/adc.h
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ */
+#ifndef MICROPY_INCLUDED_STMHAL_ADC_H
+#define MICROPY_INCLUDED_STMHAL_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
diff --git a/ports/stm32/autoflash b/ports/stm32/autoflash
new file mode 100755
index 000000000..d2240ccb5
--- /dev/null
+++ b/ports/stm32/autoflash
@@ -0,0 +1,44 @@
+#!/bin/sh
+#
+# This script loops doing the following:
+# - wait for DFU device
+# - flash DFU device
+# - wait for DFU to exit
+# - wait for serial port to appear
+# - run a terminal
+
+SERIAL=/dev/ttyACM0
+DEVICE=0483:df11
+
+while true; do
+ echo "waiting for DFU device..."
+ while true; do
+ if lsusb | grep -q DFU; then
+ break
+ fi
+ sleep 1s
+ done
+
+ echo "found DFU device, flashing"
+ dfu-util -a 0 -d $DEVICE -D build/flash.dfu
+
+ echo "waiting for DFU to exit..."
+ while true; do
+ if lsusb | grep -q DFU; then
+ sleep 1s
+ continue
+ fi
+ break
+ done
+
+ echo "waiting for $SERIAL..."
+ while true; do
+ if ls /dev/tty* | grep -q $SERIAL; then
+ break
+ fi
+ sleep 1s
+ continue
+ done
+ sleep 1s
+ picocom $SERIAL
+done
diff --git a/ports/stm32/boards/CERB40/mpconfigboard.h b/ports/stm32/boards/CERB40/mpconfigboard.h
new file mode 100644
index 000000000..284de7a40
--- /dev/null
+++ b/ports/stm32/boards/CERB40/mpconfigboard.h
@@ -0,0 +1,67 @@
+#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)
+
+// HSE is 12MHz
+#define MICROPY_HW_CLK_PLLM (12)
+#define MICROPY_HW_CLK_PLLN (336)
+#define MICROPY_HW_CLK_PLLP (RCC_PLLP_DIV2)
+#define MICROPY_HW_CLK_PLLQ (7)
+
+// UART config
+#define MICROPY_HW_UART1_TX (pin_A9)
+#define MICROPY_HW_UART1_RX (pin_A10)
+#define MICROPY_HW_UART2_TX (pin_A2)
+#define MICROPY_HW_UART2_RX (pin_A3)
+#define MICROPY_HW_UART2_RTS (pin_A1)
+#define MICROPY_HW_UART2_CTS (pin_A0)
+#define MICROPY_HW_UART3_TX (pin_D8)
+#define MICROPY_HW_UART3_RX (pin_D9)
+#define MICROPY_HW_UART3_RTS (pin_D12)
+#define MICROPY_HW_UART3_CTS (pin_D11)
+#define MICROPY_HW_UART4_TX (pin_A0)
+#define MICROPY_HW_UART4_RX (pin_A1)
+#define MICROPY_HW_UART5_TX (pin_C12)
+#define MICROPY_HW_UART5_RX (pin_D2)
+#define MICROPY_HW_UART6_TX (pin_C6)
+#define MICROPY_HW_UART6_RX (pin_C7)
+
+// I2C busses
+#define MICROPY_HW_I2C1_SCL (pin_B6)
+#define MICROPY_HW_I2C1_SDA (pin_B7)
+#define MICROPY_HW_I2C2_SCL (pin_B10)
+#define MICROPY_HW_I2C2_SDA (pin_B11)
+#define MICROPY_HW_I2C3_SCL (pin_A8)
+#define MICROPY_HW_I2C3_SDA (pin_C9)
+
+// SPI busses
+#define MICROPY_HW_SPI1_NSS (pin_A4)
+#define MICROPY_HW_SPI1_SCK (pin_A5)
+#define MICROPY_HW_SPI1_MISO (pin_A6)
+#define MICROPY_HW_SPI1_MOSI (pin_A7)
+#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)
+
+// The Cerb40 has No LEDs
+
+// The Cerb40 has No SDCard
+
+// USB config
+//#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
new file mode 100644
index 000000000..5734c6690
--- /dev/null
+++ b/ports/stm32/boards/CERB40/mpconfigboard.mk
@@ -0,0 +1,4 @@
+MCU_SERIES = f4
+CMSIS_MCU = STM32F405xx
+AF_FILE = boards/stm32f405_af.csv
+LD_FILE = boards/stm32f405.ld
diff --git a/ports/stm32/boards/CERB40/pins.csv b/ports/stm32/boards/CERB40/pins.csv
new file mode 100644
index 000000000..411031e8f
--- /dev/null
+++ b/ports/stm32/boards/CERB40/pins.csv
@@ -0,0 +1,46 @@
+JP1,3.3V
+JP2,GND
+JP3,PA8
+JP4,PA13
+JP5,PA7
+JP6,PA6
+JP7,PC10
+JP8,PA14
+JP9,PC11
+JP10,PB4
+JP11,PB9
+JP12,PB3
+JP13,PD2
+JP14,PC12
+JP15,VBAT
+JP16,PB8
+JP17,Loader
+JP18,PB7
+JP19,PB6
+JP20,PB5
+JP21,Reset
+JP22,PC0
+JP23,PC1
+JP24,PC2
+JP25,PC3
+JP26,PA0
+JP27,PA1
+JP28,PA2
+JP29,PA3
+JP30,PA4
+JP31,PA5
+JP32,PB10
+JP33,PB11
+JP34,PB14
+JP35,PB15
+JP36,PC6
+JP37,PC7
+JP38,PC8
+JP39,PC9
+JP40,VUSB
+UART1_TX,PA9
+UART1_RX,PA10
+UART3_TX,PD8
+UART3_RX,PD9
+UART3_RTS,PD12
+UART3_CTS,PD11
diff --git a/ports/stm32/boards/CERB40/stm32f4xx_hal_conf.h b/ports/stm32/boards/CERB40/stm32f4xx_hal_conf.h
new file mode 100644
index 000000000..d6aca705c
--- /dev/null
+++ b/ports/stm32/boards/CERB40/stm32f4xx_hal_conf.h
@@ -0,0 +1,411 @@
+/**
+ ******************************************************************************
+ * @file stm32f4xx_hal_conf.h
+ * @author MCD Application Team
+ * @version V1.1.0
+ * @date 19-June-2014
+ * @brief HAL configuration file.
+ ******************************************************************************
+ * @attention
+ *
+ * <h2><center>&copy; COPYRIGHT(c) 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.
+ *
+ ******************************************************************************
+ */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __STM32F4xx_HAL_CONF_H
+#define __STM32F4xx_HAL_CONF_H
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/* Exported types ------------------------------------------------------------*/
+/* Exported constants --------------------------------------------------------*/
+
+#define USE_USB_FS
+
+/* ########################## 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_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_PCCARD_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_LTDC_MODULE_ENABLED */
+#define HAL_PWR_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_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 */
+
+
+/* ########################## 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)12000000) /*!< Value of the External oscillator in Hz */
+#endif /* HSE_VALUE */
+
+#if !defined (HSE_STARTUP_TIMEOUT)
+ #define HSE_STARTUP_TIMEOUT ((uint32_t)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 ((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)40000)
+#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 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 */
+
+/* ################## 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 0
+#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)4) /* 4 Rx buffers of size ETH_RX_BUF_SIZE */
+#define ETH_TXBUFNB ((uint32_t)4) /* 4 Tx buffers of size ETH_TX_BUF_SIZE */
+
+/* Section 2: PHY configuration section */
+
+/* DP83848 PHY Address*/
+#define DP83848_PHY_ADDRESS 0x01
+/* PHY Reset delay these values are based on a 1 ms Systick interrupt*/
+#define PHY_RESET_DELAY ((uint32_t)0x000000FF)
+/* PHY Configuration delay */
+#define PHY_CONFIG_DELAY ((uint32_t)0x00000FFF)
+
+#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 "stm32f4xx_hal_rcc.h"
+#endif /* HAL_RCC_MODULE_ENABLED */
+
+#ifdef HAL_GPIO_MODULE_ENABLED
+ #include "stm32f4xx_hal_gpio.h"
+#endif /* HAL_GPIO_MODULE_ENABLED */
+
+#ifdef HAL_DMA_MODULE_ENABLED
+ #include "stm32f4xx_hal_dma.h"
+#endif /* HAL_DMA_MODULE_ENABLED */
+
+#ifdef HAL_CORTEX_MODULE_ENABLED
+ #include "stm32f4xx_hal_cortex.h"
+#endif /* HAL_CORTEX_MODULE_ENABLED */
+
+#ifdef HAL_ADC_MODULE_ENABLED
+ #include "stm32f4xx_hal_adc.h"
+#endif /* HAL_ADC_MODULE_ENABLED */
+
+#ifdef HAL_CAN_MODULE_ENABLED
+ #include "stm32f4xx_hal_can.h"
+#endif /* HAL_CAN_MODULE_ENABLED */
+
+#ifdef HAL_CRC_MODULE_ENABLED
+ #include "stm32f4xx_hal_crc.h"
+#endif /* HAL_CRC_MODULE_ENABLED */
+
+#ifdef HAL_CRYP_MODULE_ENABLED
+ #include "stm32f4xx_hal_cryp.h"
+#endif /* HAL_CRYP_MODULE_ENABLED */
+
+#ifdef HAL_DMA2D_MODULE_ENABLED
+ #include "stm32f4xx_hal_dma2d.h"
+#endif /* HAL_DMA2D_MODULE_ENABLED */
+
+#ifdef HAL_DAC_MODULE_ENABLED
+ #include "stm32f4xx_hal_dac.h"
+#endif /* HAL_DAC_MODULE_ENABLED */
+
+#ifdef HAL_DCMI_MODULE_ENABLED
+ #include "stm32f4xx_hal_dcmi.h"
+#endif /* HAL_DCMI_MODULE_ENABLED */
+
+#ifdef HAL_ETH_MODULE_ENABLED
+ #include "stm32f4xx_hal_eth.h"
+#endif /* HAL_ETH_MODULE_ENABLED */
+
+#ifdef HAL_FLASH_MODULE_ENABLED
+ #include "stm32f4xx_hal_flash.h"
+#endif /* HAL_FLASH_MODULE_ENABLED */
+
+#ifdef HAL_SRAM_MODULE_ENABLED
+ #include "stm32f4xx_hal_sram.h"
+#endif /* HAL_SRAM_MODULE_ENABLED */
+
+#ifdef HAL_NOR_MODULE_ENABLED
+ #include "stm32f4xx_hal_nor.h"
+#endif /* HAL_NOR_MODULE_ENABLED */
+
+#ifdef HAL_NAND_MODULE_ENABLED
+ #include "stm32f4xx_hal_nand.h"
+#endif /* HAL_NAND_MODULE_ENABLED */
+
+#ifdef HAL_PCCARD_MODULE_ENABLED
+ #include "stm32f4xx_hal_pccard.h"
+#endif /* HAL_PCCARD_MODULE_ENABLED */
+
+#ifdef HAL_SDRAM_MODULE_ENABLED
+ #include "stm32f4xx_hal_sdram.h"
+#endif /* HAL_SDRAM_MODULE_ENABLED */
+
+#ifdef HAL_HASH_MODULE_ENABLED
+ #include "stm32f4xx_hal_hash.h"
+#endif /* HAL_HASH_MODULE_ENABLED */
+
+#ifdef HAL_I2C_MODULE_ENABLED
+ #include "stm32f4xx_hal_i2c.h"
+#endif /* HAL_I2C_MODULE_ENABLED */
+
+#ifdef HAL_I2S_MODULE_ENABLED
+ #include "stm32f4xx_hal_i2s.h"
+#endif /* HAL_I2S_MODULE_ENABLED */
+
+#ifdef HAL_IWDG_MODULE_ENABLED
+ #include "stm32f4xx_hal_iwdg.h"
+#endif /* HAL_IWDG_MODULE_ENABLED */
+
+#ifdef HAL_LTDC_MODULE_ENABLED
+ #include "stm32f4xx_hal_ltdc.h"
+#endif /* HAL_LTDC_MODULE_ENABLED */
+
+#ifdef HAL_PWR_MODULE_ENABLED
+ #include "stm32f4xx_hal_pwr.h"
+#endif /* HAL_PWR_MODULE_ENABLED */
+
+#ifdef HAL_RNG_MODULE_ENABLED
+ #include "stm32f4xx_hal_rng.h"
+#endif /* HAL_RNG_MODULE_ENABLED */
+
+#ifdef HAL_RTC_MODULE_ENABLED
+ #include "stm32f4xx_hal_rtc.h"
+#endif /* HAL_RTC_MODULE_ENABLED */
+
+#ifdef HAL_SAI_MODULE_ENABLED
+ #include "stm32f4xx_hal_sai.h"
+#endif /* HAL_SAI_MODULE_ENABLED */
+
+#ifdef HAL_SD_MODULE_ENABLED
+ #include "stm32f4xx_hal_sd.h"
+#endif /* HAL_SD_MODULE_ENABLED */
+
+#ifdef HAL_SPI_MODULE_ENABLED
+ #include "stm32f4xx_hal_spi.h"
+#endif /* HAL_SPI_MODULE_ENABLED */
+
+#ifdef HAL_TIM_MODULE_ENABLED
+ #include "stm32f4xx_hal_tim.h"
+#endif /* HAL_TIM_MODULE_ENABLED */
+
+#ifdef HAL_UART_MODULE_ENABLED
+ #include "stm32f4xx_hal_uart.h"
+#endif /* HAL_UART_MODULE_ENABLED */
+
+#ifdef HAL_USART_MODULE_ENABLED
+ #include "stm32f4xx_hal_usart.h"
+#endif /* HAL_USART_MODULE_ENABLED */
+
+#ifdef HAL_IRDA_MODULE_ENABLED
+ #include "stm32f4xx_hal_irda.h"
+#endif /* HAL_IRDA_MODULE_ENABLED */
+
+#ifdef HAL_SMARTCARD_MODULE_ENABLED
+ #include "stm32f4xx_hal_smartcard.h"
+#endif /* HAL_SMARTCARD_MODULE_ENABLED */
+
+#ifdef HAL_WWDG_MODULE_ENABLED
+ #include "stm32f4xx_hal_wwdg.h"
+#endif /* HAL_WWDG_MODULE_ENABLED */
+
+#ifdef HAL_PCD_MODULE_ENABLED
+ #include "stm32f4xx_hal_pcd.h"
+#endif /* HAL_PCD_MODULE_ENABLED */
+
+#ifdef HAL_HCD_MODULE_ENABLED
+ #include "stm32f4xx_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 /* __STM32F4xx_HAL_CONF_H */
+
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/ports/stm32/boards/ESPRUINO_PICO/mpconfigboard.h b/ports/stm32/boards/ESPRUINO_PICO/mpconfigboard.h
new file mode 100644
index 000000000..d065180d8
--- /dev/null
+++ b/ports/stm32/boards/ESPRUINO_PICO/mpconfigboard.h
@@ -0,0 +1,72 @@
+#define MICROPY_HW_BOARD_NAME "Espruino Pico"
+#define MICROPY_HW_MCU_NAME "STM32F401CD"
+
+#define MICROPY_EMIT_THUMB (0)
+#define MICROPY_EMIT_INLINE_THUMB (0)
+#define MICROPY_PY_BUILTINS_COMPLEX (0)
+#define MICROPY_PY_USOCKET (0)
+#define MICROPY_PY_NETWORK (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 (0)
+#define MICROPY_HW_ENABLE_RTC (1)
+#define MICROPY_HW_ENABLE_TIMER (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)
+#define MICROPY_HW_CLK_PLLN (210)
+#define MICROPY_HW_CLK_PLLP (RCC_PLLP_DIV4)
+#define MICROPY_HW_CLK_PLLQ (7)
+
+// does not have a 32kHz crystal
+#define MICROPY_HW_RTC_USE_LSE (0)
+
+// 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)
+#define MICROPY_HW_UART2_RTS (pin_A1)
+#define MICROPY_HW_UART2_CTS (pin_A0)
+#define MICROPY_HW_UART6_TX (pin_A11)
+#define MICROPY_HW_UART6_RX (pin_A12)
+
+// I2C busses
+#define MICROPY_HW_I2C1_SCL (pin_B6)
+#define MICROPY_HW_I2C1_SDA (pin_B7)
+#define MICROPY_HW_I2C2_SCL (pin_B10)
+#define MICROPY_HW_I2C2_SDA (pin_B3)
+#define MICROPY_HW_I2C3_SCL (pin_A8)
+#define MICROPY_HW_I2C3_SDA (pin_B4)
+
+// SPI busses
+#define MICROPY_HW_SPI1_NSS (pin_A4)
+#define MICROPY_HW_SPI1_SCK (pin_A5)
+#define MICROPY_HW_SPI1_MISO (pin_A6)
+#define MICROPY_HW_SPI1_MOSI (pin_A7)
+#define MICROPY_HW_SPI2_NSS (pin_B12)
+#define MICROPY_HW_SPI2_SCK (pin_B13)
+#define MICROPY_HW_SPI2_MISO (pin_B14)
+#define MICROPY_HW_SPI2_MOSI (pin_B15)
+
+// BTN1 has no pullup or pulldown; it is active high and broken out on a header
+#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)
+
+// Pico has 2 LEDs
+#define MICROPY_HW_LED1 (pin_B2) // red
+#define MICROPY_HW_LED2 (pin_B12) // green
+#define MICROPY_HW_LED3 (pin_B12) // green
+#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))
diff --git a/ports/stm32/boards/ESPRUINO_PICO/mpconfigboard.mk b/ports/stm32/boards/ESPRUINO_PICO/mpconfigboard.mk
new file mode 100644
index 000000000..d531a594a
--- /dev/null
+++ b/ports/stm32/boards/ESPRUINO_PICO/mpconfigboard.mk
@@ -0,0 +1,7 @@
+MCU_SERIES = f4
+CMSIS_MCU = STM32F401xE
+AF_FILE = boards/stm32f401_af.csv
+LD_FILE = boards/stm32f401xd.ld
+
+# Don't include default frozen modules because MCU is tight on flash space
+FROZEN_MPY_DIR ?=
diff --git a/ports/stm32/boards/ESPRUINO_PICO/pins.csv b/ports/stm32/boards/ESPRUINO_PICO/pins.csv
new file mode 100644
index 000000000..636eb2cb3
--- /dev/null
+++ b/ports/stm32/boards/ESPRUINO_PICO/pins.csv
@@ -0,0 +1,34 @@
+B3,PB3
+B4,PB4
+B5,PB5
+B6,PB6
+B7,PB7
+A8,PA8
+B8,PB8
+B9,PB9
+A10,PA10
+A0,PA0
+A1,PA1
+A2,PA2
+A3,PA3
+A4,PA4
+A5,PA5
+A6,PA6
+A7,PA7
+B1,PB1
+B10,PB10
+B13,PB13
+B14,PB14
+B15,PB15
+B0,PB0
+SW,PC13
+LED_RED,PB2
+LED_GREEN,PB12
+USB_VBUS,PA9
+USB_DM,PA11
+USB_DP,PA12
+OSC32_IN,PC14
+OSC32_OUT,PC15
+NC1,PA13
+NC2,PA14
+NC3,PA15
diff --git a/ports/stm32/boards/ESPRUINO_PICO/stm32f4xx_hal_conf.h b/ports/stm32/boards/ESPRUINO_PICO/stm32f4xx_hal_conf.h
new file mode 100644
index 000000000..11a396b73
--- /dev/null
+++ b/ports/stm32/boards/ESPRUINO_PICO/stm32f4xx_hal_conf.h
@@ -0,0 +1,411 @@
+/**
+ ******************************************************************************
+ * @file stm32f4xx_hal_conf.h
+ * @author MCD Application Team
+ * @version V1.1.0
+ * @date 19-June-2014
+ * @brief HAL configuration file.
+ ******************************************************************************
+ * @attention
+ *
+ * <h2><center>&copy; COPYRIGHT(c) 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.
+ *
+ ******************************************************************************
+ */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __STM32F4xx_HAL_CONF_H
+#define __STM32F4xx_HAL_CONF_H
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/* Exported types ------------------------------------------------------------*/
+/* Exported constants --------------------------------------------------------*/
+
+#define USE_USB_FS
+
+/* ########################## 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_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_PCCARD_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_LTDC_MODULE_ENABLED */
+#define HAL_PWR_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_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 */
+
+
+/* ########################## 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)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 ((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)40000)
+#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 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 */
+
+/* ################## 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 0
+#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)4) /* 4 Rx buffers of size ETH_RX_BUF_SIZE */
+#define ETH_TXBUFNB ((uint32_t)4) /* 4 Tx buffers of size ETH_TX_BUF_SIZE */
+
+/* Section 2: PHY configuration section */
+
+/* DP83848 PHY Address*/
+#define DP83848_PHY_ADDRESS 0x01
+/* PHY Reset delay these values are based on a 1 ms Systick interrupt*/
+#define PHY_RESET_DELAY ((uint32_t)0x000000FF)
+/* PHY Configuration delay */
+#define PHY_CONFIG_DELAY ((uint32_t)0x00000FFF)
+
+#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 "stm32f4xx_hal_rcc.h"
+#endif /* HAL_RCC_MODULE_ENABLED */
+
+#ifdef HAL_GPIO_MODULE_ENABLED
+ #include "stm32f4xx_hal_gpio.h"
+#endif /* HAL_GPIO_MODULE_ENABLED */
+
+#ifdef HAL_DMA_MODULE_ENABLED
+ #include "stm32f4xx_hal_dma.h"
+#endif /* HAL_DMA_MODULE_ENABLED */
+
+#ifdef HAL_CORTEX_MODULE_ENABLED
+ #include "stm32f4xx_hal_cortex.h"
+#endif /* HAL_CORTEX_MODULE_ENABLED */
+
+#ifdef HAL_ADC_MODULE_ENABLED
+ #include "stm32f4xx_hal_adc.h"
+#endif /* HAL_ADC_MODULE_ENABLED */
+
+#ifdef HAL_CAN_MODULE_ENABLED
+ #include "stm32f4xx_hal_can.h"
+#endif /* HAL_CAN_MODULE_ENABLED */
+
+#ifdef HAL_CRC_MODULE_ENABLED
+ #include "stm32f4xx_hal_crc.h"
+#endif /* HAL_CRC_MODULE_ENABLED */
+
+#ifdef HAL_CRYP_MODULE_ENABLED
+ #include "stm32f4xx_hal_cryp.h"
+#endif /* HAL_CRYP_MODULE_ENABLED */
+
+#ifdef HAL_DMA2D_MODULE_ENABLED
+ #include "stm32f4xx_hal_dma2d.h"
+#endif /* HAL_DMA2D_MODULE_ENABLED */
+
+#ifdef HAL_DAC_MODULE_ENABLED
+ #include "stm32f4xx_hal_dac.h"
+#endif /* HAL_DAC_MODULE_ENABLED */
+
+#ifdef HAL_DCMI_MODULE_ENABLED
+ #include "stm32f4xx_hal_dcmi.h"
+#endif /* HAL_DCMI_MODULE_ENABLED */
+
+#ifdef HAL_ETH_MODULE_ENABLED
+ #include "stm32f4xx_hal_eth.h"
+#endif /* HAL_ETH_MODULE_ENABLED */
+
+#ifdef HAL_FLASH_MODULE_ENABLED
+ #include "stm32f4xx_hal_flash.h"
+#endif /* HAL_FLASH_MODULE_ENABLED */
+
+#ifdef HAL_SRAM_MODULE_ENABLED
+ #include "stm32f4xx_hal_sram.h"
+#endif /* HAL_SRAM_MODULE_ENABLED */
+
+#ifdef HAL_NOR_MODULE_ENABLED
+ #include "stm32f4xx_hal_nor.h"
+#endif /* HAL_NOR_MODULE_ENABLED */
+
+#ifdef HAL_NAND_MODULE_ENABLED
+ #include "stm32f4xx_hal_nand.h"
+#endif /* HAL_NAND_MODULE_ENABLED */
+
+#ifdef HAL_PCCARD_MODULE_ENABLED
+ #include "stm32f4xx_hal_pccard.h"
+#endif /* HAL_PCCARD_MODULE_ENABLED */
+
+#ifdef HAL_SDRAM_MODULE_ENABLED
+ #include "stm32f4xx_hal_sdram.h"
+#endif /* HAL_SDRAM_MODULE_ENABLED */
+
+#ifdef HAL_HASH_MODULE_ENABLED
+ #include "stm32f4xx_hal_hash.h"
+#endif /* HAL_HASH_MODULE_ENABLED */
+
+#ifdef HAL_I2C_MODULE_ENABLED
+ #include "stm32f4xx_hal_i2c.h"
+#endif /* HAL_I2C_MODULE_ENABLED */
+
+#ifdef HAL_I2S_MODULE_ENABLED
+ #include "stm32f4xx_hal_i2s.h"
+#endif /* HAL_I2S_MODULE_ENABLED */
+
+#ifdef HAL_IWDG_MODULE_ENABLED
+ #include "stm32f4xx_hal_iwdg.h"
+#endif /* HAL_IWDG_MODULE_ENABLED */
+
+#ifdef HAL_LTDC_MODULE_ENABLED
+ #include "stm32f4xx_hal_ltdc.h"
+#endif /* HAL_LTDC_MODULE_ENABLED */
+
+#ifdef HAL_PWR_MODULE_ENABLED
+ #include "stm32f4xx_hal_pwr.h"
+#endif /* HAL_PWR_MODULE_ENABLED */
+
+#ifdef HAL_RNG_MODULE_ENABLED
+ #include "stm32f4xx_hal_rng.h"
+#endif /* HAL_RNG_MODULE_ENABLED */
+
+#ifdef HAL_RTC_MODULE_ENABLED
+ #include "stm32f4xx_hal_rtc.h"
+#endif /* HAL_RTC_MODULE_ENABLED */
+
+#ifdef HAL_SAI_MODULE_ENABLED
+ #include "stm32f4xx_hal_sai.h"
+#endif /* HAL_SAI_MODULE_ENABLED */
+
+#ifdef HAL_SD_MODULE_ENABLED
+ #include "stm32f4xx_hal_sd.h"
+#endif /* HAL_SD_MODULE_ENABLED */
+
+#ifdef HAL_SPI_MODULE_ENABLED
+ #include "stm32f4xx_hal_spi.h"
+#endif /* HAL_SPI_MODULE_ENABLED */
+
+#ifdef HAL_TIM_MODULE_ENABLED
+ #include "stm32f4xx_hal_tim.h"
+#endif /* HAL_TIM_MODULE_ENABLED */
+
+#ifdef HAL_UART_MODULE_ENABLED
+ #include "stm32f4xx_hal_uart.h"
+#endif /* HAL_UART_MODULE_ENABLED */
+
+#ifdef HAL_USART_MODULE_ENABLED
+ #include "stm32f4xx_hal_usart.h"
+#endif /* HAL_USART_MODULE_ENABLED */
+
+#ifdef HAL_IRDA_MODULE_ENABLED
+ #include "stm32f4xx_hal_irda.h"
+#endif /* HAL_IRDA_MODULE_ENABLED */
+
+#ifdef HAL_SMARTCARD_MODULE_ENABLED
+ #include "stm32f4xx_hal_smartcard.h"
+#endif /* HAL_SMARTCARD_MODULE_ENABLED */
+
+#ifdef HAL_WWDG_MODULE_ENABLED
+ #include "stm32f4xx_hal_wwdg.h"
+#endif /* HAL_WWDG_MODULE_ENABLED */
+
+#ifdef HAL_PCD_MODULE_ENABLED
+ #include "stm32f4xx_hal_pcd.h"
+#endif /* HAL_PCD_MODULE_ENABLED */
+
+#ifdef HAL_HCD_MODULE_ENABLED
+ #include "stm32f4xx_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 /* __STM32F4xx_HAL_CONF_H */
+
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/ports/stm32/boards/HYDRABUS/mpconfigboard.h b/ports/stm32/boards/HYDRABUS/mpconfigboard.h
new file mode 100644
index 000000000..38fba9787
--- /dev/null
+++ b/ports/stm32/boards/HYDRABUS/mpconfigboard.h
@@ -0,0 +1,81 @@
+#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)
+
+// HSE is 8MHz
+#define MICROPY_HW_CLK_PLLM (8)
+#define MICROPY_HW_CLK_PLLN (336)
+#define MICROPY_HW_CLK_PLLP (RCC_PLLP_DIV2)
+#define MICROPY_HW_CLK_PLLQ (7)
+
+// UART config
+#define MICROPY_HW_UART1_TX (pin_A9)
+#define MICROPY_HW_UART1_RX (pin_A10)
+#define MICROPY_HW_UART2_TX (pin_A2)
+#define MICROPY_HW_UART2_RX (pin_A3)
+#define MICROPY_HW_UART2_RTS (pin_A1)
+#define MICROPY_HW_UART2_CTS (pin_A0)
+#define MICROPY_HW_UART3_TX (pin_D8)
+#define MICROPY_HW_UART3_RX (pin_D9)
+#define MICROPY_HW_UART3_RTS (pin_D12)
+#define MICROPY_HW_UART3_CTS (pin_D11)
+#define MICROPY_HW_UART4_TX (pin_A0)
+#define MICROPY_HW_UART4_RX (pin_A1)
+#define MICROPY_HW_UART6_TX (pin_C6)
+#define MICROPY_HW_UART6_RX (pin_C7)
+
+// I2C busses
+#define MICROPY_HW_I2C1_SCL (pin_B6)
+#define MICROPY_HW_I2C1_SDA (pin_B7)
+#define MICROPY_HW_I2C2_SCL (pin_B10)
+#define MICROPY_HW_I2C2_SDA (pin_B11)
+
+// SPI busses
+#define MICROPY_HW_SPI1_NSS (pin_A4)
+#define MICROPY_HW_SPI1_SCK (pin_A5)
+#define MICROPY_HW_SPI1_MISO (pin_A6)
+#define MICROPY_HW_SPI1_MOSI (pin_A7)
+#define MICROPY_HW_SPI2_NSS (pin_B12)
+#define MICROPY_HW_SPI2_SCK (pin_B13)
+#define MICROPY_HW_SPI2_MISO (pin_B14)
+#define MICROPY_HW_SPI2_MOSI (pin_B15)
+#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)
+
+// USRSW/UBTN (Needs Jumper UBTN) 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)
+#define MICROPY_HW_USRSW_EXTI_MODE (GPIO_MODE_IT_RISING)
+#define MICROPY_HW_USRSW_PRESSED (1)
+
+// The HydraBus has 1 LED (Needs jumper on ULED)
+#define MICROPY_HW_LED1 (pin_A4) // green
+#define MICROPY_HW_LED2 (pin_A4) // same as LED1
+#define MICROPY_HW_LED3 (pin_A4) // same as LED1
+#define MICROPY_HW_LED4 (pin_A4) // same as LED1
+#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_high(pin))
+#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin))
+
+// SD card detect switch (not used, always on)
+#define MICROPY_HW_SDCARD_DETECT_PIN (pin_A8)
+#define MICROPY_HW_SDCARD_DETECT_PULL (GPIO_PULLUP)
+#define MICROPY_HW_SDCARD_DETECT_PRESENT (1)
+
+// USB config
+#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
new file mode 100644
index 000000000..5734c6690
--- /dev/null
+++ b/ports/stm32/boards/HYDRABUS/mpconfigboard.mk
@@ -0,0 +1,4 @@
+MCU_SERIES = f4
+CMSIS_MCU = STM32F405xx
+AF_FILE = boards/stm32f405_af.csv
+LD_FILE = boards/stm32f405.ld
diff --git a/ports/stm32/boards/HYDRABUS/pins.csv b/ports/stm32/boards/HYDRABUS/pins.csv
new file mode 100644
index 000000000..47e1f4313
--- /dev/null
+++ b/ports/stm32/boards/HYDRABUS/pins.csv
@@ -0,0 +1,52 @@
+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
+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
+VUSB,PB13
+USB1D_N,PB14
+USB1D_P,PB15
+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
+PD2,PD2
+BOOT0,BOOT0
+PA15,PA15
+UART3_TX,PD8
+UART3_RX,PD9
+UART3_RTS,PD12
+UART3_CTS,PD11
diff --git a/ports/stm32/boards/HYDRABUS/stm32f4xx_hal_conf.h b/ports/stm32/boards/HYDRABUS/stm32f4xx_hal_conf.h
new file mode 100644
index 000000000..8941e8290
--- /dev/null
+++ b/ports/stm32/boards/HYDRABUS/stm32f4xx_hal_conf.h
@@ -0,0 +1,411 @@
+/**
+ ******************************************************************************
+ * @file stm32f4xx_hal_conf.h
+ * @author MCD Application Team
+ * @version V1.1.0
+ * @date 19-June-2014
+ * @brief HAL configuration file.
+ ******************************************************************************
+ * @attention
+ *
+ * <h2><center>&copy; COPYRIGHT(c) 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.
+ *
+ ******************************************************************************
+ */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __STM32F4xx_HAL_CONF_H
+#define __STM32F4xx_HAL_CONF_H
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/* Exported types ------------------------------------------------------------*/
+/* Exported constants --------------------------------------------------------*/
+
+#define USE_USB_FS
+
+/* ########################## 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_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_PCCARD_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_LTDC_MODULE_ENABLED */
+#define HAL_PWR_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_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 */
+
+
+/* ########################## 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)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 ((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)40000)
+#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 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 */
+
+/* ################## 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 0
+#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)4) /* 4 Rx buffers of size ETH_RX_BUF_SIZE */
+#define ETH_TXBUFNB ((uint32_t)4) /* 4 Tx buffers of size ETH_TX_BUF_SIZE */
+
+/* Section 2: PHY configuration section */
+
+/* DP83848 PHY Address*/
+#define DP83848_PHY_ADDRESS 0x01
+/* PHY Reset delay these values are based on a 1 ms Systick interrupt*/
+#define PHY_RESET_DELAY ((uint32_t)0x000000FF)
+/* PHY Configuration delay */
+#define PHY_CONFIG_DELAY ((uint32_t)0x00000FFF)
+
+#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 "stm32f4xx_hal_rcc.h"
+#endif /* HAL_RCC_MODULE_ENABLED */
+
+#ifdef HAL_GPIO_MODULE_ENABLED
+ #include "stm32f4xx_hal_gpio.h"
+#endif /* HAL_GPIO_MODULE_ENABLED */
+
+#ifdef HAL_DMA_MODULE_ENABLED
+ #include "stm32f4xx_hal_dma.h"
+#endif /* HAL_DMA_MODULE_ENABLED */
+
+#ifdef HAL_CORTEX_MODULE_ENABLED
+ #include "stm32f4xx_hal_cortex.h"
+#endif /* HAL_CORTEX_MODULE_ENABLED */
+
+#ifdef HAL_ADC_MODULE_ENABLED
+ #include "stm32f4xx_hal_adc.h"
+#endif /* HAL_ADC_MODULE_ENABLED */
+
+#ifdef HAL_CAN_MODULE_ENABLED
+ #include "stm32f4xx_hal_can.h"
+#endif /* HAL_CAN_MODULE_ENABLED */
+
+#ifdef HAL_CRC_MODULE_ENABLED
+ #include "stm32f4xx_hal_crc.h"
+#endif /* HAL_CRC_MODULE_ENABLED */
+
+#ifdef HAL_CRYP_MODULE_ENABLED
+ #include "stm32f4xx_hal_cryp.h"
+#endif /* HAL_CRYP_MODULE_ENABLED */
+
+#ifdef HAL_DMA2D_MODULE_ENABLED
+ #include "stm32f4xx_hal_dma2d.h"
+#endif /* HAL_DMA2D_MODULE_ENABLED */
+
+#ifdef HAL_DAC_MODULE_ENABLED
+ #include "stm32f4xx_hal_dac.h"
+#endif /* HAL_DAC_MODULE_ENABLED */
+
+#ifdef HAL_DCMI_MODULE_ENABLED
+ #include "stm32f4xx_hal_dcmi.h"
+#endif /* HAL_DCMI_MODULE_ENABLED */
+
+#ifdef HAL_ETH_MODULE_ENABLED
+ #include "stm32f4xx_hal_eth.h"
+#endif /* HAL_ETH_MODULE_ENABLED */
+
+#ifdef HAL_FLASH_MODULE_ENABLED
+ #include "stm32f4xx_hal_flash.h"
+#endif /* HAL_FLASH_MODULE_ENABLED */
+
+#ifdef HAL_SRAM_MODULE_ENABLED
+ #include "stm32f4xx_hal_sram.h"
+#endif /* HAL_SRAM_MODULE_ENABLED */
+
+#ifdef HAL_NOR_MODULE_ENABLED
+ #include "stm32f4xx_hal_nor.h"
+#endif /* HAL_NOR_MODULE_ENABLED */
+
+#ifdef HAL_NAND_MODULE_ENABLED
+ #include "stm32f4xx_hal_nand.h"
+#endif /* HAL_NAND_MODULE_ENABLED */
+
+#ifdef HAL_PCCARD_MODULE_ENABLED
+ #include "stm32f4xx_hal_pccard.h"
+#endif /* HAL_PCCARD_MODULE_ENABLED */
+
+#ifdef HAL_SDRAM_MODULE_ENABLED
+ #include "stm32f4xx_hal_sdram.h"
+#endif /* HAL_SDRAM_MODULE_ENABLED */
+
+#ifdef HAL_HASH_MODULE_ENABLED
+ #include "stm32f4xx_hal_hash.h"
+#endif /* HAL_HASH_MODULE_ENABLED */
+
+#ifdef HAL_I2C_MODULE_ENABLED
+ #include "stm32f4xx_hal_i2c.h"
+#endif /* HAL_I2C_MODULE_ENABLED */
+
+#ifdef HAL_I2S_MODULE_ENABLED
+ #include "stm32f4xx_hal_i2s.h"
+#endif /* HAL_I2S_MODULE_ENABLED */
+
+#ifdef HAL_IWDG_MODULE_ENABLED
+ #include "stm32f4xx_hal_iwdg.h"
+#endif /* HAL_IWDG_MODULE_ENABLED */
+
+#ifdef HAL_LTDC_MODULE_ENABLED
+ #include "stm32f4xx_hal_ltdc.h"
+#endif /* HAL_LTDC_MODULE_ENABLED */
+
+#ifdef HAL_PWR_MODULE_ENABLED
+ #include "stm32f4xx_hal_pwr.h"
+#endif /* HAL_PWR_MODULE_ENABLED */
+
+#ifdef HAL_RNG_MODULE_ENABLED
+ #include "stm32f4xx_hal_rng.h"
+#endif /* HAL_RNG_MODULE_ENABLED */
+
+#ifdef HAL_RTC_MODULE_ENABLED
+ #include "stm32f4xx_hal_rtc.h"
+#endif /* HAL_RTC_MODULE_ENABLED */
+
+#ifdef HAL_SAI_MODULE_ENABLED
+ #include "stm32f4xx_hal_sai.h"
+#endif /* HAL_SAI_MODULE_ENABLED */
+
+#ifdef HAL_SD_MODULE_ENABLED
+ #include "stm32f4xx_hal_sd.h"
+#endif /* HAL_SD_MODULE_ENABLED */
+
+#ifdef HAL_SPI_MODULE_ENABLED
+ #include "stm32f4xx_hal_spi.h"
+#endif /* HAL_SPI_MODULE_ENABLED */
+
+#ifdef HAL_TIM_MODULE_ENABLED
+ #include "stm32f4xx_hal_tim.h"
+#endif /* HAL_TIM_MODULE_ENABLED */
+
+#ifdef HAL_UART_MODULE_ENABLED
+ #include "stm32f4xx_hal_uart.h"
+#endif /* HAL_UART_MODULE_ENABLED */
+
+#ifdef HAL_USART_MODULE_ENABLED
+ #include "stm32f4xx_hal_usart.h"
+#endif /* HAL_USART_MODULE_ENABLED */
+
+#ifdef HAL_IRDA_MODULE_ENABLED
+ #include "stm32f4xx_hal_irda.h"
+#endif /* HAL_IRDA_MODULE_ENABLED */
+
+#ifdef HAL_SMARTCARD_MODULE_ENABLED
+ #include "stm32f4xx_hal_smartcard.h"
+#endif /* HAL_SMARTCARD_MODULE_ENABLED */
+
+#ifdef HAL_WWDG_MODULE_ENABLED
+ #include "stm32f4xx_hal_wwdg.h"
+#endif /* HAL_WWDG_MODULE_ENABLED */
+
+#ifdef HAL_PCD_MODULE_ENABLED
+ #include "stm32f4xx_hal_pcd.h"
+#endif /* HAL_PCD_MODULE_ENABLED */
+
+#ifdef HAL_HCD_MODULE_ENABLED
+ #include "stm32f4xx_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 /* __STM32F4xx_HAL_CONF_H */
+
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/ports/stm32/boards/LIMIFROG/board_init.c b/ports/stm32/boards/LIMIFROG/board_init.c
new file mode 100644
index 000000000..72f920842
--- /dev/null
+++ b/ports/stm32/boards/LIMIFROG/board_init.c
@@ -0,0 +1,154 @@
+// The code is this file allows the user to enter DFU mode when the board
+// starts up, by connecting POS10 on the external connector to GND.
+// The code itself is taken from the LimiFrog software repository found at
+// https://github.com/LimiFrog/LimiFrog-SW, and the original license header
+// is copied below.
+
+#include STM32_HAL_H
+
+static void LBF_DFU_If_Needed(void);
+
+void LIMIFROG_board_early_init(void) {
+ LBF_DFU_If_Needed();
+}
+
+/*******************************************************************************
+ * LBF_DFU_If_Needed.c
+ *
+ * (c)2015 LimiFrog / CYMEYA
+ * This program is licensed under the terms of the MIT License.
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND.
+ * Please refer to the License File LICENSE.txt located at the root of this
+ * project for full licensing conditions,
+ * or visit https://opensource.org/licenses/MIT.
+ ******************************************************************************/
+
+#define __LIMIFROG_02
+
+/* ==== BTLE (excl UART) ======================================== */
+// PC9 = BT_RST (active high)
+
+#define BT_RST_PIN GPIO_PIN_9
+#define BT_RST_PORT GPIOC
+
+// Position 10
+#ifdef __LIMIFROG_01
+ #define CONN_POS10_PIN GPIO_PIN_9
+ #define CONN_POS10_PORT GPIOB
+#else
+ #define CONN_POS10_PIN GPIO_PIN_8
+ #define CONN_POS10_PORT GPIOB
+#endif
+
+static inline void GPIO_HIGH(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
+{
+ GPIOx->BSRR = (uint32_t)GPIO_Pin;
+}
+
+static inline int IS_GPIO_RESET(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
+{
+ GPIO_PinState bitstatus;
+ if((GPIOx->IDR & GPIO_Pin) != (uint32_t)GPIO_PIN_RESET)
+ {
+ bitstatus = GPIO_PIN_SET;
+ }
+ else
+ {
+ bitstatus = GPIO_PIN_RESET;
+ }
+ return (bitstatus==GPIO_PIN_RESET);
+}
+
+/**************************************************************
+ RATIONALE FOR THIS FUNCTION :
+
+ - The STM32 embeds in ROM a bootloader that allows to
+ obtain code and boot from a number of different interfaces,
+ including USB in a mode called "DFU" (Device Frimware Update)
+ [see AN3606 from ST for full details]
+ This bootloader code is executed instead of the regular
+ application code when pin BOOT0 is pulled-up (which on
+ LimiFrog0.2 is achieved by pressing the general-purpose
+ pushbutton switch on the side.
+ - The bootloader monitors a number of IOs of the STM32 to decide
+ from which interface it should boot.
+ - Problem in LimiFrog (up to versions 0.2a at least): upon
+ power-up the BLE modules generates some activity on UART3,
+ which is part of the pins monitored by the STM32.
+ This misleads the bootloader in trying to boot from UART3
+ and, as a result, not continuing with booting from USB.
+
+ - This code implements an alternative solution to launch the
+ bootloader while making sure UART3 remains stable.
+ - The idea it to start application code with a check, prior to any
+ other applicative code, of whether USB bootload is required (as
+ flagged by a GPIO pulled low at reset, in the same way as BOOT0).
+ The hadware reset pin of BLE is asserted (so that now it won't
+ generate any acitivity on UART3), and if USB bootload is required :
+ bootload ROM is remapped at address 0x0, stack pointer is
+ updated and the code is branched to the start of the bootloader.
+ - This code is run prior to any applicative configuration of clocks,
+ IRQs etc. -- the STM32 is therefore still running from MSI
+
+ THIS FUNCTION MAY BE SUPPRESSED IF YOU NEVER NEED TO BOOT DFU MODE
+
+ ********************************************************************/
+
+static void LBF_DFU_If_Needed(void)
+{
+
+
+ GPIO_InitTypeDef GPIO_InitStruct;
+
+
+ // Initialize and assert pin BTLE_RST
+ // (hw reset to BLE module, so it won't drive UART3)
+
+ __GPIOC_CLK_ENABLE();
+ GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
+ GPIO_InitStruct.Pull = GPIO_NOPULL;
+ GPIO_InitStruct.Speed = GPIO_SPEED_LOW;
+ GPIO_InitStruct.Pin = BT_RST_PIN;
+ HAL_GPIO_Init(BT_RST_PORT, &GPIO_InitStruct);
+
+ GPIO_HIGH(BT_RST_PORT, BT_RST_PIN); // assert BTLE reset
+
+
+ /* -- Bootloader will be called if position 10 on the extension port
+ is actively pulled low -- */
+ // Note - this is an arbitrary choice, code could be modified to
+ // monitor another GPIO of the STM32 and/or decide that active level
+ // is high rather than low
+
+
+ // Initialize Extension Port Position 10 = PB8 (bears I2C1_SCL)
+ // Use weak pull-up to detect if pin is externally pulled low
+
+ __GPIOB_CLK_ENABLE();
+ GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
+ GPIO_InitStruct.Pull = GPIO_PULLUP;
+ GPIO_InitStruct.Pin = CONN_POS10_PIN;
+ HAL_GPIO_Init(CONN_POS10_PORT, &GPIO_InitStruct);
+
+ // If selection pin pulled low...
+ if ( IS_GPIO_RESET(CONN_POS10_PORT, CONN_POS10_PIN ))
+
+ {
+ // Remap bootloader ROM (ie System Flash) to address 0x0
+ SYSCFG->MEMRMP = 0x00000001;
+
+ // Init stack pointer with value residing at ROM base
+ asm (
+ "LDR R0, =0x00000000\n\t" // load ROM base address"
+ "LDR SP,[R0, #0]\n\t" // assign main stack pointer"
+ );
+
+ // Jump to address pointed by 0x00000004 -- */
+
+ asm (
+ "LDR R0,[R0, #4]\n\t" // load bootloader address
+ "BX R0\n\t"
+ );
+
+ }
+}
diff --git a/ports/stm32/boards/LIMIFROG/mpconfigboard.h b/ports/stm32/boards/LIMIFROG/mpconfigboard.h
new file mode 100644
index 000000000..42b862fcf
--- /dev/null
+++ b/ports/stm32/boards/LIMIFROG/mpconfigboard.h
@@ -0,0 +1,61 @@
+#define MICROPY_HW_BOARD_NAME "LIMIFROG"
+#define MICROPY_HW_MCU_NAME "STM32L476"
+
+#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_BOARD_EARLY_INIT LIMIFROG_board_early_init
+void LIMIFROG_board_early_init(void);
+
+// MSI is used and is 4MHz
+#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_UART3_TX (pin_C10)
+#define MICROPY_HW_UART3_RX (pin_C11)
+
+// I2C busses
+#define MICROPY_HW_I2C1_SCL (pin_B8)
+#define MICROPY_HW_I2C1_SDA (pin_B9)
+#define MICROPY_HW_I2C2_SCL (pin_B10)
+#define MICROPY_HW_I2C2_SDA (pin_B11)
+
+// SPI busses
+#define MICROPY_HW_SPI1_NSS (pin_A4)
+#define MICROPY_HW_SPI1_SCK (pin_A5)
+#define MICROPY_HW_SPI1_MISO (pin_A6)
+#define MICROPY_HW_SPI1_MOSI (pin_A7)
+
+#define MICROPY_HW_SPI3_NSS (pin_A15)
+#define MICROPY_HW_SPI3_SCK (pin_B3)
+#define MICROPY_HW_SPI3_MISO (pin_B4)
+#define MICROPY_HW_SPI3_MOSI (pin_B5)
+
+#define MICROPY_HW_USRSW_PIN (pin_A15)
+#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_C3) // 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_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
new file mode 100644
index 000000000..a1304b655
--- /dev/null
+++ b/ports/stm32/boards/LIMIFROG/mpconfigboard.mk
@@ -0,0 +1,5 @@
+MCU_SERIES = l4
+CMSIS_MCU = STM32L476xx
+AF_FILE = boards/stm32l476_af.csv
+LD_FILE = boards/stm32l476xe.ld
+TEXT_ADDR = 0x08004000
diff --git a/ports/stm32/boards/LIMIFROG/pins.csv b/ports/stm32/boards/LIMIFROG/pins.csv
new file mode 100644
index 000000000..52f96b669
--- /dev/null
+++ b/ports/stm32/boards/LIMIFROG/pins.csv
@@ -0,0 +1,114 @@
+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
diff --git a/ports/stm32/boards/LIMIFROG/stm32l4xx_hal_conf.h b/ports/stm32/boards/LIMIFROG/stm32l4xx_hal_conf.h
new file mode 100644
index 000000000..9348e0679
--- /dev/null
+++ b/ports/stm32/boards/LIMIFROG/stm32l4xx_hal_conf.h
@@ -0,0 +1,373 @@
+/**
+ ******************************************************************************
+ * @file stm32l4xx_hal_conf.h
+ * @author MCD Application Team
+ * @version V1.2.0
+ * @date 25-November-2015
+ * @brief HAL configuration template file.
+ * This file should be copied to the application folder and renamed
+ * to stm32l4xx_hal_conf.h.
+ ******************************************************************************
+ * @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 __STM32L4xx_HAL_CONF_H
+#define __STM32L4xx_HAL_CONF_H
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+#define USE_USB_FS
+/* 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_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_DFSDM_MODULE_ENABLED */
+#define HAL_DMA_MODULE_ENABLED
+/* #define HAL_FIREWALL_MODULE_ENABLED */
+#define HAL_FLASH_MODULE_ENABLED
+/* #define HAL_HCD_MODULE_ENABLED */
+/* #define HAL_NAND_MODULE_ENABLED */
+/* #define HAL_NOR_MODULE_ENABLED */
+/* #define HAL_SRAM_MODULE_ENABLED */
+#define HAL_GPIO_MODULE_ENABLED
+#define HAL_I2C_MODULE_ENABLED
+/* #define HAL_IRDA_MODULE_ENABLED */
+/* #define HAL_IWDG_MODULE_ENABLED */
+/* #define HAL_LCD_MODULE_ENABLED */
+/* #define HAL_LPTIM_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_SMARTCARD_MODULE_ENABLED */
+/* #define HAL_SMBUS_MODULE_ENABLED */
+#define HAL_SPI_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 */
+
+
+/* ########################## 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 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 */
+
+/* Includes ------------------------------------------------------------------*/
+/**
+ * @brief Include module's header file
+ */
+
+#ifdef HAL_RCC_MODULE_ENABLED
+ #include "stm32l4xx_hal_rcc.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_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_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_OPAMP_MODULE_ENABLED
+#include "stm32l4xx_hal_opamp.h"
+#endif /* HAL_OPAMP_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 */
+
+/* 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 /* __STM32L4xx_HAL_CONF_H */
+
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/ports/stm32/boards/NETDUINO_PLUS_2/board_init.c b/ports/stm32/boards/NETDUINO_PLUS_2/board_init.c
new file mode 100644
index 000000000..085034b2d
--- /dev/null
+++ b/ports/stm32/boards/NETDUINO_PLUS_2/board_init.c
@@ -0,0 +1,24 @@
+#include STM32_HAL_H
+
+void NETDUINO_PLUS_2_board_early_init(void) {
+
+ __GPIOB_CLK_ENABLE();
+
+ // Turn off the backlight. LCD_BL_CTRL = PK3
+ GPIO_InitTypeDef GPIO_InitStructure;
+ GPIO_InitStructure.Speed = GPIO_SPEED_HIGH;
+ GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
+ GPIO_InitStructure.Pull = GPIO_PULLUP;
+
+#if MICROPY_HW_HAS_SDCARD
+ // Turn on the power enable for the sdcard (PB1)
+ GPIO_InitStructure.Pin = GPIO_PIN_1;
+ HAL_GPIO_Init(GPIOB, &GPIO_InitStructure);
+ HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_SET);
+#endif
+
+ // Turn on the power for the 5V on the expansion header (PB2)
+ GPIO_InitStructure.Pin = GPIO_PIN_2;
+ HAL_GPIO_Init(GPIOB, &GPIO_InitStructure);
+ HAL_GPIO_WritePin(GPIOB, GPIO_PIN_2, GPIO_PIN_SET);
+}
diff --git a/ports/stm32/boards/NETDUINO_PLUS_2/mpconfigboard.h b/ports/stm32/boards/NETDUINO_PLUS_2/mpconfigboard.h
new file mode 100644
index 000000000..9586ae4e5
--- /dev/null
+++ b/ports/stm32/boards/NETDUINO_PLUS_2/mpconfigboard.h
@@ -0,0 +1,73 @@
+#define MICROPY_HW_BOARD_NAME "NetduinoPlus2"
+#define MICROPY_HW_MCU_NAME "STM32F405RG"
+
+#define MICROPY_HW_HAS_SWITCH (1)
+
+#define MICROPY_HW_HAS_FLASH (1)
+// On the netuino, the sdcard appears to be wired up as a 1-bit
+// 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_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
+
+// HSE is 25MHz
+#define MICROPY_HW_CLK_PLLM (25)
+#define MICROPY_HW_CLK_PLLN (336)
+#define MICROPY_HW_CLK_PLLP (RCC_PLLP_DIV2)
+#define MICROPY_HW_CLK_PLLQ (7)
+
+// UART config
+#define MICROPY_HW_UART1_TX (pin_A9)
+#define MICROPY_HW_UART1_RX (pin_A10)
+#define MICROPY_HW_UART2_TX (pin_A2)
+#define MICROPY_HW_UART2_RX (pin_A3)
+#define MICROPY_HW_UART2_RTS (pin_A1)
+#define MICROPY_HW_UART2_CTS (pin_A0)
+#define MICROPY_HW_UART3_TX (pin_D8)
+#define MICROPY_HW_UART3_RX (pin_D9)
+#define MICROPY_HW_UART3_RTS (pin_D12)
+#define MICROPY_HW_UART3_CTS (pin_D11)
+#define MICROPY_HW_UART4_TX (pin_A0)
+#define MICROPY_HW_UART4_RX (pin_A1)
+#define MICROPY_HW_UART5_TX (pin_C12)
+#define MICROPY_HW_UART5_RX (pin_D2)
+#define MICROPY_HW_UART6_TX (pin_C6)
+#define MICROPY_HW_UART6_RX (pin_C7)
+
+// I2C busses
+#define MICROPY_HW_I2C1_SCL (pin_B6)
+#define MICROPY_HW_I2C1_SDA (pin_B7)
+
+// SPI busses
+#define MICROPY_HW_SPI2_NSS (pin_B12)
+#define MICROPY_HW_SPI2_SCK (pin_B13)
+#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_B11)
+#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_A10) // Blue LED
+#define MICROPY_HW_LED2 (pin_C13) // White LED (aka Power)
+#define MICROPY_HW_LED3 (pin_A10) // Same as Led(1)
+#define MICROPY_HW_LED4 (pin_C13) // Same as Led(2)
+#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
+#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
new file mode 100644
index 000000000..5734c6690
--- /dev/null
+++ b/ports/stm32/boards/NETDUINO_PLUS_2/mpconfigboard.mk
@@ -0,0 +1,4 @@
+MCU_SERIES = f4
+CMSIS_MCU = STM32F405xx
+AF_FILE = boards/stm32f405_af.csv
+LD_FILE = boards/stm32f405.ld
diff --git a/ports/stm32/boards/NETDUINO_PLUS_2/pins.csv b/ports/stm32/boards/NETDUINO_PLUS_2/pins.csv
new file mode 100644
index 000000000..3e71fade6
--- /dev/null
+++ b/ports/stm32/boards/NETDUINO_PLUS_2/pins.csv
@@ -0,0 +1,35 @@
+D0,PC7
+D1,PC6
+D2,PA3
+D3,PA2
+D4,PB12
+D5,PB8
+D6,PB9
+D7,PA1
+D8,PA0
+D9,PA6
+D10,PB10
+D11,PB15
+D12,PB14
+D13,PB13
+SDA,PB6
+SCL,PB7
+A0,PC0
+A1,PC1
+A2,PC2
+A3,PC3
+A4,PC4
+A5,PC5
+LED,PA10
+SW,PB11
+PWR_LED,PC13
+PWR_SD,PB1
+PWR_HDR,PB2
+PWR_ETH,PC15
+RST_ETH,PD2
+UART1_TX,PA9
+UART3_TX,PD8
+UART3_RX,PD9
+UART3_RTS,PD12
+UART3_CTS,PD11
+UART5_TX,PC12
diff --git a/ports/stm32/boards/NETDUINO_PLUS_2/stm32f4xx_hal_conf.h b/ports/stm32/boards/NETDUINO_PLUS_2/stm32f4xx_hal_conf.h
new file mode 100644
index 000000000..8b04c2845
--- /dev/null
+++ b/ports/stm32/boards/NETDUINO_PLUS_2/stm32f4xx_hal_conf.h
@@ -0,0 +1,411 @@
+/**
+ ******************************************************************************
+ * @file stm32f4xx_hal_conf.h
+ * @author MCD Application Team
+ * @version V1.1.0
+ * @date 19-June-2014
+ * @brief HAL configuration file.
+ ******************************************************************************
+ * @attention
+ *
+ * <h2><center>&copy; COPYRIGHT(c) 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.
+ *
+ ******************************************************************************
+ */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __STM32F4xx_HAL_CONF_H
+#define __STM32F4xx_HAL_CONF_H
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/* Exported types ------------------------------------------------------------*/
+/* Exported constants --------------------------------------------------------*/
+
+#define USE_USB_FS
+
+/* ########################## 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_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_PCCARD_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_LTDC_MODULE_ENABLED */
+#define HAL_PWR_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_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 */
+
+
+/* ########################## 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)25000000) /*!< Value of the External oscillator in Hz */
+#endif /* HSE_VALUE */
+
+#if !defined (HSE_STARTUP_TIMEOUT)
+ #define HSE_STARTUP_TIMEOUT ((uint32_t)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 ((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)40000)
+#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 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 */
+
+/* ################## 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 0
+#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)4) /* 4 Rx buffers of size ETH_RX_BUF_SIZE */
+#define ETH_TXBUFNB ((uint32_t)4) /* 4 Tx buffers of size ETH_TX_BUF_SIZE */
+
+/* Section 2: PHY configuration section */
+
+/* DP83848 PHY Address*/
+#define DP83848_PHY_ADDRESS 0x01
+/* PHY Reset delay these values are based on a 1 ms Systick interrupt*/
+#define PHY_RESET_DELAY ((uint32_t)0x000000FF)
+/* PHY Configuration delay */
+#define PHY_CONFIG_DELAY ((uint32_t)0x00000FFF)
+
+#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 "stm32f4xx_hal_rcc.h"
+#endif /* HAL_RCC_MODULE_ENABLED */
+
+#ifdef HAL_GPIO_MODULE_ENABLED
+ #include "stm32f4xx_hal_gpio.h"
+#endif /* HAL_GPIO_MODULE_ENABLED */
+
+#ifdef HAL_DMA_MODULE_ENABLED
+ #include "stm32f4xx_hal_dma.h"
+#endif /* HAL_DMA_MODULE_ENABLED */
+
+#ifdef HAL_CORTEX_MODULE_ENABLED
+ #include "stm32f4xx_hal_cortex.h"
+#endif /* HAL_CORTEX_MODULE_ENABLED */
+
+#ifdef HAL_ADC_MODULE_ENABLED
+ #include "stm32f4xx_hal_adc.h"
+#endif /* HAL_ADC_MODULE_ENABLED */
+
+#ifdef HAL_CAN_MODULE_ENABLED
+ #include "stm32f4xx_hal_can.h"
+#endif /* HAL_CAN_MODULE_ENABLED */
+
+#ifdef HAL_CRC_MODULE_ENABLED
+ #include "stm32f4xx_hal_crc.h"
+#endif /* HAL_CRC_MODULE_ENABLED */
+
+#ifdef HAL_CRYP_MODULE_ENABLED
+ #include "stm32f4xx_hal_cryp.h"
+#endif /* HAL_CRYP_MODULE_ENABLED */
+
+#ifdef HAL_DMA2D_MODULE_ENABLED
+ #include "stm32f4xx_hal_dma2d.h"
+#endif /* HAL_DMA2D_MODULE_ENABLED */
+
+#ifdef HAL_DAC_MODULE_ENABLED
+ #include "stm32f4xx_hal_dac.h"
+#endif /* HAL_DAC_MODULE_ENABLED */
+
+#ifdef HAL_DCMI_MODULE_ENABLED
+ #include "stm32f4xx_hal_dcmi.h"
+#endif /* HAL_DCMI_MODULE_ENABLED */
+
+#ifdef HAL_ETH_MODULE_ENABLED
+ #include "stm32f4xx_hal_eth.h"
+#endif /* HAL_ETH_MODULE_ENABLED */
+
+#ifdef HAL_FLASH_MODULE_ENABLED
+ #include "stm32f4xx_hal_flash.h"
+#endif /* HAL_FLASH_MODULE_ENABLED */
+
+#ifdef HAL_SRAM_MODULE_ENABLED
+ #include "stm32f4xx_hal_sram.h"
+#endif /* HAL_SRAM_MODULE_ENABLED */
+
+#ifdef HAL_NOR_MODULE_ENABLED
+ #include "stm32f4xx_hal_nor.h"
+#endif /* HAL_NOR_MODULE_ENABLED */
+
+#ifdef HAL_NAND_MODULE_ENABLED
+ #include "stm32f4xx_hal_nand.h"
+#endif /* HAL_NAND_MODULE_ENABLED */
+
+#ifdef HAL_PCCARD_MODULE_ENABLED
+ #include "stm32f4xx_hal_pccard.h"
+#endif /* HAL_PCCARD_MODULE_ENABLED */
+
+#ifdef HAL_SDRAM_MODULE_ENABLED
+ #include "stm32f4xx_hal_sdram.h"
+#endif /* HAL_SDRAM_MODULE_ENABLED */
+
+#ifdef HAL_HASH_MODULE_ENABLED
+ #include "stm32f4xx_hal_hash.h"
+#endif /* HAL_HASH_MODULE_ENABLED */
+
+#ifdef HAL_I2C_MODULE_ENABLED
+ #include "stm32f4xx_hal_i2c.h"
+#endif /* HAL_I2C_MODULE_ENABLED */
+
+#ifdef HAL_I2S_MODULE_ENABLED
+ #include "stm32f4xx_hal_i2s.h"
+#endif /* HAL_I2S_MODULE_ENABLED */
+
+#ifdef HAL_IWDG_MODULE_ENABLED
+ #include "stm32f4xx_hal_iwdg.h"
+#endif /* HAL_IWDG_MODULE_ENABLED */
+
+#ifdef HAL_LTDC_MODULE_ENABLED
+ #include "stm32f4xx_hal_ltdc.h"
+#endif /* HAL_LTDC_MODULE_ENABLED */
+
+#ifdef HAL_PWR_MODULE_ENABLED
+ #include "stm32f4xx_hal_pwr.h"
+#endif /* HAL_PWR_MODULE_ENABLED */
+
+#ifdef HAL_RNG_MODULE_ENABLED
+ #include "stm32f4xx_hal_rng.h"
+#endif /* HAL_RNG_MODULE_ENABLED */
+
+#ifdef HAL_RTC_MODULE_ENABLED
+ #include "stm32f4xx_hal_rtc.h"
+#endif /* HAL_RTC_MODULE_ENABLED */
+
+#ifdef HAL_SAI_MODULE_ENABLED
+ #include "stm32f4xx_hal_sai.h"
+#endif /* HAL_SAI_MODULE_ENABLED */
+
+#ifdef HAL_SD_MODULE_ENABLED
+ #include "stm32f4xx_hal_sd.h"
+#endif /* HAL_SD_MODULE_ENABLED */
+
+#ifdef HAL_SPI_MODULE_ENABLED
+ #include "stm32f4xx_hal_spi.h"
+#endif /* HAL_SPI_MODULE_ENABLED */
+
+#ifdef HAL_TIM_MODULE_ENABLED
+ #include "stm32f4xx_hal_tim.h"
+#endif /* HAL_TIM_MODULE_ENABLED */
+
+#ifdef HAL_UART_MODULE_ENABLED
+ #include "stm32f4xx_hal_uart.h"
+#endif /* HAL_UART_MODULE_ENABLED */
+
+#ifdef HAL_USART_MODULE_ENABLED
+ #include "stm32f4xx_hal_usart.h"
+#endif /* HAL_USART_MODULE_ENABLED */
+
+#ifdef HAL_IRDA_MODULE_ENABLED
+ #include "stm32f4xx_hal_irda.h"
+#endif /* HAL_IRDA_MODULE_ENABLED */
+
+#ifdef HAL_SMARTCARD_MODULE_ENABLED
+ #include "stm32f4xx_hal_smartcard.h"
+#endif /* HAL_SMARTCARD_MODULE_ENABLED */
+
+#ifdef HAL_WWDG_MODULE_ENABLED
+ #include "stm32f4xx_hal_wwdg.h"
+#endif /* HAL_WWDG_MODULE_ENABLED */
+
+#ifdef HAL_PCD_MODULE_ENABLED
+ #include "stm32f4xx_hal_pcd.h"
+#endif /* HAL_PCD_MODULE_ENABLED */
+
+#ifdef HAL_HCD_MODULE_ENABLED
+ #include "stm32f4xx_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 /* __STM32F4xx_HAL_CONF_H */
+
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/ports/stm32/boards/NUCLEO_F401RE/mpconfigboard.h b/ports/stm32/boards/NUCLEO_F401RE/mpconfigboard.h
new file mode 100644
index 000000000..c12d52756
--- /dev/null
+++ b/ports/stm32/boards/NUCLEO_F401RE/mpconfigboard.h
@@ -0,0 +1,57 @@
+#define MICROPY_HW_BOARD_NAME "NUCLEO-F401RE"
+#define MICROPY_HW_MCU_NAME "STM32F401xE"
+
+#define MICROPY_HW_HAS_SWITCH (1)
+#define MICROPY_HW_HAS_FLASH (1)
+#define MICROPY_HW_ENABLE_RTC (1)
+
+// HSE is 8MHz, CPU freq set to 84MHz
+#define MICROPY_HW_CLK_PLLM (8)
+#define MICROPY_HW_CLK_PLLN (336)
+#define MICROPY_HW_CLK_PLLP (RCC_PLLP_DIV4)
+#define MICROPY_HW_CLK_PLLQ (7)
+
+// UART config
+#define MICROPY_HW_UART2_TX (pin_A2)
+#define MICROPY_HW_UART2_RX (pin_A3)
+#define MICROPY_HW_UART6_TX (pin_C6)
+#define MICROPY_HW_UART6_RX (pin_C7)
+// UART 2 connects to the STM32F103 (STLINK) on the Nucleo board
+// and this is exposed as a USB Serial port.
+#define MICROPY_HW_UART_REPL PYB_UART_2
+#define MICROPY_HW_UART_REPL_BAUD 115200
+
+// I2C busses
+#define MICROPY_HW_I2C1_SCL (pin_B6) // Arduino D10, pin 17 on CN10
+#define MICROPY_HW_I2C1_SDA (pin_B7) // pin 21 on CN7
+#define MICROPY_HW_I2C2_SCL (pin_B10) // Arduino D6, pin 25 on CN10
+#define MICROPY_HW_I2C2_SDA (pin_B3) // Arduino D3, pin 31 on CN10
+#define MICROPY_HW_I2C3_SCL (pin_A8) // Arduino D7, pin 23 on CN10
+#define MICROPY_HW_I2C3_SDA (pin_C9) // pin 1 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
+
+#define MICROPY_HW_SPI3_NSS (pin_A4) // Arduino A2, pin 32 on CN7
+#define MICROPY_HW_SPI3_SCK (pin_B3) // Arduino D3, pin 31 on CN10
+#define MICROPY_HW_SPI3_MISO (pin_B4) // Arduino D5, pin 27 on CN10
+#define MICROPY_HW_SPI3_MOSI (pin_B5) // Arduino D4, pin 29 on CN10
+
+// 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_FALLING)
+#define MICROPY_HW_USRSW_PRESSED (0)
+
+// LEDs
+#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))
diff --git a/ports/stm32/boards/NUCLEO_F401RE/mpconfigboard.mk b/ports/stm32/boards/NUCLEO_F401RE/mpconfigboard.mk
new file mode 100644
index 000000000..eb391bed7
--- /dev/null
+++ b/ports/stm32/boards/NUCLEO_F401RE/mpconfigboard.mk
@@ -0,0 +1,4 @@
+MCU_SERIES = f4
+CMSIS_MCU = STM32F401xE
+AF_FILE = boards/stm32f401_af.csv
+LD_FILE = boards/stm32f401xe.ld
diff --git a/ports/stm32/boards/NUCLEO_F401RE/pins.csv b/ports/stm32/boards/NUCLEO_F401RE/pins.csv
new file mode 100644
index 000000000..6fbf91e29
--- /dev/null
+++ b/ports/stm32/boards/NUCLEO_F401RE/pins.csv
@@ -0,0 +1,75 @@
+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
+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
+PA15,PA15
+PB0,PB0
+PB1,PB1
+PB2,PB2
+PB3,PB3
+PB4,PB4
+PB5,PB5
+PB6,PB6
+PB7,PB7
+PB8,PB8
+PB9,PB9
+PB10,PB10
+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
+PH0,PH0
+PH1,PH1
+LED_GREEN,PA5
+LED_ORANGE,PA5
+LED_RED,PA5
+LED_BLUE,PA4
+SW,PC13
diff --git a/ports/stm32/boards/NUCLEO_F401RE/stm32f4xx_hal_conf.h b/ports/stm32/boards/NUCLEO_F401RE/stm32f4xx_hal_conf.h
new file mode 100644
index 000000000..c20421f0f
--- /dev/null
+++ b/ports/stm32/boards/NUCLEO_F401RE/stm32f4xx_hal_conf.h
@@ -0,0 +1,413 @@
+/**
+ ******************************************************************************
+ * @file stm32f4xx_hal_conf.h
+ * @author MCD Application Team
+ * @version V1.1.0
+ * @date 19-June-2014
+ * @brief HAL configuration file.
+ ******************************************************************************
+ * @attention
+ *
+ * <h2><center>&copy; COPYRIGHT(c) 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.
+ *
+ ******************************************************************************
+ */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __STM32F4xx_HAL_CONF_H
+#define __STM32F4xx_HAL_CONF_H
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/* Exported types ------------------------------------------------------------*/
+/* Exported constants --------------------------------------------------------*/
+
+// This board doesn't really have USB, but the stmhal 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
+ */
+#define HAL_MODULE_ENABLED
+#define HAL_ADC_MODULE_ENABLED
+#define HAL_CAN_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_PCCARD_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_LTDC_MODULE_ENABLED */
+#define HAL_PWR_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_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 */
+
+
+/* ########################## 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)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 ((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)40000)
+#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 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 */
+
+/* ################## 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 0
+#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)4) /* 4 Rx buffers of size ETH_RX_BUF_SIZE */
+#define ETH_TXBUFNB ((uint32_t)4) /* 4 Tx buffers of size ETH_TX_BUF_SIZE */
+
+/* Section 2: PHY configuration section */
+
+/* DP83848 PHY Address*/
+#define DP83848_PHY_ADDRESS 0x01
+/* PHY Reset delay these values are based on a 1 ms Systick interrupt*/
+#define PHY_RESET_DELAY ((uint32_t)0x000000FF)
+/* PHY Configuration delay */
+#define PHY_CONFIG_DELAY ((uint32_t)0x00000FFF)
+
+#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 "stm32f4xx_hal_rcc.h"
+#endif /* HAL_RCC_MODULE_ENABLED */
+
+#ifdef HAL_GPIO_MODULE_ENABLED
+ #include "stm32f4xx_hal_gpio.h"
+#endif /* HAL_GPIO_MODULE_ENABLED */
+
+#ifdef HAL_DMA_MODULE_ENABLED
+ #include "stm32f4xx_hal_dma.h"
+#endif /* HAL_DMA_MODULE_ENABLED */
+
+#ifdef HAL_CORTEX_MODULE_ENABLED
+ #include "stm32f4xx_hal_cortex.h"
+#endif /* HAL_CORTEX_MODULE_ENABLED */
+
+#ifdef HAL_ADC_MODULE_ENABLED
+ #include "stm32f4xx_hal_adc.h"
+#endif /* HAL_ADC_MODULE_ENABLED */
+
+#ifdef HAL_CAN_MODULE_ENABLED
+ #include "stm32f4xx_hal_can.h"
+#endif /* HAL_CAN_MODULE_ENABLED */
+
+#ifdef HAL_CRC_MODULE_ENABLED
+ #include "stm32f4xx_hal_crc.h"
+#endif /* HAL_CRC_MODULE_ENABLED */
+
+#ifdef HAL_CRYP_MODULE_ENABLED
+ #include "stm32f4xx_hal_cryp.h"
+#endif /* HAL_CRYP_MODULE_ENABLED */
+
+#ifdef HAL_DMA2D_MODULE_ENABLED
+ #include "stm32f4xx_hal_dma2d.h"
+#endif /* HAL_DMA2D_MODULE_ENABLED */
+
+#ifdef HAL_DAC_MODULE_ENABLED
+ #include "stm32f4xx_hal_dac.h"
+#endif /* HAL_DAC_MODULE_ENABLED */
+
+#ifdef HAL_DCMI_MODULE_ENABLED
+ #include "stm32f4xx_hal_dcmi.h"
+#endif /* HAL_DCMI_MODULE_ENABLED */
+
+#ifdef HAL_ETH_MODULE_ENABLED
+ #include "stm32f4xx_hal_eth.h"
+#endif /* HAL_ETH_MODULE_ENABLED */
+
+#ifdef HAL_FLASH_MODULE_ENABLED
+ #include "stm32f4xx_hal_flash.h"
+#endif /* HAL_FLASH_MODULE_ENABLED */
+
+#ifdef HAL_SRAM_MODULE_ENABLED
+ #include "stm32f4xx_hal_sram.h"
+#endif /* HAL_SRAM_MODULE_ENABLED */
+
+#ifdef HAL_NOR_MODULE_ENABLED
+ #include "stm32f4xx_hal_nor.h"
+#endif /* HAL_NOR_MODULE_ENABLED */
+
+#ifdef HAL_NAND_MODULE_ENABLED
+ #include "stm32f4xx_hal_nand.h"
+#endif /* HAL_NAND_MODULE_ENABLED */
+
+#ifdef HAL_PCCARD_MODULE_ENABLED
+ #include "stm32f4xx_hal_pccard.h"
+#endif /* HAL_PCCARD_MODULE_ENABLED */
+
+#ifdef HAL_SDRAM_MODULE_ENABLED
+ #include "stm32f4xx_hal_sdram.h"
+#endif /* HAL_SDRAM_MODULE_ENABLED */
+
+#ifdef HAL_HASH_MODULE_ENABLED
+ #include "stm32f4xx_hal_hash.h"
+#endif /* HAL_HASH_MODULE_ENABLED */
+
+#ifdef HAL_I2C_MODULE_ENABLED
+ #include "stm32f4xx_hal_i2c.h"
+#endif /* HAL_I2C_MODULE_ENABLED */
+
+#ifdef HAL_I2S_MODULE_ENABLED
+ #include "stm32f4xx_hal_i2s.h"
+#endif /* HAL_I2S_MODULE_ENABLED */
+
+#ifdef HAL_IWDG_MODULE_ENABLED
+ #include "stm32f4xx_hal_iwdg.h"
+#endif /* HAL_IWDG_MODULE_ENABLED */
+
+#ifdef HAL_LTDC_MODULE_ENABLED
+ #include "stm32f4xx_hal_ltdc.h"
+#endif /* HAL_LTDC_MODULE_ENABLED */
+
+#ifdef HAL_PWR_MODULE_ENABLED
+ #include "stm32f4xx_hal_pwr.h"
+#endif /* HAL_PWR_MODULE_ENABLED */
+
+#ifdef HAL_RNG_MODULE_ENABLED
+ #include "stm32f4xx_hal_rng.h"
+#endif /* HAL_RNG_MODULE_ENABLED */
+
+#ifdef HAL_RTC_MODULE_ENABLED
+ #include "stm32f4xx_hal_rtc.h"
+#endif /* HAL_RTC_MODULE_ENABLED */
+
+#ifdef HAL_SAI_MODULE_ENABLED
+ #include "stm32f4xx_hal_sai.h"
+#endif /* HAL_SAI_MODULE_ENABLED */
+
+#ifdef HAL_SD_MODULE_ENABLED
+ #include "stm32f4xx_hal_sd.h"
+#endif /* HAL_SD_MODULE_ENABLED */
+
+#ifdef HAL_SPI_MODULE_ENABLED
+ #include "stm32f4xx_hal_spi.h"
+#endif /* HAL_SPI_MODULE_ENABLED */
+
+#ifdef HAL_TIM_MODULE_ENABLED
+ #include "stm32f4xx_hal_tim.h"
+#endif /* HAL_TIM_MODULE_ENABLED */
+
+#ifdef HAL_UART_MODULE_ENABLED
+ #include "stm32f4xx_hal_uart.h"
+#endif /* HAL_UART_MODULE_ENABLED */
+
+#ifdef HAL_USART_MODULE_ENABLED
+ #include "stm32f4xx_hal_usart.h"
+#endif /* HAL_USART_MODULE_ENABLED */
+
+#ifdef HAL_IRDA_MODULE_ENABLED
+ #include "stm32f4xx_hal_irda.h"
+#endif /* HAL_IRDA_MODULE_ENABLED */
+
+#ifdef HAL_SMARTCARD_MODULE_ENABLED
+ #include "stm32f4xx_hal_smartcard.h"
+#endif /* HAL_SMARTCARD_MODULE_ENABLED */
+
+#ifdef HAL_WWDG_MODULE_ENABLED
+ #include "stm32f4xx_hal_wwdg.h"
+#endif /* HAL_WWDG_MODULE_ENABLED */
+
+#ifdef HAL_PCD_MODULE_ENABLED
+ #include "stm32f4xx_hal_pcd.h"
+#endif /* HAL_PCD_MODULE_ENABLED */
+
+#ifdef HAL_HCD_MODULE_ENABLED
+ #include "stm32f4xx_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 /* __STM32F4xx_HAL_CONF_H */
+
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/ports/stm32/boards/NUCLEO_F411RE/mpconfigboard.h b/ports/stm32/boards/NUCLEO_F411RE/mpconfigboard.h
new file mode 100644
index 000000000..1f7f0a23b
--- /dev/null
+++ b/ports/stm32/boards/NUCLEO_F411RE/mpconfigboard.h
@@ -0,0 +1,68 @@
+#define MICROPY_HW_BOARD_NAME "NUCLEO-F411RE"
+#define MICROPY_HW_MCU_NAME "STM32F411xE"
+
+#define MICROPY_HW_HAS_SWITCH (1)
+#define MICROPY_HW_HAS_FLASH (1)
+#define MICROPY_HW_ENABLE_RTC (1)
+
+// HSE is 8MHz, CPU freq set to 96MHz
+#define MICROPY_HW_CLK_PLLM (8)
+#define MICROPY_HW_CLK_PLLN (192)
+#define MICROPY_HW_CLK_PLLP (RCC_PLLP_DIV2)
+#define MICROPY_HW_CLK_PLLQ (4)
+
+// UART config
+#define MICROPY_HW_UART2_TX (pin_A2)
+#define MICROPY_HW_UART2_RX (pin_A3)
+#define MICROPY_HW_UART6_TX (pin_C6)
+#define MICROPY_HW_UART6_RX (pin_C7)
+// UART 2 connects to the STM32F103 (STLINK) on the Nucleo board
+// and this is exposed as a USB Serial port.
+#define MICROPY_HW_UART_REPL PYB_UART_2
+#define MICROPY_HW_UART_REPL_BAUD 115200
+
+// I2C busses
+#define MICROPY_HW_I2C1_SCL (pin_B6) // Arduino D10, pin 17 on CN10
+#define MICROPY_HW_I2C1_SDA (pin_B7) // pin 21 on CN7
+#define MICROPY_HW_I2C2_SCL (pin_B10) // Arduino D6, pin 25 on CN10
+#define MICROPY_HW_I2C2_SDA (pin_B3) // Arduino D3, pin 31 on CN10
+#define MICROPY_HW_I2C3_SCL (pin_A8) // Arduino D7, pin 23 on CN10
+#define MICROPY_HW_I2C3_SDA (pin_C9) // pin 1 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
+
+#define MICROPY_HW_SPI3_NSS (pin_A4) // Arduino A2, pin 32 on CN7
+#define MICROPY_HW_SPI3_SCK (pin_B3) // Arduino D3, pin 31 on CN10
+#define MICROPY_HW_SPI3_MISO (pin_B4) // Arduino D5, pin 27 on CN10
+#define MICROPY_HW_SPI3_MOSI (pin_B5) // Arduino D4, pin 29 on CN10
+
+#define MICROPY_HW_SPI4_NSS (pin_B12) // pin 16 on CN10
+#define MICROPY_HW_SPI4_SCK (pin_B13) // pin 30 on CN10
+#define MICROPY_HW_SPI4_MISO (pin_A1) // pin 30 on CN7
+#define MICROPY_HW_SPI4_MOSI (pin_A11) // pin 14 on CN10
+
+
+#define MICROPY_HW_SPI5_NSS (pin_B1) // pin 24 on CN10
+#define MICROPY_HW_SPI5_SCK (pin_A10) // pin 33 on CN10
+#define MICROPY_HW_SPI5_MISO (pin_A12) // pin 12 on CN10
+#define MICROPY_HW_SPI5_MOSI (pin_B0) // pin 34 on CN7
+
+// 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_FALLING)
+#define MICROPY_HW_USRSW_PRESSED (0)
+
+// LEDs
+#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))
diff --git a/ports/stm32/boards/NUCLEO_F411RE/mpconfigboard.mk b/ports/stm32/boards/NUCLEO_F411RE/mpconfigboard.mk
new file mode 100644
index 000000000..71b3b19d6
--- /dev/null
+++ b/ports/stm32/boards/NUCLEO_F411RE/mpconfigboard.mk
@@ -0,0 +1,4 @@
+MCU_SERIES = f4
+CMSIS_MCU = STM32F411xE
+AF_FILE = boards/stm32f411_af.csv
+LD_FILE = boards/stm32f411.ld
diff --git a/ports/stm32/boards/NUCLEO_F411RE/pins.csv b/ports/stm32/boards/NUCLEO_F411RE/pins.csv
new file mode 100644
index 000000000..6fbf91e29
--- /dev/null
+++ b/ports/stm32/boards/NUCLEO_F411RE/pins.csv
@@ -0,0 +1,75 @@
+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
+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
+PA15,PA15
+PB0,PB0
+PB1,PB1
+PB2,PB2
+PB3,PB3
+PB4,PB4
+PB5,PB5
+PB6,PB6
+PB7,PB7
+PB8,PB8
+PB9,PB9
+PB10,PB10
+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
+PH0,PH0
+PH1,PH1
+LED_GREEN,PA5
+LED_ORANGE,PA5
+LED_RED,PA5
+LED_BLUE,PA4
+SW,PC13
diff --git a/ports/stm32/boards/NUCLEO_F411RE/stm32f4xx_hal_conf.h b/ports/stm32/boards/NUCLEO_F411RE/stm32f4xx_hal_conf.h
new file mode 100644
index 000000000..e16fba155
--- /dev/null
+++ b/ports/stm32/boards/NUCLEO_F411RE/stm32f4xx_hal_conf.h
@@ -0,0 +1,413 @@
+/**
+ ******************************************************************************
+ * @file stm32f4xx_hal_conf.h
+ * @author MCD Application Team
+ * @version V1.1.0
+ * @date 19-June-2014
+ * @brief HAL configuration file.
+ ******************************************************************************
+ * @attention
+ *
+ * <h2><center>&copy; COPYRIGHT(c) 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.
+ *
+ ******************************************************************************
+ */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __STM32F4xx_HAL_CONF_H
+#define __STM32F4xx_HAL_CONF_H
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/* Exported types ------------------------------------------------------------*/
+/* Exported constants --------------------------------------------------------*/
+
+// This board doesn't really have USB, but the stmhal 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
+ */
+#define HAL_MODULE_ENABLED
+#define HAL_ADC_MODULE_ENABLED
+#define HAL_CAN_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_PCCARD_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_LTDC_MODULE_ENABLED */
+#define HAL_PWR_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_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 */
+
+
+/* ########################## 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)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 ((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)40000)
+#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 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 */
+
+/* ################## 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 0
+#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)4) /* 4 Rx buffers of size ETH_RX_BUF_SIZE */
+#define ETH_TXBUFNB ((uint32_t)4) /* 4 Tx buffers of size ETH_TX_BUF_SIZE */
+
+/* Section 2: PHY configuration section */
+
+/* DP83848 PHY Address*/
+#define DP83848_PHY_ADDRESS 0x01
+/* PHY Reset delay these values are based on a 1 ms Systick interrupt*/
+#define PHY_RESET_DELAY ((uint32_t)0x000000FF)
+/* PHY Configuration delay */
+#define PHY_CONFIG_DELAY ((uint32_t)0x00000FFF)
+
+#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 "stm32f4xx_hal_rcc.h"
+#endif /* HAL_RCC_MODULE_ENABLED */
+
+#ifdef HAL_GPIO_MODULE_ENABLED
+ #include "stm32f4xx_hal_gpio.h"
+#endif /* HAL_GPIO_MODULE_ENABLED */
+
+#ifdef HAL_DMA_MODULE_ENABLED
+ #include "stm32f4xx_hal_dma.h"
+#endif /* HAL_DMA_MODULE_ENABLED */
+
+#ifdef HAL_CORTEX_MODULE_ENABLED
+ #include "stm32f4xx_hal_cortex.h"
+#endif /* HAL_CORTEX_MODULE_ENABLED */
+
+#ifdef HAL_ADC_MODULE_ENABLED
+ #include "stm32f4xx_hal_adc.h"
+#endif /* HAL_ADC_MODULE_ENABLED */
+
+#ifdef HAL_CAN_MODULE_ENABLED
+ #include "stm32f4xx_hal_can.h"
+#endif /* HAL_CAN_MODULE_ENABLED */
+
+#ifdef HAL_CRC_MODULE_ENABLED
+ #include "stm32f4xx_hal_crc.h"
+#endif /* HAL_CRC_MODULE_ENABLED */
+
+#ifdef HAL_CRYP_MODULE_ENABLED
+ #include "stm32f4xx_hal_cryp.h"
+#endif /* HAL_CRYP_MODULE_ENABLED */
+
+#ifdef HAL_DMA2D_MODULE_ENABLED
+ #include "stm32f4xx_hal_dma2d.h"
+#endif /* HAL_DMA2D_MODULE_ENABLED */
+
+#ifdef HAL_DAC_MODULE_ENABLED
+ #include "stm32f4xx_hal_dac.h"
+#endif /* HAL_DAC_MODULE_ENABLED */
+
+#ifdef HAL_DCMI_MODULE_ENABLED
+ #include "stm32f4xx_hal_dcmi.h"
+#endif /* HAL_DCMI_MODULE_ENABLED */
+
+#ifdef HAL_ETH_MODULE_ENABLED
+ #include "stm32f4xx_hal_eth.h"
+#endif /* HAL_ETH_MODULE_ENABLED */
+
+#ifdef HAL_FLASH_MODULE_ENABLED
+ #include "stm32f4xx_hal_flash.h"
+#endif /* HAL_FLASH_MODULE_ENABLED */
+
+#ifdef HAL_SRAM_MODULE_ENABLED
+ #include "stm32f4xx_hal_sram.h"
+#endif /* HAL_SRAM_MODULE_ENABLED */
+
+#ifdef HAL_NOR_MODULE_ENABLED
+ #include "stm32f4xx_hal_nor.h"
+#endif /* HAL_NOR_MODULE_ENABLED */
+
+#ifdef HAL_NAND_MODULE_ENABLED
+ #include "stm32f4xx_hal_nand.h"
+#endif /* HAL_NAND_MODULE_ENABLED */
+
+#ifdef HAL_PCCARD_MODULE_ENABLED
+ #include "stm32f4xx_hal_pccard.h"
+#endif /* HAL_PCCARD_MODULE_ENABLED */
+
+#ifdef HAL_SDRAM_MODULE_ENABLED
+ #include "stm32f4xx_hal_sdram.h"
+#endif /* HAL_SDRAM_MODULE_ENABLED */
+
+#ifdef HAL_HASH_MODULE_ENABLED
+ #include "stm32f4xx_hal_hash.h"
+#endif /* HAL_HASH_MODULE_ENABLED */
+
+#ifdef HAL_I2C_MODULE_ENABLED
+ #include "stm32f4xx_hal_i2c.h"
+#endif /* HAL_I2C_MODULE_ENABLED */
+
+#ifdef HAL_I2S_MODULE_ENABLED
+ #include "stm32f4xx_hal_i2s.h"
+#endif /* HAL_I2S_MODULE_ENABLED */
+
+#ifdef HAL_IWDG_MODULE_ENABLED
+ #include "stm32f4xx_hal_iwdg.h"
+#endif /* HAL_IWDG_MODULE_ENABLED */
+
+#ifdef HAL_LTDC_MODULE_ENABLED
+ #include "stm32f4xx_hal_ltdc.h"
+#endif /* HAL_LTDC_MODULE_ENABLED */
+
+#ifdef HAL_PWR_MODULE_ENABLED
+ #include "stm32f4xx_hal_pwr.h"
+#endif /* HAL_PWR_MODULE_ENABLED */
+
+#ifdef HAL_RNG_MODULE_ENABLED
+ #include "stm32f4xx_hal_rng.h"
+#endif /* HAL_RNG_MODULE_ENABLED */
+
+#ifdef HAL_RTC_MODULE_ENABLED
+ #include "stm32f4xx_hal_rtc.h"
+#endif /* HAL_RTC_MODULE_ENABLED */
+
+#ifdef HAL_SAI_MODULE_ENABLED
+ #include "stm32f4xx_hal_sai.h"
+#endif /* HAL_SAI_MODULE_ENABLED */
+
+#ifdef HAL_SD_MODULE_ENABLED
+ #include "stm32f4xx_hal_sd.h"
+#endif /* HAL_SD_MODULE_ENABLED */
+
+#ifdef HAL_SPI_MODULE_ENABLED
+ #include "stm32f4xx_hal_spi.h"
+#endif /* HAL_SPI_MODULE_ENABLED */
+
+#ifdef HAL_TIM_MODULE_ENABLED
+ #include "stm32f4xx_hal_tim.h"
+#endif /* HAL_TIM_MODULE_ENABLED */
+
+#ifdef HAL_UART_MODULE_ENABLED
+ #include "stm32f4xx_hal_uart.h"
+#endif /* HAL_UART_MODULE_ENABLED */
+
+#ifdef HAL_USART_MODULE_ENABLED
+ #include "stm32f4xx_hal_usart.h"
+#endif /* HAL_USART_MODULE_ENABLED */
+
+#ifdef HAL_IRDA_MODULE_ENABLED
+ #include "stm32f4xx_hal_irda.h"
+#endif /* HAL_IRDA_MODULE_ENABLED */
+
+#ifdef HAL_SMARTCARD_MODULE_ENABLED
+ #include "stm32f4xx_hal_smartcard.h"
+#endif /* HAL_SMARTCARD_MODULE_ENABLED */
+
+#ifdef HAL_WWDG_MODULE_ENABLED
+ #include "stm32f4xx_hal_wwdg.h"
+#endif /* HAL_WWDG_MODULE_ENABLED */
+
+#ifdef HAL_PCD_MODULE_ENABLED
+ #include "stm32f4xx_hal_pcd.h"
+#endif /* HAL_PCD_MODULE_ENABLED */
+
+#ifdef HAL_HCD_MODULE_ENABLED
+ #include "stm32f4xx_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 /* __STM32F4xx_HAL_CONF_H */
+
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/ports/stm32/boards/NUCLEO_F429ZI/mpconfigboard.h b/ports/stm32/boards/NUCLEO_F429ZI/mpconfigboard.h
new file mode 100644
index 000000000..42cc9d68c
--- /dev/null
+++ b/ports/stm32/boards/NUCLEO_F429ZI/mpconfigboard.h
@@ -0,0 +1,83 @@
+#define MICROPY_HW_BOARD_NAME "NUCLEO-F429ZI"
+#define MICROPY_HW_MCU_NAME "STM32F429"
+
+#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)
+
+// HSE is 8MHz
+#define MICROPY_HW_CLK_PLLM (8)
+#define MICROPY_HW_CLK_PLLN (180)
+#define MICROPY_HW_CLK_PLLP (RCC_PLLP_DIV2)
+#define MICROPY_HW_CLK_PLLQ (4)
+
+// 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_6
+
+// UART config
+#define MICROPY_HW_UART1_TX (pin_A9)
+#define MICROPY_HW_UART1_RX (pin_A10)
+
+#define MICROPY_HW_UART2_TX (pin_D5)
+#define MICROPY_HW_UART2_RX (pin_D6)
+
+#define MICROPY_HW_UART3_TX (pin_D8)
+#define MICROPY_HW_UART3_RX (pin_D9)
+
+#define MICROPY_HW_UART4_TX (pin_A0)
+#define MICROPY_HW_UART4_RX (pin_C11)
+
+#define MICROPY_HW_UART5_TX (pin_C12)
+#define MICROPY_HW_UART5_RX (pin_D2)
+
+#define MICROPY_HW_UART_REPL PYB_UART_3
+#define MICROPY_HW_UART_REPL_BAUD 115200
+
+// I2C busses
+#define MICROPY_HW_I2C3_SCL (pin_A8)
+#define MICROPY_HW_I2C3_SDA (pin_C9)
+
+// SPI busses
+#define MICROPY_HW_SPI1_NSS (pin_A4)
+#define MICROPY_HW_SPI1_SCK (pin_B3)
+#define MICROPY_HW_SPI1_MISO (pin_B4)
+#define MICROPY_HW_SPI1_MOSI (pin_B5)
+
+#define MICROPY_HW_SPI4_NSS (pin_E4)
+#define MICROPY_HW_SPI4_SCK (pin_E2)
+#define MICROPY_HW_SPI4_MISO (pin_E5)
+#define MICROPY_HW_SPI4_MOSI (pin_E6)
+
+#define MICROPY_HW_SPI5_NSS (pin_F6)
+#define MICROPY_HW_SPI5_SCK (pin_F7)
+#define MICROPY_HW_SPI5_MISO (pin_F8)
+#define MICROPY_HW_SPI5_MOSI (pin_F9)
+
+// 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_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
new file mode 100644
index 000000000..1bbf808b6
--- /dev/null
+++ b/ports/stm32/boards/NUCLEO_F429ZI/mpconfigboard.mk
@@ -0,0 +1,4 @@
+MCU_SERIES = f4
+CMSIS_MCU = STM32F429xx
+AF_FILE = boards/stm32f429_af.csv
+LD_FILE = boards/stm32f429.ld
diff --git a/ports/stm32/boards/NUCLEO_F429ZI/pins.csv b/ports/stm32/boards/NUCLEO_F429ZI/pins.csv
new file mode 100644
index 000000000..8a892d3c2
--- /dev/null
+++ b/ports/stm32/boards/NUCLEO_F429ZI/pins.csv
@@ -0,0 +1,117 @@
+PF4,PF4
+PF5,PF5
+PF2,PF2
+PF3,PF3
+PF0,PF0
+PF1,PF1
+PC14,PC14
+PC15,PC15
+PE6,PE6
+PC13,PC13
+PE4,PE4
+PE5,PE5
+PE2,PE2
+PE3,PE3
+PE0,PE0
+PE1,PE1
+PB8,PB8
+PB9,PB9
+PB6,PB6
+PB7,PB7
+PB4,PB4
+PB5,PB5
+PG15,PG15
+PB3,PB3
+PG13,PG13
+PG14,PG14
+PG11,PG11
+PG12,PG12
+PG9,PG9
+PG10,PG10
+PD7,PD7
+PD6,PD6
+PD5,PD5
+PD4,PD4
+PD3,PD3
+PD2,PD2
+PD1,PD1
+PD0,PD0
+PC12,PC12
+PC11,PC11
+PC10,PC10
+PA15,PA15
+PA14,PA14
+PA13,PA13
+PA12,PA12
+PA11,PA11
+PA10,PA10
+PA9,PA9
+PA8,PA8
+PC9,PC9
+PC8,PC8
+PC7,PC7
+PC6,PC6
+PG8,PG8
+PG7,PG7
+PG6,PG6
+PG5,PG5
+PG4,PG4
+PF6,PF6
+PF8,PF8
+PF7,PF7
+PF10,PF10
+PF9,PF9
+PH1,PH1
+PH0,PH0
+PC1,PC1
+PC0,PC0
+PC3,PC3
+PC2,PC2
+PA1,PA1
+PA0,PA0
+PA3,PA3
+PA2,PA2
+PA5,PA5
+PA4,PA4
+PA7,PA7
+PA6,PA6
+PC5,PC5
+PC4,PC4
+PB1,PB1
+PB0,PB0
+PB2,PB2
+PF12,PF12
+PF11,PF11
+PF14,PF14
+PF13,PF13
+PG0,PG0
+PF15,PF15
+PE7,PE7
+PG1,PG1
+PE9,PE9
+PE8,PE8
+PE11,PE11
+PE10,PE10
+PE13,PE13
+PE12,PE12
+PE15,PE15
+PE14,PE14
+PB11,PB11
+PB10,PB10
+PB13,PB13
+PB12,PB12
+PB15,PB15
+PB14,PB14
+PD9,PD9
+PD8,PD8
+PD11,PD11
+PD10,PD10
+PD13,PD13
+PD12,PD12
+PD15,PD15
+PD14,PD14
+PG3,PG3
+PG2,PG2
+SW,PA0
+LED_GREEN,PG13
+LED_RED,PG14
diff --git a/ports/stm32/boards/NUCLEO_F429ZI/stm32f4xx_hal_conf.h b/ports/stm32/boards/NUCLEO_F429ZI/stm32f4xx_hal_conf.h
new file mode 100644
index 000000000..d121b18c5
--- /dev/null
+++ b/ports/stm32/boards/NUCLEO_F429ZI/stm32f4xx_hal_conf.h
@@ -0,0 +1,411 @@
+/**
+ ******************************************************************************
+ * @file stm32f4xx_hal_conf.h
+ * @author MCD Application Team
+ * @version V1.1.0
+ * @date 19-June-2014
+ * @brief HAL configuration file.
+ ******************************************************************************
+ * @attention
+ *
+ * <h2><center>&copy; COPYRIGHT(c) 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.
+ *
+ ******************************************************************************
+ */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __STM32F4xx_HAL_CONF_H
+#define __STM32F4xx_HAL_CONF_H
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/* Exported types ------------------------------------------------------------*/
+/* Exported constants --------------------------------------------------------*/
+
+#define USE_USB_FS
+
+ /* ########################## 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_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_PCCARD_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_LTDC_MODULE_ENABLED */
+#define HAL_PWR_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_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 */
+
+
+/* ########################## 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)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 ((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)40000)
+#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 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 */
+
+/* ################## 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 0
+#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)4) /* 4 Rx buffers of size ETH_RX_BUF_SIZE */
+#define ETH_TXBUFNB ((uint32_t)4) /* 4 Tx buffers of size ETH_TX_BUF_SIZE */
+
+/* Section 2: PHY configuration section */
+
+/* DP83848 PHY Address*/
+#define DP83848_PHY_ADDRESS 0x01
+/* PHY Reset delay these values are based on a 1 ms Systick interrupt*/
+#define PHY_RESET_DELAY ((uint32_t)0x000000FF)
+/* PHY Configuration delay */
+#define PHY_CONFIG_DELAY ((uint32_t)0x00000FFF)
+
+#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 "stm32f4xx_hal_rcc.h"
+#endif /* HAL_RCC_MODULE_ENABLED */
+
+#ifdef HAL_GPIO_MODULE_ENABLED
+ #include "stm32f4xx_hal_gpio.h"
+#endif /* HAL_GPIO_MODULE_ENABLED */
+
+#ifdef HAL_DMA_MODULE_ENABLED
+ #include "stm32f4xx_hal_dma.h"
+#endif /* HAL_DMA_MODULE_ENABLED */
+
+#ifdef HAL_CORTEX_MODULE_ENABLED
+ #include "stm32f4xx_hal_cortex.h"
+#endif /* HAL_CORTEX_MODULE_ENABLED */
+
+#ifdef HAL_ADC_MODULE_ENABLED
+ #include "stm32f4xx_hal_adc.h"
+#endif /* HAL_ADC_MODULE_ENABLED */
+
+#ifdef HAL_CAN_MODULE_ENABLED
+ #include "stm32f4xx_hal_can.h"
+#endif /* HAL_CAN_MODULE_ENABLED */
+
+#ifdef HAL_CRC_MODULE_ENABLED
+ #include "stm32f4xx_hal_crc.h"
+#endif /* HAL_CRC_MODULE_ENABLED */
+
+#ifdef HAL_CRYP_MODULE_ENABLED
+ #include "stm32f4xx_hal_cryp.h"
+#endif /* HAL_CRYP_MODULE_ENABLED */
+
+#ifdef HAL_DMA2D_MODULE_ENABLED
+ #include "stm32f4xx_hal_dma2d.h"
+#endif /* HAL_DMA2D_MODULE_ENABLED */
+
+#ifdef HAL_DAC_MODULE_ENABLED
+ #include "stm32f4xx_hal_dac.h"
+#endif /* HAL_DAC_MODULE_ENABLED */
+
+#ifdef HAL_DCMI_MODULE_ENABLED
+ #include "stm32f4xx_hal_dcmi.h"
+#endif /* HAL_DCMI_MODULE_ENABLED */
+
+#ifdef HAL_ETH_MODULE_ENABLED
+ #include "stm32f4xx_hal_eth.h"
+#endif /* HAL_ETH_MODULE_ENABLED */
+
+#ifdef HAL_FLASH_MODULE_ENABLED
+ #include "stm32f4xx_hal_flash.h"
+#endif /* HAL_FLASH_MODULE_ENABLED */
+
+#ifdef HAL_SRAM_MODULE_ENABLED
+ #include "stm32f4xx_hal_sram.h"
+#endif /* HAL_SRAM_MODULE_ENABLED */
+
+#ifdef HAL_NOR_MODULE_ENABLED
+ #include "stm32f4xx_hal_nor.h"
+#endif /* HAL_NOR_MODULE_ENABLED */
+
+#ifdef HAL_NAND_MODULE_ENABLED
+ #include "stm32f4xx_hal_nand.h"
+#endif /* HAL_NAND_MODULE_ENABLED */
+
+#ifdef HAL_PCCARD_MODULE_ENABLED
+ #include "stm32f4xx_hal_pccard.h"
+#endif /* HAL_PCCARD_MODULE_ENABLED */
+
+#ifdef HAL_SDRAM_MODULE_ENABLED
+ #include "stm32f4xx_hal_sdram.h"
+#endif /* HAL_SDRAM_MODULE_ENABLED */
+
+#ifdef HAL_HASH_MODULE_ENABLED
+ #include "stm32f4xx_hal_hash.h"
+#endif /* HAL_HASH_MODULE_ENABLED */
+
+#ifdef HAL_I2C_MODULE_ENABLED
+ #include "stm32f4xx_hal_i2c.h"
+#endif /* HAL_I2C_MODULE_ENABLED */
+
+#ifdef HAL_I2S_MODULE_ENABLED
+ #include "stm32f4xx_hal_i2s.h"
+#endif /* HAL_I2S_MODULE_ENABLED */
+
+#ifdef HAL_IWDG_MODULE_ENABLED
+ #include "stm32f4xx_hal_iwdg.h"
+#endif /* HAL_IWDG_MODULE_ENABLED */
+
+#ifdef HAL_LTDC_MODULE_ENABLED
+ #include "stm32f4xx_hal_ltdc.h"
+#endif /* HAL_LTDC_MODULE_ENABLED */
+
+#ifdef HAL_PWR_MODULE_ENABLED
+ #include "stm32f4xx_hal_pwr.h"
+#endif /* HAL_PWR_MODULE_ENABLED */
+
+#ifdef HAL_RNG_MODULE_ENABLED
+ #include "stm32f4xx_hal_rng.h"
+#endif /* HAL_RNG_MODULE_ENABLED */
+
+#ifdef HAL_RTC_MODULE_ENABLED
+ #include "stm32f4xx_hal_rtc.h"
+#endif /* HAL_RTC_MODULE_ENABLED */
+
+#ifdef HAL_SAI_MODULE_ENABLED
+ #include "stm32f4xx_hal_sai.h"
+#endif /* HAL_SAI_MODULE_ENABLED */
+
+#ifdef HAL_SD_MODULE_ENABLED
+ #include "stm32f4xx_hal_sd.h"
+#endif /* HAL_SD_MODULE_ENABLED */
+
+#ifdef HAL_SPI_MODULE_ENABLED
+ #include "stm32f4xx_hal_spi.h"
+#endif /* HAL_SPI_MODULE_ENABLED */
+
+#ifdef HAL_TIM_MODULE_ENABLED
+ #include "stm32f4xx_hal_tim.h"
+#endif /* HAL_TIM_MODULE_ENABLED */
+
+#ifdef HAL_UART_MODULE_ENABLED
+ #include "stm32f4xx_hal_uart.h"
+#endif /* HAL_UART_MODULE_ENABLED */
+
+#ifdef HAL_USART_MODULE_ENABLED
+ #include "stm32f4xx_hal_usart.h"
+#endif /* HAL_USART_MODULE_ENABLED */
+
+#ifdef HAL_IRDA_MODULE_ENABLED
+ #include "stm32f4xx_hal_irda.h"
+#endif /* HAL_IRDA_MODULE_ENABLED */
+
+#ifdef HAL_SMARTCARD_MODULE_ENABLED
+ #include "stm32f4xx_hal_smartcard.h"
+#endif /* HAL_SMARTCARD_MODULE_ENABLED */
+
+#ifdef HAL_WWDG_MODULE_ENABLED
+ #include "stm32f4xx_hal_wwdg.h"
+#endif /* HAL_WWDG_MODULE_ENABLED */
+
+#ifdef HAL_PCD_MODULE_ENABLED
+ #include "stm32f4xx_hal_pcd.h"
+#endif /* HAL_PCD_MODULE_ENABLED */
+
+#ifdef HAL_HCD_MODULE_ENABLED
+ #include "stm32f4xx_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 /* __STM32F4xx_HAL_CONF_H */
+
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/ports/stm32/boards/NUCLEO_F446RE/mpconfigboard.h b/ports/stm32/boards/NUCLEO_F446RE/mpconfigboard.h
new file mode 100644
index 000000000..d801fa188
--- /dev/null
+++ b/ports/stm32/boards/NUCLEO_F446RE/mpconfigboard.h
@@ -0,0 +1,64 @@
+#define MICROPY_HW_BOARD_NAME "NUCLEO-F446RE"
+#define MICROPY_HW_MCU_NAME "STM32F446xx"
+
+#define MICROPY_HW_HAS_SWITCH (1)
+#define MICROPY_HW_HAS_FLASH (1)
+#define MICROPY_HW_ENABLE_RTC (1)
+
+// HSE is 8MHz, CPU freq set to 168MHz. Using PLLQ for USB this gives a nice
+// 48 MHz clock for USB. To goto 180 MHz, I think that USB would need to be
+// configured to use PLLSAI
+#define MICROPY_HW_CLK_PLLM (8)
+#define MICROPY_HW_CLK_PLLN (336)
+#define MICROPY_HW_CLK_PLLP (RCC_PLLP_DIV2)
+#define MICROPY_HW_CLK_PLLQ (7)
+
+// UART config
+#define MICROPY_HW_UART2_TX (pin_A2)
+#define MICROPY_HW_UART2_RX (pin_A3)
+#define MICROPY_HW_UART6_TX (pin_C6)
+#define MICROPY_HW_UART6_RX (pin_C7)
+// UART 2 connects to the STM32F103 (STLINK) on the Nucleo board
+// and this is exposed as a USB Serial port.
+#define MICROPY_HW_UART_REPL PYB_UART_2
+#define MICROPY_HW_UART_REPL_BAUD 115200
+
+// I2C busses
+#define MICROPY_HW_I2C1_SCL (pin_B6) // Arduino D10, pin 17 on CN10
+#define MICROPY_HW_I2C1_SDA (pin_B7) // pin 21 on CN7
+#define MICROPY_HW_I2C2_SCL (pin_B10) // Arduino D6, pin 25 on CN10
+#define MICROPY_HW_I2C2_SDA (pin_B3) // Arduino D3, pin 31 on CN10
+#define MICROPY_HW_I2C3_SCL (pin_A8) // Arduino D7, pin 23 on CN10
+#define MICROPY_HW_I2C3_SDA (pin_C9) // pin 1 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
+
+#define MICROPY_HW_SPI3_NSS (pin_A4) // Arduino A2, pin 32 on CN7
+#define MICROPY_HW_SPI3_SCK (pin_B3) // Arduino D3, pin 31 on CN10
+#define MICROPY_HW_SPI3_MISO (pin_B4) // Arduino D5, pin 27 on CN10
+#define MICROPY_HW_SPI3_MOSI (pin_B5) // Arduino D4, pin 29 on CN10
+
+#define MICROPY_HW_SPI4_NSS (pin_B12) // pin 16 on CN10
+#define MICROPY_HW_SPI4_SCK (pin_B13) // pin 30 on CN10
+#define MICROPY_HW_SPI4_MISO (pin_A1) // pin 30 on CN7
+#define MICROPY_HW_SPI4_MOSI (pin_A11) // pin 14 on CN10
+
+// 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_FALLING)
+#define MICROPY_HW_USRSW_PRESSED (0)
+
+// LEDs
+#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))
diff --git a/ports/stm32/boards/NUCLEO_F446RE/mpconfigboard.mk b/ports/stm32/boards/NUCLEO_F446RE/mpconfigboard.mk
new file mode 100644
index 000000000..e1ec6d57c
--- /dev/null
+++ b/ports/stm32/boards/NUCLEO_F446RE/mpconfigboard.mk
@@ -0,0 +1,4 @@
+MCU_SERIES = f4
+CMSIS_MCU = STM32F446xx
+AF_FILE = boards/stm32f429_af.csv
+LD_FILE = boards/stm32f411.ld
diff --git a/ports/stm32/boards/NUCLEO_F446RE/pins.csv b/ports/stm32/boards/NUCLEO_F446RE/pins.csv
new file mode 100644
index 000000000..5b09bcc74
--- /dev/null
+++ b/ports/stm32/boards/NUCLEO_F446RE/pins.csv
@@ -0,0 +1,72 @@
+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
+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
+PA15,PA15
+PB0,PB0
+PB1,PB1
+PB2,PB2
+PB3,PB3
+PB4,PB4
+PB5,PB5
+PB6,PB6
+PB7,PB7
+PB8,PB8
+PB9,PB9
+PB10,PB10
+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
+PH0,PH0
+PH1,PH1
+LED,PA5
+SW,PC13
diff --git a/ports/stm32/boards/NUCLEO_F446RE/stm32f4xx_hal_conf.h b/ports/stm32/boards/NUCLEO_F446RE/stm32f4xx_hal_conf.h
new file mode 100644
index 000000000..3d0ce926b
--- /dev/null
+++ b/ports/stm32/boards/NUCLEO_F446RE/stm32f4xx_hal_conf.h
@@ -0,0 +1,413 @@
+/**
+ ******************************************************************************
+ * @file stm32f4xx_hal_conf.h
+ * @author MCD Application Team
+ * @version V1.1.0
+ * @date 19-June-2014
+ * @brief HAL configuration file.
+ ******************************************************************************
+ * @attention
+ *
+ * <h2><center>&copy; COPYRIGHT(c) 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.
+ *
+ ******************************************************************************
+ */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __STM32F4xx_HAL_CONF_H
+#define __STM32F4xx_HAL_CONF_H
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/* Exported types ------------------------------------------------------------*/
+/* Exported constants --------------------------------------------------------*/
+
+// This board doesn't really have USB, but the stmhal 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
+ */
+#define HAL_MODULE_ENABLED
+#define HAL_ADC_MODULE_ENABLED
+#define HAL_CAN_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_PCCARD_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_LTDC_MODULE_ENABLED */
+#define HAL_PWR_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_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 */
+
+
+/* ########################## 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)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 ((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)40000)
+#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 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 */
+
+/* ################## 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 0
+#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)4) /* 4 Rx buffers of size ETH_RX_BUF_SIZE */
+#define ETH_TXBUFNB ((uint32_t)4) /* 4 Tx buffers of size ETH_TX_BUF_SIZE */
+
+/* Section 2: PHY configuration section */
+
+/* DP83848 PHY Address*/
+#define DP83848_PHY_ADDRESS 0x01
+/* PHY Reset delay these values are based on a 1 ms Systick interrupt*/
+#define PHY_RESET_DELAY ((uint32_t)0x000000FF)
+/* PHY Configuration delay */
+#define PHY_CONFIG_DELAY ((uint32_t)0x00000FFF)
+
+#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 "stm32f4xx_hal_rcc.h"
+#endif /* HAL_RCC_MODULE_ENABLED */
+
+#ifdef HAL_GPIO_MODULE_ENABLED
+ #include "stm32f4xx_hal_gpio.h"
+#endif /* HAL_GPIO_MODULE_ENABLED */
+
+#ifdef HAL_DMA_MODULE_ENABLED
+ #include "stm32f4xx_hal_dma.h"
+#endif /* HAL_DMA_MODULE_ENABLED */
+
+#ifdef HAL_CORTEX_MODULE_ENABLED
+ #include "stm32f4xx_hal_cortex.h"
+#endif /* HAL_CORTEX_MODULE_ENABLED */
+
+#ifdef HAL_ADC_MODULE_ENABLED
+ #include "stm32f4xx_hal_adc.h"
+#endif /* HAL_ADC_MODULE_ENABLED */
+
+#ifdef HAL_CAN_MODULE_ENABLED
+ #include "stm32f4xx_hal_can.h"
+#endif /* HAL_CAN_MODULE_ENABLED */
+
+#ifdef HAL_CRC_MODULE_ENABLED
+ #include "stm32f4xx_hal_crc.h"
+#endif /* HAL_CRC_MODULE_ENABLED */
+
+#ifdef HAL_CRYP_MODULE_ENABLED
+ #include "stm32f4xx_hal_cryp.h"
+#endif /* HAL_CRYP_MODULE_ENABLED */
+
+#ifdef HAL_DMA2D_MODULE_ENABLED
+ #include "stm32f4xx_hal_dma2d.h"
+#endif /* HAL_DMA2D_MODULE_ENABLED */
+
+#ifdef HAL_DAC_MODULE_ENABLED
+ #include "stm32f4xx_hal_dac.h"
+#endif /* HAL_DAC_MODULE_ENABLED */
+
+#ifdef HAL_DCMI_MODULE_ENABLED
+ #include "stm32f4xx_hal_dcmi.h"
+#endif /* HAL_DCMI_MODULE_ENABLED */
+
+#ifdef HAL_ETH_MODULE_ENABLED
+ #include "stm32f4xx_hal_eth.h"
+#endif /* HAL_ETH_MODULE_ENABLED */
+
+#ifdef HAL_FLASH_MODULE_ENABLED
+ #include "stm32f4xx_hal_flash.h"
+#endif /* HAL_FLASH_MODULE_ENABLED */
+
+#ifdef HAL_SRAM_MODULE_ENABLED
+ #include "stm32f4xx_hal_sram.h"
+#endif /* HAL_SRAM_MODULE_ENABLED */
+
+#ifdef HAL_NOR_MODULE_ENABLED
+ #include "stm32f4xx_hal_nor.h"
+#endif /* HAL_NOR_MODULE_ENABLED */
+
+#ifdef HAL_NAND_MODULE_ENABLED
+ #include "stm32f4xx_hal_nand.h"
+#endif /* HAL_NAND_MODULE_ENABLED */
+
+#ifdef HAL_PCCARD_MODULE_ENABLED
+ #include "stm32f4xx_hal_pccard.h"
+#endif /* HAL_PCCARD_MODULE_ENABLED */
+
+#ifdef HAL_SDRAM_MODULE_ENABLED
+ #include "stm32f4xx_hal_sdram.h"
+#endif /* HAL_SDRAM_MODULE_ENABLED */
+
+#ifdef HAL_HASH_MODULE_ENABLED
+ #include "stm32f4xx_hal_hash.h"
+#endif /* HAL_HASH_MODULE_ENABLED */
+
+#ifdef HAL_I2C_MODULE_ENABLED
+ #include "stm32f4xx_hal_i2c.h"
+#endif /* HAL_I2C_MODULE_ENABLED */
+
+#ifdef HAL_I2S_MODULE_ENABLED
+ #include "stm32f4xx_hal_i2s.h"
+#endif /* HAL_I2S_MODULE_ENABLED */
+
+#ifdef HAL_IWDG_MODULE_ENABLED
+ #include "stm32f4xx_hal_iwdg.h"
+#endif /* HAL_IWDG_MODULE_ENABLED */
+
+#ifdef HAL_LTDC_MODULE_ENABLED
+ #include "stm32f4xx_hal_ltdc.h"
+#endif /* HAL_LTDC_MODULE_ENABLED */
+
+#ifdef HAL_PWR_MODULE_ENABLED
+ #include "stm32f4xx_hal_pwr.h"
+#endif /* HAL_PWR_MODULE_ENABLED */
+
+#ifdef HAL_RNG_MODULE_ENABLED
+ #include "stm32f4xx_hal_rng.h"
+#endif /* HAL_RNG_MODULE_ENABLED */
+
+#ifdef HAL_RTC_MODULE_ENABLED
+ #include "stm32f4xx_hal_rtc.h"
+#endif /* HAL_RTC_MODULE_ENABLED */
+
+#ifdef HAL_SAI_MODULE_ENABLED
+ #include "stm32f4xx_hal_sai.h"
+#endif /* HAL_SAI_MODULE_ENABLED */
+
+#ifdef HAL_SD_MODULE_ENABLED
+ #include "stm32f4xx_hal_sd.h"
+#endif /* HAL_SD_MODULE_ENABLED */
+
+#ifdef HAL_SPI_MODULE_ENABLED
+ #include "stm32f4xx_hal_spi.h"
+#endif /* HAL_SPI_MODULE_ENABLED */
+
+#ifdef HAL_TIM_MODULE_ENABLED
+ #include "stm32f4xx_hal_tim.h"
+#endif /* HAL_TIM_MODULE_ENABLED */
+
+#ifdef HAL_UART_MODULE_ENABLED
+ #include "stm32f4xx_hal_uart.h"
+#endif /* HAL_UART_MODULE_ENABLED */
+
+#ifdef HAL_USART_MODULE_ENABLED
+ #include "stm32f4xx_hal_usart.h"
+#endif /* HAL_USART_MODULE_ENABLED */
+
+#ifdef HAL_IRDA_MODULE_ENABLED
+ #include "stm32f4xx_hal_irda.h"
+#endif /* HAL_IRDA_MODULE_ENABLED */
+
+#ifdef HAL_SMARTCARD_MODULE_ENABLED
+ #include "stm32f4xx_hal_smartcard.h"
+#endif /* HAL_SMARTCARD_MODULE_ENABLED */
+
+#ifdef HAL_WWDG_MODULE_ENABLED
+ #include "stm32f4xx_hal_wwdg.h"
+#endif /* HAL_WWDG_MODULE_ENABLED */
+
+#ifdef HAL_PCD_MODULE_ENABLED
+ #include "stm32f4xx_hal_pcd.h"
+#endif /* HAL_PCD_MODULE_ENABLED */
+
+#ifdef HAL_HCD_MODULE_ENABLED
+ #include "stm32f4xx_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 /* __STM32F4xx_HAL_CONF_H */
+
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/ports/stm32/boards/NUCLEO_F767ZI/mpconfigboard.h b/ports/stm32/boards/NUCLEO_F767ZI/mpconfigboard.h
new file mode 100644
index 000000000..8952bce82
--- /dev/null
+++ b/ports/stm32/boards/NUCLEO_F767ZI/mpconfigboard.h
@@ -0,0 +1,76 @@
+// 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-F767ZI"
+#define MICROPY_HW_MCU_NAME "STM32F767"
+
+#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)
+
+// HSE is 25MHz
+// VCOClock = HSE * PLLN / PLLM = 25 MHz * 432 / 25 = 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)
+
+// 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_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
new file mode 100644
index 000000000..ba28a16e1
--- /dev/null
+++ b/ports/stm32/boards/NUCLEO_F767ZI/mpconfigboard.mk
@@ -0,0 +1,5 @@
+MCU_SERIES = f7
+CMSIS_MCU = STM32F767xx
+MICROPY_FLOAT_IMPL = double
+AF_FILE = boards/stm32f767_af.csv
+LD_FILE = boards/stm32f767.ld
diff --git a/ports/stm32/boards/NUCLEO_F767ZI/pins.csv b/ports/stm32/boards/NUCLEO_F767ZI/pins.csv
new file mode 100644
index 000000000..897b1473e
--- /dev/null
+++ b/ports/stm32/boards/NUCLEO_F767ZI/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,PJ12
+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_F767ZI/stm32f7xx_hal_conf.h b/ports/stm32/boards/NUCLEO_F767ZI/stm32f7xx_hal_conf.h
new file mode 100644
index 000000000..e1aa4578d
--- /dev/null
+++ b/ports/stm32/boards/NUCLEO_F767ZI/stm32f7xx_hal_conf.h
@@ -0,0 +1,429 @@
+/**
+ ******************************************************************************
+ * @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 --------------------------------------------------------*/
+
+#define USE_USB_FS
+
+/* ########################## 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_L476RG/mpconfigboard.h b/ports/stm32/boards/NUCLEO_L476RG/mpconfigboard.h
new file mode 100644
index 000000000..f2474619f
--- /dev/null
+++ b/ports/stm32/boards/NUCLEO_L476RG/mpconfigboard.h
@@ -0,0 +1,53 @@
+#define MICROPY_HW_BOARD_NAME "NUCLEO-L476RG"
+#define MICROPY_HW_MCU_NAME "STM32L476RG"
+
+#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)
+
+// MSI is used and is 4MHz
+#define MICROPY_HW_CLK_PLLM (1)
+#define MICROPY_HW_CLK_PLLN (40)
+#define MICROPY_HW_CLK_PLLR (2)
+#define MICROPY_HW_CLK_PLLP (7)
+#define MICROPY_HW_CLK_PLLQ (4)
+
+// UART config
+#define MICROPY_HW_UART2_TX (pin_A2)
+#define MICROPY_HW_UART2_RX (pin_A3)
+
+#define MICROPY_HW_UART_REPL PYB_UART_2
+#define MICROPY_HW_UART_REPL_BAUD 115200
+
+#define MICROPY_HW_FLASH_LATENCY FLASH_LATENCY_4
+
+// I2C busses
+#define MICROPY_HW_I2C1_SCL (pin_B6)
+#define MICROPY_HW_I2C1_SDA (pin_B7)
+#define MICROPY_HW_I2C2_SCL (pin_B10)
+#define MICROPY_HW_I2C2_SDA (pin_B11)
+#define MICROPY_HW_I2C3_SCL (pin_C0)
+#define MICROPY_HW_I2C3_SDA (pin_C1)
+
+// SPI busses
+#define MICROPY_HW_SPI1_NSS (pin_A4)
+#define MICROPY_HW_SPI1_SCK (pin_B3)
+#define MICROPY_HW_SPI1_MISO (pin_B4)
+#define MICROPY_HW_SPI1_MOSI (pin_B5)
+#define MICROPY_HW_SPI2_NSS (pin_B12)
+#define MICROPY_HW_SPI2_SCK (pin_B13)
+#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_FALLING)
+#define MICROPY_HW_USRSW_PRESSED (0)
+
+// LEDs
+#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))
diff --git a/ports/stm32/boards/NUCLEO_L476RG/mpconfigboard.mk b/ports/stm32/boards/NUCLEO_L476RG/mpconfigboard.mk
new file mode 100644
index 000000000..abb4a3570
--- /dev/null
+++ b/ports/stm32/boards/NUCLEO_L476RG/mpconfigboard.mk
@@ -0,0 +1,5 @@
+MCU_SERIES = l4
+CMSIS_MCU = STM32L476xx
+AF_FILE = boards/stm32l476_af.csv
+LD_FILE = boards/stm32l476xg.ld
+TEXT_ADDR = 0x08004000
diff --git a/ports/stm32/boards/NUCLEO_L476RG/pins.csv b/ports/stm32/boards/NUCLEO_L476RG/pins.csv
new file mode 100644
index 000000000..035d933f5
--- /dev/null
+++ b/ports/stm32/boards/NUCLEO_L476RG/pins.csv
@@ -0,0 +1,76 @@
+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
+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
+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
+PH0,PH0
+PH1,PH1
+LED_GREEN,PA5
+LED_ORANGE,PA5
+LED_RED,PA5
+LED_BLUE,PA4
+SW,PC13
diff --git a/ports/stm32/boards/NUCLEO_L476RG/stm32l4xx_hal_conf.h b/ports/stm32/boards/NUCLEO_L476RG/stm32l4xx_hal_conf.h
new file mode 100755
index 000000000..9348e0679
--- /dev/null
+++ b/ports/stm32/boards/NUCLEO_L476RG/stm32l4xx_hal_conf.h
@@ -0,0 +1,373 @@
+/**
+ ******************************************************************************
+ * @file stm32l4xx_hal_conf.h
+ * @author MCD Application Team
+ * @version V1.2.0
+ * @date 25-November-2015
+ * @brief HAL configuration template file.
+ * This file should be copied to the application folder and renamed
+ * to stm32l4xx_hal_conf.h.
+ ******************************************************************************
+ * @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 __STM32L4xx_HAL_CONF_H
+#define __STM32L4xx_HAL_CONF_H
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+#define USE_USB_FS
+/* 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_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_DFSDM_MODULE_ENABLED */
+#define HAL_DMA_MODULE_ENABLED
+/* #define HAL_FIREWALL_MODULE_ENABLED */
+#define HAL_FLASH_MODULE_ENABLED
+/* #define HAL_HCD_MODULE_ENABLED */
+/* #define HAL_NAND_MODULE_ENABLED */
+/* #define HAL_NOR_MODULE_ENABLED */
+/* #define HAL_SRAM_MODULE_ENABLED */
+#define HAL_GPIO_MODULE_ENABLED
+#define HAL_I2C_MODULE_ENABLED
+/* #define HAL_IRDA_MODULE_ENABLED */
+/* #define HAL_IWDG_MODULE_ENABLED */
+/* #define HAL_LCD_MODULE_ENABLED */
+/* #define HAL_LPTIM_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_SMARTCARD_MODULE_ENABLED */
+/* #define HAL_SMBUS_MODULE_ENABLED */
+#define HAL_SPI_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 */
+
+
+/* ########################## 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 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 */
+
+/* Includes ------------------------------------------------------------------*/
+/**
+ * @brief Include module's header file
+ */
+
+#ifdef HAL_RCC_MODULE_ENABLED
+ #include "stm32l4xx_hal_rcc.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_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_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_OPAMP_MODULE_ENABLED
+#include "stm32l4xx_hal_opamp.h"
+#endif /* HAL_OPAMP_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 */
+
+/* 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 /* __STM32L4xx_HAL_CONF_H */
+
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/ports/stm32/boards/OLIMEX_E407/mpconfigboard.h b/ports/stm32/boards/OLIMEX_E407/mpconfigboard.h
new file mode 100644
index 000000000..5ede68264
--- /dev/null
+++ b/ports/stm32/boards/OLIMEX_E407/mpconfigboard.h
@@ -0,0 +1,80 @@
+#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)
+
+// HSE is 12MHz
+#define MICROPY_HW_CLK_PLLM (12)
+#define MICROPY_HW_CLK_PLLN (336)
+#define MICROPY_HW_CLK_PLLP (RCC_PLLP_DIV2)
+#define MICROPY_HW_CLK_PLLQ (7)
+
+// 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)
+#define MICROPY_HW_UART2_RTS (pin_A1)
+#define MICROPY_HW_UART2_CTS (pin_A0)
+#define MICROPY_HW_UART3_TX (pin_D8)
+#define MICROPY_HW_UART3_RX (pin_D9)
+#define MICROPY_HW_UART3_RTS (pin_D12)
+#define MICROPY_HW_UART3_CTS (pin_D11)
+#if MICROPY_HW_HAS_SWITCH == 0
+// NOTE: A0 also connects to the user switch. To use UART4 you should
+// set MICROPY_HW_HAS_SWITCH to 0, and also remove SB20 (on the back
+// of the board near the USER switch).
+#define MICROPY_HW_UART4_TX (pin_A0)
+#define MICROPY_HW_UART4_RX (pin_A1)
+#endif
+#define MICROPY_HW_UART6_TX (pin_C6)
+#define MICROPY_HW_UART6_RX (pin_C7)
+
+// I2C busses
+#define MICROPY_HW_I2C1_SCL (pin_B8)
+#define MICROPY_HW_I2C1_SDA (pin_B9)
+#define MICROPY_HW_I2C2_SCL (pin_B10)
+#define MICROPY_HW_I2C2_SDA (pin_B11)
+
+// SPI busses
+#define MICROPY_HW_SPI1_NSS (pin_A4)
+#define MICROPY_HW_SPI1_SCK (pin_A5)
+#define MICROPY_HW_SPI1_MISO (pin_A6)
+#define MICROPY_HW_SPI1_MOSI (pin_A7)
+#define MICROPY_HW_SPI2_NSS (pin_B12)
+#define MICROPY_HW_SPI2_SCK (pin_B13)
+#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_A0)
+#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_C13)
+#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_low(pin))
+#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_high(pin))
+
+// SD card detect switch
+#define MICROPY_HW_SDCARD_DETECT_PIN (pin_C11)
+#define MICROPY_HW_SDCARD_DETECT_PULL (GPIO_PULLUP)
+#define MICROPY_HW_SDCARD_DETECT_PRESENT (GPIO_PIN_RESET)
+
+// USB config
+#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
new file mode 100644
index 000000000..ece09caa1
--- /dev/null
+++ b/ports/stm32/boards/OLIMEX_E407/mpconfigboard.mk
@@ -0,0 +1,4 @@
+MCU_SERIES = f4
+CMSIS_MCU = STM32F407xx
+AF_FILE = boards/stm32f405_af.csv
+LD_FILE = boards/stm32f405.ld
diff --git a/ports/stm32/boards/OLIMEX_E407/pins.csv b/ports/stm32/boards/OLIMEX_E407/pins.csv
new file mode 100644
index 000000000..6b91f74ae
--- /dev/null
+++ b/ports/stm32/boards/OLIMEX_E407/pins.csv
@@ -0,0 +1,85 @@
+PC0,PC0
+PC1,PC1
+PC2,PC2
+PC3,PC3
+PA0,PA0
+PA1,PA1
+PA2,PA2
+PA3,PA3
+PA4,PA4
+PA5,PA5
+PA6,PA6
+PA7,PA7
+PC4,PC4
+PC5,PC5
+PB0,PB0
+PB1,PB1
+PB2,PB2
+PE7,PE7
+PE8,PE8
+PE9,PE9
+PE10,PE10
+PE11,PE11
+PE12,PE12
+PE13,PE13
+PE14,PE14
+PE15,PE15
+PB10,PB10
+PB11,PB11
+PB12,PB12
+PB13,PB13
+PB14,PB14
+PB15,PB15
+PD8,PD8
+PD9,PD9
+PD10,PD10
+PD11,PD11
+PD12,PD12
+PD13,PD13
+PD14,PD14
+PD15,PD15
+PC6,PC6
+PC7,PC7
+PC8,PC8
+PC9,PC9
+PA8,PA8
+PA9,PA9
+PA10,PA10
+PA13,PA13
+PA14,PA14
+PA15,PA15
+PC10,PC10
+PC11,PC11
+PC12,PC12
+PD0,PD0
+PD1,PD1
+PD2,PD2
+PD3,PD3
+PD4,PD4
+PD5,PD5
+PD6,PD6
+PD7,PD7
+PB4,PB4
+PB5,PB5
+PB6,PB6
+PB7,PB7
+PB8,PB8
+PB9,PB9
+PE0,PE0
+PE1,PE1
+PE2,PE2
+PE3,PE3
+PE4,PE4
+PE5,PE5
+PE6,PE6
+LED_GREEN,PC13
+PC14,PC14
+PC15,PC15
+PH0,PH0
+PH1,PH1
+PD12,PD12
+PD13,PD13
+PD14,PD14
+PD15,PD15
+PA0,PA0
+
diff --git a/ports/stm32/boards/OLIMEX_E407/stm32f4xx_hal_conf.h b/ports/stm32/boards/OLIMEX_E407/stm32f4xx_hal_conf.h
new file mode 100644
index 000000000..b84b0a892
--- /dev/null
+++ b/ports/stm32/boards/OLIMEX_E407/stm32f4xx_hal_conf.h
@@ -0,0 +1,411 @@
+/**
+ ******************************************************************************
+ * @file stm32f4xx_hal_conf.h
+ * @author MCD Application Team
+ * @version V1.1.0
+ * @date 19-June-2014
+ * @brief HAL configuration file.
+ ******************************************************************************
+ * @attention
+ *
+ * <h2><center>&copy; COPYRIGHT(c) 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.
+ *
+ ******************************************************************************
+ */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __STM32F4xx_HAL_CONF_H
+#define __STM32F4xx_HAL_CONF_H
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/* Exported types ------------------------------------------------------------*/
+/* Exported constants --------------------------------------------------------*/
+
+#define USE_USB_FS
+
+/* ########################## 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_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_PCCARD_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_LTDC_MODULE_ENABLED */
+#define HAL_PWR_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_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 */
+
+
+/* ########################## 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)12000000) /*!< Value of the External oscillator in Hz */
+#endif /* HSE_VALUE */
+
+#if !defined (HSE_STARTUP_TIMEOUT)
+ #define HSE_STARTUP_TIMEOUT ((uint32_t)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 ((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)40000)
+#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 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 */
+
+/* ################## 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 0
+#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)4) /* 4 Rx buffers of size ETH_RX_BUF_SIZE */
+#define ETH_TXBUFNB ((uint32_t)4) /* 4 Tx buffers of size ETH_TX_BUF_SIZE */
+
+/* Section 2: PHY configuration section */
+
+/* DP83848 PHY Address*/
+#define DP83848_PHY_ADDRESS 0x01
+/* PHY Reset delay these values are based on a 1 ms Systick interrupt*/
+#define PHY_RESET_DELAY ((uint32_t)0x000000FF)
+/* PHY Configuration delay */
+#define PHY_CONFIG_DELAY ((uint32_t)0x00000FFF)
+
+#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 "stm32f4xx_hal_rcc.h"
+#endif /* HAL_RCC_MODULE_ENABLED */
+
+#ifdef HAL_GPIO_MODULE_ENABLED
+ #include "stm32f4xx_hal_gpio.h"
+#endif /* HAL_GPIO_MODULE_ENABLED */
+
+#ifdef HAL_DMA_MODULE_ENABLED
+ #include "stm32f4xx_hal_dma.h"
+#endif /* HAL_DMA_MODULE_ENABLED */
+
+#ifdef HAL_CORTEX_MODULE_ENABLED
+ #include "stm32f4xx_hal_cortex.h"
+#endif /* HAL_CORTEX_MODULE_ENABLED */
+
+#ifdef HAL_ADC_MODULE_ENABLED
+ #include "stm32f4xx_hal_adc.h"
+#endif /* HAL_ADC_MODULE_ENABLED */
+
+#ifdef HAL_CAN_MODULE_ENABLED
+ #include "stm32f4xx_hal_can.h"
+#endif /* HAL_CAN_MODULE_ENABLED */
+
+#ifdef HAL_CRC_MODULE_ENABLED
+ #include "stm32f4xx_hal_crc.h"
+#endif /* HAL_CRC_MODULE_ENABLED */
+
+#ifdef HAL_CRYP_MODULE_ENABLED
+ #include "stm32f4xx_hal_cryp.h"
+#endif /* HAL_CRYP_MODULE_ENABLED */
+
+#ifdef HAL_DMA2D_MODULE_ENABLED
+ #include "stm32f4xx_hal_dma2d.h"
+#endif /* HAL_DMA2D_MODULE_ENABLED */
+
+#ifdef HAL_DAC_MODULE_ENABLED
+ #include "stm32f4xx_hal_dac.h"
+#endif /* HAL_DAC_MODULE_ENABLED */
+
+#ifdef HAL_DCMI_MODULE_ENABLED
+ #include "stm32f4xx_hal_dcmi.h"
+#endif /* HAL_DCMI_MODULE_ENABLED */
+
+#ifdef HAL_ETH_MODULE_ENABLED
+ #include "stm32f4xx_hal_eth.h"
+#endif /* HAL_ETH_MODULE_ENABLED */
+
+#ifdef HAL_FLASH_MODULE_ENABLED
+ #include "stm32f4xx_hal_flash.h"
+#endif /* HAL_FLASH_MODULE_ENABLED */
+
+#ifdef HAL_SRAM_MODULE_ENABLED
+ #include "stm32f4xx_hal_sram.h"
+#endif /* HAL_SRAM_MODULE_ENABLED */
+
+#ifdef HAL_NOR_MODULE_ENABLED
+ #include "stm32f4xx_hal_nor.h"
+#endif /* HAL_NOR_MODULE_ENABLED */
+
+#ifdef HAL_NAND_MODULE_ENABLED
+ #include "stm32f4xx_hal_nand.h"
+#endif /* HAL_NAND_MODULE_ENABLED */
+
+#ifdef HAL_PCCARD_MODULE_ENABLED
+ #include "stm32f4xx_hal_pccard.h"
+#endif /* HAL_PCCARD_MODULE_ENABLED */
+
+#ifdef HAL_SDRAM_MODULE_ENABLED
+ #include "stm32f4xx_hal_sdram.h"
+#endif /* HAL_SDRAM_MODULE_ENABLED */
+
+#ifdef HAL_HASH_MODULE_ENABLED
+ #include "stm32f4xx_hal_hash.h"
+#endif /* HAL_HASH_MODULE_ENABLED */
+
+#ifdef HAL_I2C_MODULE_ENABLED
+ #include "stm32f4xx_hal_i2c.h"
+#endif /* HAL_I2C_MODULE_ENABLED */
+
+#ifdef HAL_I2S_MODULE_ENABLED
+ #include "stm32f4xx_hal_i2s.h"
+#endif /* HAL_I2S_MODULE_ENABLED */
+
+#ifdef HAL_IWDG_MODULE_ENABLED
+ #include "stm32f4xx_hal_iwdg.h"
+#endif /* HAL_IWDG_MODULE_ENABLED */
+
+#ifdef HAL_LTDC_MODULE_ENABLED
+ #include "stm32f4xx_hal_ltdc.h"
+#endif /* HAL_LTDC_MODULE_ENABLED */
+
+#ifdef HAL_PWR_MODULE_ENABLED
+ #include "stm32f4xx_hal_pwr.h"
+#endif /* HAL_PWR_MODULE_ENABLED */
+
+#ifdef HAL_RNG_MODULE_ENABLED
+ #include "stm32f4xx_hal_rng.h"
+#endif /* HAL_RNG_MODULE_ENABLED */
+
+#ifdef HAL_RTC_MODULE_ENABLED
+ #include "stm32f4xx_hal_rtc.h"
+#endif /* HAL_RTC_MODULE_ENABLED */
+
+#ifdef HAL_SAI_MODULE_ENABLED
+ #include "stm32f4xx_hal_sai.h"
+#endif /* HAL_SAI_MODULE_ENABLED */
+
+#ifdef HAL_SD_MODULE_ENABLED
+ #include "stm32f4xx_hal_sd.h"
+#endif /* HAL_SD_MODULE_ENABLED */
+
+#ifdef HAL_SPI_MODULE_ENABLED
+ #include "stm32f4xx_hal_spi.h"
+#endif /* HAL_SPI_MODULE_ENABLED */
+
+#ifdef HAL_TIM_MODULE_ENABLED
+ #include "stm32f4xx_hal_tim.h"
+#endif /* HAL_TIM_MODULE_ENABLED */
+
+#ifdef HAL_UART_MODULE_ENABLED
+ #include "stm32f4xx_hal_uart.h"
+#endif /* HAL_UART_MODULE_ENABLED */
+
+#ifdef HAL_USART_MODULE_ENABLED
+ #include "stm32f4xx_hal_usart.h"
+#endif /* HAL_USART_MODULE_ENABLED */
+
+#ifdef HAL_IRDA_MODULE_ENABLED
+ #include "stm32f4xx_hal_irda.h"
+#endif /* HAL_IRDA_MODULE_ENABLED */
+
+#ifdef HAL_SMARTCARD_MODULE_ENABLED
+ #include "stm32f4xx_hal_smartcard.h"
+#endif /* HAL_SMARTCARD_MODULE_ENABLED */
+
+#ifdef HAL_WWDG_MODULE_ENABLED
+ #include "stm32f4xx_hal_wwdg.h"
+#endif /* HAL_WWDG_MODULE_ENABLED */
+
+#ifdef HAL_PCD_MODULE_ENABLED
+ #include "stm32f4xx_hal_pcd.h"
+#endif /* HAL_PCD_MODULE_ENABLED */
+
+#ifdef HAL_HCD_MODULE_ENABLED
+ #include "stm32f4xx_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 /* __STM32F4xx_HAL_CONF_H */
+
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/ports/stm32/boards/PYBLITEV10/mpconfigboard.h b/ports/stm32/boards/PYBLITEV10/mpconfigboard.h
new file mode 100644
index 000000000..090ba4cf1
--- /dev/null
+++ b/ports/stm32/boards/PYBLITEV10/mpconfigboard.h
@@ -0,0 +1,87 @@
+#define MICROPY_HW_BOARD_NAME "PYBLITEv1.0"
+#define MICROPY_HW_MCU_NAME "STM32F411RE"
+
+#define MICROPY_HW_HAS_SWITCH (1)
+#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_SERVO (1)
+#define MICROPY_HW_ENABLE_DAC (0)
+#define MICROPY_HW_ENABLE_CAN (0)
+
+// HSE is 12MHz
+#define MICROPY_HW_CLK_PLLM (12)
+#define MICROPY_HW_CLK_PLLN (192)
+#define MICROPY_HW_CLK_PLLP (RCC_PLLP_DIV2)
+#define MICROPY_HW_CLK_PLLQ (4)
+#define MICROPY_HW_CLK_LAST_FREQ (1)
+
+// Pyboard lite has an optional 32kHz crystal
+#define MICROPY_HW_RTC_USE_LSE (1)
+#define MICROPY_HW_RTC_USE_US (0)
+#define MICROPY_HW_RTC_USE_CALOUT (1)
+
+// UART config
+#define MICROPY_HW_UART1_NAME "XB"
+#define MICROPY_HW_UART1_TX (pin_B6)
+#define MICROPY_HW_UART1_RX (pin_B7)
+#define MICROPY_HW_UART2_NAME "XA"
+#define MICROPY_HW_UART2_TX (pin_A2)
+#define MICROPY_HW_UART2_RX (pin_A3)
+#define MICROPY_HW_UART2_RTS (pin_A1)
+#define MICROPY_HW_UART2_CTS (pin_A0)
+#define MICROPY_HW_UART6_NAME "YA"
+#define MICROPY_HW_UART6_TX (pin_C6)
+#define MICROPY_HW_UART6_RX (pin_C7)
+
+// I2C busses
+#define MICROPY_HW_I2C1_NAME "X"
+#define MICROPY_HW_I2C1_SCL (pin_B6)
+#define MICROPY_HW_I2C1_SDA (pin_B7)
+#define MICROPY_HW_I2C3_NAME "Y"
+#define MICROPY_HW_I2C3_SCL (pin_A8)
+#define MICROPY_HW_I2C3_SDA (pin_B8)
+
+// SPI busses
+#define MICROPY_HW_SPI1_NAME "X"
+#define MICROPY_HW_SPI1_NSS (pin_A4) // X5
+#define MICROPY_HW_SPI1_SCK (pin_A5) // X6
+#define MICROPY_HW_SPI1_MISO (pin_A6) // X7
+#define MICROPY_HW_SPI1_MOSI (pin_A7) // X8
+#define MICROPY_HW_SPI2_NAME "Y"
+#define MICROPY_HW_SPI2_NSS (pin_B12) // Y5
+#define MICROPY_HW_SPI2_SCK (pin_B13) // Y6
+#define MICROPY_HW_SPI2_MISO (pin_B14) // Y7
+#define MICROPY_HW_SPI2_MOSI (pin_B15) // Y8
+
+// USRSW has no pullup or pulldown, and pressing the switch makes the input go low
+#define MICROPY_HW_USRSW_PIN (pin_B3)
+#define MICROPY_HW_USRSW_PULL (GPIO_PULLUP)
+#define MICROPY_HW_USRSW_EXTI_MODE (GPIO_MODE_IT_FALLING)
+#define MICROPY_HW_USRSW_PRESSED (0)
+
+// The pyboard has 4 LEDs
+#define MICROPY_HW_LED1 (pin_A13) // red
+#define MICROPY_HW_LED2 (pin_A14) // green
+#define MICROPY_HW_LED3 (pin_A15) // yellow
+#define MICROPY_HW_LED4 (pin_B4) // blue
+#define MICROPY_HW_LED3_PWM { TIM2, 2, TIM_CHANNEL_1, GPIO_AF1_TIM2 }
+#define MICROPY_HW_LED4_PWM { TIM3, 3, TIM_CHANNEL_1, GPIO_AF2_TIM3 }
+#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_high(pin))
+#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin))
+
+// SD card detect switch
+#define MICROPY_HW_SDCARD_DETECT_PIN (pin_B5)
+#define MICROPY_HW_SDCARD_DETECT_PULL (GPIO_PULLUP)
+#define MICROPY_HW_SDCARD_DETECT_PRESENT (GPIO_PIN_RESET)
+
+// USB config
+#define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_A9)
+
+// MMA accelerometer config
+#define MICROPY_HW_MMA_AVDD_PIN (pin_A10)
diff --git a/ports/stm32/boards/PYBLITEV10/mpconfigboard.mk b/ports/stm32/boards/PYBLITEV10/mpconfigboard.mk
new file mode 100644
index 000000000..71b3b19d6
--- /dev/null
+++ b/ports/stm32/boards/PYBLITEV10/mpconfigboard.mk
@@ -0,0 +1,4 @@
+MCU_SERIES = f4
+CMSIS_MCU = STM32F411xE
+AF_FILE = boards/stm32f411_af.csv
+LD_FILE = boards/stm32f411.ld
diff --git a/ports/stm32/boards/PYBLITEV10/pins.csv b/ports/stm32/boards/PYBLITEV10/pins.csv
new file mode 100644
index 000000000..838587c1b
--- /dev/null
+++ b/ports/stm32/boards/PYBLITEV10/pins.csv
@@ -0,0 +1,60 @@
+X1,PA2
+X2,PA3
+X3,PA0
+X4,PA1
+X5,PA4
+X6,PA5
+X7,PA6
+X8,PA7
+X9,PB6
+X10,PB7
+X11,PC4
+X12,PC5
+X13,Reset
+X14,GND
+X15,3.3V
+X16,VIN
+X17,PB3
+X18,PC13
+X19,PC0
+X20,PC1
+X21,PC2
+X22,PC3
+X23,A3.3V
+X24,AGND
+Y1,PC6
+Y2,PC7
+Y3,PB10
+Y4,PB9
+Y5,PB12
+Y6,PB13
+Y7,PB14
+Y8,PB15
+Y9,PA8
+Y10,PB8
+Y11,PB0
+Y12,PB1
+Y13,Reset
+Y14,GND
+Y15,3.3V
+Y16,VIN
+SW,PB3
+LED_BLUE,PB4
+LED_RED,PA13
+LED_GREEN,PA14
+LED_YELLOW,PA15
+MMA_AVDD,PA10
+MMA_INT,PB2
+SD_D0,PC8
+SD_D1,PC9
+SD_D2,PC10
+SD_D3,PC11
+SD_CMD,PD2
+SD_CK,PC12
+SD_SW,PB5
+USB_VBUS,PA9
+USB_DM,PA11
+USB_DP,PA12
+USB_ID,PA10
+OSC32_IN,PC14
+OSC32_OUT,PC15
diff --git a/ports/stm32/boards/PYBLITEV10/stm32f4xx_hal_conf.h b/ports/stm32/boards/PYBLITEV10/stm32f4xx_hal_conf.h
new file mode 100644
index 000000000..4ee8e7276
--- /dev/null
+++ b/ports/stm32/boards/PYBLITEV10/stm32f4xx_hal_conf.h
@@ -0,0 +1,411 @@
+/**
+ ******************************************************************************
+ * @file stm32f4xx_hal_conf.h
+ * @author MCD Application Team
+ * @version V1.1.0
+ * @date 19-June-2014
+ * @brief HAL configuration file.
+ ******************************************************************************
+ * @attention
+ *
+ * <h2><center>&copy; COPYRIGHT(c) 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.
+ *
+ ******************************************************************************
+ */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __STM32F4xx_HAL_CONF_H
+#define __STM32F4xx_HAL_CONF_H
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/* Exported types ------------------------------------------------------------*/
+/* Exported constants --------------------------------------------------------*/
+
+#define USE_USB_FS
+
+/* ########################## 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_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_PCCARD_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_LTDC_MODULE_ENABLED */
+#define HAL_PWR_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_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 */
+
+
+/* ########################## 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)12000000) /*!< Value of the External oscillator in Hz */
+#endif /* HSE_VALUE */
+
+#if !defined (HSE_STARTUP_TIMEOUT)
+ #define HSE_STARTUP_TIMEOUT ((uint32_t)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 ((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)40000)
+#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 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 */
+
+/* ################## 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 0
+#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)4) /* 4 Rx buffers of size ETH_RX_BUF_SIZE */
+#define ETH_TXBUFNB ((uint32_t)4) /* 4 Tx buffers of size ETH_TX_BUF_SIZE */
+
+/* Section 2: PHY configuration section */
+
+/* DP83848 PHY Address*/
+#define DP83848_PHY_ADDRESS 0x01
+/* PHY Reset delay these values are based on a 1 ms Systick interrupt*/
+#define PHY_RESET_DELAY ((uint32_t)0x000000FF)
+/* PHY Configuration delay */
+#define PHY_CONFIG_DELAY ((uint32_t)0x00000FFF)
+
+#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 "stm32f4xx_hal_rcc.h"
+#endif /* HAL_RCC_MODULE_ENABLED */
+
+#ifdef HAL_GPIO_MODULE_ENABLED
+ #include "stm32f4xx_hal_gpio.h"
+#endif /* HAL_GPIO_MODULE_ENABLED */
+
+#ifdef HAL_DMA_MODULE_ENABLED
+ #include "stm32f4xx_hal_dma.h"
+#endif /* HAL_DMA_MODULE_ENABLED */
+
+#ifdef HAL_CORTEX_MODULE_ENABLED
+ #include "stm32f4xx_hal_cortex.h"
+#endif /* HAL_CORTEX_MODULE_ENABLED */
+
+#ifdef HAL_ADC_MODULE_ENABLED
+ #include "stm32f4xx_hal_adc.h"
+#endif /* HAL_ADC_MODULE_ENABLED */
+
+#ifdef HAL_CAN_MODULE_ENABLED
+ #include "stm32f4xx_hal_can.h"
+#endif /* HAL_CAN_MODULE_ENABLED */
+
+#ifdef HAL_CRC_MODULE_ENABLED
+ #include "stm32f4xx_hal_crc.h"
+#endif /* HAL_CRC_MODULE_ENABLED */
+
+#ifdef HAL_CRYP_MODULE_ENABLED
+ #include "stm32f4xx_hal_cryp.h"
+#endif /* HAL_CRYP_MODULE_ENABLED */
+
+#ifdef HAL_DMA2D_MODULE_ENABLED
+ #include "stm32f4xx_hal_dma2d.h"
+#endif /* HAL_DMA2D_MODULE_ENABLED */
+
+#ifdef HAL_DAC_MODULE_ENABLED
+ #include "stm32f4xx_hal_dac.h"
+#endif /* HAL_DAC_MODULE_ENABLED */
+
+#ifdef HAL_DCMI_MODULE_ENABLED
+ #include "stm32f4xx_hal_dcmi.h"
+#endif /* HAL_DCMI_MODULE_ENABLED */
+
+#ifdef HAL_ETH_MODULE_ENABLED
+ #include "stm32f4xx_hal_eth.h"
+#endif /* HAL_ETH_MODULE_ENABLED */
+
+#ifdef HAL_FLASH_MODULE_ENABLED
+ #include "stm32f4xx_hal_flash.h"
+#endif /* HAL_FLASH_MODULE_ENABLED */
+
+#ifdef HAL_SRAM_MODULE_ENABLED
+ #include "stm32f4xx_hal_sram.h"
+#endif /* HAL_SRAM_MODULE_ENABLED */
+
+#ifdef HAL_NOR_MODULE_ENABLED
+ #include "stm32f4xx_hal_nor.h"
+#endif /* HAL_NOR_MODULE_ENABLED */
+
+#ifdef HAL_NAND_MODULE_ENABLED
+ #include "stm32f4xx_hal_nand.h"
+#endif /* HAL_NAND_MODULE_ENABLED */
+
+#ifdef HAL_PCCARD_MODULE_ENABLED
+ #include "stm32f4xx_hal_pccard.h"
+#endif /* HAL_PCCARD_MODULE_ENABLED */
+
+#ifdef HAL_SDRAM_MODULE_ENABLED
+ #include "stm32f4xx_hal_sdram.h"
+#endif /* HAL_SDRAM_MODULE_ENABLED */
+
+#ifdef HAL_HASH_MODULE_ENABLED
+ #include "stm32f4xx_hal_hash.h"
+#endif /* HAL_HASH_MODULE_ENABLED */
+
+#ifdef HAL_I2C_MODULE_ENABLED
+ #include "stm32f4xx_hal_i2c.h"
+#endif /* HAL_I2C_MODULE_ENABLED */
+
+#ifdef HAL_I2S_MODULE_ENABLED
+ #include "stm32f4xx_hal_i2s.h"
+#endif /* HAL_I2S_MODULE_ENABLED */
+
+#ifdef HAL_IWDG_MODULE_ENABLED
+ #include "stm32f4xx_hal_iwdg.h"
+#endif /* HAL_IWDG_MODULE_ENABLED */
+
+#ifdef HAL_LTDC_MODULE_ENABLED
+ #include "stm32f4xx_hal_ltdc.h"
+#endif /* HAL_LTDC_MODULE_ENABLED */
+
+#ifdef HAL_PWR_MODULE_ENABLED
+ #include "stm32f4xx_hal_pwr.h"
+#endif /* HAL_PWR_MODULE_ENABLED */
+
+#ifdef HAL_RNG_MODULE_ENABLED
+ #include "stm32f4xx_hal_rng.h"
+#endif /* HAL_RNG_MODULE_ENABLED */
+
+#ifdef HAL_RTC_MODULE_ENABLED
+ #include "stm32f4xx_hal_rtc.h"
+#endif /* HAL_RTC_MODULE_ENABLED */
+
+#ifdef HAL_SAI_MODULE_ENABLED
+ #include "stm32f4xx_hal_sai.h"
+#endif /* HAL_SAI_MODULE_ENABLED */
+
+#ifdef HAL_SD_MODULE_ENABLED
+ #include "stm32f4xx_hal_sd.h"
+#endif /* HAL_SD_MODULE_ENABLED */
+
+#ifdef HAL_SPI_MODULE_ENABLED
+ #include "stm32f4xx_hal_spi.h"
+#endif /* HAL_SPI_MODULE_ENABLED */
+
+#ifdef HAL_TIM_MODULE_ENABLED
+ #include "stm32f4xx_hal_tim.h"
+#endif /* HAL_TIM_MODULE_ENABLED */
+
+#ifdef HAL_UART_MODULE_ENABLED
+ #include "stm32f4xx_hal_uart.h"
+#endif /* HAL_UART_MODULE_ENABLED */
+
+#ifdef HAL_USART_MODULE_ENABLED
+ #include "stm32f4xx_hal_usart.h"
+#endif /* HAL_USART_MODULE_ENABLED */
+
+#ifdef HAL_IRDA_MODULE_ENABLED
+ #include "stm32f4xx_hal_irda.h"
+#endif /* HAL_IRDA_MODULE_ENABLED */
+
+#ifdef HAL_SMARTCARD_MODULE_ENABLED
+ #include "stm32f4xx_hal_smartcard.h"
+#endif /* HAL_SMARTCARD_MODULE_ENABLED */
+
+#ifdef HAL_WWDG_MODULE_ENABLED
+ #include "stm32f4xx_hal_wwdg.h"
+#endif /* HAL_WWDG_MODULE_ENABLED */
+
+#ifdef HAL_PCD_MODULE_ENABLED
+ #include "stm32f4xx_hal_pcd.h"
+#endif /* HAL_PCD_MODULE_ENABLED */
+
+#ifdef HAL_HCD_MODULE_ENABLED
+ #include "stm32f4xx_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 /* __STM32F4xx_HAL_CONF_H */
+
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/ports/stm32/boards/PYBV10/mpconfigboard.h b/ports/stm32/boards/PYBV10/mpconfigboard.h
new file mode 100644
index 000000000..c06022a34
--- /dev/null
+++ b/ports/stm32/boards/PYBV10/mpconfigboard.h
@@ -0,0 +1,99 @@
+#define MICROPY_HW_BOARD_NAME "PYBv1.0"
+#define MICROPY_HW_MCU_NAME "STM32F405RG"
+
+#define MICROPY_HW_HAS_SWITCH (1)
+#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)
+
+// HSE is 8MHz
+#define MICROPY_HW_CLK_PLLM (8)
+#define MICROPY_HW_CLK_PLLN (336)
+#define MICROPY_HW_CLK_PLLP (RCC_PLLP_DIV2)
+#define MICROPY_HW_CLK_PLLQ (7)
+#define MICROPY_HW_CLK_LAST_FREQ (1)
+
+// The pyboard has a 32kHz crystal for the RTC
+#define MICROPY_HW_RTC_USE_LSE (1)
+#define MICROPY_HW_RTC_USE_US (0)
+#define MICROPY_HW_RTC_USE_CALOUT (1)
+
+// UART config
+#define MICROPY_HW_UART1_NAME "XB"
+#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)
+#define MICROPY_HW_UART2_RTS (pin_A1)
+#define MICROPY_HW_UART2_CTS (pin_A0)
+#define MICROPY_HW_UART3_NAME "YB"
+#define MICROPY_HW_UART3_TX (pin_B10)
+#define MICROPY_HW_UART3_RX (pin_B11)
+#define MICROPY_HW_UART3_RTS (pin_B14)
+#define MICROPY_HW_UART3_CTS (pin_B13)
+#define MICROPY_HW_UART4_NAME "XA"
+#define MICROPY_HW_UART4_TX (pin_A0)
+#define MICROPY_HW_UART4_RX (pin_A1)
+#define MICROPY_HW_UART6_NAME "YA"
+#define MICROPY_HW_UART6_TX (pin_C6)
+#define MICROPY_HW_UART6_RX (pin_C7)
+
+// I2C busses
+#define MICROPY_HW_I2C1_NAME "X"
+#define MICROPY_HW_I2C1_SCL (pin_B6)
+#define MICROPY_HW_I2C1_SDA (pin_B7)
+#define MICROPY_HW_I2C2_NAME "Y"
+#define MICROPY_HW_I2C2_SCL (pin_B10)
+#define MICROPY_HW_I2C2_SDA (pin_B11)
+
+// SPI busses
+#define MICROPY_HW_SPI1_NAME "X"
+#define MICROPY_HW_SPI1_NSS (pin_A4) // X5
+#define MICROPY_HW_SPI1_SCK (pin_A5) // X6
+#define MICROPY_HW_SPI1_MISO (pin_A6) // X7
+#define MICROPY_HW_SPI1_MOSI (pin_A7) // X8
+#define MICROPY_HW_SPI2_NAME "Y"
+#define MICROPY_HW_SPI2_NSS (pin_B12) // Y5
+#define MICROPY_HW_SPI2_SCK (pin_B13) // Y6
+#define MICROPY_HW_SPI2_MISO (pin_B14) // Y7
+#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
+
+// USRSW has no pullup or pulldown, and pressing the switch makes the input go low
+#define MICROPY_HW_USRSW_PIN (pin_B3)
+#define MICROPY_HW_USRSW_PULL (GPIO_PULLUP)
+#define MICROPY_HW_USRSW_EXTI_MODE (GPIO_MODE_IT_FALLING)
+#define MICROPY_HW_USRSW_PRESSED (0)
+
+// The pyboard has 4 LEDs
+#define MICROPY_HW_LED1 (pin_A13) // red
+#define MICROPY_HW_LED2 (pin_A14) // green
+#define MICROPY_HW_LED3 (pin_A15) // yellow
+#define MICROPY_HW_LED4 (pin_B4) // blue
+#define MICROPY_HW_LED3_PWM { TIM2, 2, TIM_CHANNEL_1, GPIO_AF1_TIM2 }
+#define MICROPY_HW_LED4_PWM { TIM3, 3, TIM_CHANNEL_1, GPIO_AF2_TIM3 }
+#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_high(pin))
+#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin))
+
+// SD card detect switch
+#define MICROPY_HW_SDCARD_DETECT_PIN (pin_A8)
+#define MICROPY_HW_SDCARD_DETECT_PULL (GPIO_PULLUP)
+#define MICROPY_HW_SDCARD_DETECT_PRESENT (GPIO_PIN_RESET)
+
+// USB config
+#define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_A9)
+#define MICROPY_HW_USB_OTG_ID_PIN (pin_A10)
+
+// MMA accelerometer config
+#define MICROPY_HW_MMA_AVDD_PIN (pin_B5)
diff --git a/ports/stm32/boards/PYBV10/mpconfigboard.mk b/ports/stm32/boards/PYBV10/mpconfigboard.mk
new file mode 100644
index 000000000..5734c6690
--- /dev/null
+++ b/ports/stm32/boards/PYBV10/mpconfigboard.mk
@@ -0,0 +1,4 @@
+MCU_SERIES = f4
+CMSIS_MCU = STM32F405xx
+AF_FILE = boards/stm32f405_af.csv
+LD_FILE = boards/stm32f405.ld
diff --git a/ports/stm32/boards/PYBV10/pins.csv b/ports/stm32/boards/PYBV10/pins.csv
new file mode 100644
index 000000000..cee80a1aa
--- /dev/null
+++ b/ports/stm32/boards/PYBV10/pins.csv
@@ -0,0 +1,59 @@
+X1,PA0
+X2,PA1
+X3,PA2
+X4,PA3
+X5,PA4
+X6,PA5
+X7,PA6
+X8,PA7
+X9,PB6
+X10,PB7
+X11,PC4
+X12,PC5
+X13,Reset
+X14,GND
+X15,3.3V
+X16,VIN
+X17,PB3
+X18,PC13
+X19,PC0
+X20,PC1
+X21,PC2
+X22,PC3
+X23,A3.3V
+X24,AGND
+Y1,PC6
+Y2,PC7
+Y3,PB8
+Y4,PB9
+Y5,PB12
+Y6,PB13
+Y7,PB14
+Y8,PB15
+Y9,PB10
+Y10,PB11
+Y11,PB0
+Y12,PB1
+Y13,Reset
+Y14,GND
+Y15,3.3V
+Y16,VIN
+SW,PB3
+LED_RED,PA13
+LED_GREEN,PA14
+LED_YELLOW,PA15
+LED_BLUE,PB4
+MMA_INT,PB2
+MMA_AVDD,PB5
+SD_D0,PC8
+SD_D1,PC9
+SD_D2,PC10
+SD_D3,PC11
+SD_CMD,PD2
+SD_CK,PC12
+SD,PA8
+SD_SW,PA8
+USB_VBUS,PA9
+USB_ID,PA10
+USB_DM,PA11
+USB_DP,PA12
diff --git a/ports/stm32/boards/PYBV10/stm32f4xx_hal_conf.h b/ports/stm32/boards/PYBV10/stm32f4xx_hal_conf.h
new file mode 100644
index 000000000..52518e196
--- /dev/null
+++ b/ports/stm32/boards/PYBV10/stm32f4xx_hal_conf.h
@@ -0,0 +1,411 @@
+/**
+ ******************************************************************************
+ * @file stm32f4xx_hal_conf.h
+ * @author MCD Application Team
+ * @version V1.1.0
+ * @date 19-June-2014
+ * @brief HAL configuration file.
+ ******************************************************************************
+ * @attention
+ *
+ * <h2><center>&copy; COPYRIGHT(c) 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.
+ *
+ ******************************************************************************
+ */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __STM32F4xx_HAL_CONF_H
+#define __STM32F4xx_HAL_CONF_H
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/* Exported types ------------------------------------------------------------*/
+/* Exported constants --------------------------------------------------------*/
+
+#define USE_USB_FS
+
+/* ########################## 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_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_PCCARD_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_LTDC_MODULE_ENABLED */
+#define HAL_PWR_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_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 */
+
+
+/* ########################## 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)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 ((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)40000)
+#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 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 */
+
+/* ################## 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 0
+#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)4) /* 4 Rx buffers of size ETH_RX_BUF_SIZE */
+#define ETH_TXBUFNB ((uint32_t)4) /* 4 Tx buffers of size ETH_TX_BUF_SIZE */
+
+/* Section 2: PHY configuration section */
+
+/* DP83848 PHY Address*/
+#define DP83848_PHY_ADDRESS 0x01
+/* PHY Reset delay these values are based on a 1 ms Systick interrupt*/
+#define PHY_RESET_DELAY ((uint32_t)0x000000FF)
+/* PHY Configuration delay */
+#define PHY_CONFIG_DELAY ((uint32_t)0x00000FFF)
+
+#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 "stm32f4xx_hal_rcc.h"
+#endif /* HAL_RCC_MODULE_ENABLED */
+
+#ifdef HAL_GPIO_MODULE_ENABLED
+ #include "stm32f4xx_hal_gpio.h"
+#endif /* HAL_GPIO_MODULE_ENABLED */
+
+#ifdef HAL_DMA_MODULE_ENABLED
+ #include "stm32f4xx_hal_dma.h"
+#endif /* HAL_DMA_MODULE_ENABLED */
+
+#ifdef HAL_CORTEX_MODULE_ENABLED
+ #include "stm32f4xx_hal_cortex.h"
+#endif /* HAL_CORTEX_MODULE_ENABLED */
+
+#ifdef HAL_ADC_MODULE_ENABLED
+ #include "stm32f4xx_hal_adc.h"
+#endif /* HAL_ADC_MODULE_ENABLED */
+
+#ifdef HAL_CAN_MODULE_ENABLED
+ #include "stm32f4xx_hal_can.h"
+#endif /* HAL_CAN_MODULE_ENABLED */
+
+#ifdef HAL_CRC_MODULE_ENABLED
+ #include "stm32f4xx_hal_crc.h"
+#endif /* HAL_CRC_MODULE_ENABLED */
+
+#ifdef HAL_CRYP_MODULE_ENABLED
+ #include "stm32f4xx_hal_cryp.h"
+#endif /* HAL_CRYP_MODULE_ENABLED */
+
+#ifdef HAL_DMA2D_MODULE_ENABLED
+ #include "stm32f4xx_hal_dma2d.h"
+#endif /* HAL_DMA2D_MODULE_ENABLED */
+
+#ifdef HAL_DAC_MODULE_ENABLED
+ #include "stm32f4xx_hal_dac.h"
+#endif /* HAL_DAC_MODULE_ENABLED */
+
+#ifdef HAL_DCMI_MODULE_ENABLED
+ #include "stm32f4xx_hal_dcmi.h"
+#endif /* HAL_DCMI_MODULE_ENABLED */
+
+#ifdef HAL_ETH_MODULE_ENABLED
+ #include "stm32f4xx_hal_eth.h"
+#endif /* HAL_ETH_MODULE_ENABLED */
+
+#ifdef HAL_FLASH_MODULE_ENABLED
+ #include "stm32f4xx_hal_flash.h"
+#endif /* HAL_FLASH_MODULE_ENABLED */
+
+#ifdef HAL_SRAM_MODULE_ENABLED
+ #include "stm32f4xx_hal_sram.h"
+#endif /* HAL_SRAM_MODULE_ENABLED */
+
+#ifdef HAL_NOR_MODULE_ENABLED
+ #include "stm32f4xx_hal_nor.h"
+#endif /* HAL_NOR_MODULE_ENABLED */
+
+#ifdef HAL_NAND_MODULE_ENABLED
+ #include "stm32f4xx_hal_nand.h"
+#endif /* HAL_NAND_MODULE_ENABLED */
+
+#ifdef HAL_PCCARD_MODULE_ENABLED
+ #include "stm32f4xx_hal_pccard.h"
+#endif /* HAL_PCCARD_MODULE_ENABLED */
+
+#ifdef HAL_SDRAM_MODULE_ENABLED
+ #include "stm32f4xx_hal_sdram.h"
+#endif /* HAL_SDRAM_MODULE_ENABLED */
+
+#ifdef HAL_HASH_MODULE_ENABLED
+ #include "stm32f4xx_hal_hash.h"
+#endif /* HAL_HASH_MODULE_ENABLED */
+
+#ifdef HAL_I2C_MODULE_ENABLED
+ #include "stm32f4xx_hal_i2c.h"
+#endif /* HAL_I2C_MODULE_ENABLED */
+
+#ifdef HAL_I2S_MODULE_ENABLED
+ #include "stm32f4xx_hal_i2s.h"
+#endif /* HAL_I2S_MODULE_ENABLED */
+
+#ifdef HAL_IWDG_MODULE_ENABLED
+ #include "stm32f4xx_hal_iwdg.h"
+#endif /* HAL_IWDG_MODULE_ENABLED */
+
+#ifdef HAL_LTDC_MODULE_ENABLED
+ #include "stm32f4xx_hal_ltdc.h"
+#endif /* HAL_LTDC_MODULE_ENABLED */
+
+#ifdef HAL_PWR_MODULE_ENABLED
+ #include "stm32f4xx_hal_pwr.h"
+#endif /* HAL_PWR_MODULE_ENABLED */
+
+#ifdef HAL_RNG_MODULE_ENABLED
+ #include "stm32f4xx_hal_rng.h"
+#endif /* HAL_RNG_MODULE_ENABLED */
+
+#ifdef HAL_RTC_MODULE_ENABLED
+ #include "stm32f4xx_hal_rtc.h"
+#endif /* HAL_RTC_MODULE_ENABLED */
+
+#ifdef HAL_SAI_MODULE_ENABLED
+ #include "stm32f4xx_hal_sai.h"
+#endif /* HAL_SAI_MODULE_ENABLED */
+
+#ifdef HAL_SD_MODULE_ENABLED
+ #include "stm32f4xx_hal_sd.h"
+#endif /* HAL_SD_MODULE_ENABLED */
+
+#ifdef HAL_SPI_MODULE_ENABLED
+ #include "stm32f4xx_hal_spi.h"
+#endif /* HAL_SPI_MODULE_ENABLED */
+
+#ifdef HAL_TIM_MODULE_ENABLED
+ #include "stm32f4xx_hal_tim.h"
+#endif /* HAL_TIM_MODULE_ENABLED */
+
+#ifdef HAL_UART_MODULE_ENABLED
+ #include "stm32f4xx_hal_uart.h"
+#endif /* HAL_UART_MODULE_ENABLED */
+
+#ifdef HAL_USART_MODULE_ENABLED
+ #include "stm32f4xx_hal_usart.h"
+#endif /* HAL_USART_MODULE_ENABLED */
+
+#ifdef HAL_IRDA_MODULE_ENABLED
+ #include "stm32f4xx_hal_irda.h"
+#endif /* HAL_IRDA_MODULE_ENABLED */
+
+#ifdef HAL_SMARTCARD_MODULE_ENABLED
+ #include "stm32f4xx_hal_smartcard.h"
+#endif /* HAL_SMARTCARD_MODULE_ENABLED */
+
+#ifdef HAL_WWDG_MODULE_ENABLED
+ #include "stm32f4xx_hal_wwdg.h"
+#endif /* HAL_WWDG_MODULE_ENABLED */
+
+#ifdef HAL_PCD_MODULE_ENABLED
+ #include "stm32f4xx_hal_pcd.h"
+#endif /* HAL_PCD_MODULE_ENABLED */
+
+#ifdef HAL_HCD_MODULE_ENABLED
+ #include "stm32f4xx_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 /* __STM32F4xx_HAL_CONF_H */
+
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/ports/stm32/boards/PYBV11/mpconfigboard.h b/ports/stm32/boards/PYBV11/mpconfigboard.h
new file mode 100644
index 000000000..c69e52cc5
--- /dev/null
+++ b/ports/stm32/boards/PYBV11/mpconfigboard.h
@@ -0,0 +1,99 @@
+#define MICROPY_HW_BOARD_NAME "PYBv1.1"
+#define MICROPY_HW_MCU_NAME "STM32F405RG"
+
+#define MICROPY_HW_HAS_SWITCH (1)
+#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)
+
+// HSE is 12MHz
+#define MICROPY_HW_CLK_PLLM (12)
+#define MICROPY_HW_CLK_PLLN (336)
+#define MICROPY_HW_CLK_PLLP (RCC_PLLP_DIV2)
+#define MICROPY_HW_CLK_PLLQ (7)
+#define MICROPY_HW_CLK_LAST_FREQ (1)
+
+// The pyboard has a 32kHz crystal for the RTC
+#define MICROPY_HW_RTC_USE_LSE (1)
+#define MICROPY_HW_RTC_USE_US (0)
+#define MICROPY_HW_RTC_USE_CALOUT (1)
+
+// UART config
+#define MICROPY_HW_UART1_NAME "XB"
+#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)
+#define MICROPY_HW_UART2_RTS (pin_A1)
+#define MICROPY_HW_UART2_CTS (pin_A0)
+#define MICROPY_HW_UART3_NAME "YB"
+#define MICROPY_HW_UART3_TX (pin_B10)
+#define MICROPY_HW_UART3_RX (pin_B11)
+#define MICROPY_HW_UART3_RTS (pin_B14)
+#define MICROPY_HW_UART3_CTS (pin_B13)
+#define MICROPY_HW_UART4_NAME "XA"
+#define MICROPY_HW_UART4_TX (pin_A0)
+#define MICROPY_HW_UART4_RX (pin_A1)
+#define MICROPY_HW_UART6_NAME "YA"
+#define MICROPY_HW_UART6_TX (pin_C6)
+#define MICROPY_HW_UART6_RX (pin_C7)
+
+// I2C busses
+#define MICROPY_HW_I2C1_NAME "X"
+#define MICROPY_HW_I2C1_SCL (pin_B6)
+#define MICROPY_HW_I2C1_SDA (pin_B7)
+#define MICROPY_HW_I2C2_NAME "Y"
+#define MICROPY_HW_I2C2_SCL (pin_B10)
+#define MICROPY_HW_I2C2_SDA (pin_B11)
+
+// SPI busses
+#define MICROPY_HW_SPI1_NAME "X"
+#define MICROPY_HW_SPI1_NSS (pin_A4) // X5
+#define MICROPY_HW_SPI1_SCK (pin_A5) // X6
+#define MICROPY_HW_SPI1_MISO (pin_A6) // X7
+#define MICROPY_HW_SPI1_MOSI (pin_A7) // X8
+#define MICROPY_HW_SPI2_NAME "Y"
+#define MICROPY_HW_SPI2_NSS (pin_B12) // Y5
+#define MICROPY_HW_SPI2_SCK (pin_B13) // Y6
+#define MICROPY_HW_SPI2_MISO (pin_B14) // Y7
+#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
+
+// USRSW has no pullup or pulldown, and pressing the switch makes the input go low
+#define MICROPY_HW_USRSW_PIN (pin_B3)
+#define MICROPY_HW_USRSW_PULL (GPIO_PULLUP)
+#define MICROPY_HW_USRSW_EXTI_MODE (GPIO_MODE_IT_FALLING)
+#define MICROPY_HW_USRSW_PRESSED (0)
+
+// The pyboard has 4 LEDs
+#define MICROPY_HW_LED1 (pin_A13) // red
+#define MICROPY_HW_LED2 (pin_A14) // green
+#define MICROPY_HW_LED3 (pin_A15) // yellow
+#define MICROPY_HW_LED4 (pin_B4) // blue
+#define MICROPY_HW_LED3_PWM { TIM2, 2, TIM_CHANNEL_1, GPIO_AF1_TIM2 }
+#define MICROPY_HW_LED4_PWM { TIM3, 3, TIM_CHANNEL_1, GPIO_AF2_TIM3 }
+#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_high(pin))
+#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin))
+
+// SD card detect switch
+#define MICROPY_HW_SDCARD_DETECT_PIN (pin_A8)
+#define MICROPY_HW_SDCARD_DETECT_PULL (GPIO_PULLUP)
+#define MICROPY_HW_SDCARD_DETECT_PRESENT (GPIO_PIN_RESET)
+
+// USB config
+#define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_A9)
+#define MICROPY_HW_USB_OTG_ID_PIN (pin_A10)
+
+// MMA accelerometer config
+#define MICROPY_HW_MMA_AVDD_PIN (pin_B5)
diff --git a/ports/stm32/boards/PYBV11/mpconfigboard.mk b/ports/stm32/boards/PYBV11/mpconfigboard.mk
new file mode 100644
index 000000000..5734c6690
--- /dev/null
+++ b/ports/stm32/boards/PYBV11/mpconfigboard.mk
@@ -0,0 +1,4 @@
+MCU_SERIES = f4
+CMSIS_MCU = STM32F405xx
+AF_FILE = boards/stm32f405_af.csv
+LD_FILE = boards/stm32f405.ld
diff --git a/ports/stm32/boards/PYBV11/pins.csv b/ports/stm32/boards/PYBV11/pins.csv
new file mode 100644
index 000000000..cee80a1aa
--- /dev/null
+++ b/ports/stm32/boards/PYBV11/pins.csv
@@ -0,0 +1,59 @@
+X1,PA0
+X2,PA1
+X3,PA2
+X4,PA3
+X5,PA4
+X6,PA5
+X7,PA6
+X8,PA7
+X9,PB6
+X10,PB7
+X11,PC4
+X12,PC5
+X13,Reset
+X14,GND
+X15,3.3V
+X16,VIN
+X17,PB3
+X18,PC13
+X19,PC0
+X20,PC1
+X21,PC2
+X22,PC3
+X23,A3.3V
+X24,AGND
+Y1,PC6
+Y2,PC7
+Y3,PB8
+Y4,PB9
+Y5,PB12
+Y6,PB13
+Y7,PB14
+Y8,PB15
+Y9,PB10
+Y10,PB11
+Y11,PB0
+Y12,PB1
+Y13,Reset
+Y14,GND
+Y15,3.3V
+Y16,VIN
+SW,PB3
+LED_RED,PA13
+LED_GREEN,PA14
+LED_YELLOW,PA15
+LED_BLUE,PB4
+MMA_INT,PB2
+MMA_AVDD,PB5
+SD_D0,PC8
+SD_D1,PC9
+SD_D2,PC10
+SD_D3,PC11
+SD_CMD,PD2
+SD_CK,PC12
+SD,PA8
+SD_SW,PA8
+USB_VBUS,PA9
+USB_ID,PA10
+USB_DM,PA11
+USB_DP,PA12
diff --git a/ports/stm32/boards/PYBV11/stm32f4xx_hal_conf.h b/ports/stm32/boards/PYBV11/stm32f4xx_hal_conf.h
new file mode 100644
index 000000000..b84b0a892
--- /dev/null
+++ b/ports/stm32/boards/PYBV11/stm32f4xx_hal_conf.h
@@ -0,0 +1,411 @@
+/**
+ ******************************************************************************
+ * @file stm32f4xx_hal_conf.h
+ * @author MCD Application Team
+ * @version V1.1.0
+ * @date 19-June-2014
+ * @brief HAL configuration file.
+ ******************************************************************************
+ * @attention
+ *
+ * <h2><center>&copy; COPYRIGHT(c) 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.
+ *
+ ******************************************************************************
+ */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __STM32F4xx_HAL_CONF_H
+#define __STM32F4xx_HAL_CONF_H
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/* Exported types ------------------------------------------------------------*/
+/* Exported constants --------------------------------------------------------*/
+
+#define USE_USB_FS
+
+/* ########################## 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_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_PCCARD_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_LTDC_MODULE_ENABLED */
+#define HAL_PWR_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_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 */
+
+
+/* ########################## 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)12000000) /*!< Value of the External oscillator in Hz */
+#endif /* HSE_VALUE */
+
+#if !defined (HSE_STARTUP_TIMEOUT)
+ #define HSE_STARTUP_TIMEOUT ((uint32_t)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 ((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)40000)
+#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 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 */
+
+/* ################## 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 0
+#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)4) /* 4 Rx buffers of size ETH_RX_BUF_SIZE */
+#define ETH_TXBUFNB ((uint32_t)4) /* 4 Tx buffers of size ETH_TX_BUF_SIZE */
+
+/* Section 2: PHY configuration section */
+
+/* DP83848 PHY Address*/
+#define DP83848_PHY_ADDRESS 0x01
+/* PHY Reset delay these values are based on a 1 ms Systick interrupt*/
+#define PHY_RESET_DELAY ((uint32_t)0x000000FF)
+/* PHY Configuration delay */
+#define PHY_CONFIG_DELAY ((uint32_t)0x00000FFF)
+
+#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 "stm32f4xx_hal_rcc.h"
+#endif /* HAL_RCC_MODULE_ENABLED */
+
+#ifdef HAL_GPIO_MODULE_ENABLED
+ #include "stm32f4xx_hal_gpio.h"
+#endif /* HAL_GPIO_MODULE_ENABLED */
+
+#ifdef HAL_DMA_MODULE_ENABLED
+ #include "stm32f4xx_hal_dma.h"
+#endif /* HAL_DMA_MODULE_ENABLED */
+
+#ifdef HAL_CORTEX_MODULE_ENABLED
+ #include "stm32f4xx_hal_cortex.h"
+#endif /* HAL_CORTEX_MODULE_ENABLED */
+
+#ifdef HAL_ADC_MODULE_ENABLED
+ #include "stm32f4xx_hal_adc.h"
+#endif /* HAL_ADC_MODULE_ENABLED */
+
+#ifdef HAL_CAN_MODULE_ENABLED
+ #include "stm32f4xx_hal_can.h"
+#endif /* HAL_CAN_MODULE_ENABLED */
+
+#ifdef HAL_CRC_MODULE_ENABLED
+ #include "stm32f4xx_hal_crc.h"
+#endif /* HAL_CRC_MODULE_ENABLED */
+
+#ifdef HAL_CRYP_MODULE_ENABLED
+ #include "stm32f4xx_hal_cryp.h"
+#endif /* HAL_CRYP_MODULE_ENABLED */
+
+#ifdef HAL_DMA2D_MODULE_ENABLED
+ #include "stm32f4xx_hal_dma2d.h"
+#endif /* HAL_DMA2D_MODULE_ENABLED */
+
+#ifdef HAL_DAC_MODULE_ENABLED
+ #include "stm32f4xx_hal_dac.h"
+#endif /* HAL_DAC_MODULE_ENABLED */
+
+#ifdef HAL_DCMI_MODULE_ENABLED
+ #include "stm32f4xx_hal_dcmi.h"
+#endif /* HAL_DCMI_MODULE_ENABLED */
+
+#ifdef HAL_ETH_MODULE_ENABLED
+ #include "stm32f4xx_hal_eth.h"
+#endif /* HAL_ETH_MODULE_ENABLED */
+
+#ifdef HAL_FLASH_MODULE_ENABLED
+ #include "stm32f4xx_hal_flash.h"
+#endif /* HAL_FLASH_MODULE_ENABLED */
+
+#ifdef HAL_SRAM_MODULE_ENABLED
+ #include "stm32f4xx_hal_sram.h"
+#endif /* HAL_SRAM_MODULE_ENABLED */
+
+#ifdef HAL_NOR_MODULE_ENABLED
+ #include "stm32f4xx_hal_nor.h"
+#endif /* HAL_NOR_MODULE_ENABLED */
+
+#ifdef HAL_NAND_MODULE_ENABLED
+ #include "stm32f4xx_hal_nand.h"
+#endif /* HAL_NAND_MODULE_ENABLED */
+
+#ifdef HAL_PCCARD_MODULE_ENABLED
+ #include "stm32f4xx_hal_pccard.h"
+#endif /* HAL_PCCARD_MODULE_ENABLED */
+
+#ifdef HAL_SDRAM_MODULE_ENABLED
+ #include "stm32f4xx_hal_sdram.h"
+#endif /* HAL_SDRAM_MODULE_ENABLED */
+
+#ifdef HAL_HASH_MODULE_ENABLED
+ #include "stm32f4xx_hal_hash.h"
+#endif /* HAL_HASH_MODULE_ENABLED */
+
+#ifdef HAL_I2C_MODULE_ENABLED
+ #include "stm32f4xx_hal_i2c.h"
+#endif /* HAL_I2C_MODULE_ENABLED */
+
+#ifdef HAL_I2S_MODULE_ENABLED
+ #include "stm32f4xx_hal_i2s.h"
+#endif /* HAL_I2S_MODULE_ENABLED */
+
+#ifdef HAL_IWDG_MODULE_ENABLED
+ #include "stm32f4xx_hal_iwdg.h"
+#endif /* HAL_IWDG_MODULE_ENABLED */
+
+#ifdef HAL_LTDC_MODULE_ENABLED
+ #include "stm32f4xx_hal_ltdc.h"
+#endif /* HAL_LTDC_MODULE_ENABLED */
+
+#ifdef HAL_PWR_MODULE_ENABLED
+ #include "stm32f4xx_hal_pwr.h"
+#endif /* HAL_PWR_MODULE_ENABLED */
+
+#ifdef HAL_RNG_MODULE_ENABLED
+ #include "stm32f4xx_hal_rng.h"
+#endif /* HAL_RNG_MODULE_ENABLED */
+
+#ifdef HAL_RTC_MODULE_ENABLED
+ #include "stm32f4xx_hal_rtc.h"
+#endif /* HAL_RTC_MODULE_ENABLED */
+
+#ifdef HAL_SAI_MODULE_ENABLED
+ #include "stm32f4xx_hal_sai.h"
+#endif /* HAL_SAI_MODULE_ENABLED */
+
+#ifdef HAL_SD_MODULE_ENABLED
+ #include "stm32f4xx_hal_sd.h"
+#endif /* HAL_SD_MODULE_ENABLED */
+
+#ifdef HAL_SPI_MODULE_ENABLED
+ #include "stm32f4xx_hal_spi.h"
+#endif /* HAL_SPI_MODULE_ENABLED */
+
+#ifdef HAL_TIM_MODULE_ENABLED
+ #include "stm32f4xx_hal_tim.h"
+#endif /* HAL_TIM_MODULE_ENABLED */
+
+#ifdef HAL_UART_MODULE_ENABLED
+ #include "stm32f4xx_hal_uart.h"
+#endif /* HAL_UART_MODULE_ENABLED */
+
+#ifdef HAL_USART_MODULE_ENABLED
+ #include "stm32f4xx_hal_usart.h"
+#endif /* HAL_USART_MODULE_ENABLED */
+
+#ifdef HAL_IRDA_MODULE_ENABLED
+ #include "stm32f4xx_hal_irda.h"
+#endif /* HAL_IRDA_MODULE_ENABLED */
+
+#ifdef HAL_SMARTCARD_MODULE_ENABLED
+ #include "stm32f4xx_hal_smartcard.h"
+#endif /* HAL_SMARTCARD_MODULE_ENABLED */
+
+#ifdef HAL_WWDG_MODULE_ENABLED
+ #include "stm32f4xx_hal_wwdg.h"
+#endif /* HAL_WWDG_MODULE_ENABLED */
+
+#ifdef HAL_PCD_MODULE_ENABLED
+ #include "stm32f4xx_hal_pcd.h"
+#endif /* HAL_PCD_MODULE_ENABLED */
+
+#ifdef HAL_HCD_MODULE_ENABLED
+ #include "stm32f4xx_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 /* __STM32F4xx_HAL_CONF_H */
+
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/ports/stm32/boards/PYBV3/mpconfigboard.h b/ports/stm32/boards/PYBV3/mpconfigboard.h
new file mode 100644
index 000000000..1f49af4da
--- /dev/null
+++ b/ports/stm32/boards/PYBV3/mpconfigboard.h
@@ -0,0 +1,88 @@
+#define MICROPY_HW_BOARD_NAME "PYBv3"
+#define MICROPY_HW_MCU_NAME "STM32F405RG"
+
+#define MICROPY_HW_HAS_SWITCH (1)
+#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)
+
+// HSE is 8MHz
+#define MICROPY_HW_CLK_PLLM (8)
+#define MICROPY_HW_CLK_PLLN (336)
+#define MICROPY_HW_CLK_PLLP (RCC_PLLP_DIV2)
+#define MICROPY_HW_CLK_PLLQ (7)
+
+// The pyboard has a 32kHz crystal for the RTC
+#define MICROPY_HW_RTC_USE_LSE (1)
+
+// UART config
+#define MICROPY_HW_UART1_TX (pin_A9)
+#define MICROPY_HW_UART1_RX (pin_A10)
+#define MICROPY_HW_UART2_TX (pin_A2)
+#define MICROPY_HW_UART2_RX (pin_A3)
+#define MICROPY_HW_UART2_RTS (pin_A1)
+#define MICROPY_HW_UART2_CTS (pin_A0)
+#define MICROPY_HW_UART3_TX (pin_B10)
+#define MICROPY_HW_UART3_RX (pin_B11)
+#define MICROPY_HW_UART3_RTS (pin_B14)
+#define MICROPY_HW_UART3_CTS (pin_B13)
+#define MICROPY_HW_UART4_TX (pin_A0)
+#define MICROPY_HW_UART4_RX (pin_A1)
+#define MICROPY_HW_UART6_TX (pin_C6)
+#define MICROPY_HW_UART6_RX (pin_C7)
+
+// X-skin: X9=PB6=SCL, X10=PB7=SDA
+#define MICROPY_HW_I2C1_SCL (pin_B6)
+#define MICROPY_HW_I2C1_SDA (pin_B7)
+
+// Y-skin: Y9=PB10=SCL, Y10=PB11=SDA
+#define MICROPY_HW_I2C2_SCL (pin_B10)
+#define MICROPY_HW_I2C2_SDA (pin_B11)
+
+// SPI busses
+#define MICROPY_HW_SPI1_NAME "X"
+#define MICROPY_HW_SPI1_NSS (pin_A4) // X5
+#define MICROPY_HW_SPI1_SCK (pin_A5) // X6
+#define MICROPY_HW_SPI1_MISO (pin_A6) // X7
+#define MICROPY_HW_SPI1_MOSI (pin_A7) // X8
+#define MICROPY_HW_SPI2_NAME "Y"
+#define MICROPY_HW_SPI2_NSS (pin_B12) // Y5
+#define MICROPY_HW_SPI2_SCK (pin_B13) // Y6
+#define MICROPY_HW_SPI2_MISO (pin_B14) // Y7
+#define MICROPY_HW_SPI2_MOSI (pin_B15) // Y8
+
+// 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)
+#define MICROPY_HW_USRSW_EXTI_MODE (GPIO_MODE_IT_FALLING)
+#define MICROPY_HW_USRSW_PRESSED (0)
+
+// LEDs
+#define MICROPY_HW_LED_INVERTED (1) // LEDs are on when pin is driven low
+#define MICROPY_HW_LED1 (pin_A8) // R1 - red
+#define MICROPY_HW_LED2 (pin_A10) // R2 - red
+#define MICROPY_HW_LED3 (pin_C4) // G1 - green
+#define MICROPY_HW_LED4 (pin_C5) // G2 - green
+#define MICROPY_HW_LED1_PWM { TIM1, 1, TIM_CHANNEL_1, GPIO_AF1_TIM1 }
+#define MICROPY_HW_LED2_PWM { TIM1, 1, TIM_CHANNEL_3, GPIO_AF1_TIM1 }
+#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_low(pin))
+#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_high(pin))
+
+// SD card detect switch
+#define MICROPY_HW_SDCARD_DETECT_PIN (pin_C13)
+#define MICROPY_HW_SDCARD_DETECT_PULL (GPIO_PULLDOWN)
+#define MICROPY_HW_SDCARD_DETECT_PRESENT (GPIO_PIN_SET)
+
+// USB VBUS detect pin
+#define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_A9)
+
+// MMA accelerometer config
+#define MICROPY_HW_MMA_AVDD_PIN (pin_B5)
diff --git a/ports/stm32/boards/PYBV3/mpconfigboard.mk b/ports/stm32/boards/PYBV3/mpconfigboard.mk
new file mode 100644
index 000000000..5734c6690
--- /dev/null
+++ b/ports/stm32/boards/PYBV3/mpconfigboard.mk
@@ -0,0 +1,4 @@
+MCU_SERIES = f4
+CMSIS_MCU = STM32F405xx
+AF_FILE = boards/stm32f405_af.csv
+LD_FILE = boards/stm32f405.ld
diff --git a/ports/stm32/boards/PYBV3/pins.csv b/ports/stm32/boards/PYBV3/pins.csv
new file mode 100644
index 000000000..b20bd4ffb
--- /dev/null
+++ b/ports/stm32/boards/PYBV3/pins.csv
@@ -0,0 +1,46 @@
+B13,PB13
+B14,PB14
+B15,PB15
+C6,PC6
+C7,PC7
+A13,PA13
+A14,PA14
+A15,PA15
+B3,PB3
+B4,PB4
+B6,PB6
+B7,PB7
+B8,PB8
+B9,PB9
+C0,PC0
+C1,PC1
+C2,PC2
+C3,PC3
+A0,PA0
+A1,PA1
+A2,PA2
+A3,PA3
+A4,PA4
+A5,PA5
+A6,PA6
+A7,PA7
+B0,PB0
+B1,PB1
+B10,PB10
+B11,PB11
+B12,PB12
+LED_R1,PA8
+LED_R2,PA10
+LED_G1,PC4
+LED_G2,PC5
+SW,PA13
+SD,PC13
+MMA_INT,PB2
+MMA_AVDD,PB5
+SD_D0,PC8
+SD_D1,PC9
+SD_D2,PC10
+SD_D3,PC11
+SD_CK,PC12
+SD_CMD,PD2
+UART1_TX,PA9
diff --git a/ports/stm32/boards/PYBV3/stm32f4xx_hal_conf.h b/ports/stm32/boards/PYBV3/stm32f4xx_hal_conf.h
new file mode 100644
index 000000000..8941e8290
--- /dev/null
+++ b/ports/stm32/boards/PYBV3/stm32f4xx_hal_conf.h
@@ -0,0 +1,411 @@
+/**
+ ******************************************************************************
+ * @file stm32f4xx_hal_conf.h
+ * @author MCD Application Team
+ * @version V1.1.0
+ * @date 19-June-2014
+ * @brief HAL configuration file.
+ ******************************************************************************
+ * @attention
+ *
+ * <h2><center>&copy; COPYRIGHT(c) 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.
+ *
+ ******************************************************************************
+ */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __STM32F4xx_HAL_CONF_H
+#define __STM32F4xx_HAL_CONF_H
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/* Exported types ------------------------------------------------------------*/
+/* Exported constants --------------------------------------------------------*/
+
+#define USE_USB_FS
+
+/* ########################## 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_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_PCCARD_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_LTDC_MODULE_ENABLED */
+#define HAL_PWR_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_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 */
+
+
+/* ########################## 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)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 ((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)40000)
+#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 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 */
+
+/* ################## 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 0
+#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)4) /* 4 Rx buffers of size ETH_RX_BUF_SIZE */
+#define ETH_TXBUFNB ((uint32_t)4) /* 4 Tx buffers of size ETH_TX_BUF_SIZE */
+
+/* Section 2: PHY configuration section */
+
+/* DP83848 PHY Address*/
+#define DP83848_PHY_ADDRESS 0x01
+/* PHY Reset delay these values are based on a 1 ms Systick interrupt*/
+#define PHY_RESET_DELAY ((uint32_t)0x000000FF)
+/* PHY Configuration delay */
+#define PHY_CONFIG_DELAY ((uint32_t)0x00000FFF)
+
+#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 "stm32f4xx_hal_rcc.h"
+#endif /* HAL_RCC_MODULE_ENABLED */
+
+#ifdef HAL_GPIO_MODULE_ENABLED
+ #include "stm32f4xx_hal_gpio.h"
+#endif /* HAL_GPIO_MODULE_ENABLED */
+
+#ifdef HAL_DMA_MODULE_ENABLED
+ #include "stm32f4xx_hal_dma.h"
+#endif /* HAL_DMA_MODULE_ENABLED */
+
+#ifdef HAL_CORTEX_MODULE_ENABLED
+ #include "stm32f4xx_hal_cortex.h"
+#endif /* HAL_CORTEX_MODULE_ENABLED */
+
+#ifdef HAL_ADC_MODULE_ENABLED
+ #include "stm32f4xx_hal_adc.h"
+#endif /* HAL_ADC_MODULE_ENABLED */
+
+#ifdef HAL_CAN_MODULE_ENABLED
+ #include "stm32f4xx_hal_can.h"
+#endif /* HAL_CAN_MODULE_ENABLED */
+
+#ifdef HAL_CRC_MODULE_ENABLED
+ #include "stm32f4xx_hal_crc.h"
+#endif /* HAL_CRC_MODULE_ENABLED */
+
+#ifdef HAL_CRYP_MODULE_ENABLED
+ #include "stm32f4xx_hal_cryp.h"
+#endif /* HAL_CRYP_MODULE_ENABLED */
+
+#ifdef HAL_DMA2D_MODULE_ENABLED
+ #include "stm32f4xx_hal_dma2d.h"
+#endif /* HAL_DMA2D_MODULE_ENABLED */
+
+#ifdef HAL_DAC_MODULE_ENABLED
+ #include "stm32f4xx_hal_dac.h"
+#endif /* HAL_DAC_MODULE_ENABLED */
+
+#ifdef HAL_DCMI_MODULE_ENABLED
+ #include "stm32f4xx_hal_dcmi.h"
+#endif /* HAL_DCMI_MODULE_ENABLED */
+
+#ifdef HAL_ETH_MODULE_ENABLED
+ #include "stm32f4xx_hal_eth.h"
+#endif /* HAL_ETH_MODULE_ENABLED */
+
+#ifdef HAL_FLASH_MODULE_ENABLED
+ #include "stm32f4xx_hal_flash.h"
+#endif /* HAL_FLASH_MODULE_ENABLED */
+
+#ifdef HAL_SRAM_MODULE_ENABLED
+ #include "stm32f4xx_hal_sram.h"
+#endif /* HAL_SRAM_MODULE_ENABLED */
+
+#ifdef HAL_NOR_MODULE_ENABLED
+ #include "stm32f4xx_hal_nor.h"
+#endif /* HAL_NOR_MODULE_ENABLED */
+
+#ifdef HAL_NAND_MODULE_ENABLED
+ #include "stm32f4xx_hal_nand.h"
+#endif /* HAL_NAND_MODULE_ENABLED */
+
+#ifdef HAL_PCCARD_MODULE_ENABLED
+ #include "stm32f4xx_hal_pccard.h"
+#endif /* HAL_PCCARD_MODULE_ENABLED */
+
+#ifdef HAL_SDRAM_MODULE_ENABLED
+ #include "stm32f4xx_hal_sdram.h"
+#endif /* HAL_SDRAM_MODULE_ENABLED */
+
+#ifdef HAL_HASH_MODULE_ENABLED
+ #include "stm32f4xx_hal_hash.h"
+#endif /* HAL_HASH_MODULE_ENABLED */
+
+#ifdef HAL_I2C_MODULE_ENABLED
+ #include "stm32f4xx_hal_i2c.h"
+#endif /* HAL_I2C_MODULE_ENABLED */
+
+#ifdef HAL_I2S_MODULE_ENABLED
+ #include "stm32f4xx_hal_i2s.h"
+#endif /* HAL_I2S_MODULE_ENABLED */
+
+#ifdef HAL_IWDG_MODULE_ENABLED
+ #include "stm32f4xx_hal_iwdg.h"
+#endif /* HAL_IWDG_MODULE_ENABLED */
+
+#ifdef HAL_LTDC_MODULE_ENABLED
+ #include "stm32f4xx_hal_ltdc.h"
+#endif /* HAL_LTDC_MODULE_ENABLED */
+
+#ifdef HAL_PWR_MODULE_ENABLED
+ #include "stm32f4xx_hal_pwr.h"
+#endif /* HAL_PWR_MODULE_ENABLED */
+
+#ifdef HAL_RNG_MODULE_ENABLED
+ #include "stm32f4xx_hal_rng.h"
+#endif /* HAL_RNG_MODULE_ENABLED */
+
+#ifdef HAL_RTC_MODULE_ENABLED
+ #include "stm32f4xx_hal_rtc.h"
+#endif /* HAL_RTC_MODULE_ENABLED */
+
+#ifdef HAL_SAI_MODULE_ENABLED
+ #include "stm32f4xx_hal_sai.h"
+#endif /* HAL_SAI_MODULE_ENABLED */
+
+#ifdef HAL_SD_MODULE_ENABLED
+ #include "stm32f4xx_hal_sd.h"
+#endif /* HAL_SD_MODULE_ENABLED */
+
+#ifdef HAL_SPI_MODULE_ENABLED
+ #include "stm32f4xx_hal_spi.h"
+#endif /* HAL_SPI_MODULE_ENABLED */
+
+#ifdef HAL_TIM_MODULE_ENABLED
+ #include "stm32f4xx_hal_tim.h"
+#endif /* HAL_TIM_MODULE_ENABLED */
+
+#ifdef HAL_UART_MODULE_ENABLED
+ #include "stm32f4xx_hal_uart.h"
+#endif /* HAL_UART_MODULE_ENABLED */
+
+#ifdef HAL_USART_MODULE_ENABLED
+ #include "stm32f4xx_hal_usart.h"
+#endif /* HAL_USART_MODULE_ENABLED */
+
+#ifdef HAL_IRDA_MODULE_ENABLED
+ #include "stm32f4xx_hal_irda.h"
+#endif /* HAL_IRDA_MODULE_ENABLED */
+
+#ifdef HAL_SMARTCARD_MODULE_ENABLED
+ #include "stm32f4xx_hal_smartcard.h"
+#endif /* HAL_SMARTCARD_MODULE_ENABLED */
+
+#ifdef HAL_WWDG_MODULE_ENABLED
+ #include "stm32f4xx_hal_wwdg.h"
+#endif /* HAL_WWDG_MODULE_ENABLED */
+
+#ifdef HAL_PCD_MODULE_ENABLED
+ #include "stm32f4xx_hal_pcd.h"
+#endif /* HAL_PCD_MODULE_ENABLED */
+
+#ifdef HAL_HCD_MODULE_ENABLED
+ #include "stm32f4xx_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 /* __STM32F4xx_HAL_CONF_H */
+
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/ports/stm32/boards/PYBV4/mpconfigboard.h b/ports/stm32/boards/PYBV4/mpconfigboard.h
new file mode 100644
index 000000000..2a4829c3e
--- /dev/null
+++ b/ports/stm32/boards/PYBV4/mpconfigboard.h
@@ -0,0 +1,96 @@
+#define MICROPY_HW_BOARD_NAME "PYBv4"
+#define MICROPY_HW_MCU_NAME "STM32F405RG"
+
+#define MICROPY_HW_HAS_SWITCH (1)
+#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)
+
+// HSE is 8MHz
+#define MICROPY_HW_CLK_PLLM (8)
+#define MICROPY_HW_CLK_PLLN (336)
+#define MICROPY_HW_CLK_PLLP (RCC_PLLP_DIV2)
+#define MICROPY_HW_CLK_PLLQ (7)
+
+// The pyboard has a 32kHz crystal for the RTC
+#define MICROPY_HW_RTC_USE_LSE (1)
+
+// UART config
+#define MICROPY_HW_UART1_NAME "XB"
+#define MICROPY_HW_UART1_PORT (GPIOB)
+#define MICROPY_HW_UART1_PINS (GPIO_PIN_6 | GPIO_PIN_7)
+#define MICROPY_HW_UART2_PORT (GPIOA)
+#define MICROPY_HW_UART2_PINS (GPIO_PIN_2 | GPIO_PIN_3)
+#define MICROPY_HW_UART2_RTS (GPIO_PIN_1)
+#define MICROPY_HW_UART2_CTS (GPIO_PIN_0)
+#define MICROPY_HW_UART3_NAME "YB"
+#define MICROPY_HW_UART3_PORT (GPIOB)
+#define MICROPY_HW_UART3_PINS (GPIO_PIN_10 | GPIO_PIN_11)
+#define MICROPY_HW_UART3_RTS (GPIO_PIN_14)
+#define MICROPY_HW_UART3_CTS (GPIO_PIN_13)
+#define MICROPY_HW_UART4_NAME "XA"
+#define MICROPY_HW_UART4_PORT (GPIOA)
+#define MICROPY_HW_UART4_PINS (GPIO_PIN_0 | GPIO_PIN_1)
+#define MICROPY_HW_UART6_NAME "YA"
+#define MICROPY_HW_UART6_PORT (GPIOC)
+#define MICROPY_HW_UART6_PINS (GPIO_PIN_6 | GPIO_PIN_7)
+
+// I2C busses
+#define MICROPY_HW_I2C1_NAME "X"
+#define MICROPY_HW_I2C1_SCL (pin_B6)
+#define MICROPY_HW_I2C1_SDA (pin_B7)
+#define MICROPY_HW_I2C2_NAME "Y"
+#define MICROPY_HW_I2C2_SCL (pin_B10)
+#define MICROPY_HW_I2C2_SDA (pin_B11)
+
+// SPI busses
+#define MICROPY_HW_SPI1_NAME "X"
+#define MICROPY_HW_SPI1_NSS (pin_A4) // X5
+#define MICROPY_HW_SPI1_SCK (pin_A5) // X6
+#define MICROPY_HW_SPI1_MISO (pin_A6) // X7
+#define MICROPY_HW_SPI1_MOSI (pin_A7) // X8
+#define MICROPY_HW_SPI2_NAME "Y"
+#define MICROPY_HW_SPI2_NSS (pin_B12) // Y5
+#define MICROPY_HW_SPI2_SCK (pin_B13) // Y6
+#define MICROPY_HW_SPI2_MISO (pin_B14) // Y7
+#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
+
+// USRSW has no pullup or pulldown, and pressing the switch makes the input go low
+#define MICROPY_HW_USRSW_PIN (pin_B3)
+#define MICROPY_HW_USRSW_PULL (GPIO_PULLUP)
+#define MICROPY_HW_USRSW_EXTI_MODE (GPIO_MODE_IT_FALLING)
+#define MICROPY_HW_USRSW_PRESSED (0)
+
+// The pyboard has 4 LEDs
+#define MICROPY_HW_LED1 (pin_A13) // red
+#define MICROPY_HW_LED2 (pin_A14) // green
+#define MICROPY_HW_LED3 (pin_A15) // yellow
+#define MICROPY_HW_LED4 (pin_B4) // blue
+#define MICROPY_HW_LED3_PWM { TIM2, 2, TIM_CHANNEL_1, GPIO_AF1_TIM2 }
+#define MICROPY_HW_LED4_PWM { TIM3, 3, TIM_CHANNEL_1, GPIO_AF2_TIM3 }
+#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_high(pin))
+#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin))
+
+// SD card detect switch
+#define MICROPY_HW_SDCARD_DETECT_PIN (pin_A8)
+#define MICROPY_HW_SDCARD_DETECT_PULL (GPIO_PULLUP)
+#define MICROPY_HW_SDCARD_DETECT_PRESENT (GPIO_PIN_RESET)
+
+// USB config
+#define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_A9)
+#define MICROPY_HW_USB_OTG_ID_PIN (pin_A10)
+
+// MMA accelerometer config
+#define MICROPY_HW_MMA_AVDD_PIN (pin_B5)
diff --git a/ports/stm32/boards/PYBV4/mpconfigboard.mk b/ports/stm32/boards/PYBV4/mpconfigboard.mk
new file mode 100644
index 000000000..5734c6690
--- /dev/null
+++ b/ports/stm32/boards/PYBV4/mpconfigboard.mk
@@ -0,0 +1,4 @@
+MCU_SERIES = f4
+CMSIS_MCU = STM32F405xx
+AF_FILE = boards/stm32f405_af.csv
+LD_FILE = boards/stm32f405.ld
diff --git a/ports/stm32/boards/PYBV4/pins.csv b/ports/stm32/boards/PYBV4/pins.csv
new file mode 100644
index 000000000..cee80a1aa
--- /dev/null
+++ b/ports/stm32/boards/PYBV4/pins.csv
@@ -0,0 +1,59 @@
+X1,PA0
+X2,PA1
+X3,PA2
+X4,PA3
+X5,PA4
+X6,PA5
+X7,PA6
+X8,PA7
+X9,PB6
+X10,PB7
+X11,PC4
+X12,PC5
+X13,Reset
+X14,GND
+X15,3.3V
+X16,VIN
+X17,PB3
+X18,PC13
+X19,PC0
+X20,PC1
+X21,PC2
+X22,PC3
+X23,A3.3V
+X24,AGND
+Y1,PC6
+Y2,PC7
+Y3,PB8
+Y4,PB9
+Y5,PB12
+Y6,PB13
+Y7,PB14
+Y8,PB15
+Y9,PB10
+Y10,PB11
+Y11,PB0
+Y12,PB1
+Y13,Reset
+Y14,GND
+Y15,3.3V
+Y16,VIN
+SW,PB3
+LED_RED,PA13
+LED_GREEN,PA14
+LED_YELLOW,PA15
+LED_BLUE,PB4
+MMA_INT,PB2
+MMA_AVDD,PB5
+SD_D0,PC8
+SD_D1,PC9
+SD_D2,PC10
+SD_D3,PC11
+SD_CMD,PD2
+SD_CK,PC12
+SD,PA8
+SD_SW,PA8
+USB_VBUS,PA9
+USB_ID,PA10
+USB_DM,PA11
+USB_DP,PA12
diff --git a/ports/stm32/boards/PYBV4/stm32f4xx_hal_conf.h b/ports/stm32/boards/PYBV4/stm32f4xx_hal_conf.h
new file mode 100644
index 000000000..8941e8290
--- /dev/null
+++ b/ports/stm32/boards/PYBV4/stm32f4xx_hal_conf.h
@@ -0,0 +1,411 @@
+/**
+ ******************************************************************************
+ * @file stm32f4xx_hal_conf.h
+ * @author MCD Application Team
+ * @version V1.1.0
+ * @date 19-June-2014
+ * @brief HAL configuration file.
+ ******************************************************************************
+ * @attention
+ *
+ * <h2><center>&copy; COPYRIGHT(c) 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.
+ *
+ ******************************************************************************
+ */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __STM32F4xx_HAL_CONF_H
+#define __STM32F4xx_HAL_CONF_H
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/* Exported types ------------------------------------------------------------*/
+/* Exported constants --------------------------------------------------------*/
+
+#define USE_USB_FS
+
+/* ########################## 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_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_PCCARD_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_LTDC_MODULE_ENABLED */
+#define HAL_PWR_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_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 */
+
+
+/* ########################## 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)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 ((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)40000)
+#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 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 */
+
+/* ################## 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 0
+#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)4) /* 4 Rx buffers of size ETH_RX_BUF_SIZE */
+#define ETH_TXBUFNB ((uint32_t)4) /* 4 Tx buffers of size ETH_TX_BUF_SIZE */
+
+/* Section 2: PHY configuration section */
+
+/* DP83848 PHY Address*/
+#define DP83848_PHY_ADDRESS 0x01
+/* PHY Reset delay these values are based on a 1 ms Systick interrupt*/
+#define PHY_RESET_DELAY ((uint32_t)0x000000FF)
+/* PHY Configuration delay */
+#define PHY_CONFIG_DELAY ((uint32_t)0x00000FFF)
+
+#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 "stm32f4xx_hal_rcc.h"
+#endif /* HAL_RCC_MODULE_ENABLED */
+
+#ifdef HAL_GPIO_MODULE_ENABLED
+ #include "stm32f4xx_hal_gpio.h"
+#endif /* HAL_GPIO_MODULE_ENABLED */
+
+#ifdef HAL_DMA_MODULE_ENABLED
+ #include "stm32f4xx_hal_dma.h"
+#endif /* HAL_DMA_MODULE_ENABLED */
+
+#ifdef HAL_CORTEX_MODULE_ENABLED
+ #include "stm32f4xx_hal_cortex.h"
+#endif /* HAL_CORTEX_MODULE_ENABLED */
+
+#ifdef HAL_ADC_MODULE_ENABLED
+ #include "stm32f4xx_hal_adc.h"
+#endif /* HAL_ADC_MODULE_ENABLED */
+
+#ifdef HAL_CAN_MODULE_ENABLED
+ #include "stm32f4xx_hal_can.h"
+#endif /* HAL_CAN_MODULE_ENABLED */
+
+#ifdef HAL_CRC_MODULE_ENABLED
+ #include "stm32f4xx_hal_crc.h"
+#endif /* HAL_CRC_MODULE_ENABLED */
+
+#ifdef HAL_CRYP_MODULE_ENABLED
+ #include "stm32f4xx_hal_cryp.h"
+#endif /* HAL_CRYP_MODULE_ENABLED */
+
+#ifdef HAL_DMA2D_MODULE_ENABLED
+ #include "stm32f4xx_hal_dma2d.h"
+#endif /* HAL_DMA2D_MODULE_ENABLED */
+
+#ifdef HAL_DAC_MODULE_ENABLED
+ #include "stm32f4xx_hal_dac.h"
+#endif /* HAL_DAC_MODULE_ENABLED */
+
+#ifdef HAL_DCMI_MODULE_ENABLED
+ #include "stm32f4xx_hal_dcmi.h"
+#endif /* HAL_DCMI_MODULE_ENABLED */
+
+#ifdef HAL_ETH_MODULE_ENABLED
+ #include "stm32f4xx_hal_eth.h"
+#endif /* HAL_ETH_MODULE_ENABLED */
+
+#ifdef HAL_FLASH_MODULE_ENABLED
+ #include "stm32f4xx_hal_flash.h"
+#endif /* HAL_FLASH_MODULE_ENABLED */
+
+#ifdef HAL_SRAM_MODULE_ENABLED
+ #include "stm32f4xx_hal_sram.h"
+#endif /* HAL_SRAM_MODULE_ENABLED */
+
+#ifdef HAL_NOR_MODULE_ENABLED
+ #include "stm32f4xx_hal_nor.h"
+#endif /* HAL_NOR_MODULE_ENABLED */
+
+#ifdef HAL_NAND_MODULE_ENABLED
+ #include "stm32f4xx_hal_nand.h"
+#endif /* HAL_NAND_MODULE_ENABLED */
+
+#ifdef HAL_PCCARD_MODULE_ENABLED
+ #include "stm32f4xx_hal_pccard.h"
+#endif /* HAL_PCCARD_MODULE_ENABLED */
+
+#ifdef HAL_SDRAM_MODULE_ENABLED
+ #include "stm32f4xx_hal_sdram.h"
+#endif /* HAL_SDRAM_MODULE_ENABLED */
+
+#ifdef HAL_HASH_MODULE_ENABLED
+ #include "stm32f4xx_hal_hash.h"
+#endif /* HAL_HASH_MODULE_ENABLED */
+
+#ifdef HAL_I2C_MODULE_ENABLED
+ #include "stm32f4xx_hal_i2c.h"
+#endif /* HAL_I2C_MODULE_ENABLED */
+
+#ifdef HAL_I2S_MODULE_ENABLED
+ #include "stm32f4xx_hal_i2s.h"
+#endif /* HAL_I2S_MODULE_ENABLED */
+
+#ifdef HAL_IWDG_MODULE_ENABLED
+ #include "stm32f4xx_hal_iwdg.h"
+#endif /* HAL_IWDG_MODULE_ENABLED */
+
+#ifdef HAL_LTDC_MODULE_ENABLED
+ #include "stm32f4xx_hal_ltdc.h"
+#endif /* HAL_LTDC_MODULE_ENABLED */
+
+#ifdef HAL_PWR_MODULE_ENABLED
+ #include "stm32f4xx_hal_pwr.h"
+#endif /* HAL_PWR_MODULE_ENABLED */
+
+#ifdef HAL_RNG_MODULE_ENABLED
+ #include "stm32f4xx_hal_rng.h"
+#endif /* HAL_RNG_MODULE_ENABLED */
+
+#ifdef HAL_RTC_MODULE_ENABLED
+ #include "stm32f4xx_hal_rtc.h"
+#endif /* HAL_RTC_MODULE_ENABLED */
+
+#ifdef HAL_SAI_MODULE_ENABLED
+ #include "stm32f4xx_hal_sai.h"
+#endif /* HAL_SAI_MODULE_ENABLED */
+
+#ifdef HAL_SD_MODULE_ENABLED
+ #include "stm32f4xx_hal_sd.h"
+#endif /* HAL_SD_MODULE_ENABLED */
+
+#ifdef HAL_SPI_MODULE_ENABLED
+ #include "stm32f4xx_hal_spi.h"
+#endif /* HAL_SPI_MODULE_ENABLED */
+
+#ifdef HAL_TIM_MODULE_ENABLED
+ #include "stm32f4xx_hal_tim.h"
+#endif /* HAL_TIM_MODULE_ENABLED */
+
+#ifdef HAL_UART_MODULE_ENABLED
+ #include "stm32f4xx_hal_uart.h"
+#endif /* HAL_UART_MODULE_ENABLED */
+
+#ifdef HAL_USART_MODULE_ENABLED
+ #include "stm32f4xx_hal_usart.h"
+#endif /* HAL_USART_MODULE_ENABLED */
+
+#ifdef HAL_IRDA_MODULE_ENABLED
+ #include "stm32f4xx_hal_irda.h"
+#endif /* HAL_IRDA_MODULE_ENABLED */
+
+#ifdef HAL_SMARTCARD_MODULE_ENABLED
+ #include "stm32f4xx_hal_smartcard.h"
+#endif /* HAL_SMARTCARD_MODULE_ENABLED */
+
+#ifdef HAL_WWDG_MODULE_ENABLED
+ #include "stm32f4xx_hal_wwdg.h"
+#endif /* HAL_WWDG_MODULE_ENABLED */
+
+#ifdef HAL_PCD_MODULE_ENABLED
+ #include "stm32f4xx_hal_pcd.h"
+#endif /* HAL_PCD_MODULE_ENABLED */
+
+#ifdef HAL_HCD_MODULE_ENABLED
+ #include "stm32f4xx_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 /* __STM32F4xx_HAL_CONF_H */
+
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/ports/stm32/boards/STM32F411DISC/mpconfigboard.h b/ports/stm32/boards/STM32F411DISC/mpconfigboard.h
new file mode 100644
index 000000000..1488cd764
--- /dev/null
+++ b/ports/stm32/boards/STM32F411DISC/mpconfigboard.h
@@ -0,0 +1,70 @@
+#define MICROPY_HW_BOARD_NAME "F411DISC"
+#define MICROPY_HW_MCU_NAME "STM32F411"
+
+#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_SERVO (1)
+#define MICROPY_HW_ENABLE_DAC (0)
+#define MICROPY_HW_ENABLE_CAN (0)
+
+// HSE is 8MHz
+#define MICROPY_HW_CLK_PLLM (5)
+#define MICROPY_HW_CLK_PLLN (210)
+#define MICROPY_HW_CLK_PLLP (RCC_PLLP_DIV4)
+#define MICROPY_HW_CLK_PLLQ (7)
+
+// does not have a 32kHz crystal
+#define MICROPY_HW_RTC_USE_LSE (0)
+
+// UART config
+#define MICROPY_HW_UART1_TX (pin_A9)
+#define MICROPY_HW_UART1_RX (pin_A10)
+#define MICROPY_HW_UART2_TX (pin_A2)
+#define MICROPY_HW_UART2_RX (pin_A3)
+#define MICROPY_HW_UART2_RTS (pin_A1)
+#define MICROPY_HW_UART2_CTS (pin_A0)
+#define MICROPY_HW_UART6_TX (pin_C6)
+#define MICROPY_HW_UART6_RX (pin_C7)
+
+// I2C busses
+#define MICROPY_HW_I2C1_SCL (pin_B6)
+#define MICROPY_HW_I2C1_SDA (pin_B9)
+//#define MICROPY_HW_I2C2_SCL (pin_B10)
+//#define MICROPY_HW_I2C2_SDA (pin_B11)
+#define MICROPY_HW_I2C3_SCL (pin_A8)
+#define MICROPY_HW_I2C3_SDA (pin_A9)
+
+// SPI busses
+#define MICROPY_HW_SPI1_NSS (pin_A4)
+#define MICROPY_HW_SPI1_SCK (pin_A5)
+#define MICROPY_HW_SPI1_MISO (pin_A6)
+#define MICROPY_HW_SPI1_MOSI (pin_A7)
+#define MICROPY_HW_SPI2_NSS (pin_B12)
+#define MICROPY_HW_SPI2_SCK (pin_B13)
+#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_A0)
+#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_D14) // red
+#define MICROPY_HW_LED2 (pin_D12) // green
+#define MICROPY_HW_LED3 (pin_D13) // orange
+#define MICROPY_HW_LED4 (pin_D15) // blue
+#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_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
new file mode 100644
index 000000000..71b3b19d6
--- /dev/null
+++ b/ports/stm32/boards/STM32F411DISC/mpconfigboard.mk
@@ -0,0 +1,4 @@
+MCU_SERIES = f4
+CMSIS_MCU = STM32F411xE
+AF_FILE = boards/stm32f411_af.csv
+LD_FILE = boards/stm32f411.ld
diff --git a/ports/stm32/boards/STM32F411DISC/pins.csv b/ports/stm32/boards/STM32F411DISC/pins.csv
new file mode 100644
index 000000000..96077d54d
--- /dev/null
+++ b/ports/stm32/boards/STM32F411DISC/pins.csv
@@ -0,0 +1,84 @@
+PC0,PC0
+PC1,PC1
+PC2,PC2
+PC3,PC3
+PA0,PA0
+PA1,PA1
+PA2,PA2
+PA3,PA3
+PA4,PA4
+PA5,PA5
+PA6,PA6
+PA7,PA7
+PC4,PC4
+PC5,PC5
+PB0,PB0
+PB1,PB1
+PB2,PB2
+PE7,PE7
+PE8,PE8
+PE9,PE9
+PE10,PE10
+PE11,PE11
+PE12,PE12
+PE13,PE13
+PE14,PE14
+PE15,PE15
+PB10,PB10
+PB11,PB11
+PB12,PB12
+PB13,PB13
+PB14,PB14
+PB15,PB15
+PD8,PD8
+PD9,PD9
+PD10,PD10
+PD11,PD11
+PD12,PD12
+PD13,PD13
+PD14,PD14
+PD15,PD15
+PC6,PC6
+PC7,PC7
+PC8,PC8
+PC9,PC9
+PA8,PA8
+PA9,PA9
+PA10,PA10
+PA13,PA13
+PA14,PA14
+PA15,PA15
+PC10,PC10
+PC11,PC11
+PC12,PC12
+PD0,PD0
+PD1,PD1
+PD2,PD2
+PD3,PD3
+PD4,PD4
+PD5,PD5
+PD6,PD6
+PD7,PD7
+PB4,PB4
+PB5,PB5
+PB6,PB6
+PB7,PB7
+PB8,PB8
+PB9,PB9
+PE0,PE0
+PE1,PE1
+PE2,PE2
+PE3,PE3
+PE4,PE4
+PE5,PE5
+PE6,PE6
+PC13,PC13
+PC14,PC14
+PC15,PC15
+PH0,PH0
+PH1,PH1
+LED_GREEN,PD12
+LED_ORANGE,PD13
+LED_RED,PD14
+LED_BLUE,PD15
+SW,PA0
diff --git a/ports/stm32/boards/STM32F411DISC/stm32f4xx_hal_conf.h b/ports/stm32/boards/STM32F411DISC/stm32f4xx_hal_conf.h
new file mode 100644
index 000000000..921cbe5fe
--- /dev/null
+++ b/ports/stm32/boards/STM32F411DISC/stm32f4xx_hal_conf.h
@@ -0,0 +1,411 @@
+/**
+ ******************************************************************************
+ * @file stm32f4xx_hal_conf.h
+ * @author MCD Application Team
+ * @version V1.1.0
+ * @date 19-June-2014
+ * @brief HAL configuration file.
+ ******************************************************************************
+ * @attention
+ *
+ * <h2><center>&copy; COPYRIGHT(c) 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.
+ *
+ ******************************************************************************
+ */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __STM32F4xx_HAL_CONF_H
+#define __STM32F4xx_HAL_CONF_H
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/* Exported types ------------------------------------------------------------*/
+/* Exported constants --------------------------------------------------------*/
+
+#define USE_USB_FS
+
+/* ########################## 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_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_PCCARD_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_LTDC_MODULE_ENABLED */
+#define HAL_PWR_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_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 */
+
+
+/* ########################## 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)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 ((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)40000)
+#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 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 */
+
+/* ################## 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 0
+#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)4) /* 4 Rx buffers of size ETH_RX_BUF_SIZE */
+#define ETH_TXBUFNB ((uint32_t)4) /* 4 Tx buffers of size ETH_TX_BUF_SIZE */
+
+/* Section 2: PHY configuration section */
+
+/* DP83848 PHY Address*/
+#define DP83848_PHY_ADDRESS 0x01
+/* PHY Reset delay these values are based on a 1 ms Systick interrupt*/
+#define PHY_RESET_DELAY ((uint32_t)0x000000FF)
+/* PHY Configuration delay */
+#define PHY_CONFIG_DELAY ((uint32_t)0x00000FFF)
+
+#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 "stm32f4xx_hal_rcc.h"
+#endif /* HAL_RCC_MODULE_ENABLED */
+
+#ifdef HAL_GPIO_MODULE_ENABLED
+ #include "stm32f4xx_hal_gpio.h"
+#endif /* HAL_GPIO_MODULE_ENABLED */
+
+#ifdef HAL_DMA_MODULE_ENABLED
+ #include "stm32f4xx_hal_dma.h"
+#endif /* HAL_DMA_MODULE_ENABLED */
+
+#ifdef HAL_CORTEX_MODULE_ENABLED
+ #include "stm32f4xx_hal_cortex.h"
+#endif /* HAL_CORTEX_MODULE_ENABLED */
+
+#ifdef HAL_ADC_MODULE_ENABLED
+ #include "stm32f4xx_hal_adc.h"
+#endif /* HAL_ADC_MODULE_ENABLED */
+
+#ifdef HAL_CAN_MODULE_ENABLED
+ #include "stm32f4xx_hal_can.h"
+#endif /* HAL_CAN_MODULE_ENABLED */
+
+#ifdef HAL_CRC_MODULE_ENABLED
+ #include "stm32f4xx_hal_crc.h"
+#endif /* HAL_CRC_MODULE_ENABLED */
+
+#ifdef HAL_CRYP_MODULE_ENABLED
+ #include "stm32f4xx_hal_cryp.h"
+#endif /* HAL_CRYP_MODULE_ENABLED */
+
+#ifdef HAL_DMA2D_MODULE_ENABLED
+ #include "stm32f4xx_hal_dma2d.h"
+#endif /* HAL_DMA2D_MODULE_ENABLED */
+
+#ifdef HAL_DAC_MODULE_ENABLED
+ #include "stm32f4xx_hal_dac.h"
+#endif /* HAL_DAC_MODULE_ENABLED */
+
+#ifdef HAL_DCMI_MODULE_ENABLED
+ #include "stm32f4xx_hal_dcmi.h"
+#endif /* HAL_DCMI_MODULE_ENABLED */
+
+#ifdef HAL_ETH_MODULE_ENABLED
+ #include "stm32f4xx_hal_eth.h"
+#endif /* HAL_ETH_MODULE_ENABLED */
+
+#ifdef HAL_FLASH_MODULE_ENABLED
+ #include "stm32f4xx_hal_flash.h"
+#endif /* HAL_FLASH_MODULE_ENABLED */
+
+#ifdef HAL_SRAM_MODULE_ENABLED
+ #include "stm32f4xx_hal_sram.h"
+#endif /* HAL_SRAM_MODULE_ENABLED */
+
+#ifdef HAL_NOR_MODULE_ENABLED
+ #include "stm32f4xx_hal_nor.h"
+#endif /* HAL_NOR_MODULE_ENABLED */
+
+#ifdef HAL_NAND_MODULE_ENABLED
+ #include "stm32f4xx_hal_nand.h"
+#endif /* HAL_NAND_MODULE_ENABLED */
+
+#ifdef HAL_PCCARD_MODULE_ENABLED
+ #include "stm32f4xx_hal_pccard.h"
+#endif /* HAL_PCCARD_MODULE_ENABLED */
+
+#ifdef HAL_SDRAM_MODULE_ENABLED
+ #include "stm32f4xx_hal_sdram.h"
+#endif /* HAL_SDRAM_MODULE_ENABLED */
+
+#ifdef HAL_HASH_MODULE_ENABLED
+ #include "stm32f4xx_hal_hash.h"
+#endif /* HAL_HASH_MODULE_ENABLED */
+
+#ifdef HAL_I2C_MODULE_ENABLED
+ #include "stm32f4xx_hal_i2c.h"
+#endif /* HAL_I2C_MODULE_ENABLED */
+
+#ifdef HAL_I2S_MODULE_ENABLED
+ #include "stm32f4xx_hal_i2s.h"
+#endif /* HAL_I2S_MODULE_ENABLED */
+
+#ifdef HAL_IWDG_MODULE_ENABLED
+ #include "stm32f4xx_hal_iwdg.h"
+#endif /* HAL_IWDG_MODULE_ENABLED */
+
+#ifdef HAL_LTDC_MODULE_ENABLED
+ #include "stm32f4xx_hal_ltdc.h"
+#endif /* HAL_LTDC_MODULE_ENABLED */
+
+#ifdef HAL_PWR_MODULE_ENABLED
+ #include "stm32f4xx_hal_pwr.h"
+#endif /* HAL_PWR_MODULE_ENABLED */
+
+#ifdef HAL_RNG_MODULE_ENABLED
+ #include "stm32f4xx_hal_rng.h"
+#endif /* HAL_RNG_MODULE_ENABLED */
+
+#ifdef HAL_RTC_MODULE_ENABLED
+ #include "stm32f4xx_hal_rtc.h"
+#endif /* HAL_RTC_MODULE_ENABLED */
+
+#ifdef HAL_SAI_MODULE_ENABLED
+ #include "stm32f4xx_hal_sai.h"
+#endif /* HAL_SAI_MODULE_ENABLED */
+
+#ifdef HAL_SD_MODULE_ENABLED
+ #include "stm32f4xx_hal_sd.h"
+#endif /* HAL_SD_MODULE_ENABLED */
+
+#ifdef HAL_SPI_MODULE_ENABLED
+ #include "stm32f4xx_hal_spi.h"
+#endif /* HAL_SPI_MODULE_ENABLED */
+
+#ifdef HAL_TIM_MODULE_ENABLED
+ #include "stm32f4xx_hal_tim.h"
+#endif /* HAL_TIM_MODULE_ENABLED */
+
+#ifdef HAL_UART_MODULE_ENABLED
+ #include "stm32f4xx_hal_uart.h"
+#endif /* HAL_UART_MODULE_ENABLED */
+
+#ifdef HAL_USART_MODULE_ENABLED
+ #include "stm32f4xx_hal_usart.h"
+#endif /* HAL_USART_MODULE_ENABLED */
+
+#ifdef HAL_IRDA_MODULE_ENABLED
+ #include "stm32f4xx_hal_irda.h"
+#endif /* HAL_IRDA_MODULE_ENABLED */
+
+#ifdef HAL_SMARTCARD_MODULE_ENABLED
+ #include "stm32f4xx_hal_smartcard.h"
+#endif /* HAL_SMARTCARD_MODULE_ENABLED */
+
+#ifdef HAL_WWDG_MODULE_ENABLED
+ #include "stm32f4xx_hal_wwdg.h"
+#endif /* HAL_WWDG_MODULE_ENABLED */
+
+#ifdef HAL_PCD_MODULE_ENABLED
+ #include "stm32f4xx_hal_pcd.h"
+#endif /* HAL_PCD_MODULE_ENABLED */
+
+#ifdef HAL_HCD_MODULE_ENABLED
+ #include "stm32f4xx_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 /* __STM32F4xx_HAL_CONF_H */
+
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/ports/stm32/boards/STM32F429DISC/mpconfigboard.h b/ports/stm32/boards/STM32F429DISC/mpconfigboard.h
new file mode 100644
index 000000000..fc0702025
--- /dev/null
+++ b/ports/stm32/boards/STM32F429DISC/mpconfigboard.h
@@ -0,0 +1,73 @@
+#define MICROPY_HW_BOARD_NAME "F429I-DISCO"
+#define MICROPY_HW_MCU_NAME "STM32F429"
+
+#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)
+
+// HSE is 8MHz
+#define MICROPY_HW_CLK_PLLM (8)
+#define MICROPY_HW_CLK_PLLN (336)
+#define MICROPY_HW_CLK_PLLP (RCC_PLLP_DIV2)
+#define MICROPY_HW_CLK_PLLQ (7)
+
+// UART config
+#define MICROPY_HW_UART1_TX (pin_A9)
+#define MICROPY_HW_UART1_RX (pin_A10)
+#define MICROPY_HW_UART2_TX (pin_D8)
+#define MICROPY_HW_UART2_RX (pin_D9)
+
+// I2C busses
+#define MICROPY_HW_I2C3_SCL (pin_A8)
+#define MICROPY_HW_I2C3_SDA (pin_C9)
+
+// SPI busses
+//#define MICROPY_HW_SPI1_NSS (pin_A4)
+//#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)
+// The HS USB uses B14 & B15 for D- and D+
+#else
+#define MICROPY_HW_SPI2_NSS (pin_B12)
+#define MICROPY_HW_SPI2_SCK (pin_B13)
+#define MICROPY_HW_SPI2_MISO (pin_B14)
+#define MICROPY_HW_SPI2_MOSI (pin_B15)
+#endif
+//#define MICROPY_HW_SPI4_NSS (pin_E11)
+//#define MICROPY_HW_SPI4_SCK (pin_E12)
+//#define MICROPY_HW_SPI4_MISO (pin_E13)
+//#define MICROPY_HW_SPI4_MOSI (pin_E14)
+#define MICROPY_HW_SPI5_NSS (pin_F6)
+#define MICROPY_HW_SPI5_SCK (pin_F7)
+#define MICROPY_HW_SPI5_MISO (pin_F8)
+#define MICROPY_HW_SPI5_MOSI (pin_F9)
+//#define MICROPY_HW_SPI6_NSS (pin_G8)
+//#define MICROPY_HW_SPI6_SCK (pin_G13)
+//#define MICROPY_HW_SPI6_MISO (pin_G12)
+//#define MICROPY_HW_SPI6_MOSI (pin_G14)
+
+// 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)
+#define MICROPY_HW_USRSW_EXTI_MODE (GPIO_MODE_IT_RISING)
+#define MICROPY_HW_USRSW_PRESSED (1)
+
+// LEDs
+#define MICROPY_HW_LED1 (pin_G14) // red
+#define MICROPY_HW_LED2 (pin_G13) // 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_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
new file mode 100644
index 000000000..1bbf808b6
--- /dev/null
+++ b/ports/stm32/boards/STM32F429DISC/mpconfigboard.mk
@@ -0,0 +1,4 @@
+MCU_SERIES = f4
+CMSIS_MCU = STM32F429xx
+AF_FILE = boards/stm32f429_af.csv
+LD_FILE = boards/stm32f429.ld
diff --git a/ports/stm32/boards/STM32F429DISC/pins.csv b/ports/stm32/boards/STM32F429DISC/pins.csv
new file mode 100644
index 000000000..8a892d3c2
--- /dev/null
+++ b/ports/stm32/boards/STM32F429DISC/pins.csv
@@ -0,0 +1,117 @@
+PF4,PF4
+PF5,PF5
+PF2,PF2
+PF3,PF3
+PF0,PF0
+PF1,PF1
+PC14,PC14
+PC15,PC15
+PE6,PE6
+PC13,PC13
+PE4,PE4
+PE5,PE5
+PE2,PE2
+PE3,PE3
+PE0,PE0
+PE1,PE1
+PB8,PB8
+PB9,PB9
+PB6,PB6
+PB7,PB7
+PB4,PB4
+PB5,PB5
+PG15,PG15
+PB3,PB3
+PG13,PG13
+PG14,PG14
+PG11,PG11
+PG12,PG12
+PG9,PG9
+PG10,PG10
+PD7,PD7
+PD6,PD6
+PD5,PD5
+PD4,PD4
+PD3,PD3
+PD2,PD2
+PD1,PD1
+PD0,PD0
+PC12,PC12
+PC11,PC11
+PC10,PC10
+PA15,PA15
+PA14,PA14
+PA13,PA13
+PA12,PA12
+PA11,PA11
+PA10,PA10
+PA9,PA9
+PA8,PA8
+PC9,PC9
+PC8,PC8
+PC7,PC7
+PC6,PC6
+PG8,PG8
+PG7,PG7
+PG6,PG6
+PG5,PG5
+PG4,PG4
+PF6,PF6
+PF8,PF8
+PF7,PF7
+PF10,PF10
+PF9,PF9
+PH1,PH1
+PH0,PH0
+PC1,PC1
+PC0,PC0
+PC3,PC3
+PC2,PC2
+PA1,PA1
+PA0,PA0
+PA3,PA3
+PA2,PA2
+PA5,PA5
+PA4,PA4
+PA7,PA7
+PA6,PA6
+PC5,PC5
+PC4,PC4
+PB1,PB1
+PB0,PB0
+PB2,PB2
+PF12,PF12
+PF11,PF11
+PF14,PF14
+PF13,PF13
+PG0,PG0
+PF15,PF15
+PE7,PE7
+PG1,PG1
+PE9,PE9
+PE8,PE8
+PE11,PE11
+PE10,PE10
+PE13,PE13
+PE12,PE12
+PE15,PE15
+PE14,PE14
+PB11,PB11
+PB10,PB10
+PB13,PB13
+PB12,PB12
+PB15,PB15
+PB14,PB14
+PD9,PD9
+PD8,PD8
+PD11,PD11
+PD10,PD10
+PD13,PD13
+PD12,PD12
+PD15,PD15
+PD14,PD14
+PG3,PG3
+PG2,PG2
+SW,PA0
+LED_GREEN,PG13
+LED_RED,PG14
diff --git a/ports/stm32/boards/STM32F429DISC/stm32f4xx_hal_conf.h b/ports/stm32/boards/STM32F429DISC/stm32f4xx_hal_conf.h
new file mode 100644
index 000000000..4f5962dcb
--- /dev/null
+++ b/ports/stm32/boards/STM32F429DISC/stm32f4xx_hal_conf.h
@@ -0,0 +1,412 @@
+/**
+ ******************************************************************************
+ * @file stm32f4xx_hal_conf.h
+ * @author MCD Application Team
+ * @version V1.1.0
+ * @date 19-June-2014
+ * @brief HAL configuration file.
+ ******************************************************************************
+ * @attention
+ *
+ * <h2><center>&copy; COPYRIGHT(c) 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.
+ *
+ ******************************************************************************
+ */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __STM32F4xx_HAL_CONF_H
+#define __STM32F4xx_HAL_CONF_H
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/* 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
+ */
+#define HAL_MODULE_ENABLED
+#define HAL_ADC_MODULE_ENABLED
+#define HAL_CAN_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_PCCARD_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_LTDC_MODULE_ENABLED */
+#define HAL_PWR_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_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 */
+
+
+/* ########################## 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)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 ((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)40000)
+#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 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 */
+
+/* ################## 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 0
+#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)4) /* 4 Rx buffers of size ETH_RX_BUF_SIZE */
+#define ETH_TXBUFNB ((uint32_t)4) /* 4 Tx buffers of size ETH_TX_BUF_SIZE */
+
+/* Section 2: PHY configuration section */
+
+/* DP83848 PHY Address*/
+#define DP83848_PHY_ADDRESS 0x01
+/* PHY Reset delay these values are based on a 1 ms Systick interrupt*/
+#define PHY_RESET_DELAY ((uint32_t)0x000000FF)
+/* PHY Configuration delay */
+#define PHY_CONFIG_DELAY ((uint32_t)0x00000FFF)
+
+#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 "stm32f4xx_hal_rcc.h"
+#endif /* HAL_RCC_MODULE_ENABLED */
+
+#ifdef HAL_GPIO_MODULE_ENABLED
+ #include "stm32f4xx_hal_gpio.h"
+#endif /* HAL_GPIO_MODULE_ENABLED */
+
+#ifdef HAL_DMA_MODULE_ENABLED
+ #include "stm32f4xx_hal_dma.h"
+#endif /* HAL_DMA_MODULE_ENABLED */
+
+#ifdef HAL_CORTEX_MODULE_ENABLED
+ #include "stm32f4xx_hal_cortex.h"
+#endif /* HAL_CORTEX_MODULE_ENABLED */
+
+#ifdef HAL_ADC_MODULE_ENABLED
+ #include "stm32f4xx_hal_adc.h"
+#endif /* HAL_ADC_MODULE_ENABLED */
+
+#ifdef HAL_CAN_MODULE_ENABLED
+ #include "stm32f4xx_hal_can.h"
+#endif /* HAL_CAN_MODULE_ENABLED */
+
+#ifdef HAL_CRC_MODULE_ENABLED
+ #include "stm32f4xx_hal_crc.h"
+#endif /* HAL_CRC_MODULE_ENABLED */
+
+#ifdef HAL_CRYP_MODULE_ENABLED
+ #include "stm32f4xx_hal_cryp.h"
+#endif /* HAL_CRYP_MODULE_ENABLED */
+
+#ifdef HAL_DMA2D_MODULE_ENABLED
+ #include "stm32f4xx_hal_dma2d.h"
+#endif /* HAL_DMA2D_MODULE_ENABLED */
+
+#ifdef HAL_DAC_MODULE_ENABLED
+ #include "stm32f4xx_hal_dac.h"
+#endif /* HAL_DAC_MODULE_ENABLED */
+
+#ifdef HAL_DCMI_MODULE_ENABLED
+ #include "stm32f4xx_hal_dcmi.h"
+#endif /* HAL_DCMI_MODULE_ENABLED */
+
+#ifdef HAL_ETH_MODULE_ENABLED
+ #include "stm32f4xx_hal_eth.h"
+#endif /* HAL_ETH_MODULE_ENABLED */
+
+#ifdef HAL_FLASH_MODULE_ENABLED
+ #include "stm32f4xx_hal_flash.h"
+#endif /* HAL_FLASH_MODULE_ENABLED */
+
+#ifdef HAL_SRAM_MODULE_ENABLED
+ #include "stm32f4xx_hal_sram.h"
+#endif /* HAL_SRAM_MODULE_ENABLED */
+
+#ifdef HAL_NOR_MODULE_ENABLED
+ #include "stm32f4xx_hal_nor.h"
+#endif /* HAL_NOR_MODULE_ENABLED */
+
+#ifdef HAL_NAND_MODULE_ENABLED
+ #include "stm32f4xx_hal_nand.h"
+#endif /* HAL_NAND_MODULE_ENABLED */
+
+#ifdef HAL_PCCARD_MODULE_ENABLED
+ #include "stm32f4xx_hal_pccard.h"
+#endif /* HAL_PCCARD_MODULE_ENABLED */
+
+#ifdef HAL_SDRAM_MODULE_ENABLED
+ #include "stm32f4xx_hal_sdram.h"
+#endif /* HAL_SDRAM_MODULE_ENABLED */
+
+#ifdef HAL_HASH_MODULE_ENABLED
+ #include "stm32f4xx_hal_hash.h"
+#endif /* HAL_HASH_MODULE_ENABLED */
+
+#ifdef HAL_I2C_MODULE_ENABLED
+ #include "stm32f4xx_hal_i2c.h"
+#endif /* HAL_I2C_MODULE_ENABLED */
+
+#ifdef HAL_I2S_MODULE_ENABLED
+ #include "stm32f4xx_hal_i2s.h"
+#endif /* HAL_I2S_MODULE_ENABLED */
+
+#ifdef HAL_IWDG_MODULE_ENABLED
+ #include "stm32f4xx_hal_iwdg.h"
+#endif /* HAL_IWDG_MODULE_ENABLED */
+
+#ifdef HAL_LTDC_MODULE_ENABLED
+ #include "stm32f4xx_hal_ltdc.h"
+#endif /* HAL_LTDC_MODULE_ENABLED */
+
+#ifdef HAL_PWR_MODULE_ENABLED
+ #include "stm32f4xx_hal_pwr.h"
+#endif /* HAL_PWR_MODULE_ENABLED */
+
+#ifdef HAL_RNG_MODULE_ENABLED
+ #include "stm32f4xx_hal_rng.h"
+#endif /* HAL_RNG_MODULE_ENABLED */
+
+#ifdef HAL_RTC_MODULE_ENABLED
+ #include "stm32f4xx_hal_rtc.h"
+#endif /* HAL_RTC_MODULE_ENABLED */
+
+#ifdef HAL_SAI_MODULE_ENABLED
+ #include "stm32f4xx_hal_sai.h"
+#endif /* HAL_SAI_MODULE_ENABLED */
+
+#ifdef HAL_SD_MODULE_ENABLED
+ #include "stm32f4xx_hal_sd.h"
+#endif /* HAL_SD_MODULE_ENABLED */
+
+#ifdef HAL_SPI_MODULE_ENABLED
+ #include "stm32f4xx_hal_spi.h"
+#endif /* HAL_SPI_MODULE_ENABLED */
+
+#ifdef HAL_TIM_MODULE_ENABLED
+ #include "stm32f4xx_hal_tim.h"
+#endif /* HAL_TIM_MODULE_ENABLED */
+
+#ifdef HAL_UART_MODULE_ENABLED
+ #include "stm32f4xx_hal_uart.h"
+#endif /* HAL_UART_MODULE_ENABLED */
+
+#ifdef HAL_USART_MODULE_ENABLED
+ #include "stm32f4xx_hal_usart.h"
+#endif /* HAL_USART_MODULE_ENABLED */
+
+#ifdef HAL_IRDA_MODULE_ENABLED
+ #include "stm32f4xx_hal_irda.h"
+#endif /* HAL_IRDA_MODULE_ENABLED */
+
+#ifdef HAL_SMARTCARD_MODULE_ENABLED
+ #include "stm32f4xx_hal_smartcard.h"
+#endif /* HAL_SMARTCARD_MODULE_ENABLED */
+
+#ifdef HAL_WWDG_MODULE_ENABLED
+ #include "stm32f4xx_hal_wwdg.h"
+#endif /* HAL_WWDG_MODULE_ENABLED */
+
+#ifdef HAL_PCD_MODULE_ENABLED
+ #include "stm32f4xx_hal_pcd.h"
+#endif /* HAL_PCD_MODULE_ENABLED */
+
+#ifdef HAL_HCD_MODULE_ENABLED
+ #include "stm32f4xx_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 /* __STM32F4xx_HAL_CONF_H */
+
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/ports/stm32/boards/STM32F439/mpconfigboard.h b/ports/stm32/boards/STM32F439/mpconfigboard.h
new file mode 100644
index 000000000..eca79bf58
--- /dev/null
+++ b/ports/stm32/boards/STM32F439/mpconfigboard.h
@@ -0,0 +1,85 @@
+#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)
+
+// SD card detect switch
+#if MICROPY_HW_HAS_SDCARD
+#define MICROPY_HW_SDCARD_DETECT_PIN (pin_A8)
+#define MICROPY_HW_SDCARD_DETECT_PULL (GPIO_PULLUP)
+#define MICROPY_HW_SDCARD_DETECT_PRESENT (1)
+#endif
+
+// HSE is 8MHz
+#define MICROPY_HW_CLK_PLLM (8) //divide external clock by this to get 1MHz
+#define MICROPY_HW_CLK_PLLN (384) //this number is the PLL clock in MHz
+#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
+
+// UART config
+#define MICROPY_HW_UART1_TX (pin_A9)
+#define MICROPY_HW_UART1_RX (pin_A10)
+#define MICROPY_HW_UART2_TX (pin_D5)
+#define MICROPY_HW_UART2_RX (pin_D6)
+#define MICROPY_HW_UART2_RTS (pin_D1)
+#define MICROPY_HW_UART2_CTS (pin_D0)
+#define MICROPY_HW_UART3_TX (pin_D8)
+#define MICROPY_HW_UART3_RX (pin_D9)
+#define MICROPY_HW_UART3_RTS (pin_D12)
+#define MICROPY_HW_UART3_CTS (pin_D11)
+#define MICROPY_HW_UART4_TX (pin_A0)
+#define MICROPY_HW_UART4_RX (pin_A1)
+#define MICROPY_HW_UART6_TX (pin_C6)
+#define MICROPY_HW_UART6_RX (pin_C7)
+
+// I2C busses
+#define MICROPY_HW_I2C1_SCL (pin_A8)
+#define MICROPY_HW_I2C1_SDA (pin_C9)
+
+// SPI busses
+#define MICROPY_HW_SPI1_NSS (pin_A4)
+#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)
+// The HS USB uses B14 & B15 for D- and D+
+#else
+#define MICROPY_HW_SPI2_NSS (pin_B12)
+#define MICROPY_HW_SPI2_SCK (pin_B13)
+#define MICROPY_HW_SPI2_MISO (pin_B14)
+#define MICROPY_HW_SPI2_MOSI (pin_B15)
+#endif
+#define MICROPY_HW_SPI3_NSS (pin_E11)
+#define MICROPY_HW_SPI3_SCK (pin_E12)
+#define MICROPY_HW_SPI3_MISO (pin_E13)
+#define MICROPY_HW_SPI3_MOSI (pin_E14)
+//#define MICROPY_HW_SPI4_NSS (pin_E11)
+//#define MICROPY_HW_SPI4_SCK (pin_E12)
+//#define MICROPY_HW_SPI4_MISO (pin_E13)
+//#define MICROPY_HW_SPI4_MOSI (pin_E14)
+//#define MICROPY_HW_SPI5_NSS (pin_F6)
+//#define MICROPY_HW_SPI5_SCK (pin_F7)
+//#define MICROPY_HW_SPI5_MISO (pin_F8)
+//#define MICROPY_HW_SPI5_MOSI (pin_F9)
+//#define MICROPY_HW_SPI6_NSS (pin_G8)
+//#define MICROPY_HW_SPI6_SCK (pin_G13)
+//#define MICROPY_HW_SPI6_MISO (pin_G12)
+//#define MICROPY_HW_SPI6_MOSI (pin_G14)
+
+// 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)
+#define MICROPY_HW_USRSW_EXTI_MODE (GPIO_MODE_IT_RISING)
+#define MICROPY_HW_USRSW_PRESSED (1)
+
diff --git a/ports/stm32/boards/STM32F439/mpconfigboard.mk b/ports/stm32/boards/STM32F439/mpconfigboard.mk
new file mode 100644
index 000000000..0c30c06a3
--- /dev/null
+++ b/ports/stm32/boards/STM32F439/mpconfigboard.mk
@@ -0,0 +1,4 @@
+MCU_SERIES = f4
+CMSIS_MCU = STM32F439xx
+AF_FILE = boards/stm32f439_af.csv
+LD_FILE = boards/stm32f439.ld
diff --git a/ports/stm32/boards/STM32F439/pins.csv b/ports/stm32/boards/STM32F439/pins.csv
new file mode 100644
index 000000000..cc9443dea
--- /dev/null
+++ b/ports/stm32/boards/STM32F439/pins.csv
@@ -0,0 +1,85 @@
+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
+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
+VUSB,PB13
+USB1D_N,PB14
+USB1D_P,PB15
+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
+PD2,PD2
+BOOT0,BOOT0
+PA15,PA15
+PA13,PA13
+PA14,PA14
+PB13,PB13
+PB14,PB14
+PB15,PB15
+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
diff --git a/ports/stm32/boards/STM32F439/stm32f4xx_hal_conf.h b/ports/stm32/boards/STM32F439/stm32f4xx_hal_conf.h
new file mode 100644
index 000000000..d121b18c5
--- /dev/null
+++ b/ports/stm32/boards/STM32F439/stm32f4xx_hal_conf.h
@@ -0,0 +1,411 @@
+/**
+ ******************************************************************************
+ * @file stm32f4xx_hal_conf.h
+ * @author MCD Application Team
+ * @version V1.1.0
+ * @date 19-June-2014
+ * @brief HAL configuration file.
+ ******************************************************************************
+ * @attention
+ *
+ * <h2><center>&copy; COPYRIGHT(c) 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.
+ *
+ ******************************************************************************
+ */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __STM32F4xx_HAL_CONF_H
+#define __STM32F4xx_HAL_CONF_H
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/* Exported types ------------------------------------------------------------*/
+/* Exported constants --------------------------------------------------------*/
+
+#define USE_USB_FS
+
+ /* ########################## 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_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_PCCARD_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_LTDC_MODULE_ENABLED */
+#define HAL_PWR_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_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 */
+
+
+/* ########################## 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)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 ((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)40000)
+#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 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 */
+
+/* ################## 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 0
+#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)4) /* 4 Rx buffers of size ETH_RX_BUF_SIZE */
+#define ETH_TXBUFNB ((uint32_t)4) /* 4 Tx buffers of size ETH_TX_BUF_SIZE */
+
+/* Section 2: PHY configuration section */
+
+/* DP83848 PHY Address*/
+#define DP83848_PHY_ADDRESS 0x01
+/* PHY Reset delay these values are based on a 1 ms Systick interrupt*/
+#define PHY_RESET_DELAY ((uint32_t)0x000000FF)
+/* PHY Configuration delay */
+#define PHY_CONFIG_DELAY ((uint32_t)0x00000FFF)
+
+#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 "stm32f4xx_hal_rcc.h"
+#endif /* HAL_RCC_MODULE_ENABLED */
+
+#ifdef HAL_GPIO_MODULE_ENABLED
+ #include "stm32f4xx_hal_gpio.h"
+#endif /* HAL_GPIO_MODULE_ENABLED */
+
+#ifdef HAL_DMA_MODULE_ENABLED
+ #include "stm32f4xx_hal_dma.h"
+#endif /* HAL_DMA_MODULE_ENABLED */
+
+#ifdef HAL_CORTEX_MODULE_ENABLED
+ #include "stm32f4xx_hal_cortex.h"
+#endif /* HAL_CORTEX_MODULE_ENABLED */
+
+#ifdef HAL_ADC_MODULE_ENABLED
+ #include "stm32f4xx_hal_adc.h"
+#endif /* HAL_ADC_MODULE_ENABLED */
+
+#ifdef HAL_CAN_MODULE_ENABLED
+ #include "stm32f4xx_hal_can.h"
+#endif /* HAL_CAN_MODULE_ENABLED */
+
+#ifdef HAL_CRC_MODULE_ENABLED
+ #include "stm32f4xx_hal_crc.h"
+#endif /* HAL_CRC_MODULE_ENABLED */
+
+#ifdef HAL_CRYP_MODULE_ENABLED
+ #include "stm32f4xx_hal_cryp.h"
+#endif /* HAL_CRYP_MODULE_ENABLED */
+
+#ifdef HAL_DMA2D_MODULE_ENABLED
+ #include "stm32f4xx_hal_dma2d.h"
+#endif /* HAL_DMA2D_MODULE_ENABLED */
+
+#ifdef HAL_DAC_MODULE_ENABLED
+ #include "stm32f4xx_hal_dac.h"
+#endif /* HAL_DAC_MODULE_ENABLED */
+
+#ifdef HAL_DCMI_MODULE_ENABLED
+ #include "stm32f4xx_hal_dcmi.h"
+#endif /* HAL_DCMI_MODULE_ENABLED */
+
+#ifdef HAL_ETH_MODULE_ENABLED
+ #include "stm32f4xx_hal_eth.h"
+#endif /* HAL_ETH_MODULE_ENABLED */
+
+#ifdef HAL_FLASH_MODULE_ENABLED
+ #include "stm32f4xx_hal_flash.h"
+#endif /* HAL_FLASH_MODULE_ENABLED */
+
+#ifdef HAL_SRAM_MODULE_ENABLED
+ #include "stm32f4xx_hal_sram.h"
+#endif /* HAL_SRAM_MODULE_ENABLED */
+
+#ifdef HAL_NOR_MODULE_ENABLED
+ #include "stm32f4xx_hal_nor.h"
+#endif /* HAL_NOR_MODULE_ENABLED */
+
+#ifdef HAL_NAND_MODULE_ENABLED
+ #include "stm32f4xx_hal_nand.h"
+#endif /* HAL_NAND_MODULE_ENABLED */
+
+#ifdef HAL_PCCARD_MODULE_ENABLED
+ #include "stm32f4xx_hal_pccard.h"
+#endif /* HAL_PCCARD_MODULE_ENABLED */
+
+#ifdef HAL_SDRAM_MODULE_ENABLED
+ #include "stm32f4xx_hal_sdram.h"
+#endif /* HAL_SDRAM_MODULE_ENABLED */
+
+#ifdef HAL_HASH_MODULE_ENABLED
+ #include "stm32f4xx_hal_hash.h"
+#endif /* HAL_HASH_MODULE_ENABLED */
+
+#ifdef HAL_I2C_MODULE_ENABLED
+ #include "stm32f4xx_hal_i2c.h"
+#endif /* HAL_I2C_MODULE_ENABLED */
+
+#ifdef HAL_I2S_MODULE_ENABLED
+ #include "stm32f4xx_hal_i2s.h"
+#endif /* HAL_I2S_MODULE_ENABLED */
+
+#ifdef HAL_IWDG_MODULE_ENABLED
+ #include "stm32f4xx_hal_iwdg.h"
+#endif /* HAL_IWDG_MODULE_ENABLED */
+
+#ifdef HAL_LTDC_MODULE_ENABLED
+ #include "stm32f4xx_hal_ltdc.h"
+#endif /* HAL_LTDC_MODULE_ENABLED */
+
+#ifdef HAL_PWR_MODULE_ENABLED
+ #include "stm32f4xx_hal_pwr.h"
+#endif /* HAL_PWR_MODULE_ENABLED */
+
+#ifdef HAL_RNG_MODULE_ENABLED
+ #include "stm32f4xx_hal_rng.h"
+#endif /* HAL_RNG_MODULE_ENABLED */
+
+#ifdef HAL_RTC_MODULE_ENABLED
+ #include "stm32f4xx_hal_rtc.h"
+#endif /* HAL_RTC_MODULE_ENABLED */
+
+#ifdef HAL_SAI_MODULE_ENABLED
+ #include "stm32f4xx_hal_sai.h"
+#endif /* HAL_SAI_MODULE_ENABLED */
+
+#ifdef HAL_SD_MODULE_ENABLED
+ #include "stm32f4xx_hal_sd.h"
+#endif /* HAL_SD_MODULE_ENABLED */
+
+#ifdef HAL_SPI_MODULE_ENABLED
+ #include "stm32f4xx_hal_spi.h"
+#endif /* HAL_SPI_MODULE_ENABLED */
+
+#ifdef HAL_TIM_MODULE_ENABLED
+ #include "stm32f4xx_hal_tim.h"
+#endif /* HAL_TIM_MODULE_ENABLED */
+
+#ifdef HAL_UART_MODULE_ENABLED
+ #include "stm32f4xx_hal_uart.h"
+#endif /* HAL_UART_MODULE_ENABLED */
+
+#ifdef HAL_USART_MODULE_ENABLED
+ #include "stm32f4xx_hal_usart.h"
+#endif /* HAL_USART_MODULE_ENABLED */
+
+#ifdef HAL_IRDA_MODULE_ENABLED
+ #include "stm32f4xx_hal_irda.h"
+#endif /* HAL_IRDA_MODULE_ENABLED */
+
+#ifdef HAL_SMARTCARD_MODULE_ENABLED
+ #include "stm32f4xx_hal_smartcard.h"
+#endif /* HAL_SMARTCARD_MODULE_ENABLED */
+
+#ifdef HAL_WWDG_MODULE_ENABLED
+ #include "stm32f4xx_hal_wwdg.h"
+#endif /* HAL_WWDG_MODULE_ENABLED */
+
+#ifdef HAL_PCD_MODULE_ENABLED
+ #include "stm32f4xx_hal_pcd.h"
+#endif /* HAL_PCD_MODULE_ENABLED */
+
+#ifdef HAL_HCD_MODULE_ENABLED
+ #include "stm32f4xx_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 /* __STM32F4xx_HAL_CONF_H */
+
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/ports/stm32/boards/STM32F4DISC/mpconfigboard.h b/ports/stm32/boards/STM32F4DISC/mpconfigboard.h
new file mode 100644
index 000000000..105875515
--- /dev/null
+++ b/ports/stm32/boards/STM32F4DISC/mpconfigboard.h
@@ -0,0 +1,86 @@
+#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)
+
+// HSE is 8MHz
+#define MICROPY_HW_CLK_PLLM (8)
+#define MICROPY_HW_CLK_PLLN (336)
+#define MICROPY_HW_CLK_PLLP (RCC_PLLP_DIV2)
+#define MICROPY_HW_CLK_PLLQ (7)
+
+// UART config
+#if 0
+// A9 is used for USB VBUS detect, and A10 is used for USB_FS_ID.
+// UART1 is also on PB6/7 but PB6 is tied to the Audio SCL line.
+// Without board modifications, this makes UART1 unusable on this board.
+#define MICROPY_HW_UART1_TX (pin_A9)
+#define MICROPY_HW_UART1_RX (pin_A10)
+#endif
+#define MICROPY_HW_UART2_TX (pin_A2)
+#define MICROPY_HW_UART2_RX (pin_A3)
+#define MICROPY_HW_UART2_RTS (pin_A1)
+#define MICROPY_HW_UART2_CTS (pin_A0)
+#define MICROPY_HW_UART3_TX (pin_D8)
+#define MICROPY_HW_UART3_RX (pin_D9)
+#define MICROPY_HW_UART3_RTS (pin_D12)
+#define MICROPY_HW_UART3_CTS (pin_D11)
+#if MICROPY_HW_HAS_SWITCH == 0
+// NOTE: A0 also connects to the user switch. To use UART4 you should
+// set MICROPY_HW_HAS_SWITCH to 0, and also remove SB20 (on the back
+// of the board near the USER switch).
+#define MICROPY_HW_UART4_TX (pin_A0)
+#define MICROPY_HW_UART4_RX (pin_A1)
+#endif
+// NOTE: PC7 is connected to MCLK on the Audio chip. This is an input signal
+// so I think as long as you're not using the audio chip then it should
+// be fine to use as a UART pin.
+#define MICROPY_HW_UART6_TX (pin_C6)
+#define MICROPY_HW_UART6_RX (pin_C7)
+
+// I2C busses
+#define MICROPY_HW_I2C1_SCL (pin_B6)
+#define MICROPY_HW_I2C1_SDA (pin_B7)
+#define MICROPY_HW_I2C2_SCL (pin_B10)
+#define MICROPY_HW_I2C2_SDA (pin_B11)
+
+// SPI busses
+#define MICROPY_HW_SPI1_NSS (pin_A4)
+#define MICROPY_HW_SPI1_SCK (pin_A5)
+#define MICROPY_HW_SPI1_MISO (pin_A6)
+#define MICROPY_HW_SPI1_MOSI (pin_A7)
+#define MICROPY_HW_SPI2_NSS (pin_B12)
+#define MICROPY_HW_SPI2_SCK (pin_B13)
+#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_A0)
+#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_D14) // red
+#define MICROPY_HW_LED2 (pin_D12) // green
+#define MICROPY_HW_LED3 (pin_D13) // orange
+#define MICROPY_HW_LED4 (pin_D15) // blue
+#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_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
new file mode 100644
index 000000000..ece09caa1
--- /dev/null
+++ b/ports/stm32/boards/STM32F4DISC/mpconfigboard.mk
@@ -0,0 +1,4 @@
+MCU_SERIES = f4
+CMSIS_MCU = STM32F407xx
+AF_FILE = boards/stm32f405_af.csv
+LD_FILE = boards/stm32f405.ld
diff --git a/ports/stm32/boards/STM32F4DISC/pins.csv b/ports/stm32/boards/STM32F4DISC/pins.csv
new file mode 100644
index 000000000..4049fef7d
--- /dev/null
+++ b/ports/stm32/boards/STM32F4DISC/pins.csv
@@ -0,0 +1,85 @@
+PC0,PC0
+PC1,PC1
+PC2,PC2
+PC3,PC3
+PA0,PA0
+PA1,PA1
+PA2,PA2
+PA3,PA3
+PA4,PA4
+PA5,PA5
+PA6,PA6
+PA7,PA7
+PC4,PC4
+PC5,PC5
+PB0,PB0
+PB1,PB1
+PB2,PB2
+PE7,PE7
+PE8,PE8
+PE9,PE9
+PE10,PE10
+PE11,PE11
+PE12,PE12
+PE13,PE13
+PE14,PE14
+PE15,PE15
+PB10,PB10
+PB11,PB11
+PB12,PB12
+PB13,PB13
+PB14,PB14
+PB15,PB15
+PD8,PD8
+PD9,PD9
+PD10,PD10
+PD11,PD11
+PD12,PD12
+PD13,PD13
+PD14,PD14
+PD15,PD15
+PC6,PC6
+PC7,PC7
+PC8,PC8
+PC9,PC9
+PA8,PA8
+PA9,PA9
+PA10,PA10
+PA13,PA13
+PA14,PA14
+PA15,PA15
+PC10,PC10
+PC11,PC11
+PC12,PC12
+PD0,PD0
+PD1,PD1
+PD2,PD2
+PD3,PD3
+PD4,PD4
+PD5,PD5
+PD6,PD6
+PD7,PD7
+PB4,PB4
+PB5,PB5
+PB6,PB6
+PB7,PB7
+PB8,PB8
+PB9,PB9
+PE0,PE0
+PE1,PE1
+PE2,PE2
+PE3,PE3
+PE4,PE4
+PE5,PE5
+PE6,PE6
+PC13,PC13
+PC14,PC14
+PC15,PC15
+PH0,PH0
+PH1,PH1
+LED_GREEN,PD12
+LED_ORANGE,PD13
+LED_RED,PD14
+LED_BLUE,PD15
+SW,PA0
+
diff --git a/ports/stm32/boards/STM32F4DISC/staccel.py b/ports/stm32/boards/STM32F4DISC/staccel.py
new file mode 100644
index 000000000..2f2561d1c
--- /dev/null
+++ b/ports/stm32/boards/STM32F4DISC/staccel.py
@@ -0,0 +1,98 @@
+"""
+Driver for accelerometer on STM32F4 Discover board.
+
+Sets accelerometer range at +-2g.
+Returns list containing X,Y,Z axis acceleration values in 'g' units (9.8m/s^2).
+
+See:
+ STM32Cube_FW_F4_V1.1.0/Drivers/BSP/Components/lis302dl/lis302dl.h
+ STM32Cube_FW_F4_V1.1.0/Drivers/BSP/Components/lis302dl/lis302dl.c
+ STM32Cube_FW_F4_V1.1.0/Drivers/BSP/STM32F4-Discovery/stm32f4_discovery.c
+ STM32Cube_FW_F4_V1.1.0/Drivers/BSP/STM32F4-Discovery/stm32f4_discovery.h
+ STM32Cube_FW_F4_V1.1.0/Drivers/BSP/STM32F4-Discovery/stm32f4_discovery_accelerometer.c
+ STM32Cube_FW_F4_V1.1.0/Drivers/BSP/STM32F4-Discovery/stm32f4_discovery_accelerometer.h
+ STM32Cube_FW_F4_V1.1.0/Projects/STM32F4-Discovery/Demonstrations/Src/main.c
+"""
+
+from micropython import const
+from pyb import Pin
+from pyb import SPI
+
+READWRITE_CMD = const(0x80)
+MULTIPLEBYTE_CMD = const(0x40)
+WHO_AM_I_ADDR = const(0x0f)
+OUT_X_ADDR = const(0x29)
+OUT_Y_ADDR = const(0x2b)
+OUT_Z_ADDR = const(0x2d)
+OUT_T_ADDR = const(0x0c)
+
+LIS302DL_WHO_AM_I_VAL = const(0x3b)
+LIS302DL_CTRL_REG1_ADDR = const(0x20)
+# Configuration for 100Hz sampling rate, +-2g range
+LIS302DL_CONF = const(0b01000111)
+
+LIS3DSH_WHO_AM_I_VAL = const(0x3f)
+LIS3DSH_CTRL_REG4_ADDR = const(0x20)
+LIS3DSH_CTRL_REG5_ADDR = const(0x24)
+# Configuration for 100Hz sampling rate, +-2g range
+LIS3DSH_CTRL_REG4_CONF = const(0b01100111)
+LIS3DSH_CTRL_REG5_CONF = const(0b00000000)
+
+class STAccel:
+ def __init__(self):
+ self.cs_pin = Pin('PE3', Pin.OUT_PP, Pin.PULL_NONE)
+ self.cs_pin.high()
+ self.spi = SPI(1, SPI.MASTER, baudrate=328125, polarity=0, phase=1, bits=8)
+
+ self.who_am_i = self.read_id()
+
+ if self.who_am_i == LIS302DL_WHO_AM_I_VAL:
+ self.write_bytes(LIS302DL_CTRL_REG1_ADDR, bytearray([LIS302DL_CONF]))
+ self.sensitivity = 18
+ elif self.who_am_i == LIS3DSH_WHO_AM_I_VAL:
+ self.write_bytes(LIS3DSH_CTRL_REG4_ADDR, bytearray([LIS3DSH_CTRL_REG4_CONF]))
+ self.write_bytes(LIS3DSH_CTRL_REG5_ADDR, bytearray([LIS3DSH_CTRL_REG5_CONF]))
+ self.sensitivity = 0.06 * 256
+ else:
+ raise Exception('LIS302DL or LIS3DSH accelerometer not present')
+
+ def convert_raw_to_g(self, x):
+ if x & 0x80:
+ x = x - 256
+ return x * self.sensitivity / 1000
+
+ def read_bytes(self, addr, nbytes):
+ if nbytes > 1:
+ addr |= READWRITE_CMD | MULTIPLEBYTE_CMD
+ else:
+ addr |= READWRITE_CMD
+ self.cs_pin.low()
+ self.spi.send(addr)
+ #buf = self.spi.send_recv(bytearray(nbytes * [0])) # read data, MSB first
+ buf = self.spi.recv(nbytes)
+ self.cs_pin.high()
+ return buf
+
+ def write_bytes(self, addr, buf):
+ if len(buf) > 1:
+ addr |= MULTIPLEBYTE_CMD
+ self.cs_pin.low()
+ self.spi.send(addr)
+ for b in buf:
+ self.spi.send(b)
+ self.cs_pin.high()
+
+ def read_id(self):
+ return self.read_bytes(WHO_AM_I_ADDR, 1)[0]
+
+ def x(self):
+ return self.convert_raw_to_g(self.read_bytes(OUT_X_ADDR, 1)[0])
+
+ def y(self):
+ return self.convert_raw_to_g(self.read_bytes(OUT_Y_ADDR, 1)[0])
+
+ def z(self):
+ return self.convert_raw_to_g(self.read_bytes(OUT_Z_ADDR, 1)[0])
+
+ def xyz(self):
+ return (self.x(), self.y(), self.z())
diff --git a/ports/stm32/boards/STM32F4DISC/stm32f4xx_hal_conf.h b/ports/stm32/boards/STM32F4DISC/stm32f4xx_hal_conf.h
new file mode 100644
index 000000000..8941e8290
--- /dev/null
+++ b/ports/stm32/boards/STM32F4DISC/stm32f4xx_hal_conf.h
@@ -0,0 +1,411 @@
+/**
+ ******************************************************************************
+ * @file stm32f4xx_hal_conf.h
+ * @author MCD Application Team
+ * @version V1.1.0
+ * @date 19-June-2014
+ * @brief HAL configuration file.
+ ******************************************************************************
+ * @attention
+ *
+ * <h2><center>&copy; COPYRIGHT(c) 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.
+ *
+ ******************************************************************************
+ */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __STM32F4xx_HAL_CONF_H
+#define __STM32F4xx_HAL_CONF_H
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/* Exported types ------------------------------------------------------------*/
+/* Exported constants --------------------------------------------------------*/
+
+#define USE_USB_FS
+
+/* ########################## 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_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_PCCARD_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_LTDC_MODULE_ENABLED */
+#define HAL_PWR_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_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 */
+
+
+/* ########################## 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)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 ((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)40000)
+#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 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 */
+
+/* ################## 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 0
+#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)4) /* 4 Rx buffers of size ETH_RX_BUF_SIZE */
+#define ETH_TXBUFNB ((uint32_t)4) /* 4 Tx buffers of size ETH_TX_BUF_SIZE */
+
+/* Section 2: PHY configuration section */
+
+/* DP83848 PHY Address*/
+#define DP83848_PHY_ADDRESS 0x01
+/* PHY Reset delay these values are based on a 1 ms Systick interrupt*/
+#define PHY_RESET_DELAY ((uint32_t)0x000000FF)
+/* PHY Configuration delay */
+#define PHY_CONFIG_DELAY ((uint32_t)0x00000FFF)
+
+#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 "stm32f4xx_hal_rcc.h"
+#endif /* HAL_RCC_MODULE_ENABLED */
+
+#ifdef HAL_GPIO_MODULE_ENABLED
+ #include "stm32f4xx_hal_gpio.h"
+#endif /* HAL_GPIO_MODULE_ENABLED */
+
+#ifdef HAL_DMA_MODULE_ENABLED
+ #include "stm32f4xx_hal_dma.h"
+#endif /* HAL_DMA_MODULE_ENABLED */
+
+#ifdef HAL_CORTEX_MODULE_ENABLED
+ #include "stm32f4xx_hal_cortex.h"
+#endif /* HAL_CORTEX_MODULE_ENABLED */
+
+#ifdef HAL_ADC_MODULE_ENABLED
+ #include "stm32f4xx_hal_adc.h"
+#endif /* HAL_ADC_MODULE_ENABLED */
+
+#ifdef HAL_CAN_MODULE_ENABLED
+ #include "stm32f4xx_hal_can.h"
+#endif /* HAL_CAN_MODULE_ENABLED */
+
+#ifdef HAL_CRC_MODULE_ENABLED
+ #include "stm32f4xx_hal_crc.h"
+#endif /* HAL_CRC_MODULE_ENABLED */
+
+#ifdef HAL_CRYP_MODULE_ENABLED
+ #include "stm32f4xx_hal_cryp.h"
+#endif /* HAL_CRYP_MODULE_ENABLED */
+
+#ifdef HAL_DMA2D_MODULE_ENABLED
+ #include "stm32f4xx_hal_dma2d.h"
+#endif /* HAL_DMA2D_MODULE_ENABLED */
+
+#ifdef HAL_DAC_MODULE_ENABLED
+ #include "stm32f4xx_hal_dac.h"
+#endif /* HAL_DAC_MODULE_ENABLED */
+
+#ifdef HAL_DCMI_MODULE_ENABLED
+ #include "stm32f4xx_hal_dcmi.h"
+#endif /* HAL_DCMI_MODULE_ENABLED */
+
+#ifdef HAL_ETH_MODULE_ENABLED
+ #include "stm32f4xx_hal_eth.h"
+#endif /* HAL_ETH_MODULE_ENABLED */
+
+#ifdef HAL_FLASH_MODULE_ENABLED
+ #include "stm32f4xx_hal_flash.h"
+#endif /* HAL_FLASH_MODULE_ENABLED */
+
+#ifdef HAL_SRAM_MODULE_ENABLED
+ #include "stm32f4xx_hal_sram.h"
+#endif /* HAL_SRAM_MODULE_ENABLED */
+
+#ifdef HAL_NOR_MODULE_ENABLED
+ #include "stm32f4xx_hal_nor.h"
+#endif /* HAL_NOR_MODULE_ENABLED */
+
+#ifdef HAL_NAND_MODULE_ENABLED
+ #include "stm32f4xx_hal_nand.h"
+#endif /* HAL_NAND_MODULE_ENABLED */
+
+#ifdef HAL_PCCARD_MODULE_ENABLED
+ #include "stm32f4xx_hal_pccard.h"
+#endif /* HAL_PCCARD_MODULE_ENABLED */
+
+#ifdef HAL_SDRAM_MODULE_ENABLED
+ #include "stm32f4xx_hal_sdram.h"
+#endif /* HAL_SDRAM_MODULE_ENABLED */
+
+#ifdef HAL_HASH_MODULE_ENABLED
+ #include "stm32f4xx_hal_hash.h"
+#endif /* HAL_HASH_MODULE_ENABLED */
+
+#ifdef HAL_I2C_MODULE_ENABLED
+ #include "stm32f4xx_hal_i2c.h"
+#endif /* HAL_I2C_MODULE_ENABLED */
+
+#ifdef HAL_I2S_MODULE_ENABLED
+ #include "stm32f4xx_hal_i2s.h"
+#endif /* HAL_I2S_MODULE_ENABLED */
+
+#ifdef HAL_IWDG_MODULE_ENABLED
+ #include "stm32f4xx_hal_iwdg.h"
+#endif /* HAL_IWDG_MODULE_ENABLED */
+
+#ifdef HAL_LTDC_MODULE_ENABLED
+ #include "stm32f4xx_hal_ltdc.h"
+#endif /* HAL_LTDC_MODULE_ENABLED */
+
+#ifdef HAL_PWR_MODULE_ENABLED
+ #include "stm32f4xx_hal_pwr.h"
+#endif /* HAL_PWR_MODULE_ENABLED */
+
+#ifdef HAL_RNG_MODULE_ENABLED
+ #include "stm32f4xx_hal_rng.h"
+#endif /* HAL_RNG_MODULE_ENABLED */
+
+#ifdef HAL_RTC_MODULE_ENABLED
+ #include "stm32f4xx_hal_rtc.h"
+#endif /* HAL_RTC_MODULE_ENABLED */
+
+#ifdef HAL_SAI_MODULE_ENABLED
+ #include "stm32f4xx_hal_sai.h"
+#endif /* HAL_SAI_MODULE_ENABLED */
+
+#ifdef HAL_SD_MODULE_ENABLED
+ #include "stm32f4xx_hal_sd.h"
+#endif /* HAL_SD_MODULE_ENABLED */
+
+#ifdef HAL_SPI_MODULE_ENABLED
+ #include "stm32f4xx_hal_spi.h"
+#endif /* HAL_SPI_MODULE_ENABLED */
+
+#ifdef HAL_TIM_MODULE_ENABLED
+ #include "stm32f4xx_hal_tim.h"
+#endif /* HAL_TIM_MODULE_ENABLED */
+
+#ifdef HAL_UART_MODULE_ENABLED
+ #include "stm32f4xx_hal_uart.h"
+#endif /* HAL_UART_MODULE_ENABLED */
+
+#ifdef HAL_USART_MODULE_ENABLED
+ #include "stm32f4xx_hal_usart.h"
+#endif /* HAL_USART_MODULE_ENABLED */
+
+#ifdef HAL_IRDA_MODULE_ENABLED
+ #include "stm32f4xx_hal_irda.h"
+#endif /* HAL_IRDA_MODULE_ENABLED */
+
+#ifdef HAL_SMARTCARD_MODULE_ENABLED
+ #include "stm32f4xx_hal_smartcard.h"
+#endif /* HAL_SMARTCARD_MODULE_ENABLED */
+
+#ifdef HAL_WWDG_MODULE_ENABLED
+ #include "stm32f4xx_hal_wwdg.h"
+#endif /* HAL_WWDG_MODULE_ENABLED */
+
+#ifdef HAL_PCD_MODULE_ENABLED
+ #include "stm32f4xx_hal_pcd.h"
+#endif /* HAL_PCD_MODULE_ENABLED */
+
+#ifdef HAL_HCD_MODULE_ENABLED
+ #include "stm32f4xx_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 /* __STM32F4xx_HAL_CONF_H */
+
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/ports/stm32/boards/STM32F769DISC/mpconfigboard.h b/ports/stm32/boards/STM32F769DISC/mpconfigboard.h
new file mode 100644
index 000000000..50b9c1618
--- /dev/null
+++ b/ports/stm32/boards/STM32F769DISC/mpconfigboard.h
@@ -0,0 +1,78 @@
+// This board is confirmed to operate using stlink and openocd.
+// REPL is on UART(1) and is available through the stlink USB-UART device.
+// To use openocd run "OPENOCD_CONFIG=boards/openocd_stm32f7.cfg" in
+// the make command.
+#define MICROPY_HW_BOARD_NAME "F769DISC"
+#define MICROPY_HW_MCU_NAME "STM32F769"
+
+#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)
+
+// HSE is 25MHz
+// VCOClock = HSE * PLLN / PLLM = 25 MHz * 432 / 25 = 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 (25)
+#define MICROPY_HW_CLK_PLLN (432)
+#define MICROPY_HW_CLK_PLLP (RCC_PLLP_DIV2)
+#define MICROPY_HW_CLK_PLLQ (9)
+
+#define MICROPY_HW_FLASH_LATENCY FLASH_LATENCY_7 // 210-216 MHz needs 7 wait states
+
+// UART config
+#define MICROPY_HW_UART1_TX (pin_A9)
+#define MICROPY_HW_UART1_RX (pin_A10)
+#define MICROPY_HW_UART5_TX (pin_C12)
+#define MICROPY_HW_UART5_RX (pin_D2)
+#define MICROPY_HW_UART_REPL PYB_UART_1
+#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_SPI2_NSS (pin_A11)
+#define MICROPY_HW_SPI2_SCK (pin_A12)
+#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_A0)
+#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_J13) // red
+#define MICROPY_HW_LED2 (pin_J5) // green
+#define MICROPY_HW_LED3 (pin_A12) // green
+#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_high(pin))
+#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin))
+
+// SD card detect switch
+#define MICROPY_HW_SDMMC2_CK (pin_D6)
+#define MICROPY_HW_SDMMC2_CMD (pin_D7)
+#define MICROPY_HW_SDMMC2_D0 (pin_G9)
+#define MICROPY_HW_SDMMC2_D1 (pin_G10)
+#define MICROPY_HW_SDMMC2_D2 (pin_B3)
+#define MICROPY_HW_SDMMC2_D3 (pin_B4)
+#define MICROPY_HW_SDCARD_DETECT_PIN (pin_I15)
+#define MICROPY_HW_SDCARD_DETECT_PULL (GPIO_PULLUP)
+#define MICROPY_HW_SDCARD_DETECT_PRESENT (GPIO_PIN_RESET)
+
+// USB config (CN13 - USB OTG FS)
+/*#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
new file mode 100644
index 000000000..99234e4cf
--- /dev/null
+++ b/ports/stm32/boards/STM32F769DISC/mpconfigboard.mk
@@ -0,0 +1,5 @@
+MCU_SERIES = f7
+CMSIS_MCU = STM32F769xx
+MICROPY_FLOAT_IMPL = double
+AF_FILE = boards/stm32f767_af.csv
+LD_FILE = boards/stm32f769.ld
diff --git a/ports/stm32/boards/STM32F769DISC/pins.csv b/ports/stm32/boards/STM32F769DISC/pins.csv
new file mode 100644
index 000000000..dcc2df208
--- /dev/null
+++ b/ports/stm32/boards/STM32F769DISC/pins.csv
@@ -0,0 +1,57 @@
+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
+LED1,PJ13
+LED2,PJ5
+LED3,PA12
+SW,PI11
+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_D0,PG9
+SD_D1,PG10
+SD_D2,PB3
+SD_D3,PB4
+SD_CK,PD6
+SD_CMD,PD7
+SD_SW,PI15
+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
diff --git a/ports/stm32/boards/STM32F769DISC/stm32f7xx_hal_conf.h b/ports/stm32/boards/STM32F769DISC/stm32f7xx_hal_conf.h
new file mode 100644
index 000000000..ce8254902
--- /dev/null
+++ b/ports/stm32/boards/STM32F769DISC/stm32f7xx_hal_conf.h
@@ -0,0 +1,430 @@
+/**
+ ******************************************************************************
+ * @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 --------------------------------------------------------*/
+
+#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
+ */
+#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)25000000) /*!< 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/STM32F7DISC/board_init.c b/ports/stm32/boards/STM32F7DISC/board_init.c
new file mode 100644
index 000000000..4530a4706
--- /dev/null
+++ b/ports/stm32/boards/STM32F7DISC/board_init.c
@@ -0,0 +1,15 @@
+#include STM32_HAL_H
+
+void STM32F7DISC_board_early_init(void) {
+ GPIO_InitTypeDef GPIO_InitStructure;
+
+ __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;
+ 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
new file mode 100644
index 000000000..44a39c0a1
--- /dev/null
+++ b/ports/stm32/boards/STM32F7DISC/mpconfigboard.h
@@ -0,0 +1,82 @@
+#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_BOARD_EARLY_INIT STM32F7DISC_board_early_init
+void STM32F7DISC_board_early_init(void);
+
+// HSE is 25MHz
+// VCOClock = HSE * PLLN / PLLM = 25 MHz * 432 / 25 = 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 (25)
+#define MICROPY_HW_CLK_PLLN (432)
+#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_UART1_TX (pin_A9)
+#define MICROPY_HW_UART1_RX (pin_B7)
+#define MICROPY_HW_UART6_TX (pin_C6)
+#define MICROPY_HW_UART6_RX (pin_C7)
+#define MICROPY_HW_UART7_TX (pin_F6)
+#define MICROPY_HW_UART7_RX (pin_F7)
+#define MICROPY_HW_UART_REPL PYB_UART_1
+#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_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_I11)
+#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_I1) // green
+#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_high(pin))
+#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin))
+
+// SD card detect switch
+#define MICROPY_HW_SDCARD_DETECT_PIN (pin_C13)
+#define MICROPY_HW_SDCARD_DETECT_PULL (GPIO_PULLUP)
+#define MICROPY_HW_SDCARD_DETECT_PRESENT (GPIO_PIN_RESET)
+
+// USB config (CN13 - USB OTG FS)
+// 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_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
new file mode 100644
index 000000000..7c6bc4584
--- /dev/null
+++ b/ports/stm32/boards/STM32F7DISC/mpconfigboard.mk
@@ -0,0 +1,4 @@
+MCU_SERIES = f7
+CMSIS_MCU = STM32F746xx
+AF_FILE = boards/stm32f746_af.csv
+LD_FILE = boards/stm32f746.ld
diff --git a/ports/stm32/boards/STM32F7DISC/pins.csv b/ports/stm32/boards/STM32F7DISC/pins.csv
new file mode 100644
index 000000000..1aa8a9b3a
--- /dev/null
+++ b/ports/stm32/boards/STM32F7DISC/pins.csv
@@ -0,0 +1,53 @@
+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
+LED,PI1
+SW,PI11
+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_D0,PC8
+SD_D1,PC9
+SD_D2,PC10
+SD_D3,PC11
+SD_CK,PC12
+SD_CMD,PD2
+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,PJ12
+USB_ID,PA10
+USB_DM,PA11
+USB_DP,PA12
+VCP_TX,PA9
+VCP_RX,PB7
diff --git a/ports/stm32/boards/STM32F7DISC/stm32f7xx_hal_conf.h b/ports/stm32/boards/STM32F7DISC/stm32f7xx_hal_conf.h
new file mode 100644
index 000000000..3fbfb4310
--- /dev/null
+++ b/ports/stm32/boards/STM32F7DISC/stm32f7xx_hal_conf.h
@@ -0,0 +1,429 @@
+/**
+ ******************************************************************************
+ * @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 --------------------------------------------------------*/
+
+#define USE_USB_FS
+
+/* ########################## 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)25000000) /*!< 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/STM32L476DISC/board_init.c b/ports/stm32/boards/STM32L476DISC/board_init.c
new file mode 100644
index 000000000..fdc41c401
--- /dev/null
+++ b/ports/stm32/boards/STM32L476DISC/board_init.c
@@ -0,0 +1,10 @@
+#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);
+}
diff --git a/ports/stm32/boards/STM32L476DISC/mpconfigboard.h b/ports/stm32/boards/STM32L476DISC/mpconfigboard.h
new file mode 100644
index 000000000..9dbadd530
--- /dev/null
+++ b/ports/stm32/boards/STM32L476DISC/mpconfigboard.h
@@ -0,0 +1,68 @@
+#define MICROPY_BOARD_EARLY_INIT STM32L476DISC_board_early_init
+void STM32L476DISC_board_early_init(void);
+
+#define MICROPY_HW_BOARD_NAME "L476-DISCO"
+#define MICROPY_HW_MCU_NAME "STM32L476"
+
+#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)
+
+// use external SPI flash for storage
+#define MICROPY_HW_SPIFLASH_SIZE_BITS (128 * 1024 * 1024)
+#define MICROPY_HW_SPIFLASH_CS (pin_E11)
+#define MICROPY_HW_SPIFLASH_SCK (pin_E10)
+#define MICROPY_HW_SPIFLASH_MOSI (pin_E12)
+#define MICROPY_HW_SPIFLASH_MISO (pin_E13)
+
+// MSI is used and is 4MHz
+#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_D5)
+#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_B6)
+#define MICROPY_HW_I2C1_SDA (pin_B7)
+#define MICROPY_HW_I2C2_SCL (pin_B10)
+#define MICROPY_HW_I2C2_SDA (pin_B11)
+
+// SPI busses
+#define MICROPY_HW_SPI2_NSS (pin_D0)
+#define MICROPY_HW_SPI2_SCK (pin_D1)
+#define MICROPY_HW_SPI2_MISO (pin_D3)
+#define MICROPY_HW_SPI2_MOSI (pin_D4)
+
+// 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)
+#define MICROPY_HW_USRSW_EXTI_MODE (GPIO_MODE_IT_RISING)
+#define MICROPY_HW_USRSW_PRESSED (1)
+
+// LEDs
+#define MICROPY_HW_LED1 (pin_B2) // red
+#define MICROPY_HW_LED2 (pin_E8) // 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_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
new file mode 100644
index 000000000..72468d89c
--- /dev/null
+++ b/ports/stm32/boards/STM32L476DISC/mpconfigboard.mk
@@ -0,0 +1,6 @@
+MCU_SERIES = l4
+CMSIS_MCU = STM32L476xx
+AF_FILE = boards/stm32l476_af.csv
+LD_FILE = boards/stm32l476xg.ld
+TEXT_ADDR = 0x08004000
+OPENOCD_CONFIG = boards/openocd_stm32l4.cfg
diff --git a/ports/stm32/boards/STM32L476DISC/pins.csv b/ports/stm32/boards/STM32L476DISC/pins.csv
new file mode 100644
index 000000000..52f96b669
--- /dev/null
+++ b/ports/stm32/boards/STM32L476DISC/pins.csv
@@ -0,0 +1,114 @@
+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
diff --git a/ports/stm32/boards/STM32L476DISC/stm32l4xx_hal_conf.h b/ports/stm32/boards/STM32L476DISC/stm32l4xx_hal_conf.h
new file mode 100644
index 000000000..9348e0679
--- /dev/null
+++ b/ports/stm32/boards/STM32L476DISC/stm32l4xx_hal_conf.h
@@ -0,0 +1,373 @@
+/**
+ ******************************************************************************
+ * @file stm32l4xx_hal_conf.h
+ * @author MCD Application Team
+ * @version V1.2.0
+ * @date 25-November-2015
+ * @brief HAL configuration template file.
+ * This file should be copied to the application folder and renamed
+ * to stm32l4xx_hal_conf.h.
+ ******************************************************************************
+ * @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 __STM32L4xx_HAL_CONF_H
+#define __STM32L4xx_HAL_CONF_H
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+#define USE_USB_FS
+/* 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_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_DFSDM_MODULE_ENABLED */
+#define HAL_DMA_MODULE_ENABLED
+/* #define HAL_FIREWALL_MODULE_ENABLED */
+#define HAL_FLASH_MODULE_ENABLED
+/* #define HAL_HCD_MODULE_ENABLED */
+/* #define HAL_NAND_MODULE_ENABLED */
+/* #define HAL_NOR_MODULE_ENABLED */
+/* #define HAL_SRAM_MODULE_ENABLED */
+#define HAL_GPIO_MODULE_ENABLED
+#define HAL_I2C_MODULE_ENABLED
+/* #define HAL_IRDA_MODULE_ENABLED */
+/* #define HAL_IWDG_MODULE_ENABLED */
+/* #define HAL_LCD_MODULE_ENABLED */
+/* #define HAL_LPTIM_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_SMARTCARD_MODULE_ENABLED */
+/* #define HAL_SMBUS_MODULE_ENABLED */
+#define HAL_SPI_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 */
+
+
+/* ########################## 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 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 */
+
+/* Includes ------------------------------------------------------------------*/
+/**
+ * @brief Include module's header file
+ */
+
+#ifdef HAL_RCC_MODULE_ENABLED
+ #include "stm32l4xx_hal_rcc.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_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_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_OPAMP_MODULE_ENABLED
+#include "stm32l4xx_hal_opamp.h"
+#endif /* HAL_OPAMP_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 */
+
+/* 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 /* __STM32L4xx_HAL_CONF_H */
+
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/ports/stm32/boards/common.ld b/ports/stm32/boards/common.ld
new file mode 100644
index 000000000..e5dea49d0
--- /dev/null
+++ b/ports/stm32/boards/common.ld
@@ -0,0 +1,90 @@
+ENTRY(Reset_Handler)
+
+/* define output sections */
+SECTIONS
+{
+ /* The startup code goes first into FLASH */
+ .isr_vector :
+ {
+ . = ALIGN(4);
+ KEEP(*(.isr_vector)) /* Startup code */
+
+ /* This first flash block is 16K annd the isr vectors only take up
+ about 400 bytes. So we pull in a couple of object files to pad it
+ out. */
+
+ . = ALIGN(4);
+
+ /* NOTE: If you update the list of files contained in .isr_vector,
+ then be sure to also update smhal/Makefile where it forcibly
+ builds each of these files with -Os */
+
+ */ff.o(.text*)
+ */vfs_fat_*.o(.text*)
+ */py/formatfloat.o(.text*)
+ */py/parsenum.o(.text*)
+ */py/mpprint.o(.text*)
+
+ . = ALIGN(4);
+ } >FLASH_ISR
+
+ /* 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_TEXT
+
+ /* 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_TEXT
+
+ /* 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/make-pins.py b/ports/stm32/boards/make-pins.py
new file mode 100755
index 000000000..210c7b63c
--- /dev/null
+++ b/ports/stm32/boards/make-pins.py
@@ -0,0 +1,468 @@
+#!/usr/bin/env python
+"""Creates the pin file for the STM32F4xx."""
+
+from __future__ import print_function
+
+import argparse
+import sys
+import csv
+
+SUPPORTED_FN = {
+ 'TIM' : ['CH1', 'CH2', 'CH3', 'CH4',
+ 'CH1N', 'CH2N', 'CH3N', 'CH1_ETR', 'ETR', 'BKIN'],
+ 'I2C' : ['SDA', 'SCL'],
+ 'I2S' : ['CK', 'MCK', 'SD', 'WS', 'EXTSD'],
+ 'USART' : ['RX', 'TX', 'CTS', 'RTS', 'CK'],
+ 'UART' : ['RX', 'TX', 'CTS', 'RTS'],
+ 'SPI' : ['NSS', 'SCK', 'MISO', 'MOSI'],
+ 'SDMMC' : ['CK', 'CMD', 'D0', 'D1', 'D2', 'D3'],
+}
+
+CONDITIONAL_VAR = {
+ 'I2C' : 'MICROPY_HW_I2C{num}_SCL',
+ 'I2S' : 'MICROPY_HW_ENABLE_I2S{num}',
+ 'SPI' : 'MICROPY_HW_SPI{num}_SCK',
+ 'UART' : 'MICROPY_HW_UART{num}_TX',
+ 'USART' : 'MICROPY_HW_UART{num}_TX',
+ 'SDMMC' : 'MICROPY_HW_SDMMC{num}_CK',
+}
+
+def parse_port_pin(name_str):
+ """Parses a string and returns a (port-num, pin-num) tuple."""
+ if len(name_str) < 3:
+ raise ValueError("Expecting pin name to be at least 3 charcters.")
+ if name_str[0] != 'P':
+ raise ValueError("Expecting pin name to start with P")
+ if name_str[1] < 'A' or name_str[1] > 'K':
+ raise ValueError("Expecting pin port to be between A and K")
+ port = ord(name_str[1]) - ord('A')
+ pin_str = name_str[2:]
+ if not pin_str.isdigit():
+ raise ValueError("Expecting numeric pin number.")
+ return (port, int(pin_str))
+
+def split_name_num(name_num):
+ num = None
+ for num_idx in range(len(name_num) - 1, -1, -1):
+ if not name_num[num_idx].isdigit():
+ name = name_num[0:num_idx + 1]
+ num_str = name_num[num_idx + 1:]
+ if len(num_str) > 0:
+ num = int(num_str)
+ break
+ return name, num
+
+def conditional_var(name_num):
+ # Try the specific instance first. For example, if name_num is UART4_RX
+ # then try UART4 first, and then try UART second.
+ name, num = split_name_num(name_num)
+ var = []
+ if name in CONDITIONAL_VAR:
+ var.append(CONDITIONAL_VAR[name].format(num=num))
+ if name_num in CONDITIONAL_VAR:
+ var.append(CONDITIONAL_VAR[name_num])
+ return var
+
+def print_conditional_if(cond_var, file=None):
+ if cond_var:
+ cond_str = []
+ for var in cond_var:
+ if var.find('ENABLE') >= 0:
+ cond_str.append('(defined({0}) && {0})'.format(var))
+ else:
+ cond_str.append('defined({0})'.format(var))
+ print('#if ' + ' || '.join(cond_str), file=file)
+
+def print_conditional_endif(cond_var, file=None):
+ if cond_var:
+ print('#endif', file=file)
+
+
+class AlternateFunction(object):
+ """Holds the information associated with a pins alternate function."""
+
+ def __init__(self, idx, af_str):
+ self.idx = idx
+ # Special case. We change I2S2ext_SD into I2S2_EXTSD so that it parses
+ # the same way the other peripherals do.
+ af_str = af_str.replace('ext_', '_EXT')
+
+ self.af_str = af_str
+
+ self.func = ''
+ self.fn_num = None
+ self.pin_type = ''
+ self.supported = False
+
+ af_words = af_str.split('_', 1)
+ self.func, self.fn_num = split_name_num(af_words[0])
+ if len(af_words) > 1:
+ self.pin_type = af_words[1]
+ if self.func in SUPPORTED_FN:
+ pin_types = SUPPORTED_FN[self.func]
+ if self.pin_type in pin_types:
+ self.supported = True
+
+ def is_supported(self):
+ return self.supported
+
+ def ptr(self):
+ """Returns the numbered function (i.e. USART6) for this AF."""
+ if self.fn_num is None:
+ return self.func
+ return '{:s}{:d}'.format(self.func, self.fn_num)
+
+ def mux_name(self):
+ return 'AF{:d}_{:s}'.format(self.idx, self.ptr())
+
+ def print(self):
+ """Prints the C representation of this AF."""
+ cond_var = None
+ if self.supported:
+ cond_var = conditional_var('{}{}'.format(self.func, self.fn_num))
+ print_conditional_if(cond_var)
+ print(' AF', end='')
+ else:
+ print(' //', end='')
+ fn_num = self.fn_num
+ if fn_num is None:
+ fn_num = 0
+ print('({:2d}, {:8s}, {:2d}, {:10s}, {:8s}), // {:s}'.format(self.idx,
+ self.func, fn_num, self.pin_type, self.ptr(), self.af_str))
+ print_conditional_endif(cond_var)
+
+ def qstr_list(self):
+ return [self.mux_name()]
+
+
+class Pin(object):
+ """Holds the information associated with a pin."""
+
+ def __init__(self, port, pin):
+ self.port = port
+ self.pin = pin
+ self.alt_fn = []
+ self.alt_fn_count = 0
+ self.adc_num = 0
+ self.adc_channel = 0
+ self.board_pin = False
+
+ def port_letter(self):
+ return chr(self.port + ord('A'))
+
+ def cpu_pin_name(self):
+ return '{:s}{:d}'.format(self.port_letter(), self.pin)
+
+ def is_board_pin(self):
+ return self.board_pin
+
+ def set_is_board_pin(self):
+ self.board_pin = True
+
+ def parse_adc(self, adc_str):
+ if (adc_str[:3] != 'ADC'):
+ return
+ (adc,channel) = adc_str.split('_')
+ for idx in range(3, len(adc)):
+ adc_num = int(adc[idx]) # 1, 2, or 3
+ self.adc_num |= (1 << (adc_num - 1))
+ self.adc_channel = int(channel[2:])
+
+ def parse_af(self, af_idx, af_strs_in):
+ if len(af_strs_in) == 0:
+ return
+ # If there is a slash, then the slash separates 2 aliases for the
+ # same alternate function.
+ af_strs = af_strs_in.split('/')
+ for af_str in af_strs:
+ alt_fn = AlternateFunction(af_idx, af_str)
+ self.alt_fn.append(alt_fn)
+ if alt_fn.is_supported():
+ self.alt_fn_count += 1
+
+ def alt_fn_name(self, null_if_0=False):
+ if null_if_0 and self.alt_fn_count == 0:
+ return 'NULL'
+ return 'pin_{:s}_af'.format(self.cpu_pin_name())
+
+ def adc_num_str(self):
+ str = ''
+ for adc_num in range(1,4):
+ if self.adc_num & (1 << (adc_num - 1)):
+ if len(str) > 0:
+ str += ' | '
+ str += 'PIN_ADC'
+ str += chr(ord('0') + adc_num)
+ if len(str) == 0:
+ str = '0'
+ return str
+
+ def print(self):
+ if self.alt_fn_count == 0:
+ print("// ", end='')
+ print('const pin_af_obj_t {:s}[] = {{'.format(self.alt_fn_name()))
+ for alt_fn in self.alt_fn:
+ alt_fn.print()
+ if self.alt_fn_count == 0:
+ print("// ", end='')
+ print('};')
+ print('')
+ print('const pin_obj_t pin_{:s} = 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()))
+ if self.alt_fn_count > 0:
+ hdr_file.write('extern const pin_af_obj_t pin_{:s}_af[];\n'.
+ format(self.cpu_pin_name()))
+
+ def qstr_list(self):
+ result = []
+ for alt_fn in self.alt_fn:
+ if alt_fn.is_supported():
+ result += alt_fn.qstr_list()
+ return result
+
+
+class NamedPin(object):
+
+ def __init__(self, name, pin):
+ self._name = name
+ self._pin = pin
+
+ def pin(self):
+ return self._pin
+
+ def name(self):
+ return self._name
+
+
+class Pins(object):
+
+ def __init__(self):
+ self.cpu_pins = [] # list of NamedPin objects
+ self.board_pins = [] # list of NamedPin objects
+
+ def find_pin(self, port_num, pin_num):
+ for named_pin in self.cpu_pins:
+ pin = named_pin.pin()
+ if pin.port == port_num and pin.pin == pin_num:
+ return pin
+
+ def parse_af_file(self, filename, pinname_col, af_col):
+ with open(filename, 'r') as csvfile:
+ rows = csv.reader(csvfile)
+ for row in rows:
+ try:
+ (port_num, pin_num) = parse_port_pin(row[pinname_col])
+ except:
+ continue
+ pin = Pin(port_num, pin_num)
+ for af_idx in range(af_col, len(row)):
+ if af_idx < af_col + 16:
+ pin.parse_af(af_idx - af_col, row[af_idx])
+ elif af_idx == af_col + 16:
+ pin.parse_adc(row[af_idx])
+ self.cpu_pins.append(NamedPin(pin.cpu_pin_name(), pin))
+
+ def parse_board_file(self, filename):
+ with open(filename, 'r') as csvfile:
+ rows = csv.reader(csvfile)
+ for row in rows:
+ try:
+ (port_num, pin_num) = parse_port_pin(row[1])
+ except:
+ continue
+ pin = self.find_pin(port_num, pin_num)
+ if pin:
+ pin.set_is_board_pin()
+ self.board_pins.append(NamedPin(row[0], pin))
+
+ def print_named(self, label, named_pins):
+ print('STATIC const mp_rom_map_elem_t pin_{:s}_pins_locals_dict_table[] = {{'.format(label))
+ 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('};')
+ print('MP_DEFINE_CONST_DICT(pin_{:s}_pins_locals_dict, pin_{:s}_pins_locals_dict_table);'.format(label, label));
+
+ def print(self):
+ for named_pin in self.cpu_pins:
+ pin = named_pin.pin()
+ if pin.is_board_pin():
+ pin.print()
+ self.print_named('cpu', self.cpu_pins)
+ print('')
+ self.print_named('board', self.board_pins)
+
+ def print_adc(self, adc_num):
+ print('');
+ 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)')
+ 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))
+ adc_found = True
+ break
+ if not adc_found:
+ print(' NULL, // {:d}'.format(channel))
+ if channel == 16:
+ print('#endif')
+ print('};')
+
+
+ def print_header(self, hdr_filename):
+ with open(hdr_filename, 'wt') as hdr_file:
+ for named_pin in self.cpu_pins:
+ pin = named_pin.pin()
+ if pin.is_board_pin():
+ pin.print_header(hdr_file)
+ hdr_file.write('extern const pin_obj_t * const pin_adc1[];\n')
+ hdr_file.write('extern const pin_obj_t * const pin_adc2[];\n')
+ hdr_file.write('extern const pin_obj_t * const pin_adc3[];\n')
+ # provide #define's mapping board to cpu name
+ for named_pin in self.board_pins:
+ hdr_file.write("#define pyb_pin_{:s} pin_{:s}\n".format(named_pin.name(), named_pin.pin().cpu_pin_name()))
+
+ def print_qstr(self, qstr_filename):
+ with open(qstr_filename, 'wt') as qstr_file:
+ qstr_set = set([])
+ for named_pin in self.cpu_pins:
+ pin = named_pin.pin()
+ if pin.is_board_pin():
+ qstr_set |= set(pin.qstr_list())
+ qstr_set |= set([named_pin.name()])
+ for named_pin in self.board_pins:
+ qstr_set |= set([named_pin.name()])
+ for qstr in sorted(qstr_set):
+ cond_var = None
+ if qstr.startswith('AF'):
+ af_words = qstr.split('_')
+ cond_var = conditional_var(af_words[1])
+ print_conditional_if(cond_var, file=qstr_file)
+ print('Q({})'.format(qstr), file=qstr_file)
+ print_conditional_endif(cond_var, file=qstr_file)
+
+ def print_af_hdr(self, af_const_filename):
+ with open(af_const_filename, 'wt') as af_const_file:
+ af_hdr_set = set([])
+ mux_name_width = 0
+ for named_pin in self.cpu_pins:
+ pin = named_pin.pin()
+ if pin.is_board_pin():
+ for af in pin.alt_fn:
+ if af.is_supported():
+ mux_name = af.mux_name()
+ af_hdr_set |= set([mux_name])
+ if len(mux_name) > mux_name_width:
+ mux_name_width = len(mux_name)
+ for mux_name in sorted(af_hdr_set):
+ af_words = mux_name.split('_') # ex mux_name: AF9_I2C2
+ cond_var = conditional_var(af_words[1])
+ print_conditional_if(cond_var, file=af_const_file)
+ key = 'MP_ROM_QSTR(MP_QSTR_{}),'.format(mux_name)
+ val = 'MP_ROM_INT(GPIO_{})'.format(mux_name)
+ print(' { %-*s %s },' % (mux_name_width + 26, key, val),
+ file=af_const_file)
+ print_conditional_endif(cond_var, file=af_const_file)
+
+ def print_af_py(self, af_py_filename):
+ with open(af_py_filename, 'wt') as af_py_file:
+ print('PINS_AF = (', file=af_py_file);
+ for named_pin in self.board_pins:
+ print(" ('%s', " % named_pin.name(), end='', file=af_py_file)
+ for af in named_pin.pin().alt_fn:
+ if af.is_supported():
+ print("(%d, '%s'), " % (af.idx, af.af_str), end='', file=af_py_file)
+ print('),', file=af_py_file)
+ print(')', file=af_py_file)
+
+
+def main():
+ parser = argparse.ArgumentParser(
+ prog="make-pins.py",
+ usage="%(prog)s [options] [command]",
+ description="Generate board specific pin file"
+ )
+ parser.add_argument(
+ "-a", "--af",
+ dest="af_filename",
+ help="Specifies the alternate function file for the chip",
+ default="stm32f4xx_af.csv"
+ )
+ parser.add_argument(
+ "--af-const",
+ dest="af_const_filename",
+ help="Specifies header file for alternate function constants.",
+ default="build/pins_af_const.h"
+ )
+ parser.add_argument(
+ "--af-py",
+ dest="af_py_filename",
+ help="Specifies the filename for the python alternate function mappings.",
+ default="build/pins_af.py"
+ )
+ parser.add_argument(
+ "-b", "--board",
+ dest="board_filename",
+ help="Specifies the board file",
+ )
+ parser.add_argument(
+ "-p", "--prefix",
+ dest="prefix_filename",
+ help="Specifies beginning portion of generated pins file",
+ default="stm32f4xx_prefix.c"
+ )
+ parser.add_argument(
+ "-q", "--qstr",
+ dest="qstr_filename",
+ help="Specifies name of generated qstr header file",
+ default="build/pins_qstr.h"
+ )
+ parser.add_argument(
+ "-r", "--hdr",
+ dest="hdr_filename",
+ help="Specifies name of generated pin header file",
+ default="build/pins.h"
+ )
+ args = parser.parse_args(sys.argv[1:])
+
+ pins = Pins()
+
+ print('// This file was automatically generated by make-pins.py')
+ print('//')
+ if args.af_filename:
+ print('// --af {:s}'.format(args.af_filename))
+ pins.parse_af_file(args.af_filename, 1, 2)
+
+ if args.board_filename:
+ print('// --board {:s}'.format(args.board_filename))
+ pins.parse_board_file(args.board_filename)
+
+ if args.prefix_filename:
+ print('// --prefix {:s}'.format(args.prefix_filename))
+ print('')
+ with open(args.prefix_filename, 'r') as prefix_file:
+ print(prefix_file.read())
+ pins.print()
+ pins.print_adc(1)
+ pins.print_adc(2)
+ pins.print_adc(3)
+ pins.print_header(args.hdr_filename)
+ pins.print_qstr(args.qstr_filename)
+ pins.print_af_hdr(args.af_const_filename)
+ pins.print_af_py(args.af_py_filename)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ports/stm32/boards/openocd_stm32f4.cfg b/ports/stm32/boards/openocd_stm32f4.cfg
new file mode 100644
index 000000000..ee96b91bd
--- /dev/null
+++ b/ports/stm32/boards/openocd_stm32f4.cfg
@@ -0,0 +1,42 @@
+# This script configures OpenOCD for use with an ST-Link V2 programmer/debugger
+# and an STM32F4 target microcontroller.
+#
+# To flash your firmware:
+#
+# $ openocd -f openocd_stm32f4.cfg \
+# -c "stm_flash build-BOARD/firmware0.bin 0x08000000 build-BOARD/firmware1.bin 0x08020000"
+#
+# For a gdb server on port 3333:
+#
+# $ openocd -f openocd_stm32f4.cfg
+
+
+source [find interface/stlink-v2.cfg]
+transport select hla_swd
+source [find target/stm32f4x.cfg]
+reset_config srst_only
+init
+
+proc stm_flash { BIN0 ADDR0 BIN1 ADDR1 } {
+ reset halt
+ sleep 100
+ wait_halt 2
+ flash write_image erase $BIN0 $ADDR0
+ sleep 100
+ verify_image $BIN0 $ADDR0
+ sleep 100
+ flash write_image erase $BIN1 $ADDR1
+ sleep 100
+ verify_image $BIN1 $ADDR1
+ sleep 100
+ reset run
+ shutdown
+}
+
+proc stm_erase {} {
+ reset halt
+ sleep 100
+ stm32f4x mass_erase 0
+ sleep 100
+ shutdown
+}
diff --git a/ports/stm32/boards/openocd_stm32f7.cfg b/ports/stm32/boards/openocd_stm32f7.cfg
new file mode 100644
index 000000000..55b632650
--- /dev/null
+++ b/ports/stm32/boards/openocd_stm32f7.cfg
@@ -0,0 +1,42 @@
+# This script configures OpenOCD for use with an ST-Link V2 programmer/debugger
+# and an STM32F7 target microcontroller.
+#
+# To flash your firmware:
+#
+# $ openocd -f openocd_stm32f7.cfg \
+# -c "stm_flash build-BOARD/firmware0.bin 0x08000000 build-BOARD/firmware1.bin 0x08020000"
+#
+# For a gdb server on port 3333:
+#
+# $ openocd -f openocd_stm32f7.cfg
+
+
+source [find interface/stlink-v2-1.cfg]
+transport select hla_swd
+source [find target/stm32f7x.cfg]
+reset_config srst_only
+init
+
+proc stm_flash { BIN0 ADDR0 BIN1 ADDR1 } {
+ reset halt
+ sleep 100
+ wait_halt 2
+ flash write_image erase $BIN0 $ADDR0
+ sleep 100
+ verify_image $BIN0 $ADDR0
+ sleep 100
+ flash write_image erase $BIN1 $ADDR1
+ sleep 100
+ verify_image $BIN1 $ADDR1
+ sleep 100
+ reset run
+ shutdown
+}
+
+proc stm_erase {} {
+ reset halt
+ sleep 100
+ stm32f7x mass_erase 0
+ sleep 100
+ shutdown
+}
diff --git a/ports/stm32/boards/openocd_stm32l4.cfg b/ports/stm32/boards/openocd_stm32l4.cfg
new file mode 100644
index 000000000..59e98de03
--- /dev/null
+++ b/ports/stm32/boards/openocd_stm32l4.cfg
@@ -0,0 +1,42 @@
+# This script configures OpenOCD for use with an ST-Link V2 programmer/debugger
+# and an STM32L4 target microcontroller.
+#
+# To flash your firmware:
+#
+# $ openocd -f openocd_stm32l4.cfg \
+# -c "stm_flash build-BOARD/firmware0.bin 0x08000000 build-BOARD/firmware1.bin 0x08004000"
+#
+# For a gdb server on port 3333:
+#
+# $ openocd -f openocd_stm32l4.cfg
+
+
+source [find interface/stlink-v2-1.cfg]
+transport select hla_swd
+source [find target/stm32l4x.cfg]
+reset_config srst_only
+init
+
+proc stm_flash { BIN0 ADDR0 BIN1 ADDR1 } {
+ reset halt
+ sleep 100
+ wait_halt 2
+ flash write_image erase $BIN0 $ADDR0
+ sleep 100
+ verify_image $BIN0 $ADDR0
+ sleep 100
+ flash write_image erase $BIN1 $ADDR1
+ sleep 100
+ verify_image $BIN1 $ADDR1
+ sleep 100
+ reset run
+ shutdown
+}
+
+proc stm_erase {} {
+ reset halt
+ sleep 100
+ stm32l4x mass_erase 0
+ sleep 100
+ shutdown
+}
diff --git a/ports/stm32/boards/pllvalues.py b/ports/stm32/boards/pllvalues.py
new file mode 100644
index 000000000..befd6cfa0
--- /dev/null
+++ b/ports/stm32/boards/pllvalues.py
@@ -0,0 +1,165 @@
+"""
+This is an auxiliary script that is used to compute valid PLL values to set
+the CPU frequency to a given value. The algorithm here appears as C code
+for the machine.freq() function.
+"""
+
+from __future__ import print_function
+
+def close_int(x):
+ return abs(x - round(x)) < 0.01
+
+# original version that requires N/M to be an integer (for simplicity)
+def compute_pll(hse, sys):
+ for P in (2, 4, 6, 8): # allowed values of P
+ Q = sys * P / 48
+ NbyM = sys * P / hse
+ # N/M and Q must be integers
+ if not (close_int(NbyM) and close_int(Q)):
+ continue
+ # VCO_OUT must be between 192MHz and 432MHz
+ if not (192 <= hse * NbyM <= 432):
+ continue
+ # compute M
+ M = int(192 // NbyM)
+ while hse > 2 * M or NbyM * M < 192:
+ M += 1
+ # VCO_IN must be between 1MHz and 2MHz (2MHz recommended)
+ if not (M <= hse):
+ continue
+ # compute N
+ N = NbyM * M
+ # N and Q are restricted
+ if not (192 <= N <= 432 and 2 <= Q <= 15):
+ continue
+ # found valid values
+ assert NbyM == N // M
+ return (M, N, P, Q)
+ # no valid values found
+ return None
+
+# improved version that doesn't require N/M to be an integer
+def compute_pll2(hse, sys):
+ # Loop over the allowed values of P, looking for a valid PLL configuration
+ # that gives the desired "sys" frequency. We use floats for P to force
+ # floating point arithmetic on Python 2.
+ for P in (2.0, 4.0, 6.0, 8.0):
+ Q = sys * P / 48
+ # Q must be an integer in a set range
+ if not (close_int(Q) and 2 <= Q <= 15):
+ continue
+ NbyM = sys * P / hse
+ # VCO_OUT must be between 192MHz and 432MHz
+ if not (192 <= hse * NbyM <= 432):
+ continue
+ # compute M
+ M = 192 // NbyM # starting value
+ while hse > 2 * M or NbyM * M < 192 or not close_int(NbyM * M):
+ M += 1
+ # VCO_IN must be between 1MHz and 2MHz (2MHz recommended)
+ if not (M <= hse):
+ continue
+ # compute N
+ N = NbyM * M
+ # N must be an integer
+ if not close_int(N):
+ continue
+ # N is restricted
+ if not (192 <= N <= 432):
+ continue
+ # found valid values
+ return (M, N, P, Q)
+ # no valid values found
+ return None
+
+def compute_derived(hse, pll):
+ M, N, P, Q = pll
+ vco_in = hse / M
+ vco_out = hse * N / M
+ pllck = hse / M * N / P
+ pll48ck = hse / M * N / Q
+ return (vco_in, vco_out, pllck, pll48ck)
+
+def verify_pll(hse, pll):
+ M, N, P, Q = pll
+ vco_in, vco_out, pllck, pll48ck = compute_derived(hse, pll)
+
+ # verify ints
+ assert close_int(M)
+ assert close_int(N)
+ assert close_int(P)
+ assert close_int(Q)
+
+ # verify range
+ assert 2 <= M <= 63
+ assert 192 <= N <= 432
+ assert P in (2, 4, 6, 8)
+ assert 2 <= Q <= 15
+ assert 1 <= vco_in <= 2
+ assert 192 <= vco_out <= 432
+
+def generate_c_table(hse, valid_plls):
+ valid_plls = valid_plls + [(16, (0, 0, 2, 0))]
+ if hse < 16:
+ valid_plls.append((hse, (1, 0, 2, 0)))
+ valid_plls.sort()
+ print("// (M, P/2-1, SYS) values for %u MHz HSE" % hse)
+ print("static const uint16_t pll_freq_table[%u] = {" % len(valid_plls))
+ for sys, (M, N, P, Q) in valid_plls:
+ print(" (%u << 10) | (%u << 8) | %u," % (M, P // 2 - 1, sys))
+ print("};")
+
+def print_table(hse, valid_plls):
+ print("HSE =", hse, "MHz")
+ print("sys : M N P Q : VCO_IN VCO_OUT PLLCK PLL48CK")
+ out_format = "%3u : %2u %.1f %.2f %.2f : %5.2f %6.2f %6.2f %6.2f"
+ for sys, pll in valid_plls:
+ print(out_format % ((sys,) + pll + compute_derived(hse, pll)))
+ print("found %u valid configurations" % len(valid_plls))
+
+def main():
+ global out_format
+
+ # parse input args
+ import sys
+ argv = sys.argv[1:]
+
+ c_table = False
+ if argv[0] == '-c':
+ c_table = True
+ argv.pop(0)
+
+ if len(argv) != 1:
+ print("usage: pllvalues.py [-c] <hse in MHz>")
+ sys.exit(1)
+
+ if argv[0].startswith("file:"):
+ # extract HSE_VALUE from header file
+ with open(argv[0][5:]) as f:
+ for line in f:
+ line = line.strip()
+ if line.startswith("#define") and line.find("HSE_VALUE") != -1:
+ idx_start = line.find("((uint32_t)") + 11
+ idx_end = line.find(")", idx_start)
+ hse = int(line[idx_start:idx_end]) // 1000000
+ break
+ else:
+ raise ValueError("%s does not contain a definition of HSE_VALUE" % argv[0])
+ else:
+ # HSE given directly as an integer
+ hse = int(argv[0])
+
+ valid_plls = []
+ for sysclk in range(1, 217):
+ pll = compute_pll2(hse, sysclk)
+ if pll is not None:
+ verify_pll(hse, pll)
+ valid_plls.append((sysclk, pll))
+
+ if c_table:
+ generate_c_table(hse, valid_plls)
+ else:
+ print_table(hse, valid_plls)
+
+if __name__ == "__main__":
+ main()
diff --git a/ports/stm32/boards/stm32f401_af.csv b/ports/stm32/boards/stm32f401_af.csv
new file mode 100644
index 000000000..3b29e1349
--- /dev/null
+++ b/ports/stm32/boards/stm32f401_af.csv
@@ -0,0 +1,83 @@
+Port,,AF0,AF1,AF2,AF3,AF4,AF5,AF6,AF7,AF8,AF9,AF10,AF11,AF12,AF13,AF14,AF15,
+,,SYS_AF,TIM1/TIM2,TIM3/TIM4/TIM5,TIM9/TIM10/TIM11,I2C1/I2C2/I2C3,SPI1/SPI2/I2S2/SPI3/I2S3/SPI4,SPI2/I2S2/SPI3/I2S3,SPI3/I2S3/USART1/USART2,USART6,I2C2/I2C3,OTG1_FS,,SDIO,,,,ADC
+PortA,PA0,,TIM2_CH1/TIM2_ETR,TIM5_CH1,,,,,USART2_CTS,,,,,,,,EVENTOUT,ADC1_IN0
+PortA,PA1,,TIM2_CH2,TIM5_CH2,,,,,USART2_RTS,,,,,,,,EVENTOUT,ADC1_IN1
+PortA,PA2,,TIM2_CH3,TIM5_CH3,TIM9_CH1,,,,USART2_TX,,,,,,,,EVENTOUT,ADC1_IN2
+PortA,PA3,,TIM2_CH4,TIM5_CH4,TIM9_CH2,,,,USART2_RX,,,,,,,,EVENTOUT,ADC1_IN3
+PortA,PA4,,,,,,SPI1_NSS,SPI3_NSS/I2S3_WS,USART2_CK,,,,,,,,EVENTOUT,ADC1_IN4
+PortA,PA5,,TIM2_CH1/TIM2_ETR,,,,SPI1_SCK,,,,,,,,,,EVENTOUT,ADC1_IN5
+PortA,PA6,,TIM1_BKIN,TIM3_CH1,,,SPI1_MISO,,,,,,,,,,EVENTOUT,ADC1_IN6
+PortA,PA7,,TIM1_CH1N,TIM3_CH2,,,SPI1_MOSI,,,,,,,,,,EVENTOUT,ADC1_IN7
+PortA,PA8,MCO_1,TIM1_CH1,,,I2C3_SCL,,,USART1_CK,,,OTG_FS_SOF,,,,,EVENTOUT,
+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,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,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,
+PortB,PB7,,,TIM4_CH2,,I2C1_SDA,,,USART1_RX,,,,,,,,EVENTOUT,
+PortB,PB8,,,TIM4_CH3,TIM10_CH1,I2C1_SCL,,,,,,,,SDIO_D4,,,EVENTOUT,
+PortB,PB9,,,TIM4_CH4,TIM11_CH1,I2C1_SDA,SPI2_NSS/I2S2_WS,,,,,,,SDIO_D5,,,EVENTOUT,
+PortB,PB10,,TIM2_CH3,,,I2C2_SCL,SPI2_SCK/I2S2_CK,,,,,,,,,,EVENTOUT,
+PortB,PB12,,TIM1_BKIN,,,I2C2_SMBA,SPI2_NSS/I2S2_WS,,,,,,,,,,EVENTOUT,
+PortB,PB13,,TIM1_CH1N,,,,SPI2_SCK/I2S2_CK,,,,,,,,,,EVENTOUT,
+PortB,PB14,,TIM1_CH2N,,,,SPI2_MISO,I2S2ext_SD,,,,,,,,,EVENTOUT,
+PortB,PB15,RTC_REFIN,TIM1_CH3N,,,,SPI2_MOSI/I2S2_SD,,,,,,,,,,EVENTOUT,
+PortC,PC0,,,,,,,,,,,,,,,,EVENTOUT,ADC1_IN10
+PortC,PC1,,,,,,,,,,,,,,,,EVENTOUT,ADC1_IN11
+PortC,PC2,,,,,,SPI2_MISO,I2S2ext_SD,,,,,,,,,EVENTOUT,ADC1_IN12
+PortC,PC3,,,,,,SPI2_MOSI/I2S2_SD,,,,,,,,,,EVENTOUT,ADC1_IN13
+PortC,PC4,,,,,,,,,,,,,,,,EVENTOUT,ADC1_IN14
+PortC,PC5,,,,,,,,,,,,,,,,EVENTOUT,ADC1_IN15
+PortC,PC6,,,TIM3_CH1,,,I2S2_MCK,,,USART6_TX,,,,SDIO_D6,,,EVENTOUT,
+PortC,PC7,,,TIM3_CH2,,,,I2S3_MCK,,USART6_RX,,,,SDIO_D7,,,EVENTOUT,
+PortC,PC8,,,TIM3_CH3,,,,,,USART6_CK,,,,SDIO_D0,,,EVENTOUT,
+PortC,PC9,MCO_2,,TIM3_CH4,,I2C3_SDA,I2S_CKIN,,,,,,,SDIO_D1,,,EVENTOUT,
+PortC,PC10,,,,,,,SPI3_SCK/I2S3_CK,,,,,,SDIO_D2,,,EVENTOUT,
+PortC,PC11,,,,,,I2S3ext_SD,SPI3_MISO,,,,,,SDIO_D3,,,EVENTOUT,
+PortC,PC12,,,,,,,SPI3_MOSI/I2S3_SD,,,,,,SDIO_CK,,,EVENTOUT,
+PortC,PC13,,,,,,,,,,,,,,,,EVENTOUT,
+PortC,PC14,,,,,,,,,,,,,,,,EVENTOUT,
+PortC,PC15,,,,,,,,,,,,,,,,EVENTOUT,
+PortD,PD0,,,,,,,,,,,,,,,,EVENTOUT,
+PortD,PD1,,,,,,,,,,,,,,,,EVENTOUT,
+PortD,PD2,,,TIM3_ETR,,,,,,,,,,SDIO_CMD,,,EVENTOUT,
+PortD,PD3,,,,,,SPI2_SCK/I2S2_CK,,USART2_CTS,,,,,,,,EVENTOUT,
+PortD,PD4,,,,,,,,USART2_RTS,,,,,,,,EVENTOUT,
+PortD,PD5,,,,,,,,USART2_TX,,,,,,,,EVENTOUT,
+PortD,PD6,,,,,,SPI3_MOSI/I2S3_SD,,USART2_RX,,,,,,,,EVENTOUT,
+PortD,PD7,,,,,,,,USART2_CK,,,,,,,,EVENTOUT,
+PortD,PD8,,,,,,,,,,,,,,,,EVENTOUT,
+PortD,PD9,,,,,,,,,,,,,,,,EVENTOUT,
+PortD,PD10,,,,,,,,,,,,,,,,EVENTOUT,
+PortD,PD11,,,,,,,,,,,,,,,,EVENTOUT,
+PortD,PD12,,,TIM4_CH1,,,,,,,,,,,,,EVENTOUT,
+PortD,PD13,,,TIM4_CH2,,,,,,,,,,,,,EVENTOUT,
+PortD,PD14,,,TIM4_CH3,,,,,,,,,,,,,EVENTOUT,
+PortD,PD15,,,TIM4_CH4,,,,,,,,,,,,,EVENTOUT,
+PortE,PE0,,,TIM4_ETR,,,,,,,,,,,,,EVENTOUT,
+PortE,PE1,,TIM1_CH2N,,,,,,,,,,,,,,EVENTOUT,
+PortE,PE2,TRACECLK,,,,,SPI4_SCK,,,,,,,,,,EVENTOUT,
+PortE,PE3,TRACED0,,,,,,,,,,,,,,,EVENTOUT,
+PortE,PE4,TRACED1,,,,,SPI4_NSS,,,,,,,,,,EVENTOUT,
+PortE,PE5,TRACED2,,,TIM9_CH1,,SPI4_MISO,,,,,,,,,,EVENTOUT,
+PortE,PE6,TRACED3,,,TIM9_CH2,,SPI4_MOSI,,,,,,,,,,EVENTOUT,
+PortE,PE7,,TIM1_ETR,,,,,,,,,,,,,,EVENTOUT,
+PortE,PE8,,TIM1_CH1N,,,,,,,,,,,,,,EVENTOUT,
+PortE,PE9,,TIM1_CH1,,,,,,,,,,,,,,EVENTOUT,
+PortE,PE10,,TIM1_CH2N,,,,,,,,,,,,,,EVENTOUT,
+PortE,PE11,,TIM1_CH2,,,,SPI4_NSS,,,,,,,,,,EVENTOUT,
+PortE,PE12,,TIM1_CH3N,,,,SPI4_SCK,,,,,,,,,,EVENTOUT,
+PortE,PE13,,TIM1_CH3,,,,SPI4_MISO,,,,,,,,,,EVENTOUT,
+PortE,PE14,,TIM1_CH4,,,,SPI4_MOSI,,,,,,,,,,EVENTOUT,
+PortE,PE15,,TIM1_BKIN,,,,,,,,,,,,,,EVENTOUT,
+PortH,PH0,,,,,,,,,,,,,,,,EVENTOUT,
+PortH,PH1,,,,,,,,,,,,,,,,EVENTOUT,
diff --git a/ports/stm32/boards/stm32f401xd.ld b/ports/stm32/boards/stm32f401xd.ld
new file mode 100644
index 000000000..415c25849
--- /dev/null
+++ b/ports/stm32/boards/stm32f401xd.ld
@@ -0,0 +1,31 @@
+/*
+ GNU linker script for STM32F401xD
+*/
+
+/* Specify the memory areas */
+MEMORY
+{
+ FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 0x060000 /* entire flash, 384 KiB */
+ FLASH_ISR (rx) : ORIGIN = 0x08000000, LENGTH = 0x004000 /* sector 0, 16 KiB */
+ FLASH_FS (rx) : ORIGIN = 0x08004000, LENGTH = 0x01C000 /* sectors 1,2,3 are 16K, 4 is 64K */
+ FLASH_TEXT (rx) : ORIGIN = 0x08020000, LENGTH = 0x040000 /* sectors 5,6 2*128KiB = 256 KiB */
+ RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 0x018000 /* 96 KiB */
+}
+
+/* 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);
+
+/* define common sections and symbols */
+INCLUDE common.ld
+
+/* 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 = 0x20014000; /* tunable */
diff --git a/ports/stm32/boards/stm32f401xe.ld b/ports/stm32/boards/stm32f401xe.ld
new file mode 100644
index 000000000..a2e693b49
--- /dev/null
+++ b/ports/stm32/boards/stm32f401xe.ld
@@ -0,0 +1,31 @@
+/*
+ GNU linker script for STM32F401xE
+*/
+
+/* Specify the memory areas */
+MEMORY
+{
+ FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 0x080000 /* entire flash, 512 KiB */
+ FLASH_ISR (rx) : ORIGIN = 0x08000000, LENGTH = 0x004000 /* sector 0, 16 KiB */
+ FLASH_FS (rx) : ORIGIN = 0x08004000, LENGTH = 0x01C000 /* sectors 1,2,3 are 16K, 4 is 64K */
+ FLASH_TEXT (rx) : ORIGIN = 0x08020000, LENGTH = 0x060000 /* sectors 5,6,7 3*128KiB = 384 KiB */
+ RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 0x018000 /* 96 KiB */
+}
+
+/* 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);
+
+/* define common sections and symbols */
+INCLUDE common.ld
+
+/* 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 = 0x20014000; /* tunable */
diff --git a/ports/stm32/boards/stm32f405.ld b/ports/stm32/boards/stm32f405.ld
new file mode 100644
index 000000000..c6107913f
--- /dev/null
+++ b/ports/stm32/boards/stm32f405.ld
@@ -0,0 +1,32 @@
+/*
+ GNU linker script for STM32F405
+*/
+
+/* Specify the memory areas */
+MEMORY
+{
+ FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1024K /* entire flash */
+ FLASH_ISR (rx) : ORIGIN = 0x08000000, LENGTH = 16K /* sector 0 */
+ FLASH_FS (rx) : ORIGIN = 0x08004000, LENGTH = 112K /* sectors 1,2,3,4 are for filesystem */
+ FLASH_TEXT (rx) : ORIGIN = 0x08020000, LENGTH = 896K /* sectors 5,6,7,8,9,10,11 */
+ CCMRAM (xrw) : ORIGIN = 0x10000000, LENGTH = 64K
+ RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K
+}
+
+/* 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);
+
+/* define common sections and symbols */
+INCLUDE common.ld
+
+/* 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 = 0x2001c000; /* tunable */
diff --git a/ports/stm32/boards/stm32f405_af.csv b/ports/stm32/boards/stm32f405_af.csv
new file mode 100644
index 000000000..81f5e80ed
--- /dev/null
+++ b/ports/stm32/boards/stm32f405_af.csv
@@ -0,0 +1,142 @@
+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,I2C1/2/3,SPI1/SPI2/I2S2/I2S2ext,SPI3/I2Sext/I2S3,USART1/2/3/I2S3ext,UART4/5/USART6,CAN1/CAN2/TIM12/13/14,OTG_FS/OTG_HS,ETH,FSMC/SDIO/OTG_FS,DCMI,,,ADC
+PortA,PA0,,TIM2_CH1/TIM2_ETR,TIM5_CH1,TIM8_ETR,,,,USART2_CTS,UART4_TX,,,ETH_MII_CRS,,,,EVENTOUT,ADC123_IN0
+PortA,PA1,,TIM2_CH2,TIM5_CH2,,,,,USART2_RTS,UART4_RX,,,ETH_MII_RX_CLK/ETH_RMII__REF_CLK,,,,EVENTOUT,ADC123_IN1
+PortA,PA2,,TIM2_CH3,TIM5_CH3,TIM9_CH1,,,,USART2_TX,,,,ETH_MDIO,,,,EVENTOUT,ADC123_IN2
+PortA,PA3,,TIM2_CH4,TIM5_CH4,TIM9_CH2,,,,USART2_RX,,,OTG_HS_ULPI_D0,ETH_MII_COL,,,,EVENTOUT,ADC123_IN3
+PortA,PA4,,,,,,SPI1_NSS,SPI3_NSS/I2S3_WS,USART2_CK,,,,,OTG_HS_SOF,DCMI_HSYNC,,EVENTOUT,ADC12_IN4
+PortA,PA5,,TIM2_CH1/TIM2_ETR,,TIM8_CH1N,,SPI1_SCK,,,,,OTG_HS_ULPI_CK,,,,,EVENTOUT,ADC12_IN5
+PortA,PA6,,TIM1_BKIN,TIM3_CH1,TIM8_BKIN,,SPI1_MISO,,,,TIM13_CH1,,,,DCMI_PIXCK,,EVENTOUT,ADC12_IN6
+PortA,PA7,,TIM1_CH1N,TIM3_CH2,TIM8_CH1N,,SPI1_MOSI,,,,TIM14_CH1,,ETH_MII_RX_DV/ETH_RMII_CRS_DV,,,,EVENTOUT,ADC12_IN7
+PortA,PA8,MCO1,TIM1_CH1,,,I2C3_SCL,,,USART1_CK,,,OTG_FS_SOF,,,,,EVENTOUT,
+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,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
+PortB,PB2,,,,,,,,,,,,,,,,EVENTOUT,
+PortB,PB3,JTDO/TRACESWO,TIM2_CH2,,,,SPI1_SCK,SPI3_SCK/I2S3_CK,,,,,,,,,EVENTOUT,
+PortB,PB4,NJTRST,,TIM3_CH1,,,SPI1_MISO,SPI3_MISO,I2S3ext_SD,,,,,,,,EVENTOUT,
+PortB,PB5,,,TIM3_CH2,,I2C1_SMBA,SPI1_MOSI,SPI3_MOSI/I2S3_SD,,,CAN2_RX,OTG_HS_ULPI_D7,ETH_PPS_OUT,,DCMI_D10,,EVENTOUT,
+PortB,PB6,,,TIM4_CH1,,I2C1_SCL,,,USART1_TX,,CAN2_TX,,,,DCMI_D5,,EVENTOUT,
+PortB,PB7,,,TIM4_CH2,,I2C1_SDA,,,USART1_RX,,,,,FSMC_NL,DCMI_VSYNC,,EVENTOUT,
+PortB,PB8,,,TIM4_CH3,TIM10_CH1,I2C1_SCL,,,,,CAN1_RX,,ETH_MII_TXD3,SDIO_D4,DCMI_D6,,EVENTOUT,
+PortB,PB9,,,TIM4_CH4,TIM11_CH1,I2C1_SDA,SPI2_NSS/I2S2_WS,,,,CAN1_TX,,,SDIO_D5,DCMI_D7,,EVENTOUT,
+PortB,PB10,,TIM2_CH3,,,I2C2_SCL,SPI2_SCK/I2S2_CK,,USART3_TX,,,OTG_HS_ULPI_D3,ETH_MII_RX_ER,,,,EVENTOUT,
+PortB,PB11,,TIM2_CH4,,,I2C2_SDA,,,USART3_RX,,,OTG_HS_ULPI_D4,ETH_MII_TX_EN/ETH_RMII_TX_EN,,,,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,I2S2ext_SD,USART3_RTS,,TIM12_CH1,,,OTG_HS_DM,,,EVENTOUT,
+PortB,PB15,RTC_REFIN,TIM1_CH3N,,TIM8_CH3N,,SPI2_MOSI/I2S2_SD,,,,TIM12_CH2,,,OTG_HS_DP,,,EVENTOUT,
+PortC,PC0,,,,,,,,,,,OTG_HS_ULPI_STP,,,,,EVENTOUT,ADC123_IN10
+PortC,PC1,,,,,,,,,,,,ETH_MDC,,,,EVENTOUT,ADC123_IN11
+PortC,PC2,,,,,,SPI2_MISO,I2S2ext_SD,,,,OTG_HS_ULPI_DIR,ETH_MII_TXD2,,,,EVENTOUT,ADC123_IN12
+PortC,PC3,,,,,,SPI2_MOSI/I2S2_SD,,,,,OTG_HS_ULPI_NXT,ETH_MII_TX_CLK,,,,EVENTOUT,ADC123_IN13
+PortC,PC4,,,,,,,,,,,,ETH_MII_RXD0/ETH_RMII_RXD0,,,,EVENTOUT,ADC123_IN14
+PortC,PC5,,,,,,,,,,,,ETH_MII_RXD1/ETH_RMII_RXD1,,,,EVENTOUT,ADC123_IN15
+PortC,PC6,,,TIM3_CH1,TIM8_CH1,,I2S2_MCK,,,USART6_TX,,,,SDIO_D6,DCMI_D0,,EVENTOUT,
+PortC,PC7,,,TIM3_CH2,TIM8_CH2,,,I2S3_MCK,,USART6_RX,,,,SDIO_D7,DCMI_D1,,EVENTOUT,
+PortC,PC8,,,TIM3_CH3,TIM8_CH3,,,,,USART6_CK,,,,SDIO_D0,DCMI_D2,,EVENTOUT,
+PortC,PC9,MCO2,,TIM3_CH4,TIM8_CH4,I2C3_SDA,I2S_CKIN,,,,,,,SDIO_D1,DCMI_D3,,EVENTOUT,
+PortC,PC10,,,,,,,SPI3_SCK/I2S3_CK,USART3_TX,UART4_TX,,,,SDIO_D2,DCMI_D8,,EVENTOUT,
+PortC,PC11,,,,,,I2S3ext_SD,SPI3_MISO,USART3_RX,UART4_RX,,,,SDIO_D3,DCMI_D4,,EVENTOUT,
+PortC,PC12,,,,,,,SPI3_MOSI/I2S3_SD,USART3_CK,UART5_TX,,,,SDIO_CK,DCMI_D9,,EVENTOUT,
+PortC,PC13,,,,,,,,,,,,,,,,EVENTOUT,
+PortC,PC14,,,,,,,,,,,,,,,,EVENTOUT,
+PortC,PC15,,,,,,,,,,,,,,,,EVENTOUT,
+PortD,PD0,,,,,,,,,,CAN1_RX,,,FSMC_D2,,,EVENTOUT,
+PortD,PD1,,,,,,,,,,CAN1_TX,,,FSMC_D3,,,EVENTOUT,
+PortD,PD2,,,TIM3_ETR,,,,,,UART5_RX,,,,SDIO_CMD,DCMI_D11,,EVENTOUT,
+PortD,PD3,,,,,,,,USART2_CTS,,,,,FSMC_CLK,,,EVENTOUT,
+PortD,PD4,,,,,,,,USART2_RTS,,,,,FSMC_NOE,,,EVENTOUT,
+PortD,PD5,,,,,,,,USART2_TX,,,,,FSMC_NWE,,,EVENTOUT,
+PortD,PD6,,,,,,,,USART2_RX,,,,,FSMC_NWAIT,,,EVENTOUT,
+PortD,PD7,,,,,,,,USART2_CK,,,,,FSMC_NE1/FSMC_NCE2,,,EVENTOUT,
+PortD,PD8,,,,,,,,USART3_TX,,,,,FSMC_D13,,,EVENTOUT,
+PortD,PD9,,,,,,,,USART3_RX,,,,,FSMC_D14,,,EVENTOUT,
+PortD,PD10,,,,,,,,USART3_CK,,,,,FSMC_D15,,,EVENTOUT,
+PortD,PD11,,,,,,,,USART3_CTS,,,,,FSMC_A16,,,EVENTOUT,
+PortD,PD12,,,TIM4_CH1,,,,,USART3_RTS,,,,,FSMC_A17,,,EVENTOUT,
+PortD,PD13,,,TIM4_CH2,,,,,,,,,,FSMC_A18,,,EVENTOUT,
+PortD,PD14,,,TIM4_CH3,,,,,,,,,,FSMC_D0,,,EVENTOUT,
+PortD,PD15,,,TIM4_CH4,,,,,,,,,,FSMC_D1,,,EVENTOUT,
+PortE,PE0,,,TIM4_ETR,,,,,,,,,,FSMC_NBL0,DCMI_D2,,EVENTOUT,
+PortE,PE1,,,,,,,,,,,,,FSMC_NBL1,DCMI_D3,,EVENTOUT,
+PortE,PE2,TRACECLK,,,,,,,,,,,ETH_MII_TXD3,FSMC_A23,,,EVENTOUT,
+PortE,PE3,TRACED0,,,,,,,,,,,,FSMC_A19,,,EVENTOUT,
+PortE,PE4,TRACED1,,,,,,,,,,,,FSMC_A20,DCMI_D4,,EVENTOUT,
+PortE,PE5,TRACED2,,,TIM9_CH1,,,,,,,,,FSMC_A21,DCMI_D6,,EVENTOUT,
+PortE,PE6,TRACED3,,,TIM9_CH2,,,,,,,,,FSMC_A22,DCMI_D7,,EVENTOUT,
+PortE,PE7,,TIM1_ETR,,,,,,,,,,,FSMC_D4,,,EVENTOUT,
+PortE,PE8,,TIM1_CH1N,,,,,,,,,,,FSMC_D5,,,EVENTOUT,
+PortE,PE9,,TIM1_CH1,,,,,,,,,,,FSMC_D6,,,EVENTOUT,
+PortE,PE10,,TIM1_CH2N,,,,,,,,,,,FSMC_D7,,,EVENTOUT,
+PortE,PE11,,TIM1_CH2,,,,,,,,,,,FSMC_D8,,,EVENTOUT,
+PortE,PE12,,TIM1_CH3N,,,,,,,,,,,FSMC_D9,,,EVENTOUT,
+PortE,PE13,,TIM1_CH3,,,,,,,,,,,FSMC_D10,,,EVENTOUT,
+PortE,PE14,,TIM1_CH4,,,,,,,,,,,FSMC_D11,,,EVENTOUT,
+PortE,PE15,,TIM1_BKIN,,,,,,,,,,,FSMC_D12,,,EVENTOUT,
+PortF,PF0,,,,,I2C2_SDA,,,,,,,,FSMC_A0,,,EVENTOUT,
+PortF,PF1,,,,,I2C2_SCL,,,,,,,,FSMC_A1,,,EVENTOUT,
+PortF,PF2,,,,,I2C2_SMBA,,,,,,,,FSMC_A2,,,EVENTOUT,
+PortF,PF3,,,,,,,,,,,,,FSMC_A3,,,EVENTOUT,ADC3_IN9
+PortF,PF4,,,,,,,,,,,,,FSMC_A4,,,EVENTOUT,ADC3_IN14
+PortF,PF5,,,,,,,,,,,,,FSMC_A5,,,EVENTOUT,ADC3_IN15
+PortF,PF6,,,,TIM10_CH1,,,,,,,,,FSMC_NIORD,,,EVENTOUT,ADC3_IN4
+PortF,PF7,,,,TIM11_CH1,,,,,,,,,FSMC_NREG,,,EVENTOUT,ADC3_IN5
+PortF,PF8,,,,,,,,,,TIM13_CH1,,,FSMC_NIOWR,,,EVENTOUT,ADC3_IN6
+PortF,PF9,,,,,,,,,,TIM14_CH1,,,FSMC_CD,,,EVENTOUT,ADC3_IN7
+PortF,PF10,,,,,,,,,,,,,FSMC_INTR,,,EVENTOUT,ADC3_IN8
+PortF,PF11,,,,,,,,,,,,,,DCMI_D12,,EVENTOUT,
+PortF,PF12,,,,,,,,,,,,,FSMC_A6,,,EVENTOUT,
+PortF,PF13,,,,,,,,,,,,,FSMC_A7,,,EVENTOUT,
+PortF,PF14,,,,,,,,,,,,,FSMC_A8,,,EVENTOUT,
+PortF,PF15,,,,,,,,,,,,,FSMC_A9,,,EVENTOUT,
+PortG,PG0,,,,,,,,,,,,,FSMC_A10,,,EVENTOUT,
+PortG,PG1,,,,,,,,,,,,,FSMC_A11,,,EVENTOUT,
+PortG,PG2,,,,,,,,,,,,,FSMC_A12,,,EVENTOUT,
+PortG,PG3,,,,,,,,,,,,,FSMC_A13,,,EVENTOUT,
+PortG,PG4,,,,,,,,,,,,,FSMC_A14,,,EVENTOUT,
+PortG,PG5,,,,,,,,,,,,,FSMC_A15,,,EVENTOUT,
+PortG,PG6,,,,,,,,,,,,,FSMC_INT2,,,EVENTOUT,
+PortG,PG7,,,,,,,,,USART6_CK,,,,FSMC_INT3,,,EVENTOUT,
+PortG,PG8,,,,,,,,,USART6_RTS,,,ETH_PPS_OUT,,,,EVENTOUT,
+PortG,PG9,,,,,,,,,USART6_RX,,,,FSMC_NE2/FSMC_NCE3,,,EVENTOUT,
+PortG,PG10,,,,,,,,,,,,,FSMC_NCE4_1/FSMC_NE3,,,EVENTOUT,
+PortG,PG11,,,,,,,,,,,,ETH_MII_TX_EN/ETH_RMII_TX_EN,FSMC_NCE4_2,,,EVENTOUT,
+PortG,PG12,,,,,,,,,USART6_RTS,,,,FSMC_NE4,,,EVENTOUT,
+PortG,PG13,,,,,,,,,USART6_CTS,,,ETH_MII_TXD0/ETH_RMII_TXD0,FSMC_A24,,,EVENTOUT,
+PortG,PG14,,,,,,,,,USART6_TX,,,ETH_MII_TXD1/ETH_RMII_TXD1,FSMC_A25,,,EVENTOUT,
+PortG,PG15,,,,,,,,,USART6_CTS,,,,,DCMI_D13,,EVENTOUT,
+PortH,PH0,,,,,,,,,,,,,,,,EVENTOUT,
+PortH,PH1,,,,,,,,,,,,,,,,EVENTOUT,
+PortH,PH2,,,,,,,,,,,,ETH_MII_CRS,,,,EVENTOUT,
+PortH,PH3,,,,,,,,,,,,ETH_MII_COL,,,,EVENTOUT,
+PortH,PH4,,,,,I2C2_SCL,,,,,,OTG_HS_ULPI_NXT,,,,,EVENTOUT,
+PortH,PH5,,,,,I2C2_SDA,,,,,,,,,,,EVENTOUT,
+PortH,PH6,,,,,I2C2_SMBA,,,,,TIM12_CH1,,ETH_MII_RXD2,,,,EVENTOUT,
+PortH,PH7,,,,,I2C3_SCL,,,,,,,ETH_MII_RXD3,,,,EVENTOUT,
+PortH,PH8,,,,,I2C3_SDA,,,,,,,,,DCMI_HSYNC,,EVENTOUT,
+PortH,PH9,,,,,I2C3_SMBA,,,,,TIM12_CH2,,,,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/I2S2_WS,,,,,,,,DCMI_D13,,EVENTOUT,
+PortI,PI1,,,,,,SPI2_SCK/I2S2_CK,,,,,,,,DCMI_D8,,EVENTOUT,
+PortI,PI2,,,,TIM8_CH4,,SPI2_MISO,I2S2ext_SD,,,,,,,DCMI_D9,,EVENTOUT,
+PortI,PI3,,,,TIM8_ETR,,SPI2_MOSI/I2S2_SD,,,,,,,,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,,,,,,,,,,,,,,,,EVENTOUT,
+PortI,PI9,,,,,,,,,,CAN1_RX,,,,,,EVENTOUT,
+PortI,PI10,,,,,,,,,,,,ETH_MII_RX_ER,,,,EVENTOUT,
+PortI,PI11,,,,,,,,,,,OTG_HS_ULPI_DIR,,,,,EVENTOUT,
diff --git a/ports/stm32/boards/stm32f411.ld b/ports/stm32/boards/stm32f411.ld
new file mode 100644
index 000000000..d156e852a
--- /dev/null
+++ b/ports/stm32/boards/stm32f411.ld
@@ -0,0 +1,31 @@
+/*
+ GNU linker script for STM32F411
+*/
+
+/* Specify the memory areas */
+MEMORY
+{
+ FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 0x080000 /* entire flash, 512 KiB */
+ FLASH_ISR (rx) : ORIGIN = 0x08000000, LENGTH = 0x004000 /* sector 0, 16 KiB */
+ /* sectors 1,2,3 are 16K, 4 is 64K (for filesystem) */
+ FLASH_TEXT (rx) : ORIGIN = 0x08020000, LENGTH = 0x060000 /* sectors 5,6,7 3*128KiB = 384 KiB */
+ RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 0x020000 /* 128 KiB */
+}
+
+/* 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);
+
+/* define common sections and symbols */
+INCLUDE common.ld
+
+/* 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 = 0x2001c000; /* tunable */
diff --git a/ports/stm32/boards/stm32f411_af.csv b/ports/stm32/boards/stm32f411_af.csv
new file mode 100644
index 000000000..29267b1d9
--- /dev/null
+++ b/ports/stm32/boards/stm32f411_af.csv
@@ -0,0 +1,84 @@
+Port,,AF0,AF1,AF2,AF3,AF4,AF5,AF6,AF7,AF8,AF9,AF10,AF11,AF12,AF13,AF14,AF15,
+,,SYS_AF,TIM1/TIM2,TIM3/TIM4/TIM5,TIM9/TIM10/TIM11,I2C1/I2C2/I2C3,SPI1/I2S1/SPI2/I2S2/SPI3/I2S3,SPI2/I2S2/SPI3/I2S3/SPI4/I2S4/SPI5/I2S5,SPI3/I2S3/USART1/USART2,USART6,I2C2/I2C3,,,SDIO,,,,ADC
+PortA,PA0,,TIM2_CH1/TIM2_ETR,TIM5_CH1,,,,,USART2_CTS,,,,,,,,EVENTOUT,ADC1_IN0
+PortA,PA1,,TIM2_CH2,TIM5_CH2,,,SPI4_MOSI/I2S4_SD,,USART2_RTS,,,,,,,,EVENTOUT,ADC1_IN1
+PortA,PA2,,TIM2_CH3,TIM5_CH3,TIM9_CH1,,I2S2_CKIN,,USART2_TX,,,,,,,,EVENTOUT,ADC1_IN2
+PortA,PA3,,TIM2_CH4,TIM5_CH4,TIM9_CH2,,I2S2_MCK,,USART2_RX,,,,,,,,EVENTOUT,ADC1_IN3
+PortA,PA4,,,,,,SPI1_NSS/I2S1_WS,SPI3_NSS/I2S3_WS,USART2_CK,,,,,,,,EVENTOUT,ADC1_IN4
+PortA,PA5,,TIM2_CH1/TIM2_ETR,,,,SPI1_SCK/I2S1_CK,,,,,,,,,,EVENTOUT,ADC1_IN5
+PortA,PA6,,TIM1_BKIN,TIM3_CH1,,,SPI1_MISO,I2S2_MCK,,,,,,SDIO_CMD,,,EVENTOUT,ADC1_IN6
+PortA,PA7,,TIM1_CH1N,TIM3_CH2,,,SPI1_MOSI/I2S1_SD,,,,,,,,,,EVENTOUT,ADC1_IN7
+PortA,PA8,MCO_1,TIM1_CH1,,,I2C3_SCL,,,USART1_CK,,,USB_FS_SOF,,SDIO_D1,,,EVENTOUT,
+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,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,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,
+PortB,PB7,,,TIM4_CH2,,I2C1_SDA,,,USART1_RX,,,,,SDIO_D0,,,EVENTOUT,
+PortB,PB8,,,TIM4_CH3,TIM10_CH1,I2C1_SCL,,SPI5_MOSI/I2S5_SD,,,I2C3_SDA,,,SDIO_D4,,,EVENTOUT,
+PortB,PB9,,,TIM4_CH4,TIM11_CH1,I2C1_SDA,SPI2_NSS/I2S2_WS,,,,I2C2_SDA,,,SDIO_D5,,,EVENTOUT,
+PortB,PB10,,TIM2_CH3,,,I2C2_SCL,SPI2_SCK/I2S2_CK,I2S3_MCK,,,,,,SDIO_D7,,,EVENTOUT,
+PortB,PB11,,TIM2_CH4,,,I2C2_SDA,I2S2_CKIN,,,,,,,,,,EVENTOUT,
+PortB,PB12,,TIM1_BKIN,,,I2C2_SMBA,SPI2_NSS/I2S2_WS,SPI4_NSS/I2S4_WS,SPI3_SCK/I2S3_CK,,,,,,,,EVENTOUT,
+PortB,PB13,,TIM1_CH1N,,,,SPI2_SCK/I2S2_CK,SPI4_SCK/I2S4_CK,,,,,,,,,EVENTOUT,
+PortB,PB14,,TIM1_CH2N,,,,SPI2_MISO,I2S2ext_SD,,,,,,SDIO_D6,,,EVENTOUT,
+PortB,PB15,RTC_50Hz,TIM1_CH3N,,,,SPI2_MOSI/I2S2_SD,,,,,,,SDIO_CK,,,EVENTOUT,
+PortC,PC0,,,,,,,,,,,,,,,,EVENTOUT,ADC1_IN10
+PortC,PC1,,,,,,,,,,,,,,,,EVENTOUT,ADC1_IN11
+PortC,PC2,,,,,,SPI2_MISO,I2S2ext_SD,,,,,,,,,EVENTOUT,ADC1_IN12
+PortC,PC3,,,,,,SPI2_MOSI/I2S2_SD,,,,,,,,,,EVENTOUT,ADC1_IN13
+PortC,PC4,,,,,,,,,,,,,,,,EVENTOUT,ADC1_IN14
+PortC,PC5,,,,,,,,,,,,,,,,EVENTOUT,ADC1_IN15
+PortC,PC6,,,TIM3_CH1,,,I2S2_MCK,,,USART6_TX,,,,SDIO_D6,,,EVENTOUT,
+PortC,PC7,,,TIM3_CH2,,,SPI2_SCK/I2S2_CK,I2S3_MCK,,USART6_RX,,,,SDIO_D7,,,EVENTOUT,
+PortC,PC8,,,TIM3_CH3,,,,,,USART6_CK,,,,SDIO_D0,,,EVENTOUT,
+PortC,PC9,MCO_2,,TIM3_CH4,,I2C3_SDA,I2S2_CKIN,,,,,,,SDIO_D1,,,EVENTOUT,
+PortC,PC10,,,,,,,SPI3_SCK/I2S3_CK,,,,,,SDIO_D2,,,EVENTOUT,
+PortC,PC11,,,,,,I2S3ext_SD,SPI3_MISO,,,,,,SDIO_D3,,,EVENTOUT,
+PortC,PC12,,,,,,,SPI3_MOSI/I2S3_SD,,,,,,SDIO_CK,,,EVENTOUT,
+PortC,PC13,,,,,,,,,,,,,,,,EVENTOUT,
+PortC,PC14,,,,,,,,,,,,,,,,EVENTOUT,
+PortC,PC15,,,,,,,,,,,,,,,,EVENTOUT,
+PortD,PD0,,,,,,,,,,,,,,,,EVENTOUT,
+PortD,PD1,,,,,,,,,,,,,,,,EVENTOUT,
+PortD,PD2,,,TIM3_ETR,,,,,,,,,,SDIO_CMD,,,EVENTOUT,
+PortD,PD3,,,,,,SPI2_SCK/I2S2_CK,,USART2_CTS,,,,,,,,EVENTOUT,
+PortD,PD4,,,,,,,,USART2_RTS,,,,,,,,EVENTOUT,
+PortD,PD5,,,,,,,,USART2_TX,,,,,,,,EVENTOUT,
+PortD,PD6,,,,,,SPI3_MOSI/I2S3_SD,,USART2_RX,,,,,,,,EVENTOUT,
+PortD,PD7,,,,,,,,USART2_CK,,,,,,,,EVENTOUT,
+PortD,PD8,,,,,,,,,,,,,,,,EVENTOUT,
+PortD,PD9,,,,,,,,,,,,,,,,EVENTOUT,
+PortD,PD10,,,,,,,,,,,,,,,,EVENTOUT,
+PortD,PD11,,,,,,,,,,,,,,,,EVENTOUT,
+PortD,PD12,,,TIM4_CH1,,,,,,,,,,,,,EVENTOUT,
+PortD,PD13,,,TIM4_CH2,,,,,,,,,,,,,EVENTOUT,
+PortD,PD14,,,TIM4_CH3,,,,,,,,,,,,,EVENTOUT,
+PortD,PD15,,,TIM4_CH4,,,,,,,,,,,,,EVENTOUT,
+PortE,PE0,,,TIM4_ETR,,,,,,,,,,,,,EVENTOUT,
+PortE,PE1,,,,,,,,,,,,,,,,EVENTOUT,
+PortE,PE2,TRACECLK,,,,,SPI4_SCK/I2S4_CK,SPI5_SCK/I2S5_CK,,,,,,,,,EVENTOUT,
+PortE,PE3,TRACED0,,,,,,,,,,,,,,,EVENTOUT,
+PortE,PE4,TRACED1,,,,,SPI4_NSS/I2S4_WS,SPI5_NSS/I2S5_WS,,,,,,,,,EVENTOUT,
+PortE,PE5,TRACED2,,,TIM9_CH1,,SPI4_MISO,SPI5_MISO,,,,,,,,,EVENTOUT,
+PortE,PE6,TRACED3,,,TIM9_CH2,,SPI4_MOSI/I2S4_SD,SPI5_MOSI/I2S5_SD,,,,,,,,,EVENTOUT,
+PortE,PE7,,TIM1_ETR,,,,,,,,,,,,,,EVENTOUT,
+PortE,PE8,,TIM1_CH1N,,,,,,,,,,,,,,EVENTOUT,
+PortE,PE9,,TIM1_CH1,,,,,,,,,,,,,,EVENTOUT,
+PortE,PE10,,TIM1_CH2N,,,,,,,,,,,,,,EVENTOUT,
+PortE,PE11,,TIM1_CH2,,,,SPI4_NSS/I2S4_WS,SPI5_NSS/I2S5_WS,,,,,,,,,EVENTOUT,
+PortE,PE12,,TIM1_CH3N,,,,SPI4_SCK/I2S4_CK,SPI5_SCK/I2S5_CK,,,,,,,,,EVENTOUT,
+PortE,PE13,,TIM1_CH3,,,,SPI4_MISO,SPI5_MISO,,,,,,,,,EVENTOUT,
+PortE,PE14,,TIM1_CH4,,,,SPI4_MOSI/I2S4_SD,SPI5_MOSI/I2S5_SD,,,,,,,,,EVENTOUT,
+PortE,PE15,,TIM1_BKIN,,,,,,,,,,,,,,EVENTOUT,
+PortH,PH0,,,,,,,,,,,,,,,,EVENTOUT,
+PortH,PH1,,,,,,,,,,,,,,,,EVENTOUT,
diff --git a/ports/stm32/boards/stm32f429.ld b/ports/stm32/boards/stm32f429.ld
new file mode 100644
index 000000000..f358233a6
--- /dev/null
+++ b/ports/stm32/boards/stm32f429.ld
@@ -0,0 +1,31 @@
+/*
+ GNU linker script for STM32F429i-Discovery kit with external 8MByte SDRam
+*/
+
+/* Specify the memory areas */
+MEMORY
+{
+ FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 0x0200000 /* entire flash, 2048 KiB */
+ FLASH_ISR (rx) : ORIGIN = 0x08000000, LENGTH = 0x0004000 /* sector 0, 16 KiB */
+ FLASH_TEXT (rx) : ORIGIN = 0x08020000, LENGTH = 0x0088000 /* sectors 5,6,7,8, 4*128KiB = 512 KiB (could increase it more) */
+ RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 0x0030000 /* 192 KiB */
+ SDRAM(xrw) : ORIGIN = 0xC0000000, LENGTH = 0x0800000 /* 8 MByte */
+}
+
+/* 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);
+
+/* define common sections and symbols */
+INCLUDE common.ld
+
+/* 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 = 0x2001c000; /* tunable */
diff --git a/ports/stm32/boards/stm32f429_af.csv b/ports/stm32/boards/stm32f429_af.csv
new file mode 100644
index 000000000..2e501ade0
--- /dev/null
+++ b/ports/stm32/boards/stm32f429_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,TIM3/4/5,TIM8/9/10/11,I2C1/2/3,SPI1/2/3/4/5/6,SPI2/3/SAI1,SPI3/USART1/2/3,USART6/UART4/5/7/8,CAN1/2/TIM12/13/14/LCD,OTG2_HS/OTG1_FS,ETH,FMC/SDIO/OTG2_FS,DCMI,LCD,SYS,
+PortA,PA0,,TIM2_CH1/TIM2_ETR,TIM5_CH1,TIM8_ETR,,,,USART2_CTS,UART4_TX,,,ETH_MII_CRS,,,,EVENTOUT,
+PortA,PA1,,TIM2_CH2,TIM5_CH2,,,,,USART2_RTS,UART4_RX,,,ETH_MII_RX_CLK/ETH_RMII_REF_CLK,,,,EVENTOUT,ADC123_IN1
+PortA,PA2,,TIM2_CH3,TIM5_CH3,TIM9_CH1,,,,USART2_TX,,,,ETH_MDIO,,,,EVENTOUT,ADC123_IN2
+PortA,PA3,,TIM2_CH4,TIM5_CH4,TIM9_CH2,,,,USART2_RX,,,OTG_HS_ULPI_D0,ETH_MII_COL,,,LCD_B5,EVENTOUT,ADC123_IN3
+PortA,PA4,,,,,,SPI1_NSS,SPI3_NSS/I2S3_WS,USART2_CK,,,,,OTG_HS_SOF,DCMI_HSYNC,LCD_VSYNC,EVENTOUT,ADC12_IN4
+PortA,PA5,,TIM2_CH1/TIM2_ETR,,TIM8_CH1N,,SPI1_SCK,,,,,OTG_HS_ULPI_CK,,,,,EVENTOUT,ADC12_IN5
+PortA,PA6,,TIM1_BKIN,TIM3_CH1,TIM8_BKIN,,SPI1_MISO,,,,TIM13_CH1,,,,DCMI_PIXCLK,LCD_G2,EVENTOUT,ADC12_IN6
+PortA,PA7,,TIM1_CH1N,TIM3_CH2,TIM8_CH1N,,SPI1_MOSI,,,,TIM14_CH1,,ETH_MII_RX_DV/ETH_RMII_CRS_DV,,,,EVENTOUT,ADC12_IN7
+PortA,PA8,MCO1,TIM1_CH1,,,I2C3_SCL,,,USART1_CK,,,OTG_FS_SOF,,,,LCD_R6,EVENTOUT,
+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,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
+PortB,PB2,,,,,,,,,,,,,,,,EVENTOUT,
+PortB,PB3,JTDO/TRACESWO,TIM2_CH2,,,,SPI1_SCK,SPI3_SCK/I2S3_CK,,,,,,,,,EVENTOUT,
+PortB,PB4,NJTRST,,TIM3_CH1,,,SPI1_MISO,SPI3_MISO,I2S3ext_SD,,,,,,,,EVENTOUT,
+PortB,PB5,,,TIM3_CH2,,I2C1_SMBA,SPI1_MOSI,SPI3_MOSI/I2S3_SD,,,CAN2_RX,OTG_HS_ULPI_D7,ETH_PPS_OUT,FMC_SDCKE1,DCMI_D10,,EVENTOUT,
+PortB,PB6,,,TIM4_CH1,,I2C1_SCL,,,USART1_TX,,CAN2_TX,,,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,SDIO_D4,DCMI_D6,LCD_B6,EVENTOUT,
+PortB,PB9,,,TIM4_CH4,TIM11_CH1,I2C1_SDA,SPI2_NSS/I2S2_WS,,,,CAN1_TX,,,SDIO_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,I2S2ext_SD,USART3_RTS,,TIM12_CH1,,,OTG_HS_DM,,,EVENTOUT,
+PortB,PB15,RTC_REFIN,TIM1_CH3N,,TIM8_CH3N,,SPI2_MOSI/I2S2_SD,,,,TIM12_CH2,,,OTG_HS_DP,,,EVENTOUT,
+PortC,PC0,,,,,,,,,,,OTG_HS_ULPI_STP,,FMC_SDNWE,,,EVENTOUT,ADC123_IN10
+PortC,PC1,,,,,,,,,,,,ETH_MDC,,,,EVENTOUT,ADC123_IN11
+PortC,PC2,,,,,,SPI2_MISO,I2S2ext_SD,,,,OTG_HS_ULPI_DIR,ETH_MII_TXD2,FMC_SDNE0,,,EVENTOUT,ADC123_IN12
+PortC,PC3,,,,,,SPI2_MOSI/I2S2_SD,,,,,OTG_HS_ULPI_NXT,ETH_MII_TX_CLK,FMC_SDCKE0,,,EVENTOUT,ADC123_IN13
+PortC,PC4,,,,,,,,,,,,ETH_MII_RXD0/ETH_RMII_RXD0,,,,EVENTOUT,ADC12_IN14
+PortC,PC5,,,,,,,,,,,,ETH_MII_RXD1/ETH_RMII_RXD1,,,,EVENTOUT,ADC12_IN15
+PortC,PC6,,,TIM3_CH1,TIM8_CH1,,I2S2_MCK,,,USART6_TX,,,,SDIO_D6,DCMI_D0,LCD_HSYNC,EVENTOUT,
+PortC,PC7,,,TIM3_CH2,TIM8_CH2,,,I2S3_MCK,,USART6_RX,,,,SDIO_D7,DCMI_D1,LCD_G6,EVENTOUT,
+PortC,PC8,,,TIM3_CH3,TIM8_CH3,,,,,USART6_CK,,,,SDIO_D0,DCMI_D2,,EVENTOUT,
+PortC,PC9,MCO2,,TIM3_CH4,TIM8_CH4,I2C3_SDA,I2S_CKIN,,,,,,,SDIO_D1,DCMI_D3,,EVENTOUT,
+PortC,PC10,,,,,,,SPI3_SCK/I2S3_CK,USART3_TX,UART4_TX,,,,SDIO_D2,DCMI_D8,LCD_R2,EVENTOUT,
+PortC,PC11,,,,,,I2S3ext_SD,SPI3_MISO,USART3_RX,UART4_RX,,,,SDIO_D3,DCMI_D4,,EVENTOUT,
+PortC,PC12,,,,,,,SPI3_MOSI/I2S3_SD,USART3_CK,UART5_TX,,,,SDIO_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,,,TIM3_ETR,,,,,,UART5_RX,,,,SDIO_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,,,,,FMC_NWAIT,DCMI_D10,LCD_B2,EVENTOUT,
+PortD,PD7,,,,,,,,USART2_CK,,,,,FMC_NE1/FMC_NCE2,,,EVENTOUT,
+PortD,PD8,,,,,,,,USART3_TX,,,,,FMC_D13,,,EVENTOUT,
+PortD,PD9,,,,,,,,USART3_RX,,,,,FMC_D14,,,EVENTOUT,
+PortD,PD10,,,,,,,,USART3_CK,,,,,FMC_D15,,LCD_B3,EVENTOUT,
+PortD,PD11,,,,,,,,USART3_CTS,,,,,FMC_A16,,,EVENTOUT,
+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,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,PE9,,TIM1_CH1,,,,,,,,,,,FMC_D6,,,EVENTOUT,
+PortE,PE10,,TIM1_CH2N,,,,,,,,,,,FMC_D7,,,EVENTOUT,
+PortE,PE11,,TIM1_CH2,,,,SPI4_NSS,,,,,,,FMC_D8,,LCD_G3,EVENTOUT,
+PortE,PE12,,TIM1_CH3N,,,,SPI4_SCK,,,,,,,FMC_D9,,LCD_B4,EVENTOUT,
+PortE,PE13,,TIM1_CH3,,,,SPI4_MISO,,,,,,,FMC_D10,,LCD_DE,EVENTOUT,
+PortE,PE14,,TIM1_CH4,,,,SPI4_MOSI,,,,,,,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,,,,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
+PortF,PF11,,,,,,SPI5_MOSI,,,,,,,FMC_SDNRAS,DCMI_D12,,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,,,,,,,,,,,,,FMC_INT2,DCMI_D12,LCD_R7,EVENTOUT,
+PortG,PG7,,,,,,,,,USART6_CK,,,,FMC_INT3,DCMI_D13,LCD_CLK,EVENTOUT,
+PortG,PG8,,,,,,SPI6_NSS,,,USART6_RTS,,,ETH_PPS_OUT,FMC_SDCLK,,,EVENTOUT,
+PortG,PG9,,,,,,,,,USART6_RX,,,,FMC_NE2/FMC_NCE3,DCMI_VSYNC(1),,EVENTOUT,
+PortG,PG10,,,,,,,,,,LCD_G3,,,FMC_NCE4_1/FMC_NE3,DCMI_D2,LCD_B2,EVENTOUT,
+PortG,PG11,,,,,,,,,,,,ETH_MII_TX_EN/ETH_RMII_TX_EN,FMC_NCE4_2,DCMI_D3,LCD_B3,EVENTOUT,
+PortG,PG12,,,,,,SPI6_MISO,,,USART6_RTS,LCD_B4,,,FMC_NE4,,LCD_B1,EVENTOUT,
+PortG,PG13,,,,,,SPI6_SCK,,,USART6_CTS,,,ETH_MII_TXD0/ETH_RMII_TXD0,FMC_A24,,,EVENTOUT,
+PortG,PG14,,,,,,SPI6_MOSI,,,USART6_TX,,,ETH_MII_TXD1/ETH_RMII_TXD1,FMC_A25,,,EVENTOUT,
+PortG,PG15,,,,,,,,,USART6_CTS,,,,FMC_SDNCAS,DCMI_D13,,EVENTOUT,
+PortH,PH0,,,,,,,,,,,,,,,,EVENTOUT,
+PortH,PH1,,,,,,,,,,,,,,,,EVENTOUT,
+PortH,PH2,,,,,,,,,,,,ETH_MII_CRS,FMC_SDCKE0,,LCD_R0,EVENTOUT,
+PortH,PH3,,,,,,,,,,,,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,,,FMC_SDNE1,DCMI_D8,,,
+PortH,PH7,,,,,I2C3_SCL,SPI5_MISO,,,,,,ETH_MII_RXD3,FMC_SDCKE1,DCMI_D9,,,
+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,,,,,,,,,,FMC_D18,DCMI_D1,LCD_R4,EVENTOUT,
+PortH,PH11,,,TIM5_CH2,,,,,,,,,,FMC_D19,DCMI_D2,LCD_R5,EVENTOUT,
+PortH,PH12,,,TIM5_CH3,,,,,,,,,,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,,,,,,SPI2_SCK/I2S2_CK,,,,,,,FMC_D25,DCMI_D8,LCD_G6,EVENTOUT,
+PortI,PI2,,,,TIM8_CH4,,SPI2_MISO,I2S2ext_SD,,,,,,FMC_D26,DCMI_D9,LCD_G7,EVENTOUT,
+PortI,PI3,,,,TIM8_ETR,,SPI2_MOSI/I2S2_SD,,,,,,,FMC_D27,DCMI_D10,,EVENTOUT,
+PortI,PI4,,,,TIM8_BKIN,,,,,,,,,FMC_NBL2,DCMI_D5,LCD_B4,EVENTOUT,
+PortI,PI5,,,,TIM8_CH1,,,,,,,,,FMC_NBL3,DCMI_VSYNC,LCD_B5,EVENTOUT,
+PortI,PI6,,,,TIM8_CH2,,,,,,,,,FMC_D28,DCMI_D6,LCD_B6,EVENTOUT,
+PortI,PI7,,,,TIM8_CH3,,,,,,,,,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,
diff --git a/ports/stm32/boards/stm32f439.ld b/ports/stm32/boards/stm32f439.ld
new file mode 100644
index 000000000..0da185e89
--- /dev/null
+++ b/ports/stm32/boards/stm32f439.ld
@@ -0,0 +1,29 @@
+/*
+ GNU linker script for STM32F439
+*/
+
+/* Specify the memory areas */
+MEMORY
+{
+ FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 0x200000 /* entire flash, 2048 KiB */
+ FLASH_ISR (rx) : ORIGIN = 0x08000000, LENGTH = 0x004000 /* sector 0, 16 KiB */
+ FLASH_TEXT (rx) : ORIGIN = 0x08020000, LENGTH = 0x080000 /* sectors 5,6,7,8, 4*128KiB = 512 KiB (could increase it more) */
+ RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 0x030000 /* 192 KiB */
+ CCMRAM (xrw) : ORIGIN = 0x10000000, LENGTH = 0x010000 /* 64 KiB */
+}
+
+/* produce a link error if there is not this amount of RAM for these sections */
+_minimum_stack_size = 2K;
+_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);
+_heap_start = _ebss; /* heap starts just after statically allocated memory */
+_heap_end = 0x2002c000; /* tunable */
diff --git a/ports/stm32/boards/stm32f439_af.csv b/ports/stm32/boards/stm32f439_af.csv
new file mode 100644
index 000000000..5d5c3e72d
--- /dev/null
+++ b/ports/stm32/boards/stm32f439_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,TIM3/4/5,TIM8/9/10/11,I2C1/2/3,SPI1/2/3/4/5/6,SPI2/3/SAI1,SPI3/USART1/2/3,USART6/UART4/5/7/8,CAN1/2/TIM12/13/14/LCD,OTG2_HS/OTG1_FS,ETH,FMC/SDIO/OTG2_FS,DCMI,LCD,SYS,
+PortA,PA0,,TIM2_CH1/TIM2_ETR,TIM5_CH1,TIM8_ETR,,,,USART2_CTS,UART4_TX,,,ETH_MII_CRS,,,,EVENTOUT,ADC123_IN0
+PortA,PA1,,TIM2_CH2,TIM5_CH2,,,,,USART2_RTS,UART4_RX,,,ETH_MII_RX_CLK/ETH_RMII_REF_CLK,,,,EVENTOUT,ADC123_IN1
+PortA,PA2,,TIM2_CH3,TIM5_CH3,TIM9_CH1,,,,USART2_TX,,,,ETH_MDIO,,,,EVENTOUT,ADC123_IN2
+PortA,PA3,,TIM2_CH4,TIM5_CH4,TIM9_CH2,,,,USART2_RX,,,OTG_HS_ULPI_D0,ETH_MII_COL,,,LCD_B5,EVENTOUT,ADC123_IN3
+PortA,PA4,,,,,,SPI1_NSS,SPI3_NSS/I2S3_WS,USART2_CK,,,,,OTG_HS_SOF,DCMI_HSYNC,LCD_VSYNC,EVENTOUT,ADC12_IN4
+PortA,PA5,,TIM2_CH1/TIM2_ETR,,TIM8_CH1N,,SPI1_SCK,,,,,OTG_HS_ULPI_CK,,,,,EVENTOUT,ADC12_IN5
+PortA,PA6,,TIM1_BKIN,TIM3_CH1,TIM8_BKIN,,SPI1_MISO,,,,TIM13_CH1,,,,DCMI_PIXCLK,LCD_G2,EVENTOUT,ADC12_IN6
+PortA,PA7,,TIM1_CH1N,TIM3_CH2,TIM8_CH1N,,SPI1_MOSI,,,,TIM14_CH1,,ETH_MII_RX_DV/ETH_RMII_CRS_DV,,,,EVENTOUT,ADC12_IN7
+PortA,PA8,MCO1,TIM1_CH1,,,I2C3_SCL,,,USART1_CK,,,OTG_FS_SOF,,,,LCD_R6,EVENTOUT,
+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,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
+PortB,PB2,,,,,,,,,,,,,,,,EVENTOUT,
+PortB,PB3,JTDO/TRACESWO,TIM2_CH2,,,,SPI1_SCK,SPI3_SCK/I2S3_CK,,,,,,,,,EVENTOUT,
+PortB,PB4,NJTRST,,TIM3_CH1,,,SPI1_MISO,SPI3_MISO,I2S3ext_SD,,,,,,,,EVENTOUT,
+PortB,PB5,,,TIM3_CH2,,I2C1_SMBA,SPI1_MOSI,SPI3_MOSI/I2S3_SD,,,CAN2_RX,OTG_HS_ULPI_D7,ETH_PPS_OUT,FMC_SDCKE1,DCMI_D10,,EVENTOUT,
+PortB,PB6,,,TIM4_CH1,,I2C1_SCL,,,USART1_TX,,CAN2_TX,,,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,SDIO_D4,DCMI_D6,LCD_B6,EVENTOUT,
+PortB,PB9,,,TIM4_CH4,TIM11_CH1,I2C1_SDA,SPI2_NSS/I2S2_WS,,,,CAN1_TX,,,SDIO_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,I2S2ext_SD,USART3_RTS,,TIM12_CH1,,,OTG_HS_DM,,,EVENTOUT,
+PortB,PB15,RTC_REFIN,TIM1_CH3N,,TIM8_CH3N,,SPI2_MOSI/I2S2_SD,,,,TIM12_CH2,,,OTG_HS_DP,,,EVENTOUT,
+PortC,PC0,,,,,,,,,,,OTG_HS_ULPI_STP,,FMC_SDNWE,,,EVENTOUT,ADC123_IN10
+PortC,PC1,,,,,,,,,,,,ETH_MDC,,,,EVENTOUT,ADC123_IN11
+PortC,PC2,,,,,,SPI2_MISO,I2S2ext_SD,,,,OTG_HS_ULPI_DIR,ETH_MII_TXD2,FMC_SDNE0,,,EVENTOUT,ADC123_IN12
+PortC,PC3,,,,,,SPI2_MOSI/I2S2_SD,,,,,OTG_HS_ULPI_NXT,ETH_MII_TX_CLK,FMC_SDCKE0,,,EVENTOUT,ADC123_IN13
+PortC,PC4,,,,,,,,,,,,ETH_MII_RXD0/ETH_RMII_RXD0,,,,EVENTOUT,ADC12_IN14
+PortC,PC5,,,,,,,,,,,,ETH_MII_RXD1/ETH_RMII_RXD1,,,,EVENTOUT,ADC12_IN15
+PortC,PC6,,,TIM3_CH1,TIM8_CH1,,I2S2_MCK,,,USART6_TX,,,,SDIO_D6,DCMI_D0,LCD_HSYNC,EVENTOUT,
+PortC,PC7,,,TIM3_CH2,TIM8_CH2,,,I2S3_MCK,,USART6_RX,,,,SDIO_D7,DCMI_D1,LCD_G6,EVENTOUT,
+PortC,PC8,,,TIM3_CH3,TIM8_CH3,,,,,USART6_CK,,,,SDIO_D0,DCMI_D2,,EVENTOUT,
+PortC,PC9,MCO2,,TIM3_CH4,TIM8_CH4,I2C3_SDA,I2S_CKIN,,,,,,,SDIO_D1,DCMI_D3,,EVENTOUT,
+PortC,PC10,,,,,,,SPI3_SCK/I2S3_CK,USART3_TX,UART4_TX,,,,SDIO_D2,DCMI_D8,LCD_R2,EVENTOUT,
+PortC,PC11,,,,,,I2S3ext_SD,SPI3_MISO,USART3_RX,UART4_RX,,,,SDIO_D3,DCMI_D4,,EVENTOUT,
+PortC,PC12,,,,,,,SPI3_MOSI/I2S3_SD,USART3_CK,UART5_TX,,,,SDIO_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,,,TIM3_ETR,,,,,,UART5_RX,,,,SDIO_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,,,,,,I2S3_SD,SAI1_SD_A,USART2_RX,,,,,FMC_NWAIT,DCMI_D10,LCD_B2,EVENTOUT,
+PortD,PD7,,,,,,,,USART2_CK,,,,,FMC_NE1/FMC_NCE2,,,EVENTOUT,
+PortD,PD8,,,,,,,,USART3_TX,,,,,FMC_D13,,,EVENTOUT,
+PortD,PD9,,,,,,,,USART3_RX,,,,,FMC_D14,,,EVENTOUT,
+PortD,PD10,,,,,,,,USART3_CK,,,,,FMC_D15,,LCD_B3,EVENTOUT,
+PortD,PD11,,,,,,,,USART3_CTS,,,,,FMC_A16,,,EVENTOUT,
+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,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,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,
+PortE,PE12,,TIM1_CH3N,,,,SPI4_SCK,SPI3_SCK,,,,,,FMC_D9,,LCD_B4,EVENTOUT,
+PortE,PE13,,TIM1_CH3,,,,SPI4_MISO,SPI3_MISO,,,,,,FMC_D10,,LCD_DE,EVENTOUT,
+PortE,PE14,,TIM1_CH4,,,,SPI4_MOSI,SP3_MOSI,,,,,,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,,,,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
+PortF,PF11,,,,,,SPI5_MOSI,,,,,,,FMC_SDNRAS,DCMI_D12,,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,,,,,,,,,,,,,FMC_INT2,DCMI_D12,LCD_R7,EVENTOUT,
+PortG,PG7,,,,,,,,,USART6_CK,,,,FMC_INT3,DCMI_D13,LCD_CLK,EVENTOUT,
+PortG,PG8,,,,,,SPI6_NSS,,,USART6_RTS,,,ETH_PPS_OUT,FMC_SDCLK,,,EVENTOUT,
+PortG,PG9,,,,,,,,,USART6_RX,,,,FMC_NE2/FMC_NCE3,DCMI_VSYNC(1),,EVENTOUT,
+PortG,PG10,,,,,,,,,,LCD_G3,,,FMC_NCE4_1/FMC_NE3,DCMI_D2,LCD_B2,EVENTOUT,
+PortG,PG11,,,,,,,,,,,,ETH_MII_TX_EN/ETH_RMII_TX_EN,FMC_NCE4_2,DCMI_D3,LCD_B3,EVENTOUT,
+PortG,PG12,,,,,,SPI6_MISO,,,USART6_RTS,LCD_B4,,,FMC_NE4,,LCD_B1,EVENTOUT,
+PortG,PG13,,,,,,SPI6_SCK,,,USART6_CTS,,,ETH_MII_TXD0/ETH_RMII_TXD0,FMC_A24,,,EVENTOUT,
+PortG,PG14,,,,,,SPI6_MOSI,,,USART6_TX,,,ETH_MII_TXD1/ETH_RMII_TXD1,FMC_A25,,,EVENTOUT,
+PortG,PG15,,,,,,,,,USART6_CTS,,,,FMC_SDNCAS,DCMI_D13,,EVENTOUT,
+PortH,PH0,,,,,,,,,,,,,,,,EVENTOUT,
+PortH,PH1,,,,,,,,,,,,,,,,EVENTOUT,
+PortH,PH2,,,,,,,,,,,,ETH_MII_CRS,FMC_SDCKE0,,LCD_R0,EVENTOUT,
+PortH,PH3,,,,,,,,,,,,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,,,FMC_SDNE1,DCMI_D8,,,
+PortH,PH7,,,,,I2C3_SCL,SPI5_MISO,,,,,,ETH_MII_RXD3,FMC_SDCKE1,DCMI_D9,,,
+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,,,,,,,,,,FMC_D18,DCMI_D1,LCD_R4,EVENTOUT,
+PortH,PH11,,,TIM5_CH2,,,,,,,,,,FMC_D19,DCMI_D2,LCD_R5,EVENTOUT,
+PortH,PH12,,,TIM5_CH3,,,,,,,,,,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,,,,,,SPI2_SCK/I2S2_CK,,,,,,,FMC_D25,DCMI_D8,LCD_G6,EVENTOUT,
+PortI,PI2,,,,TIM8_CH4,,SPI2_MISO,I2S2ext_SD,,,,,,FMC_D26,DCMI_D9,LCD_G7,EVENTOUT,
+PortI,PI3,,,,TIM8_ETR,,SPI2_MOSI/I2S2_SD,,,,,,,FMC_D27,DCMI_D10,,EVENTOUT,
+PortI,PI4,,,,TIM8_BKIN,,,,,,,,,FMC_NBL2,DCMI_D5,LCD_B4,EVENTOUT,
+PortI,PI5,,,,TIM8_CH1,,,,,,,,,FMC_NBL3,DCMI_VSYNC,LCD_B5,EVENTOUT,
+PortI,PI6,,,,TIM8_CH2,,,,,,,,,FMC_D28,DCMI_D6,LCD_B6,EVENTOUT,
+PortI,PI7,,,,TIM8_CH3,,,,,,,,,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,
diff --git a/ports/stm32/boards/stm32f4xx_prefix.c b/ports/stm32/boards/stm32f4xx_prefix.c
new file mode 100644
index 000000000..f4ffdab68
--- /dev/null
+++ b/ports/stm32/boards/stm32f4xx_prefix.c
@@ -0,0 +1,32 @@
+// stm32f4xx_prefix.c becomes the initial portion of the generated pins file.
+
+#include <stdio.h>
+
+#include "py/obj.h"
+#include "py/mphal.h"
+#include "pin.h"
+
+#define AF(af_idx, af_fn, af_unit, af_type, af_ptr) \
+{ \
+ { &pin_af_type }, \
+ .name = MP_QSTR_AF ## af_idx ## _ ## af_fn ## af_unit, \
+ .idx = (af_idx), \
+ .fn = AF_FN_ ## af_fn, \
+ .unit = (af_unit), \
+ .type = AF_PIN_TYPE_ ## af_fn ## _ ## af_type, \
+ .af_fn = (af_ptr) \
+}
+
+#define PIN(p_port, p_pin, p_af, p_adc_num, p_adc_channel) \
+{ \
+ { &pin_type }, \
+ .name = MP_QSTR_ ## p_port ## p_pin, \
+ .port = PORT_ ## p_port, \
+ .pin = (p_pin), \
+ .num_af = (sizeof(p_af) / sizeof(pin_af_obj_t)), \
+ .pin_mask = (1 << ((p_pin) & 0x0f)), \
+ .gpio = GPIO ## p_port, \
+ .af = p_af, \
+ .adc_num = p_adc_num, \
+ .adc_channel = p_adc_channel, \
+}
diff --git a/ports/stm32/boards/stm32f746.ld b/ports/stm32/boards/stm32f746.ld
new file mode 100644
index 000000000..ce5e85bb6
--- /dev/null
+++ b/ports/stm32/boards/stm32f746.ld
@@ -0,0 +1,32 @@
+/*
+ GNU linker script for STM32F405
+*/
+
+/* Specify the memory areas */
+MEMORY
+{
+ FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1024K
+ FLASH_ISR (rx) : ORIGIN = 0x08000000, LENGTH = 32K /* sector 0, 32K */
+ 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 = 64K /* Used for storage cache */
+ RAM (xrw) : ORIGIN = 0x20010000, LENGTH = 256K /* SRAM1 = 240K, SRAM2 = 16K */
+}
+
+/* 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);
+
+/* define common sections and symbols */
+INCLUDE common.ld
+
+/* 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 = 0x2004c000; /* tunable */
diff --git a/ports/stm32/boards/stm32f746_af.csv b/ports/stm32/boards/stm32f746_af.csv
new file mode 100644
index 000000000..eabc9ab3b
--- /dev/null
+++ b/ports/stm32/boards/stm32f746_af.csv
@@ -0,0 +1,171 @@
+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/OTG2_HS/OTG1_FS,ETH/OTG1_FS,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,,,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
+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,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
+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,,,OTG_HS_DM,,,EVENTOUT
+PortB,PB15,RTC_REFIN,TIM1_CH3N,,TIM8_CH3N,,SPI2_MOSI/I2S2_SD,,,,TIM12_CH2,,,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,,,,SDMMC1_D6,DCMI_D0,LCD_HSYNC,EVENTOUT
+PortC,PC7,,,TIM3_CH2,TIM8_CH2,,,I2S3_MCK,,USART6_RX,,,,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,I2S_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,,,,,FMC_NWAIT,DCMI_D10,LCD_B2,EVENTOUT
+PortD,PD7,,,,,,,,USART2_CK,SPDIFRX_IN0,,,,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,,FMC_NE2/FMC_NCE,DCMI_VSYNC,,EVENTOUT
+PortG,PG10,,,,,,,,,,LCD_G3,SAI2_SD_B,,FMC_NE3,DCMI_D2,LCD_B2,EVENTOUT
+PortG,PG11,,,,,,,,SPDIFRX_IN0,,,,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,,,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
+
diff --git a/ports/stm32/boards/stm32f767.ld b/ports/stm32/boards/stm32f767.ld
new file mode 100644
index 000000000..225abd810
--- /dev/null
+++ b/ports/stm32/boards/stm32f767.ld
@@ -0,0 +1,32 @@
+/*
+ GNU linker script for STM32F767
+*/
+
+/* Specify the memory areas */
+MEMORY
+{
+ FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1024K
+ FLASH_ISR (rx) : ORIGIN = 0x08000000, LENGTH = 32K /* sector 0, 32K */
+ 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 */
+ RAM (xrw) : ORIGIN = 0x20020000, LENGTH = 384K /* SRAM1 = 368K, SRAM2 = 16K */
+}
+
+/* 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);
+
+/* define common sections and symbols */
+INCLUDE common.ld
+
+/* 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 = 0x20078000; /* tunable */
diff --git a/ports/stm32/boards/stm32f767_af.csv b/ports/stm32/boards/stm32f767_af.csv
new file mode 100644
index 000000000..db27818c6
--- /dev/null
+++ b/ports/stm32/boards/stm32f767_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,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,,,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
+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,I2S_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
diff --git a/ports/stm32/boards/stm32f769.ld b/ports/stm32/boards/stm32f769.ld
new file mode 100644
index 000000000..c4cabe7a4
--- /dev/null
+++ b/ports/stm32/boards/stm32f769.ld
@@ -0,0 +1,32 @@
+/*
+ GNU linker script for STM32F769
+*/
+
+/* Specify the memory areas */
+MEMORY
+{
+ FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1024K
+ FLASH_ISR (rx) : ORIGIN = 0x08000000, LENGTH = 32K /* sector 0, 32K */
+ 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 */
+ RAM (xrw) : ORIGIN = 0x20020000, LENGTH = 384K /* SRAM1 = 368K, SRAM2 = 16K */
+}
+
+/* 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);
+
+/* define common sections and symbols */
+INCLUDE common.ld
+
+/* 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 = 0x20078000; /* tunable */
diff --git a/ports/stm32/boards/stm32l476_af.csv b/ports/stm32/boards/stm32l476_af.csv
new file mode 100644
index 000000000..d67c33880
--- /dev/null
+++ b/ports/stm32/boards/stm32l476_af.csv
@@ -0,0 +1,116 @@
+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,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,
+PortA,PA5,,TIM2_CH1,TIM2_ETR,TIM8_CH1N,,SPI1_SCK,,,,,,,,,LPTIM2_ETR,EVENTOUT,ADC12_IN10,
+PortA,PA6,,TIM1_BKIN,TIM3_CH1,TIM8_BKIN,,SPI1_MISO,,USART3_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,,SPI1_MOSI,,,,,QUADSPI_BK1_IO2,LCD_SEG4,,,TIM17_CH1,EVENTOUT,ADC12_IN12,
+PortA,PA8,MCO,TIM1_CH1,,,,,,USART1_CK,,,OTG_FS_SOF,LCD_COM0,,,LPTIM2_OUT,EVENTOUT,,
+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,,
+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,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,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
+PortB,PB8,,,TIM4_CH3,,I2C1_SCL,,DFSDM_DATIN6,,,CAN1_RX,,LCD_SEG16,SDMMC1_D4,SAI1_MCLK_A,TIM16_CH1,EVENTOUT,,
+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,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,,
+PortC,PC0,,LPTIM1_IN1,,,I2C3_SCL,,DFSDM_DATIN4,,LPUART1_RX,,,LCD_SEG18,,,LPTIM2_IN1,EVENTOUT,ADC123_IN1,
+PortC,PC1,,LPTIM1_OUT,,,I2C3_SDA,,DFSDM_CKIN4,,LPUART1_TX,,,LCD_SEG19,,,,EVENTOUT,ADC123_IN2,
+PortC,PC2,,LPTIM1_IN2,,,,SPI2_MISO,DFSDM_CKOUT,,,,,LCD_SEG20,,,,EVENTOUT,ADC123_IN3,
+PortC,PC3,,LPTIM1_ETR,,,,SPI2_MOSI,,,,,,LCD_VLCD,,SAI1_SD_A,LPTIM2_ETR,EVENTOUT,ADC123_IN4,
+PortC,PC4,,,,,,,,USART3_TX,,,,LCD_SEG22,,,,EVENTOUT,ADC12_IN13,COMP1_INM
+PortC,PC5,,,,,,,,USART3_RX,,,,LCD_SEG23,,,,EVENTOUT,ADC12_IN14,COMP1_INP
+PortC,PC6,,,TIM3_CH1,TIM8_CH1,,,DFSDM_CKIN3,,,TSC_G4_IO1,,LCD_SEG24,SDMMC1_D6,SAI2_MCLK_A,,EVENTOUT,,
+PortC,PC7,,,TIM3_CH2,TIM8_CH2,,,DFSDM_DATIN3,,,TSC_G4_IO2,,LCD_SEG25,SDMMC1_D7,SAI2_MCLK_B,,EVENTOUT,,
+PortC,PC8,,,TIM3_CH3,TIM8_CH3,,,,,,TSC_G4_IO3,,LCD_SEG26,SDMMC1_D0,,,EVENTOUT,,
+PortC,PC9,,TIM8_BKIN2,TIM3_CH4,TIM8_CH4,,,,,,TSC_G4_IO4,OTG_FS_NOE,LCD_SEG27,SDMMC1_D1,SAI2_EXTCLK,TIM8_BKIN2_COMP1,EVENTOUT,,
+PortC,PC10,,,,,,,SPI3_SCK,USART3_TX,UART4_TX,TSC_G3_IO2,,LCD_COM4/LCD_SEG28/LCD_SEG40,SDMMC1_D2,SAI2_SCK_B,,EVENTOUT,,
+PortC,PC11,,,,,,,SPI3_MISO,USART3_RX,UART4_RX,TSC_G3_IO3,,LCD_COM5/LCD_SEG29/LCD_SEG41,SDMMC1_D3,SAI2_MCLK_B,,EVENTOUT,,
+PortC,PC12,,,,,,,SPI3_MOSI,USART3_CK,UART5_TX,TSC_G3_IO4,,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,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,PD3,,,,,,SPI2_MISO,DFSDM_DATIN0,USART2_CTS,,,,,FMC_CLK,,,EVENTOUT,,
+PortD,PD4,,,,,,SPI2_MOSI,DFSDM_CKIN0,USART2_RTS_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,,
+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,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,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,,
+PortE,PE6,TRACED3,,TIM3_CH4,,,,,,,,,,FMC_A22,SAI1_SD_A,,EVENTOUT,,
+PortE,PE7,,TIM1_ETR,,,,,DFSDM_DATIN2,,,,,,FMC_D4,SAI1_SD_B,,EVENTOUT,,
+PortE,PE8,,TIM1_CH1N,,,,,DFSDM_CKIN2,,,,,,FMC_D5,SAI1_SCK_B,,EVENTOUT,,
+PortE,PE9,,TIM1_CH1,,,,,DFSDM_CKOUT,,,,,,FMC_D6,SAI1_FS_B,,EVENTOUT,,
+PortE,PE10,,TIM1_CH2N,,,,,DFSDM_DATIN4,,,TSC_G5_IO1,QUADSPI_CLK,,FMC_D7,SAI1_MCLK_B,,EVENTOUT,,
+PortE,PE11,,TIM1_CH2,,,,,DFSDM_CKIN4,,,TSC_G5_IO2,QUADSPI_NCS,,FMC_D8,,,EVENTOUT,,
+PortE,PE12,,TIM1_CH3N,,,,SPI1_NSS,DFSDM_DATIN5,,,TSC_G5_IO3,QUADSPI_BK1_IO0,,FMC_D9,,,EVENTOUT,,
+PortE,PE13,,TIM1_CH3,,,,SPI1_SCK,DFSDM_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,,,,,,,,,,,SAI1_SD_B,,EVENTOUT,ADC3_IN9,
+PortF,PF7,,,TIM5_CH2,,,,,,,,,,,SAI1_MCLK_B,,EVENTOUT,ADC3_IN10,
+PortF,PF8,,,TIM5_CH3,,,,,,,,,,,SAI1_SCK_B,,EVENTOUT,ADC3_IN11,
+PortF,PF9,,,TIM5_CH4,,,,,,,,,,,SAI1_FS_B,TIM15_CH1,EVENTOUT,ADC3_IN12,
+PortF,PF10,,,,,,,,,,,,,,,TIM15_CH2,EVENTOUT,ADC3_IN13,
+PortF,PF11,,,,,,,,,,,,,,,,EVENTOUT,,
+PortF,PF12,,,,,,,,,,,,,FMC_A6,,,EVENTOUT,,
+PortF,PF13,,,,,,,DFSDM_DATIN6,,,,,,FMC_A7,,,EVENTOUT,,
+PortF,PF14,,,,,,,DFSDM_CKIN6,,,TSC_G8_IO1,,,FMC_A8,,,EVENTOUT,,
+PortF,PF15,,,,,,,,,,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_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,PG13,,,,,I2C1_SDA,,,USART1_CK,,,,,FMC_A24,,,EVENTOUT,,
+PortG,PG14,,,,,I2C1_SCL,,,,,,,,FMC_A25,,,EVENTOUT,,
+PortG,PG15,,LPTIM1_OUT,,,I2C1_SMBA,,,,,,,,,,,EVENTOUT,,
+PortH,PH0,,,,,,,,,,,,,,,,EVENTOUT,,
+PortH,PH1,,,,,,,,,,,,,,,,EVENTOUT,,
diff --git a/ports/stm32/boards/stm32l476xe.ld b/ports/stm32/boards/stm32l476xe.ld
new file mode 100644
index 000000000..bb9895d2a
--- /dev/null
+++ b/ports/stm32/boards/stm32l476xe.ld
@@ -0,0 +1,35 @@
+/*
+ GNU linker script for STM32L476XE
+*/
+
+/* Specify the memory areas */
+MEMORY
+{
+ FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 512K
+ FLASH_ISR (rx) : ORIGIN = 0x08000000, LENGTH = 0x0004000 /* sectors 0-7, 16 KiB */
+ FLASH_TEXT (rx) : ORIGIN = 0x08004000, LENGTH = 0x005C000 /* sectors 8-191, 368 KiB */
+ FLASH_FS (r) : ORIGIN = 0x08060000, LENGTH = 0x0020000 /* sectors 192-255, 128 KiB */
+ RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 96K
+ SRAM2 (xrw) : ORIGIN = 0x10000000, 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 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);
+
+/* define common sections and symbols */
+INCLUDE common.ld
+
+/* 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 = 0x20014000; /* tunable */
+
+_flash_fs_start = ORIGIN(FLASH_FS);
+_flash_fs_end = ORIGIN(FLASH_FS) + LENGTH(FLASH_FS);
diff --git a/ports/stm32/boards/stm32l476xg.ld b/ports/stm32/boards/stm32l476xg.ld
new file mode 100644
index 000000000..684078c43
--- /dev/null
+++ b/ports/stm32/boards/stm32l476xg.ld
@@ -0,0 +1,37 @@
+/*
+ GNU linker script for STM32L476XG
+*/
+
+/* Specify the memory areas */
+MEMORY
+{
+ FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1024K
+ FLASH_ISR (rx) : ORIGIN = 0x08000000, LENGTH = 0x0004000 /* sectors 0-7, 16 KiB */
+ FLASH_TEXT (rx) : ORIGIN = 0x08004000, LENGTH = 0x007C000 /* sectors 8-255, 496 KiB */
+ FLASH_FS (r) : ORIGIN = 0x08080000, LENGTH = 0x0080000 /* sectors 256-511 512 KiB */
+ RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 96K
+ SRAM2 (xrw) : ORIGIN = 0x10000000, LENGTH = 32K
+}
+
+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;
+
+/* 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);
+
+/* define common sections and symbols */
+INCLUDE common.ld
+
+/* 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 = 0x20014000; /* tunable */
+
+_flash_fs_start = ORIGIN(FLASH_FS);
+_flash_fs_end = ORIGIN(FLASH_FS) + LENGTH(FLASH_FS);
diff --git a/ports/stm32/bufhelper.c b/ports/stm32/bufhelper.c
new file mode 100644
index 000000000..79511969b
--- /dev/null
+++ b/ports/stm32/bufhelper.c
@@ -0,0 +1,54 @@
+/*
+ * 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 "py/obj.h"
+#include "bufhelper.h"
+
+void pyb_buf_get_for_send(mp_obj_t o, mp_buffer_info_t *bufinfo, byte *tmp_data) {
+ if (MP_OBJ_IS_INT(o)) {
+ tmp_data[0] = mp_obj_get_int(o);
+ bufinfo->buf = tmp_data;
+ bufinfo->len = 1;
+ bufinfo->typecode = 'B';
+ } else {
+ mp_get_buffer_raise(o, bufinfo, MP_BUFFER_READ);
+ }
+}
+
+mp_obj_t pyb_buf_get_for_recv(mp_obj_t o, vstr_t *vstr) {
+ if (MP_OBJ_IS_INT(o)) {
+ // allocate a new bytearray of given length
+ vstr_init_len(vstr, mp_obj_get_int(o));
+ return MP_OBJ_NULL;
+ } else {
+ // get the existing buffer
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(o, &bufinfo, MP_BUFFER_WRITE);
+ vstr->buf = bufinfo.buf;
+ vstr->len = bufinfo.len;
+ return o;
+ }
+}
diff --git a/ports/stm32/bufhelper.h b/ports/stm32/bufhelper.h
new file mode 100644
index 000000000..c1967bf43
--- /dev/null
+++ b/ports/stm32/bufhelper.h
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ */
+#ifndef MICROPY_INCLUDED_STMHAL_BUFHELPER_H
+#define MICROPY_INCLUDED_STMHAL_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
diff --git a/ports/stm32/can.c b/ports/stm32/can.c
new file mode 100644
index 000000000..2fd593d58
--- /dev/null
+++ b/ports/stm32/can.c
@@ -0,0 +1,901 @@
+/*
+ * 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.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+
+#include "py/nlr.h"
+#include "py/objtuple.h"
+#include "py/runtime.h"
+#include "py/gc.h"
+#include "py/stream.h"
+#include "py/mperrno.h"
+#include "py/mphal.h"
+#include "bufhelper.h"
+#include "can.h"
+#include "irq.h"
+
+#if MICROPY_HW_ENABLE_CAN
+
+#define MASK16 (0)
+#define LIST16 (1)
+#define MASK32 (2)
+#define LIST32 (3)
+
+/// \moduleref pyb
+/// \class CAN - controller area network communication bus
+///
+/// CAN implements the standard CAN communications protocol. At
+/// the physical level it consists of 2 lines: RX and TX. Note that
+/// to connect the pyboard to a CAN bus you must use a CAN transceiver
+/// to convert the CAN logic signals from the pyboard to the correct
+/// voltage levels on the bus.
+///
+/// Note that this driver does not yet support filter configuration
+/// (it defaults to a single filter that lets through all messages),
+/// or bus timing configuration (except for setting the prescaler).
+///
+/// Example usage (works without anything connected):
+///
+/// from pyb import CAN
+/// can = pyb.CAN(1, pyb.CAN.LOOPBACK)
+/// can.send('message!', 123) # send message with id 123
+/// can.recv(0) # receive message on FIFO 0
+
+typedef enum _rx_state_t {
+ RX_STATE_FIFO_EMPTY = 0,
+ RX_STATE_MESSAGE_PENDING,
+ RX_STATE_FIFO_FULL,
+ RX_STATE_FIFO_OVERFLOW,
+} rx_state_t;
+
+typedef struct _pyb_can_obj_t {
+ mp_obj_base_t base;
+ mp_obj_t rxcallback0;
+ mp_obj_t rxcallback1;
+ mp_uint_t can_id : 8;
+ bool is_enabled : 1;
+ bool extframe : 1;
+ byte rx_state0;
+ byte rx_state1;
+ CAN_HandleTypeDef can;
+} pyb_can_obj_t;
+
+STATIC mp_obj_t pyb_can_deinit(mp_obj_t self_in);
+
+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;
+
+ switch (can_obj->can_id) {
+ // CAN1 is on RX,TX = Y3,Y4 = PB9,PB9
+ case PYB_CAN_1:
+ CANx = CAN1;
+ GPIO_AF_CANx = GPIO_AF9_CAN1;
+ GPIO_Port = GPIOB;
+ GPIO_Pin = GPIO_PIN_8 | GPIO_PIN_9;
+ __CAN1_CLK_ENABLE();
+ break;
+
+ // CAN2 is on RX,TX = Y5,Y6 = PB12,PB13
+ case PYB_CAN_2:
+ CANx = CAN2;
+ GPIO_AF_CANx = GPIO_AF9_CAN2;
+ GPIO_Port = GPIOB;
+ GPIO_Pin = GPIO_PIN_12 | GPIO_PIN_13;
+ __CAN1_CLK_ENABLE(); // CAN2 is a "slave" and needs CAN1 enabled as well
+ __CAN2_CLK_ENABLE();
+ break;
+
+ 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);
+
+ // init CANx
+ can_obj->can.Instance = CANx;
+ HAL_CAN_Init(&can_obj->can);
+
+ can_obj->is_enabled = true;
+
+ return true;
+}
+
+void can_init0(void) {
+ for (uint i = 0; i < MP_ARRAY_SIZE(MP_STATE_PORT(pyb_can_obj_all)); i++) {
+ MP_STATE_PORT(pyb_can_obj_all)[i] = NULL;
+ }
+}
+
+void can_deinit(void) {
+ for (int i = 0; i < MP_ARRAY_SIZE(MP_STATE_PORT(pyb_can_obj_all)); i++) {
+ pyb_can_obj_t *can_obj = MP_STATE_PORT(pyb_can_obj_all)[i];
+ if (can_obj != NULL) {
+ pyb_can_deinit(can_obj);
+ }
+ }
+}
+
+STATIC void can_clearfilter(uint32_t f) {
+ CAN_FilterConfTypeDef filter;
+
+ filter.FilterIdHigh = 0;
+ filter.FilterIdLow = 0;
+ filter.FilterMaskIdHigh = 0;
+ filter.FilterMaskIdLow = 0;
+ filter.FilterFIFOAssignment = CAN_FILTER_FIFO0;
+ filter.FilterNumber = f;
+ filter.FilterMode = CAN_FILTERMODE_IDMASK;
+ filter.FilterScale = CAN_FILTERSCALE_16BIT;
+ filter.FilterActivation = DISABLE;
+ filter.BankNumber = can2_start_bank;
+
+ HAL_CAN_ConfigFilter(NULL, &filter);
+}
+
+// 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;
+ uint32_t tickstart;
+ uint32_t rqcpflag;
+ uint32_t txokflag;
+
+ // Check the parameters
+ assert_param(IS_CAN_IDTYPE(hcan->pTxMsg->IDE));
+ assert_param(IS_CAN_RTR(hcan->pTxMsg->RTR));
+ assert_param(IS_CAN_DLC(hcan->pTxMsg->DLC));
+
+ // Select one empty transmit mailbox
+ if ((hcan->Instance->TSR&CAN_TSR_TME0) == CAN_TSR_TME0) {
+ transmitmailbox = CAN_TXMAILBOX_0;
+ rqcpflag = CAN_FLAG_RQCP0;
+ txokflag = CAN_FLAG_TXOK0;
+ } else if ((hcan->Instance->TSR&CAN_TSR_TME1) == CAN_TSR_TME1) {
+ transmitmailbox = CAN_TXMAILBOX_1;
+ rqcpflag = CAN_FLAG_RQCP1;
+ txokflag = CAN_FLAG_TXOK1;
+ } else if ((hcan->Instance->TSR&CAN_TSR_TME2) == CAN_TSR_TME2) {
+ transmitmailbox = CAN_TXMAILBOX_2;
+ rqcpflag = CAN_FLAG_RQCP2;
+ txokflag = CAN_FLAG_TXOK2;
+ } else {
+ transmitmailbox = CAN_TXSTATUS_NOMAILBOX;
+ }
+
+ if (transmitmailbox != CAN_TXSTATUS_NOMAILBOX) {
+ // Set up the Id
+ hcan->Instance->sTxMailBox[transmitmailbox].TIR &= CAN_TI0R_TXRQ;
+ if (hcan->pTxMsg->IDE == CAN_ID_STD) {
+ assert_param(IS_CAN_STDID(hcan->pTxMsg->StdId));
+ hcan->Instance->sTxMailBox[transmitmailbox].TIR |= ((hcan->pTxMsg->StdId << 21) | \
+ hcan->pTxMsg->RTR);
+ } else {
+ assert_param(IS_CAN_EXTID(hcan->pTxMsg->ExtId));
+ hcan->Instance->sTxMailBox[transmitmailbox].TIR |= ((hcan->pTxMsg->ExtId << 3) | \
+ hcan->pTxMsg->IDE | \
+ hcan->pTxMsg->RTR);
+ }
+
+ // Set up the DLC
+ hcan->pTxMsg->DLC &= (uint8_t)0x0000000F;
+ hcan->Instance->sTxMailBox[transmitmailbox].TDTR &= (uint32_t)0xFFFFFFF0;
+ hcan->Instance->sTxMailBox[transmitmailbox].TDTR |= hcan->pTxMsg->DLC;
+
+ // Set up the data field
+ hcan->Instance->sTxMailBox[transmitmailbox].TDLR = (((uint32_t)hcan->pTxMsg->Data[3] << 24) |
+ ((uint32_t)hcan->pTxMsg->Data[2] << 16) |
+ ((uint32_t)hcan->pTxMsg->Data[1] << 8) |
+ ((uint32_t)hcan->pTxMsg->Data[0]));
+ hcan->Instance->sTxMailBox[transmitmailbox].TDHR = (((uint32_t)hcan->pTxMsg->Data[7] << 24) |
+ ((uint32_t)hcan->pTxMsg->Data[6] << 16) |
+ ((uint32_t)hcan->pTxMsg->Data[5] << 8) |
+ ((uint32_t)hcan->pTxMsg->Data[4]));
+ // Request transmission
+ hcan->Instance->sTxMailBox[transmitmailbox].TIR |= CAN_TI0R_TXRQ;
+
+ if (Timeout == 0) {
+ return HAL_OK;
+ }
+
+ // Get tick
+ tickstart = HAL_GetTick();
+ // Check End of transmission flag
+ while (!(__HAL_CAN_TRANSMIT_STATUS(hcan, transmitmailbox))) {
+ // Check for the Timeout
+ if (Timeout != HAL_MAX_DELAY) {
+ if ((HAL_GetTick() - tickstart) > Timeout) {
+ // When the timeout expires, we try to abort the transmission of the packet
+ __HAL_CAN_CANCEL_TRANSMIT(hcan, transmitmailbox);
+ while (!__HAL_CAN_GET_FLAG(hcan, rqcpflag)) {
+ }
+ if (__HAL_CAN_GET_FLAG(hcan, txokflag)) {
+ // The abort attempt failed and the message was sent properly
+ return HAL_OK;
+ } else {
+ return HAL_TIMEOUT;
+ }
+ }
+ }
+ }
+ return HAL_OK;
+ } else {
+ return HAL_BUSY;
+ }
+}
+
+/******************************************************************************/
+// MicroPython bindings
+
+STATIC void pyb_can_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
+ pyb_can_obj_t *self = self_in;
+ 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;
+ case CAN_MODE_LOOPBACK: mode = MP_QSTR_LOOPBACK; break;
+ 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);
+ }
+}
+
+// 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) {
+ 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} },
+ { MP_QSTR_prescaler, MP_ARG_INT, {.u_int = 100} },
+ { 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} },
+ };
+
+ // 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;
+
+ // 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->TTCM = DISABLE;
+ init->ABOM = DISABLE;
+ init->AWUM = DISABLE;
+ init->NART = DISABLE;
+ init->RFLM = DISABLE;
+ init->TXFP = DISABLE;
+
+ // init CAN (if it fails, it's because the port doesn't exist)
+ if (!can_init(self)) {
+ nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "CAN(%d) doesn't exist", self->can_id));
+ }
+
+ return mp_const_none;
+}
+
+/// \classmethod \constructor(bus, ...)
+///
+/// Construct a CAN object on the given bus. `bus` can be 1-2, or 'YA' or 'YB'.
+/// With no additional parameters, the CAN 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 CAN busses are:
+///
+/// - `CAN(1)` is on `YA`: `(RX, TX) = (Y3, Y4) = (PB8, PB9)`
+/// - `CAN(2)` is on `YB`: `(RX, TX) = (Y5, Y6) = (PB12, PB13)`
+STATIC mp_obj_t pyb_can_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 port
+ mp_uint_t can_idx;
+ if (MP_OBJ_IS_STR(args[0])) {
+ const char *port = mp_obj_str_get_str(args[0]);
+ if (0) {
+ #ifdef MICROPY_HW_CAN1_NAME
+ } else if (strcmp(port, MICROPY_HW_CAN1_NAME) == 0) {
+ can_idx = PYB_CAN_1;
+ #endif
+ #ifdef MICROPY_HW_CAN2_NAME
+ } else if (strcmp(port, MICROPY_HW_CAN2_NAME) == 0) {
+ can_idx = PYB_CAN_2;
+ #endif
+ } else {
+ nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "CAN(%s) doesn't exist", port));
+ }
+ } else {
+ can_idx = mp_obj_get_int(args[0]);
+ }
+ if (can_idx < 1 || can_idx > MP_ARRAY_SIZE(MP_STATE_PORT(pyb_can_obj_all))) {
+ nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "CAN(%d) doesn't exist", can_idx));
+ }
+
+ pyb_can_obj_t *self;
+ if (MP_STATE_PORT(pyb_can_obj_all)[can_idx - 1] == NULL) {
+ self = m_new_obj(pyb_can_obj_t);
+ self->base.type = &pyb_can_type;
+ self->can_id = can_idx;
+ self->is_enabled = false;
+ MP_STATE_PORT(pyb_can_obj_all)[can_idx - 1] = self;
+ } else {
+ self = MP_STATE_PORT(pyb_can_obj_all)[can_idx - 1];
+ }
+
+ if (!self->is_enabled || n_args > 1) {
+ if (self->is_enabled) {
+ // The caller is requesting a reconfiguration of the hardware
+ // this can only be done if the hardware is in init mode
+ pyb_can_deinit(self);
+ }
+
+ self->rxcallback0 = mp_const_none;
+ self->rxcallback1 = mp_const_none;
+ self->rx_state0 = RX_STATE_FIFO_EMPTY;
+ self->rx_state1 = RX_STATE_FIFO_EMPTY;
+
+ 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_can_init_helper(self, n_args - 1, args + 1, &kw_args);
+ }
+ }
+
+ return self;
+}
+
+STATIC mp_obj_t pyb_can_init(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
+ return pyb_can_init_helper(args[0], n_args - 1, args + 1, kw_args);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_can_init_obj, 1, pyb_can_init);
+
+/// \method deinit()
+/// Turn off the CAN bus.
+STATIC mp_obj_t pyb_can_deinit(mp_obj_t self_in) {
+ pyb_can_obj_t *self = self_in;
+ self->is_enabled = false;
+ HAL_CAN_DeInit(&self->can);
+ if (self->can.Instance == CAN1) {
+ HAL_NVIC_DisableIRQ(CAN1_RX0_IRQn);
+ HAL_NVIC_DisableIRQ(CAN1_RX1_IRQn);
+ __CAN1_FORCE_RESET();
+ __CAN1_RELEASE_RESET();
+ __CAN1_CLK_DISABLE();
+ } else if (self->can.Instance == CAN2) {
+ HAL_NVIC_DisableIRQ(CAN2_RX0_IRQn);
+ HAL_NVIC_DisableIRQ(CAN2_RX1_IRQn);
+ __CAN2_FORCE_RESET();
+ __CAN2_RELEASE_RESET();
+ __CAN2_CLK_DISABLE();
+ }
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_can_deinit_obj, pyb_can_deinit);
+
+/// \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) {
+ pyb_can_obj_t *self = self_in;
+ mp_int_t fifo = mp_obj_get_int(fifo_in);
+ if (fifo == 0) {
+ if (__HAL_CAN_MSG_PENDING(&self->can, CAN_FIFO0) != 0) {
+ return mp_const_true;
+ }
+ } else {
+ if (__HAL_CAN_MSG_PENDING(&self->can, CAN_FIFO1) != 0) {
+ return mp_const_true;
+ }
+ }
+ return mp_const_false;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(pyb_can_any_obj, pyb_can_any);
+
+/// \method send(send, addr, *, timeout=5000)
+/// Send a message on the bus:
+///
+/// - `send` is the data to send (an integer to send, or a buffer object).
+/// - `addr` is the address to send to
+/// - `timeout` is the timeout in milliseconds to wait for the send.
+///
+/// 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) {
+ 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} },
+ { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
+ { MP_QSTR_rtr, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
+ };
+
+ // parse args
+ pyb_can_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 (bufinfo.len > 8) {
+ mp_raise_ValueError("CAN data field too long");
+ }
+
+ // send the data
+ CanTxMsgTypeDef tx_msg;
+ if (self->extframe) {
+ tx_msg.ExtId = args[1].u_int & 0x1FFFFFFF;
+ tx_msg.IDE = CAN_ID_EXT;
+ } else {
+ tx_msg.StdId = args[1].u_int & 0x7FF;
+ tx_msg.IDE = CAN_ID_STD;
+ }
+ if (args[3].u_bool == false) {
+ tx_msg.RTR = CAN_RTR_DATA;
+ } else {
+ tx_msg.RTR = CAN_RTR_REMOTE;
+ }
+ tx_msg.DLC = bufinfo.len;
+ for (mp_uint_t i = 0; i < bufinfo.len; i++) {
+ tx_msg.Data[i] = ((byte*)bufinfo.buf)[i]; // Data is uint32_t but holds only 1 byte
+ }
+
+ self->can.pTxMsg = &tx_msg;
+ HAL_StatusTypeDef status = CAN_Transmit(&self->can, args[2].u_int);
+
+ if (status != HAL_OK) {
+ mp_hal_raise(status);
+ }
+
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_can_send_obj, 1, pyb_can_send);
+
+/// \method recv(fifo, *, timeout=5000)
+///
+/// Receive data on the bus:
+///
+/// - `fifo` is an integer, which is the FIFO to receive on
+/// - `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) {
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_fifo, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} },
+ { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 5000} },
+ };
+
+ // parse args
+ pyb_can_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);
+
+ // 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);
+ }
+
+ // 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;
+
+ 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) {
+ // Fifo is empty
+ __HAL_CAN_ENABLE_IT(&self->can, (args[0].u_int == 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);
+ *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);
+ *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);
+ } else {
+ tuple->items[0] = MP_OBJ_NEW_SMALL_INT(rx_msg.ExtId);
+ }
+ 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
+ }
+ tuple->items[3] = mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
+ return tuple;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_can_recv_obj, 1, pyb_can_recv);
+
+/// \class method initfilterbanks
+///
+/// Set up the filterbanks. All filter will be disabled and set to their reset states.
+///
+/// - `banks` is an integer that sets how many filter banks that are reserved for CAN1.
+/// 0 -> no filters assigned for CAN1
+/// 28 -> all filters are assigned to CAN1
+/// CAN2 will get the rest of the 28 available.
+///
+/// Return value: none.
+STATIC mp_obj_t pyb_can_initfilterbanks(mp_obj_t self, mp_obj_t bank_in) {
+ can2_start_bank = mp_obj_get_int(bank_in);
+
+ for (int f = 0; f < 28; f++) {
+ can_clearfilter(f);
+ }
+
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(pyb_can_initfilterbanks_fun_obj, pyb_can_initfilterbanks);
+STATIC MP_DEFINE_CONST_CLASSMETHOD_OBJ(pyb_can_initfilterbanks_obj, (const mp_obj_t)&pyb_can_initfilterbanks_fun_obj);
+
+STATIC mp_obj_t pyb_can_clearfilter(mp_obj_t self_in, mp_obj_t bank_in) {
+ pyb_can_obj_t *self = self_in;
+ mp_int_t f = mp_obj_get_int(bank_in);
+ if (self->can_id == 2) {
+ f += can2_start_bank;
+ }
+ can_clearfilter(f);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(pyb_can_clearfilter_obj, pyb_can_clearfilter);
+
+/// Configures a filterbank
+/// 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) {
+ 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} },
+ { MP_QSTR_fifo, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = CAN_FILTER_FIFO0} },
+ { MP_QSTR_params, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+ { MP_QSTR_rtr, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+ };
+
+ // parse args
+ pyb_can_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);
+
+ size_t len;
+ size_t rtr_len;
+ 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);
+ }
+
+ CAN_FilterConfTypeDef filter;
+ if (args[1].u_int == MASK16 || args[1].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) {
+ 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;
+ rtr_masks[3] = 0x02;
+ } else { // LIST16
+ rtr_masks[0] = mp_obj_get_int(rtr_flags[0]) ? 0x02 : 0;
+ rtr_masks[1] = mp_obj_get_int(rtr_flags[1]) ? 0x02 : 0;
+ rtr_masks[2] = mp_obj_get_int(rtr_flags[2]) ? 0x02 : 0;
+ rtr_masks[3] = mp_obj_get_int(rtr_flags[3]) ? 0x02 : 0;
+ }
+ }
+ filter.FilterIdLow = EXTENDED_ID_TO_16BIT_FILTER(mp_obj_get_int(params[0])) | rtr_masks[0]; // id1
+ filter.FilterMaskIdLow = EXTENDED_ID_TO_16BIT_FILTER(mp_obj_get_int(params[1])) | rtr_masks[1]; // mask1
+ 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) {
+ 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;
+ rtr_masks[3] = 0x10;
+ } else { // LIST16
+ rtr_masks[0] = mp_obj_get_int(rtr_flags[0]) ? 0x10 : 0;
+ rtr_masks[1] = mp_obj_get_int(rtr_flags[1]) ? 0x10 : 0;
+ rtr_masks[2] = mp_obj_get_int(rtr_flags[2]) ? 0x10 : 0;
+ rtr_masks[3] = mp_obj_get_int(rtr_flags[3]) ? 0x10 : 0;
+ }
+ }
+ filter.FilterIdLow = (mp_obj_get_int(params[0]) << 5) | rtr_masks[0]; // id1
+ filter.FilterMaskIdLow = (mp_obj_get_int(params[1]) << 5) | rtr_masks[1]; // mask1
+ 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) {
+ filter.FilterMode = CAN_FILTERMODE_IDMASK;
+ }
+ if (args[1].u_int == LIST16) {
+ filter.FilterMode = CAN_FILTERMODE_IDLIST;
+ }
+ }
+ else if (args[1].u_int == MASK32 || args[1].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) {
+ rtr_masks[0] = mp_obj_get_int(rtr_flags[0]) ? 0x02 : 0;
+ rtr_masks[1] = 0x02;
+ } else { // LIST32
+ rtr_masks[0] = mp_obj_get_int(rtr_flags[0]) ? 0x02 : 0;
+ rtr_masks[1] = mp_obj_get_int(rtr_flags[1]) ? 0x02 : 0;
+ }
+ }
+ filter.FilterIdHigh = (mp_obj_get_int(params[0]) & 0x1FFFE000) >> 13;
+ 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) {
+ filter.FilterMode = CAN_FILTERMODE_IDMASK;
+ }
+ if (args[1].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
+ if (self->can_id == 1) {
+ if (filter.FilterNumber >= can2_start_bank) {
+ goto error;
+ }
+ } else {
+ filter.FilterNumber = filter.FilterNumber + can2_start_bank;
+ if (filter.FilterNumber > 27) {
+ goto error;
+ }
+ }
+ filter.FilterActivation = ENABLE;
+ filter.BankNumber = can2_start_bank;
+ HAL_CAN_ConfigFilter(&self->can, &filter);
+
+ return mp_const_none;
+
+error:
+ mp_raise_ValueError("CAN filter parameter error");
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_can_setfilter_obj, 1, pyb_can_setfilter);
+
+STATIC mp_obj_t pyb_can_rxcallback(mp_obj_t self_in, mp_obj_t fifo_in, mp_obj_t callback_in) {
+ pyb_can_obj_t *self = self_in;
+ mp_int_t fifo = mp_obj_get_int(fifo_in);
+ mp_obj_t *callback;
+
+ callback = (fifo == 0) ? &self->rxcallback0 : &self->rxcallback1;
+ if (callback_in == mp_const_none) {
+ __HAL_CAN_DISABLE_IT(&self->can, (fifo == 0) ? CAN_IT_FMP0 : CAN_IT_FMP1);
+ __HAL_CAN_DISABLE_IT(&self->can, (fifo == 0) ? CAN_IT_FF0 : CAN_IT_FF1);
+ __HAL_CAN_DISABLE_IT(&self->can, (fifo == 0) ? CAN_IT_FOV0 : CAN_IT_FOV1);
+ __HAL_CAN_CLEAR_FLAG(&self->can, (fifo == CAN_FIFO0) ? CAN_FLAG_FF0 : CAN_FLAG_FF1);
+ __HAL_CAN_CLEAR_FLAG(&self->can, (fifo == CAN_FIFO0) ? CAN_FLAG_FOV0 : CAN_FLAG_FOV1);
+ *callback = mp_const_none;
+ } else if (*callback != mp_const_none) {
+ // Rx call backs has already been initialized
+ // only the callback function should be changed
+ *callback = callback_in;
+ } else if (mp_obj_is_callable(callback_in)) {
+ *callback = callback_in;
+ uint32_t irq;
+ if (self->can_id == PYB_CAN_1) {
+ irq = (fifo == 0) ? CAN1_RX0_IRQn : CAN1_RX1_IRQn;
+ } else {
+ irq = (fifo == 0) ? CAN2_RX0_IRQn : CAN2_RX1_IRQn;
+ }
+ HAL_NVIC_SetPriority(irq, IRQ_PRI_CAN, IRQ_SUBPRI_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);
+ __HAL_CAN_ENABLE_IT(&self->can, (fifo == 0) ? CAN_IT_FOV0 : CAN_IT_FOV1);
+ }
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_3(pyb_can_rxcallback_obj, pyb_can_rxcallback);
+
+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_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) },
+ { MP_ROM_QSTR(MP_QSTR_initfilterbanks), MP_ROM_PTR(&pyb_can_initfilterbanks_obj) },
+ { MP_ROM_QSTR(MP_QSTR_setfilter), MP_ROM_PTR(&pyb_can_setfilter_obj) },
+ { MP_ROM_QSTR(MP_QSTR_clearfilter), MP_ROM_PTR(&pyb_can_clearfilter_obj) },
+ { MP_ROM_QSTR(MP_QSTR_rxcallback), MP_ROM_PTR(&pyb_can_rxcallback_obj) },
+
+ // class constants
+ // Note: we use the ST constants >> 4 so they fit in a small-int. The
+ // right-shift is undone when the constants are used in the init function.
+ { MP_ROM_QSTR(MP_QSTR_NORMAL), MP_ROM_INT(CAN_MODE_NORMAL >> 4) },
+ { MP_ROM_QSTR(MP_QSTR_LOOPBACK), MP_ROM_INT(CAN_MODE_LOOPBACK >> 4) },
+ { MP_ROM_QSTR(MP_QSTR_SILENT), MP_ROM_INT(CAN_MODE_SILENT >> 4) },
+ { MP_ROM_QSTR(MP_QSTR_SILENT_LOOPBACK), MP_ROM_INT(CAN_MODE_SILENT_LOOPBACK >> 4) },
+ { MP_ROM_QSTR(MP_QSTR_MASK16), MP_ROM_INT(MASK16) },
+ { 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) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(pyb_can_locals_dict, pyb_can_locals_dict_table);
+
+mp_uint_t can_ioctl(mp_obj_t self_in, mp_uint_t request, mp_uint_t arg, int *errcode) {
+ pyb_can_obj_t *self = self_in;
+ mp_uint_t ret;
+ if (request == MP_STREAM_POLL) {
+ mp_uint_t flags = arg;
+ ret = 0;
+ if ((flags & MP_STREAM_POLL_RD)
+ && ((__HAL_CAN_MSG_PENDING(&self->can, CAN_FIFO0) != 0)
+ || (__HAL_CAN_MSG_PENDING(&self->can, CAN_FIFO1) != 0))) {
+ ret |= MP_STREAM_POLL_RD;
+ }
+ if ((flags & MP_STREAM_POLL_WR) && (self->can.Instance->TSR & CAN_TSR_TME)) {
+ ret |= MP_STREAM_POLL_WR;
+ }
+ } else {
+ *errcode = MP_EINVAL;
+ ret = -1;
+ }
+ return ret;
+}
+
+void can_rx_irq_handler(uint can_id, uint fifo_id) {
+ mp_obj_t callback;
+ pyb_can_obj_t *self;
+ mp_obj_t irq_reason = MP_OBJ_NEW_SMALL_INT(0);
+ byte *state;
+
+ self = MP_STATE_PORT(pyb_can_obj_all)[can_id - 1];
+
+ if (fifo_id == CAN_FIFO0) {
+ callback = self->rxcallback0;
+ state = &self->rx_state0;
+ } else {
+ callback = self->rxcallback1;
+ state = &self->rx_state1;
+ }
+
+ switch (*state) {
+ case RX_STATE_FIFO_EMPTY:
+ __HAL_CAN_DISABLE_IT(&self->can, (fifo_id == CAN_FIFO0) ? CAN_IT_FMP0 : CAN_IT_FMP1);
+ irq_reason = MP_OBJ_NEW_SMALL_INT(0);
+ *state = RX_STATE_MESSAGE_PENDING;
+ break;
+ case RX_STATE_MESSAGE_PENDING:
+ __HAL_CAN_DISABLE_IT(&self->can, (fifo_id == CAN_FIFO0) ? CAN_IT_FF0 : CAN_IT_FF1);
+ __HAL_CAN_CLEAR_FLAG(&self->can, (fifo_id == CAN_FIFO0) ? CAN_FLAG_FF0 : CAN_FLAG_FF1);
+ irq_reason = MP_OBJ_NEW_SMALL_INT(1);
+ *state = RX_STATE_FIFO_FULL;
+ break;
+ case RX_STATE_FIFO_FULL:
+ __HAL_CAN_DISABLE_IT(&self->can, (fifo_id == CAN_FIFO0) ? CAN_IT_FOV0 : CAN_IT_FOV1);
+ __HAL_CAN_CLEAR_FLAG(&self->can, (fifo_id == CAN_FIFO0) ? CAN_FLAG_FOV0 : CAN_FLAG_FOV1);
+ irq_reason = MP_OBJ_NEW_SMALL_INT(2);
+ *state = RX_STATE_FIFO_OVERFLOW;
+ break;
+ case RX_STATE_FIFO_OVERFLOW:
+ // This should never happen
+ break;
+ }
+
+ if (callback != mp_const_none) {
+ mp_sched_lock();
+ gc_lock();
+ nlr_buf_t nlr;
+ if (nlr_push(&nlr) == 0) {
+ mp_call_function_2(callback, self, irq_reason);
+ nlr_pop();
+ } else {
+ // Uncaught exception; disable the callback so it doesn't run again.
+ pyb_can_rxcallback(self, MP_OBJ_NEW_SMALL_INT(fifo_id), mp_const_none);
+ printf("uncaught exception in CAN(%u) rx interrupt handler\n", self->can_id);
+ mp_obj_print_exception(&mp_plat_print, (mp_obj_t)nlr.ret_val);
+ }
+ gc_unlock();
+ mp_sched_unlock();
+ }
+}
+
+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?
+ .ioctl = can_ioctl,
+ .is_text = false,
+};
+
+const mp_obj_type_t pyb_can_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_CAN,
+ .print = pyb_can_print,
+ .make_new = pyb_can_make_new,
+ .protocol = &can_stream_p,
+ .locals_dict = (mp_obj_t)&pyb_can_locals_dict,
+};
+
+#endif // MICROPY_HW_ENABLE_CAN
diff --git a/ports/stm32/can.h b/ports/stm32/can.h
new file mode 100644
index 000000000..860012813
--- /dev/null
+++ b/ports/stm32/can.h
@@ -0,0 +1,38 @@
+/*
+ * 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.
+ */
+#ifndef MICROPY_INCLUDED_STMHAL_CAN_H
+#define MICROPY_INCLUDED_STMHAL_CAN_H
+
+#define PYB_CAN_1 (1)
+#define PYB_CAN_2 (2)
+
+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);
+
+#endif // MICROPY_INCLUDED_STMHAL_CAN_H
diff --git a/ports/stm32/dac.c b/ports/stm32/dac.c
new file mode 100644
index 000000000..268b1bcfb
--- /dev/null
+++ b/ports/stm32/dac.c
@@ -0,0 +1,506 @@
+/*
+ * 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 <stdint.h>
+#include <string.h>
+
+#include "py/runtime.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
+///
+/// The DAC is used to output analog values (a specific voltage) on pin X5 or pin X6.
+/// The voltage will be between 0 and 3.3V.
+///
+/// *This module will undergo changes to the API.*
+///
+/// Example usage:
+///
+/// from pyb import DAC
+///
+/// dac = DAC(1) # create DAC 1 on pin X5
+/// dac.write(128) # write a value to the DAC (makes X5 1.65V)
+///
+/// To output a continuous sine-wave:
+///
+/// import math
+/// from pyb import DAC
+///
+/// # create a buffer containing a sine-wave
+/// buf = bytearray(100)
+/// for i in range(len(buf)):
+/// buf[i] = 128 + int(127 * math.sin(2 * math.pi * i / len(buf)))
+///
+/// # output the sine-wave at 400Hz
+/// dac = DAC(1)
+/// dac.write_timed(buf, 400 * len(buf), mode=DAC.CIRCULAR)
+
+#if defined(MICROPY_HW_ENABLE_DAC) && MICROPY_HW_ENABLE_DAC
+
+STATIC DAC_HandleTypeDef DAC_Handle;
+
+void dac_init(void) {
+ memset(&DAC_Handle, 0, sizeof DAC_Handle);
+ DAC_Handle.Instance = DAC;
+ DAC_Handle.State = HAL_DAC_STATE_RESET;
+ HAL_DAC_Init(&DAC_Handle);
+}
+
+#if defined(TIM6)
+STATIC void TIM6_Config(uint freq) {
+ // Init TIM6 at the required frequency (in Hz)
+ TIM_HandleTypeDef *tim = timer_tim6_init(freq);
+
+ // TIM6 TRGO selection
+ TIM_MasterConfigTypeDef config;
+ config.MasterOutputTrigger = TIM_TRGO_UPDATE;
+ config.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
+ HAL_TIMEx_MasterConfigSynchronization(tim, &config);
+
+ // TIM6 start counter
+ HAL_TIM_Base_Start(tim);
+}
+#endif
+
+STATIC uint32_t TIMx_Config(mp_obj_t timer) {
+ // TRGO selection to trigger DAC
+ TIM_HandleTypeDef *tim = pyb_timer_get_handle(timer);
+ TIM_MasterConfigTypeDef config;
+ config.MasterOutputTrigger = TIM_TRGO_UPDATE;
+ config.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
+ HAL_TIMEx_MasterConfigSynchronization(tim, &config);
+
+ // work out the trigger channel (only certain ones are supported)
+ if (tim->Instance == TIM2) {
+ return DAC_TRIGGER_T2_TRGO;
+ } else if (tim->Instance == TIM4) {
+ return DAC_TRIGGER_T4_TRGO;
+ } else if (tim->Instance == TIM5) {
+ return DAC_TRIGGER_T5_TRGO;
+ #if defined(TIM6)
+ } else if (tim->Instance == TIM6) {
+ return DAC_TRIGGER_T6_TRGO;
+ #endif
+ #if defined(TIM7)
+ } else if (tim->Instance == TIM7) {
+ return DAC_TRIGGER_T7_TRGO;
+ #endif
+ #if defined(TIM8)
+ } else if (tim->Instance == TIM8) {
+ return DAC_TRIGGER_T8_TRGO;
+ #endif
+ } else {
+ mp_raise_ValueError("Timer does not support DAC triggering");
+ }
+}
+
+/******************************************************************************/
+// MicroPython bindings
+
+typedef enum {
+ DAC_STATE_RESET,
+ DAC_STATE_WRITE_SINGLE,
+ DAC_STATE_BUILTIN_WAVEFORM,
+ DAC_STATE_DMA_WAVEFORM, // should be last enum since we use space beyond it
+} pyb_dac_state_t;
+
+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
+ uint8_t bits; // 8 or 12
+ uint8_t state;
+} pyb_dac_obj_t;
+
+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} },
+ };
+
+ // 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);
+
+ // 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);
+
+ // DAC peripheral clock
+ #if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7)
+ __DAC_CLK_ENABLE();
+ #elif defined(MCU_SERIES_L4)
+ __HAL_RCC_DAC1_CLK_ENABLE();
+ #else
+ #error Unsupported Processor
+ #endif
+
+ // stop anything already going on
+ __DMA1_CLK_ENABLE();
+ DMA_HandleTypeDef DMA_Handle;
+ /* Get currently configured dma */
+ dma_init_handle(&DMA_Handle, self->tx_dma_descr, (void*)NULL);
+ // Need to deinit DMA first
+ DMA_Handle.State = HAL_DMA_STATE_READY;
+ HAL_DMA_DeInit(&DMA_Handle);
+
+ HAL_DAC_Stop(&DAC_Handle, self->dac_channel);
+ if ((self->dac_channel == DAC_CHANNEL_1 && DAC_Handle.DMA_Handle1 != NULL)
+ || (self->dac_channel == DAC_CHANNEL_2 && DAC_Handle.DMA_Handle2 != NULL)) {
+ HAL_DAC_Stop_DMA(&DAC_Handle, self->dac_channel);
+ }
+
+ // set bit resolution
+ if (args[0].u_int == 8 || args[0].u_int == 12) {
+ self->bits = args[0].u_int;
+ } else {
+ mp_raise_ValueError("unsupported bits");
+ }
+
+ // reset state of DAC
+ self->state = DAC_STATE_RESET;
+
+ return mp_const_none;
+}
+
+// create the dac object
+// currently support either DAC1 on X5 (id = 1) or DAC2 on X6 (id = 2)
+
+/// \classmethod \constructor(port)
+/// Construct a new DAC object.
+///
+/// `port` can be a pin object, or an integer (1 or 2).
+/// DAC(1) is on pin X5 and DAC(2) is on pin X6.
+STATIC mp_obj_t pyb_dac_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);
+
+ // get pin/channel to output on
+ mp_int_t dac_id;
+ if (MP_OBJ_IS_INT(args[0])) {
+ dac_id = mp_obj_get_int(args[0]);
+ } else {
+ const pin_obj_t *pin = pin_find(args[0]);
+ if (pin == &pin_A4) {
+ dac_id = 1;
+ } 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));
+ }
+ }
+
+ pyb_dac_obj_t *dac = m_new_obj(pyb_dac_obj_t);
+ dac->base.type = &pyb_dac_type;
+
+ if (dac_id == 1) {
+ dac->pin = GPIO_PIN_4;
+ 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->dac_channel = DAC_CHANNEL_2;
+ dac->tx_dma_descr = &dma_DAC_2_TX;
+ } else {
+ nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "DAC(%d) doesn't exist", dac_id));
+ }
+
+ // configure the peripheral
+ mp_map_t kw_args;
+ mp_map_init_fixed_table(&kw_args, n_kw, args + n_args);
+ pyb_dac_init_helper(dac, n_args - 1, args + 1, &kw_args);
+
+ // return object
+ return dac;
+}
+
+STATIC mp_obj_t pyb_dac_init(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
+ return pyb_dac_init_helper(args[0], n_args - 1, args + 1, kw_args);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_dac_init_obj, 1, pyb_dac_init);
+
+/// \method deinit()
+/// Turn off the DAC, enable other use of pin.
+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;
+ DAC_Handle.Instance->CR |= DAC_CR_BOFF1;
+ } else {
+ DAC_Handle.Instance->CR &= ~DAC_CR_EN2;
+ DAC_Handle.Instance->CR |= DAC_CR_BOFF2;
+ }
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_dac_deinit_obj, pyb_dac_deinit);
+
+#if defined(TIM6)
+/// \method noise(freq)
+/// Generate a pseudo-random noise signal. A new random sample is written
+/// to the DAC output at the given frequency.
+STATIC mp_obj_t pyb_dac_noise(mp_obj_t self_in, mp_obj_t freq) {
+ pyb_dac_obj_t *self = self_in;
+
+ // set TIM6 to trigger the DAC at the given frequency
+ TIM6_Config(mp_obj_get_int(freq));
+
+ if (self->state != DAC_STATE_BUILTIN_WAVEFORM) {
+ // configure DAC to trigger via TIM6
+ DAC_ChannelConfTypeDef config;
+ config.DAC_Trigger = DAC_TRIGGER_T6_TRGO;
+ config.DAC_OutputBuffer = DAC_OUTPUTBUFFER_ENABLE;
+ HAL_DAC_ConfigChannel(&DAC_Handle, &config, self->dac_channel);
+ self->state = DAC_STATE_BUILTIN_WAVEFORM;
+ }
+
+ // set noise wave generation
+ HAL_DACEx_NoiseWaveGenerate(&DAC_Handle, self->dac_channel, DAC_LFSRUNMASK_BITS10_0);
+ HAL_DAC_SetValue(&DAC_Handle, self->dac_channel, DAC_ALIGN_12B_L, 0x7ff0);
+ HAL_DAC_Start(&DAC_Handle, self->dac_channel);
+
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(pyb_dac_noise_obj, pyb_dac_noise);
+#endif
+
+#if defined(TIM6)
+/// \method triangle(freq)
+/// Generate a triangle wave. The value on the DAC output changes at
+/// the given frequency, and the frequence of the repeating triangle wave
+/// itself is 256 (or 1024, need to check) times smaller.
+STATIC mp_obj_t pyb_dac_triangle(mp_obj_t self_in, mp_obj_t freq) {
+ pyb_dac_obj_t *self = self_in;
+
+ // set TIM6 to trigger the DAC at the given frequency
+ TIM6_Config(mp_obj_get_int(freq));
+
+ if (self->state != DAC_STATE_BUILTIN_WAVEFORM) {
+ // configure DAC to trigger via TIM6
+ DAC_ChannelConfTypeDef config;
+ config.DAC_Trigger = DAC_TRIGGER_T6_TRGO;
+ config.DAC_OutputBuffer = DAC_OUTPUTBUFFER_ENABLE;
+ HAL_DAC_ConfigChannel(&DAC_Handle, &config, self->dac_channel);
+ self->state = DAC_STATE_BUILTIN_WAVEFORM;
+ }
+
+ // set triangle wave generation
+ HAL_DACEx_TriangleWaveGenerate(&DAC_Handle, self->dac_channel, DAC_TRIANGLEAMPLITUDE_1023);
+ HAL_DAC_SetValue(&DAC_Handle, self->dac_channel, DAC_ALIGN_12B_R, 0x100);
+ HAL_DAC_Start(&DAC_Handle, self->dac_channel);
+
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(pyb_dac_triangle_obj, pyb_dac_triangle);
+#endif
+
+/// \method write(value)
+/// Direct access to the DAC output (8 bit only at the moment).
+STATIC mp_obj_t pyb_dac_write(mp_obj_t self_in, mp_obj_t val) {
+ pyb_dac_obj_t *self = self_in;
+
+ if (self->state != DAC_STATE_WRITE_SINGLE) {
+ DAC_ChannelConfTypeDef config;
+ config.DAC_Trigger = DAC_TRIGGER_NONE;
+ config.DAC_OutputBuffer = DAC_OUTPUTBUFFER_DISABLE;
+ HAL_DAC_ConfigChannel(&DAC_Handle, &config, self->dac_channel);
+ self->state = DAC_STATE_WRITE_SINGLE;
+ }
+
+ // DAC output is always 12-bit at the hardware level, and we provide support
+ // for multiple bit "resolutions" simply by shifting the input value.
+ HAL_DAC_SetValue(&DAC_Handle, self->dac_channel, DAC_ALIGN_12B_R,
+ mp_obj_get_int(val) << (12 - self->bits));
+
+ HAL_DAC_Start(&DAC_Handle, self->dac_channel);
+
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(pyb_dac_write_obj, pyb_dac_write);
+
+#if defined(TIM6)
+/// \method write_timed(data, freq, *, mode=DAC.NORMAL)
+/// Initiates a burst of RAM to DAC using a DMA transfer.
+/// The input data is treated as an array of bytes (8 bit data).
+///
+/// `freq` can be an integer specifying the frequency to write the DAC
+/// samples at, using Timer(6). Or it can be an already-initialised
+/// Timer object which is used to trigger the DAC sample. Valid timers
+/// are 2, 4, 5, 6, 7 and 8.
+///
+/// `mode` can be `DAC.NORMAL` or `DAC.CIRCULAR`.
+///
+// TODO add callback argument, to call when transfer is finished
+// TODO add double buffer argument
+//
+// TODO reconsider API, eg: write_trig(data, *, trig=None, loop=False)
+// Then trigger can be timer (preinitialised with desired freq) or pin (extint9),
+// and we can reuse the same timer for both DACs (and maybe also ADC) without
+// setting the freq twice.
+// Can still do 1-liner: dac.write_trig(buf, trig=Timer(6, freq=100), loop=True)
+mp_obj_t pyb_dac_write_timed(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_data, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+ { MP_QSTR_freq, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+ { MP_QSTR_mode, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = DMA_NORMAL} },
+ };
+
+ // parse args
+ pyb_dac_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 data to write
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(args[0].u_obj, &bufinfo, MP_BUFFER_READ);
+
+ uint32_t dac_trigger;
+ if (mp_obj_is_integer(args[1].u_obj)) {
+ // set TIM6 to trigger the DAC at the given frequency
+ TIM6_Config(mp_obj_get_int(args[1].u_obj));
+ dac_trigger = DAC_TRIGGER_T6_TRGO;
+ } else {
+ // set the supplied timer to trigger the DAC (timer should be initialised)
+ dac_trigger = TIMx_Config(args[1].u_obj);
+ }
+
+ __DMA1_CLK_ENABLE();
+
+ DMA_HandleTypeDef DMA_Handle;
+ /* Get currently configured dma */
+ dma_init_handle(&DMA_Handle, self->tx_dma_descr, (void*)NULL);
+ /*
+ DMA_Cmd(DMA_Handle->Instance, DISABLE);
+ while (DMA_GetCmdStatus(DMA_Handle->Instance) != DISABLE) {
+ }
+
+ DAC_Cmd(self->dac_channel, DISABLE);
+ */
+
+ /*
+ // DAC channel configuration
+ DAC_InitTypeDef DAC_InitStructure;
+ DAC_InitStructure.DAC_Trigger = DAC_Trigger_T7_TRGO;
+ DAC_InitStructure.DAC_WaveGeneration = DAC_WaveGeneration_None;
+ DAC_InitStructure.DAC_LFSRUnmask_TriangleAmplitude = DAC_TriangleAmplitude_1; // unused, but need to set it to a valid value
+ DAC_InitStructure.DAC_OutputBuffer = DAC_OutputBuffer_Enable;
+ DAC_Init(self->dac_channel, &DAC_InitStructure);
+ */
+
+ // Need to deinit DMA first
+ DMA_Handle.State = HAL_DMA_STATE_READY;
+ HAL_DMA_DeInit(&DMA_Handle);
+
+ if (self->bits == 8) {
+ DMA_Handle.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
+ DMA_Handle.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
+ } else {
+ DMA_Handle.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
+ DMA_Handle.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
+ }
+ DMA_Handle.Init.Mode = args[2].u_int;
+ HAL_DMA_Init(&DMA_Handle);
+
+ if (self->dac_channel == DAC_CHANNEL_1) {
+ __HAL_LINKDMA(&DAC_Handle, DMA_Handle1, DMA_Handle);
+ } else {
+ __HAL_LINKDMA(&DAC_Handle, DMA_Handle2, DMA_Handle);
+ }
+
+ DAC_Handle.Instance = DAC;
+ DAC_Handle.State = HAL_DAC_STATE_RESET;
+ HAL_DAC_Init(&DAC_Handle);
+
+ if (self->state != DAC_STATE_DMA_WAVEFORM + dac_trigger) {
+ DAC_ChannelConfTypeDef config;
+ config.DAC_Trigger = dac_trigger;
+ config.DAC_OutputBuffer = DAC_OUTPUTBUFFER_ENABLE;
+ HAL_DAC_ConfigChannel(&DAC_Handle, &config, self->dac_channel);
+ self->state = DAC_STATE_DMA_WAVEFORM + dac_trigger;
+ }
+
+ if (self->bits == 8) {
+ HAL_DAC_Start_DMA(&DAC_Handle, self->dac_channel,
+ (uint32_t*)bufinfo.buf, bufinfo.len, DAC_ALIGN_8B_R);
+ } else {
+ HAL_DAC_Start_DMA(&DAC_Handle, self->dac_channel,
+ (uint32_t*)bufinfo.buf, bufinfo.len / 2, DAC_ALIGN_12B_R);
+ }
+
+ /*
+ // enable DMA stream
+ DMA_Cmd(DMA_Handle->Instance, ENABLE);
+ while (DMA_GetCmdStatus(DMA_Handle->Instance) == DISABLE) {
+ }
+
+ // enable DAC channel
+ DAC_Cmd(self->dac_channel, ENABLE);
+
+ // enable DMA for DAC channel
+ DAC_DMACmd(self->dac_channel, ENABLE);
+ */
+
+ //printf("DMA: %p %lu\n", bufinfo.buf, bufinfo.len);
+
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_dac_write_timed_obj, 1, pyb_dac_write_timed);
+#endif
+
+STATIC const mp_rom_map_elem_t pyb_dac_locals_dict_table[] = {
+ // instance methods
+ { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&pyb_dac_init_obj) },
+ { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&pyb_dac_deinit_obj) },
+ { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&pyb_dac_write_obj) },
+ #if defined(TIM6)
+ { MP_ROM_QSTR(MP_QSTR_noise), MP_ROM_PTR(&pyb_dac_noise_obj) },
+ { MP_ROM_QSTR(MP_QSTR_triangle), MP_ROM_PTR(&pyb_dac_triangle_obj) },
+ { MP_ROM_QSTR(MP_QSTR_write_timed), MP_ROM_PTR(&pyb_dac_write_timed_obj) },
+ #endif
+
+ // class constants
+ { MP_ROM_QSTR(MP_QSTR_NORMAL), MP_ROM_INT(DMA_NORMAL) },
+ { MP_ROM_QSTR(MP_QSTR_CIRCULAR), MP_ROM_INT(DMA_CIRCULAR) },
+};
+
+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,
+ .make_new = pyb_dac_make_new,
+ .locals_dict = (mp_obj_dict_t*)&pyb_dac_locals_dict,
+};
+
+#endif // MICROPY_HW_ENABLE_DAC
diff --git a/ports/stm32/dac.h b/ports/stm32/dac.h
new file mode 100644
index 000000000..f487f52a9
--- /dev/null
+++ b/ports/stm32/dac.h
@@ -0,0 +1,33 @@
+/*
+ * 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.
+ */
+#ifndef MICROPY_INCLUDED_STMHAL_DAC_H
+#define MICROPY_INCLUDED_STMHAL_DAC_H
+
+void dac_init(void);
+
+extern const mp_obj_type_t pyb_dac_type;
+
+#endif // MICROPY_INCLUDED_STMHAL_DAC_H
diff --git a/ports/stm32/dma.c b/ports/stm32/dma.c
new file mode 100644
index 000000000..df6275d65
--- /dev/null
+++ b/ports/stm32/dma.c
@@ -0,0 +1,508 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2015 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 <stdint.h>
+
+#include "py/obj.h"
+#include "dma.h"
+#include "irq.h"
+
+typedef enum {
+ dma_id_not_defined=-1,
+ dma_id_0,
+ dma_id_1,
+ dma_id_2,
+ dma_id_3,
+ dma_id_4,
+ dma_id_5,
+ dma_id_6,
+ dma_id_7,
+ dma_id_8,
+ dma_id_9,
+ dma_id_10,
+ dma_id_11,
+ dma_id_12,
+ dma_id_13,
+ dma_id_14,
+ dma_id_15,
+} dma_id_t;
+
+typedef struct _dma_descr_t {
+ #if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7)
+ DMA_Stream_TypeDef *instance;
+ #elif defined(MCU_SERIES_L4)
+ DMA_Channel_TypeDef *instance;
+ #else
+ #error "Unsupported Processor"
+ #endif
+ uint32_t sub_instance;
+ 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)
+ .Channel = 0,
+ #elif defined(MCU_SERIES_L4)
+ .Request = 0,
+ #endif
+ .Direction = 0,
+ .PeriphInc = DMA_PINC_DISABLE,
+ .MemInc = DMA_MINC_ENABLE,
+ .PeriphDataAlignment = DMA_PDATAALIGN_BYTE,
+ .MemDataAlignment = DMA_MDATAALIGN_BYTE,
+ .Mode = DMA_NORMAL,
+ .Priority = DMA_PRIORITY_LOW,
+ #if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7)
+ .FIFOMode = DMA_FIFOMODE_DISABLE,
+ .FIFOThreshold = DMA_FIFO_THRESHOLD_FULL,
+ .MemBurst = DMA_MBURST_INC4,
+ .PeriphBurst = DMA_PBURST_INC4
+ #endif
+};
+
+#if defined(MICROPY_HW_HAS_SDCARD) && MICROPY_HW_HAS_SDCARD
+// 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)
+ .Channel = 0,
+ #elif defined(MCU_SERIES_L4)
+ .Request = 0,
+ #endif
+ .Direction = 0,
+ .PeriphInc = DMA_PINC_DISABLE,
+ .MemInc = DMA_MINC_ENABLE,
+ .PeriphDataAlignment = DMA_PDATAALIGN_WORD,
+ .MemDataAlignment = DMA_MDATAALIGN_WORD,
+ #if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7)
+ .Mode = DMA_PFCTRL,
+ #elif defined(MCU_SERIES_L4)
+ .Mode = DMA_NORMAL,
+ #endif
+ .Priority = DMA_PRIORITY_VERY_HIGH,
+ #if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7)
+ .FIFOMode = DMA_FIFOMODE_ENABLE,
+ .FIFOThreshold = DMA_FIFO_THRESHOLD_FULL,
+ .MemBurst = DMA_MBURST_INC4,
+ .PeriphBurst = DMA_PBURST_INC4,
+ #endif
+};
+#endif
+
+#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)
+ .Channel = 0,
+ #elif defined(MCU_SERIES_L4)
+ .Request = 0,
+ #endif
+ .Direction = 0,
+ .PeriphInc = DMA_PINC_DISABLE,
+ .MemInc = DMA_MINC_ENABLE,
+ .PeriphDataAlignment = DMA_PDATAALIGN_BYTE,
+ .MemDataAlignment = DMA_MDATAALIGN_BYTE,
+ .Mode = DMA_NORMAL,
+ .Priority = DMA_PRIORITY_HIGH,
+ #if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7)
+ .FIFOMode = DMA_FIFOMODE_DISABLE,
+ .FIFOThreshold = DMA_FIFO_THRESHOLD_HALFFULL,
+ .MemBurst = DMA_MBURST_SINGLE,
+ .PeriphBurst = DMA_PBURST_SINGLE,
+ #endif
+};
+#endif
+
+#if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7)
+
+#define NCONTROLLERS (2)
+#define NSTREAMS_PER_CONTROLLER (8)
+#define NSTREAM (NCONTROLLERS * NSTREAMS_PER_CONTROLLER)
+
+#define DMA_SUB_INSTANCE_AS_UINT8(dma_channel) (((dma_channel) & DMA_SxCR_CHSEL) >> 25)
+
+#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_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)
+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 };
+const dma_descr_t dma_I2C_2_RX = { DMA1_Stream2, DMA_CHANNEL_7, DMA_PERIPH_TO_MEMORY, dma_id_2, &dma_init_struct_spi_i2c };
+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)
+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
+const dma_descr_t dma_DAC_1_TX = { DMA1_Stream5, DMA_CHANNEL_7, DMA_MEMORY_TO_PERIPH, dma_id_5, &dma_init_struct_dac };
+const dma_descr_t dma_DAC_2_TX = { DMA1_Stream6, DMA_CHANNEL_7, DMA_MEMORY_TO_PERIPH, dma_id_6, &dma_init_struct_dac };
+#endif
+const dma_descr_t dma_SPI_3_TX = { DMA1_Stream7, DMA_CHANNEL_0, DMA_MEMORY_TO_PERIPH, dma_id_7, &dma_init_struct_spi_i2c };
+const dma_descr_t dma_I2C_1_TX = { DMA1_Stream7, DMA_CHANNEL_1, DMA_MEMORY_TO_PERIPH, dma_id_7, &dma_init_struct_spi_i2c };
+const dma_descr_t dma_I2C_2_TX = { DMA1_Stream7, DMA_CHANNEL_7, DMA_MEMORY_TO_PERIPH, dma_id_7, &dma_init_struct_spi_i2c };
+/* not preferred streams
+const dma_descr_t dma_SPI_3_RX = { DMA1_Stream0, DMA_CHANNEL_0, DMA_PERIPH_TO_MEMORY, dma_id_0, &dma_init_struct_spi_i2c };
+const dma_descr_t dma_I2C_1_TX = { DMA1_Stream6, DMA_CHANNEL_1, DMA_MEMORY_TO_PERIPH, dma_id_6, &dma_init_struct_spi_i2c };
+*/
+
+// DMA2 streams
+#if defined(MCU_SERIES_F7) && 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 };
+const dma_descr_t dma_SPI_5_RX = { DMA2_Stream3, DMA_CHANNEL_2, DMA_PERIPH_TO_MEMORY, dma_id_11, &dma_init_struct_spi_i2c };
+#if defined(MICROPY_HW_HAS_SDCARD) && MICROPY_HW_HAS_SDCARD
+const dma_descr_t dma_SDIO_0_RX= { DMA2_Stream3, DMA_CHANNEL_4, DMA_PERIPH_TO_MEMORY, dma_id_11, &dma_init_struct_sdio };
+#endif
+const dma_descr_t dma_SPI_4_RX = { DMA2_Stream3, DMA_CHANNEL_5, DMA_PERIPH_TO_MEMORY, dma_id_11, &dma_init_struct_spi_i2c };
+const dma_descr_t dma_SPI_5_TX = { DMA2_Stream4, DMA_CHANNEL_2, DMA_MEMORY_TO_PERIPH, dma_id_12, &dma_init_struct_spi_i2c };
+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
+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 };
+#if defined(MICROPY_HW_HAS_SDCARD) && MICROPY_HW_HAS_SDCARD
+const dma_descr_t dma_SDIO_0_TX= { DMA2_Stream6, DMA_CHANNEL_4, DMA_MEMORY_TO_PERIPH, dma_id_14, &dma_init_struct_sdio };
+#endif
+/* not preferred streams
+const dma_descr_t dma_SPI_1_TX = { DMA2_Stream3, DMA_CHANNEL_3, DMA_MEMORY_TO_PERIPH, dma_id_11, &dma_init_struct_spi_i2c };
+const dma_descr_t dma_SPI_1_RX = { DMA2_Stream0, DMA_CHANNEL_3, DMA_PERIPH_TO_MEMORY, dma_id_8, &dma_init_struct_spi_i2c };
+const dma_descr_t dma_SPI_4_RX = { DMA2_Stream0, DMA_CHANNEL_4, DMA_PERIPH_TO_MEMORY, dma_id_8, &dma_init_struct_spi_i2c };
+const dma_descr_t dma_SPI_4_TX = { DMA2_Stream1, DMA_CHANNEL_4, DMA_MEMORY_TO_PERIPH, dma_id_9, &dma_init_struct_spi_i2c };
+const dma_descr_t dma_SPI_5_RX = { DMA2_Stream5, DMA_CHANNEL_7, DMA_PERIPH_TO_MEMORY, dma_id_13, &dma_init_struct_spi_i2c };
+const dma_descr_t dma_SPI_5_TX = { DMA2_Stream6, DMA_CHANNEL_7, DMA_MEMORY_TO_PERIPH, 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,
+};
+
+#elif defined(MCU_SERIES_L4)
+
+#define NCONTROLLERS (2)
+#define NSTREAMS_PER_CONTROLLER (7)
+#define NSTREAM (NCONTROLLERS * NSTREAMS_PER_CONTROLLER)
+
+#define DMA_SUB_INSTANCE_AS_UINT8(dma_request) (dma_request)
+
+#define DMA1_ENABLE_MASK (0x007f) // Bits in dma_enable_mask corresponfing to DMA1
+#define DMA2_ENABLE_MASK (0x3f80) // Bits in dma_enable_mask corresponding to DMA2
+
+// These descriptors are ordered by DMAx_Channel number, and within a channel by request
+// number. The duplicate streams are ok as long as they aren't used at the same time.
+
+// DMA1 streams
+//const dma_descr_t dma_ADC_1_RX = { DMA1_Channel1, DMA_REQUEST_0, DMA_PERIPH_TO_MEMORY, dma_id_0, NULL }; // unused
+//const dma_descr_t dma_ADC_2_RX = { DMA1_Channel2, DMA_REQUEST_0, DMA_PERIPH_TO_MEMORY, dma_id_1, NULL }; // unused
+const dma_descr_t dma_SPI_1_RX = { DMA1_Channel2, DMA_REQUEST_1, DMA_PERIPH_TO_MEMORY, dma_id_1, &dma_init_struct_spi_i2c };
+const dma_descr_t dma_I2C_3_TX = { DMA1_Channel2, DMA_REQUEST_3, DMA_MEMORY_TO_PERIPH, dma_id_1, &dma_init_struct_spi_i2c };
+//const dma_descr_t dma_ADC_3_RX = { DMA1_Channel3, DMA_REQUEST_0, DMA_PERIPH_TO_MEMORY, dma_id_2, NULL }; // unused
+const dma_descr_t dma_SPI_1_TX = { DMA1_Channel3, DMA_REQUEST_1, DMA_MEMORY_TO_PERIPH, dma_id_2, &dma_init_struct_spi_i2c };
+const dma_descr_t dma_I2C_3_RX = { DMA1_Channel3, DMA_REQUEST_3, DMA_PERIPH_TO_MEMORY, dma_id_2, &dma_init_struct_spi_i2c };
+#if MICROPY_HW_ENABLE_DAC
+const dma_descr_t dma_DAC_1_TX = { DMA1_Channel3, DMA_REQUEST_6, DMA_MEMORY_TO_PERIPH, dma_id_2, &dma_init_struct_dac };
+#endif
+const dma_descr_t dma_SPI_2_RX = { DMA1_Channel4, DMA_REQUEST_1, DMA_PERIPH_TO_MEMORY, dma_id_3, &dma_init_struct_spi_i2c };
+const dma_descr_t dma_I2C_2_TX = { DMA1_Channel4, DMA_REQUEST_3, DMA_MEMORY_TO_PERIPH, dma_id_3, &dma_init_struct_spi_i2c };
+#if MICROPY_HW_ENABLE_DAC
+const dma_descr_t dma_DAC_2_TX = { DMA1_Channel4, DMA_REQUEST_5, DMA_MEMORY_TO_PERIPH, dma_id_3, &dma_init_struct_dac };
+#endif
+const dma_descr_t dma_SPI_2_TX = { DMA1_Channel5, DMA_REQUEST_1, DMA_MEMORY_TO_PERIPH, dma_id_4, &dma_init_struct_spi_i2c };
+const dma_descr_t dma_I2C_2_RX = { DMA1_Channel5, DMA_REQUEST_3, DMA_PERIPH_TO_MEMORY, dma_id_4, &dma_init_struct_spi_i2c };
+const dma_descr_t dma_I2C_1_TX = { DMA1_Channel6, DMA_REQUEST_3, DMA_MEMORY_TO_PERIPH, dma_id_5, &dma_init_struct_spi_i2c };
+const dma_descr_t dma_I2C_1_RX = { DMA1_Channel7, DMA_REQUEST_3, DMA_PERIPH_TO_MEMORY, dma_id_6, &dma_init_struct_spi_i2c };
+
+// DMA2 streams
+const dma_descr_t dma_SPI_3_RX = { DMA2_Channel1, DMA_REQUEST_3, DMA_PERIPH_TO_MEMORY, dma_id_7, &dma_init_struct_spi_i2c };
+const dma_descr_t dma_SPI_3_TX = { DMA2_Channel2, DMA_REQUEST_3, DMA_MEMORY_TO_PERIPH, dma_id_8, &dma_init_struct_spi_i2c };
+/* not preferred streams
+const dma_descr_t dma_ADC_1_RX = { DMA2_Channel3, DMA_REQUEST_0, DMA_PERIPH_TO_MEMORY, dma_id_9, NULL };
+const dma_descr_t dma_SPI_1_RX = { DMA2_Channel3, DMA_REQUEST_4, DMA_PERIPH_TO_MEMORY, dma_id_9, &dma_init_struct_spi_i2c };
+const dma_descr_t dma_ADC_2_RX = { DMA2_Channel4, DMA_REQUEST_0, DMA_PERIPH_TO_MEMORY, dma_id_10, NULL };
+const dma_descr_t dma_DAC_1_TX = { DMA2_Channel4, DMA_REQUEST_3, DMA_MEMORY_TO_PERIPH, dma_id_10, &dma_init_struct_dac };
+const dma_descr_t dma_SPI_1_TX = { DMA2_Channel4, DMA_REQUEST_4, DMA_MEMORY_TO_PERIPH, dma_id_10, &dma_init_struct_spi_i2c };
+*/
+#if defined(MICROPY_HW_HAS_SDCARD) && MICROPY_HW_HAS_SDCARD
+// defined twice as L4 HAL only needs one channel and can correctly switch direction but sdcard.c needs two channels
+const dma_descr_t dma_SDIO_0_TX= { DMA2_Channel4, DMA_REQUEST_7, DMA_MEMORY_TO_PERIPH, dma_id_10, &dma_init_struct_sdio };
+const dma_descr_t dma_SDIO_0_RX= { DMA2_Channel4, DMA_REQUEST_7, DMA_PERIPH_TO_MEMORY, dma_id_10, &dma_init_struct_sdio };
+#endif
+/* not preferred streams
+const dma_descr_t dma_ADC_3_RX = { DMA2_Channel5, DMA_REQUEST_0, DMA_PERIPH_TO_MEMORY, dma_id_11, NULL };
+const dma_descr_t dma_DAC_2_TX = { DMA2_Channel5, DMA_REQUEST_3, DMA_MEMORY_TO_PERIPH, dma_id_11, &dma_init_struct_dac };
+const dma_descr_t dma_SDIO_0_TX= { DMA2_Channel5, DMA_REQUEST_7, DMA_MEMORY_TO_PERIPH, dma_id_11, &dma_init_struct_sdio };
+const dma_descr_t dma_I2C_1_RX = { DMA2_Channel6, DMA_REQUEST_5, DMA_PERIPH_TO_MEMORY, dma_id_12, &dma_init_struct_spi_i2c };
+const dma_descr_t dma_I2C_1_TX = { DMA2_Channel7, DMA_REQUEST_5, DMA_MEMORY_TO_PERIPH, dma_id_13, &dma_init_struct_spi_i2c };
+*/
+
+static const uint8_t dma_irqn[NSTREAM] = {
+ DMA1_Channel1_IRQn,
+ DMA1_Channel2_IRQn,
+ DMA1_Channel3_IRQn,
+ DMA1_Channel4_IRQn,
+ DMA1_Channel5_IRQn,
+ DMA1_Channel6_IRQn,
+ DMA1_Channel7_IRQn,
+ DMA2_Channel1_IRQn,
+ DMA2_Channel2_IRQn,
+ DMA2_Channel3_IRQn,
+ DMA2_Channel4_IRQn,
+ DMA2_Channel5_IRQn,
+ DMA2_Channel6_IRQn,
+ DMA2_Channel7_IRQn,
+};
+
+#endif
+
+static DMA_HandleTypeDef *dma_handle[NSTREAM] = {NULL};
+static uint8_t dma_last_sub_instance[NSTREAM];
+static volatile uint32_t dma_enable_mask = 0;
+volatile dma_idle_count_t dma_idle;
+
+#define DMA_INVALID_CHANNEL 0xff // Value stored in dma_last_channel which means invalid
+
+#define DMA1_IS_CLK_ENABLED() ((RCC->AHB1ENR & RCC_AHB1ENR_DMA1EN) != 0)
+#define DMA2_IS_CLK_ENABLED() ((RCC->AHB1ENR & RCC_AHB1ENR_DMA2EN) != 0)
+
+#if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7)
+
+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); }
+void DMA1_Stream2_IRQHandler(void) { IRQ_ENTER(DMA1_Stream2_IRQn); if (dma_handle[dma_id_2] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_2]); } IRQ_EXIT(DMA1_Stream2_IRQn); }
+void DMA1_Stream3_IRQHandler(void) { IRQ_ENTER(DMA1_Stream3_IRQn); if (dma_handle[dma_id_3] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_3]); } IRQ_EXIT(DMA1_Stream3_IRQn); }
+void DMA1_Stream4_IRQHandler(void) { IRQ_ENTER(DMA1_Stream4_IRQn); if (dma_handle[dma_id_4] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_4]); } IRQ_EXIT(DMA1_Stream4_IRQn); }
+void DMA1_Stream5_IRQHandler(void) { IRQ_ENTER(DMA1_Stream5_IRQn); if (dma_handle[dma_id_5] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_5]); } IRQ_EXIT(DMA1_Stream5_IRQn); }
+void DMA1_Stream6_IRQHandler(void) { IRQ_ENTER(DMA1_Stream6_IRQn); if (dma_handle[dma_id_6] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_6]); } IRQ_EXIT(DMA1_Stream6_IRQn); }
+void DMA1_Stream7_IRQHandler(void) { IRQ_ENTER(DMA1_Stream7_IRQn); if (dma_handle[dma_id_7] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_7]); } IRQ_EXIT(DMA1_Stream7_IRQn); }
+void DMA2_Stream0_IRQHandler(void) { IRQ_ENTER(DMA2_Stream0_IRQn); if (dma_handle[dma_id_8] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_8]); } IRQ_EXIT(DMA2_Stream0_IRQn); }
+void DMA2_Stream1_IRQHandler(void) { IRQ_ENTER(DMA2_Stream1_IRQn); if (dma_handle[dma_id_9] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_9]); } IRQ_EXIT(DMA2_Stream1_IRQn); }
+void DMA2_Stream2_IRQHandler(void) { IRQ_ENTER(DMA2_Stream2_IRQn); if (dma_handle[dma_id_10] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_10]); } IRQ_EXIT(DMA2_Stream2_IRQn); }
+void DMA2_Stream3_IRQHandler(void) { IRQ_ENTER(DMA2_Stream3_IRQn); if (dma_handle[dma_id_11] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_11]); } IRQ_EXIT(DMA2_Stream3_IRQn); }
+void DMA2_Stream4_IRQHandler(void) { IRQ_ENTER(DMA2_Stream4_IRQn); if (dma_handle[dma_id_12] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_12]); } IRQ_EXIT(DMA2_Stream4_IRQn); }
+void DMA2_Stream5_IRQHandler(void) { IRQ_ENTER(DMA2_Stream5_IRQn); if (dma_handle[dma_id_13] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_13]); } IRQ_EXIT(DMA2_Stream5_IRQn); }
+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)
+
+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); }
+void DMA1_Channel3_IRQHandler(void) { IRQ_ENTER(DMA1_Channel3_IRQn); if (dma_handle[dma_id_2] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_2]); } IRQ_EXIT(DMA1_Channel3_IRQn); }
+void DMA1_Channel4_IRQHandler(void) { IRQ_ENTER(DMA1_Channel4_IRQn); if (dma_handle[dma_id_3] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_3]); } IRQ_EXIT(DMA1_Channel4_IRQn); }
+void DMA1_Channel5_IRQHandler(void) { IRQ_ENTER(DMA1_Channel5_IRQn); if (dma_handle[dma_id_4] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_4]); } IRQ_EXIT(DMA1_Channel5_IRQn); }
+void DMA1_Channel6_IRQHandler(void) { IRQ_ENTER(DMA1_Channel6_IRQn); if (dma_handle[dma_id_5] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_5]); } IRQ_EXIT(DMA1_Channel6_IRQn); }
+void DMA1_Channel7_IRQHandler(void) { IRQ_ENTER(DMA1_Channel7_IRQn); if (dma_handle[dma_id_6] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_6]); } IRQ_EXIT(DMA1_Channel7_IRQn); }
+void DMA2_Channel1_IRQHandler(void) { IRQ_ENTER(DMA2_Channel1_IRQn); if (dma_handle[dma_id_7] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_7]); } IRQ_EXIT(DMA2_Channel1_IRQn); }
+void DMA2_Channel2_IRQHandler(void) { IRQ_ENTER(DMA2_Channel2_IRQn); if (dma_handle[dma_id_8] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_8]); } IRQ_EXIT(DMA2_Channel2_IRQn); }
+void DMA2_Channel3_IRQHandler(void) { IRQ_ENTER(DMA2_Channel3_IRQn); if (dma_handle[dma_id_9] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_9]); } IRQ_EXIT(DMA2_Channel3_IRQn); }
+void DMA2_Channel4_IRQHandler(void) { IRQ_ENTER(DMA2_Channel4_IRQn); if (dma_handle[dma_id_10] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_10]);} IRQ_EXIT(DMA2_Channel4_IRQn); }
+void DMA2_Channel5_IRQHandler(void) { IRQ_ENTER(DMA2_Channel5_IRQn); if (dma_handle[dma_id_11] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_11]);} IRQ_EXIT(DMA2_Channel5_IRQn); }
+void DMA2_Channel6_IRQHandler(void) { IRQ_ENTER(DMA2_Channel6_IRQn); if (dma_handle[dma_id_12] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_12]);} IRQ_EXIT(DMA2_Channel6_IRQn); }
+void DMA2_Channel7_IRQHandler(void) { IRQ_ENTER(DMA2_Channel7_IRQn); if (dma_handle[dma_id_13] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_13]);} IRQ_EXIT(DMA2_Channel7_IRQn); }
+
+#endif
+
+// Resets the idle counter for the DMA controller associated with dma_id.
+static void dma_tickle(dma_id_t dma_id) {
+ dma_idle.counter[(dma_id < NSTREAMS_PER_CONTROLLER) ? 0 : 1] = 1;
+}
+
+static void dma_enable_clock(dma_id_t dma_id) {
+ // We don't want dma_tick_handler() to turn off the clock right after we
+ // enable it, so we need to mark the channel in use in an atomic fashion.
+ mp_uint_t irq_state = MICROPY_BEGIN_ATOMIC_SECTION();
+ uint32_t old_enable_mask = dma_enable_mask;
+ dma_enable_mask |= (1 << dma_id);
+ MICROPY_END_ATOMIC_SECTION(irq_state);
+
+ if (dma_id < NSTREAMS_PER_CONTROLLER) {
+ if (((old_enable_mask & DMA1_ENABLE_MASK) == 0) && !DMA1_IS_CLK_ENABLED()) {
+ __DMA1_CLK_ENABLE();
+
+ // We just turned on the clock. This means that anything stored
+ // in dma_last_channel (for DMA1) needs to be invalidated.
+
+ for (int channel = 0; channel < NSTREAMS_PER_CONTROLLER; channel++) {
+ dma_last_sub_instance[channel] = DMA_INVALID_CHANNEL;
+ }
+ }
+ } else {
+ if (((old_enable_mask & DMA2_ENABLE_MASK) == 0) && !DMA2_IS_CLK_ENABLED()) {
+ __DMA2_CLK_ENABLE();
+
+ // We just turned on the clock. This means that anything stored
+ // in dma_last_channel (for DMA1) needs to be invalidated.
+
+ for (int channel = NSTREAMS_PER_CONTROLLER; channel < NSTREAM; channel++) {
+ dma_last_sub_instance[channel] = DMA_INVALID_CHANNEL;
+ }
+ }
+ }
+}
+
+static void dma_disable_clock(dma_id_t dma_id) {
+ // We just mark the clock as disabled here, but we don't actually disable it.
+ // We wait for the timer to expire first, which means that back-to-back
+ // transfers don't have to initialize as much.
+ dma_tickle(dma_id);
+ dma_enable_mask &= ~(1 << dma_id);
+}
+
+void dma_init_handle(DMA_HandleTypeDef *dma, const dma_descr_t *dma_descr, void *data) {
+ // initialise parameters
+ dma->Instance = dma_descr->instance;
+ dma->Init = *dma_descr->init;
+ dma->Init.Direction = dma_descr->transfer_direction;
+ #if defined(MCU_SERIES_L4)
+ dma->Init.Request = dma_descr->sub_instance;
+ #else
+ dma->Init.Channel = dma_descr->sub_instance;
+ #endif
+ // half of __HAL_LINKDMA(data, xxx, *dma)
+ // caller must implement other half by doing: data->xxx = dma
+ dma->Parent = data;
+}
+
+void dma_init(DMA_HandleTypeDef *dma, const dma_descr_t *dma_descr, void *data){
+ // Some drivers allocate the DMA_HandleTypeDef from the stack
+ // (i.e. dac, i2c, spi) and for those cases we need to clear the
+ // structure so we don't get random values from the stack)
+ memset(dma, 0, sizeof(*dma));
+
+ if (dma_descr != NULL) {
+ dma_id_t dma_id = dma_descr->id;
+
+ dma_init_handle(dma, dma_descr, data);
+ // set global pointer for IRQ handler
+ dma_handle[dma_id] = dma;
+
+ dma_enable_clock(dma_id);
+
+ // 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);
+ if (dma_last_sub_instance[dma_id] != sub_inst) {
+ dma_last_sub_instance[dma_id] = sub_inst;
+
+ // reset and configure DMA peripheral
+ // (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);
+ } else {
+ // only necessary initialization
+ dma->State = HAL_DMA_STATE_READY;
+#if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7)
+ // calculate DMA base address and bitshift to be used in IRQ handler
+ extern uint32_t DMA_CalcBaseAndBitshift(DMA_HandleTypeDef *hdma);
+ DMA_CalcBaseAndBitshift(dma);
+#endif
+ }
+
+ HAL_NVIC_EnableIRQ(dma_irqn[dma_id]);
+ }
+}
+
+void dma_deinit(const dma_descr_t *dma_descr) {
+ if (dma_descr != NULL) {
+ HAL_NVIC_DisableIRQ(dma_irqn[dma_descr->id]);
+ dma_handle[dma_descr->id] = NULL;
+
+ dma_disable_clock(dma_descr->id);
+ }
+}
+
+void dma_invalidate_channel(const dma_descr_t *dma_descr) {
+ if (dma_descr != NULL) {
+ dma_id_t dma_id = dma_descr->id;
+ if (dma_last_sub_instance[dma_id] == DMA_SUB_INSTANCE_AS_UINT8(dma_descr->sub_instance) ) {
+ dma_last_sub_instance[dma_id] = DMA_INVALID_CHANNEL;
+ }
+ }
+}
+
+// Called from the SysTick handler
+// We use LSB of tick to select which controller to process
+void dma_idle_handler(int tick) {
+ static const uint32_t controller_mask[] = {
+ DMA1_ENABLE_MASK, DMA2_ENABLE_MASK
+ };
+ {
+ int controller = tick & 1;
+ if (dma_idle.counter[controller] == 0) {
+ return;
+ }
+ if (++dma_idle.counter[controller] > DMA_IDLE_TICK_MAX) {
+ if ((dma_enable_mask & controller_mask[controller]) == 0) {
+ // Nothing is active and we've reached our idle timeout,
+ // Now we'll really disable the clock.
+ dma_idle.counter[controller] = 0;
+ if (controller == 0) {
+ __DMA1_CLK_DISABLE();
+ } else {
+ __DMA2_CLK_DISABLE();
+ }
+ } else {
+ // Something is still active, but the counter never got
+ // reset, so we'll reset the counter here.
+ dma_idle.counter[controller] = 1;
+ }
+ }
+ }
+}
diff --git a/ports/stm32/dma.h b/ports/stm32/dma.h
new file mode 100644
index 000000000..55fb62175
--- /dev/null
+++ b/ports/stm32/dma.h
@@ -0,0 +1,103 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2015 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_STMHAL_DMA_H
+#define MICROPY_INCLUDED_STMHAL_DMA_H
+
+typedef struct _dma_descr_t dma_descr_t;
+
+#if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7)
+
+extern const dma_descr_t dma_I2C_1_RX;
+extern const dma_descr_t dma_SPI_3_RX;
+extern const dma_descr_t dma_I2C_4_RX;
+extern const dma_descr_t dma_I2C_3_RX;
+extern const dma_descr_t dma_I2C_2_RX;
+extern const dma_descr_t dma_SPI_2_RX;
+extern const dma_descr_t dma_SPI_2_TX;
+extern const dma_descr_t dma_I2C_3_TX;
+extern const dma_descr_t dma_I2C_4_TX;
+extern const dma_descr_t dma_DAC_1_TX;
+extern const dma_descr_t dma_DAC_2_TX;
+extern const dma_descr_t dma_SPI_3_TX;
+extern const dma_descr_t dma_I2C_1_TX;
+extern const dma_descr_t dma_I2C_2_TX;
+extern const dma_descr_t dma_SDMMC_2_RX;
+extern const dma_descr_t dma_SPI_1_RX;
+extern const dma_descr_t dma_SPI_5_RX;
+extern const dma_descr_t dma_SDIO_0_RX;
+extern const dma_descr_t dma_SPI_4_RX;
+extern const dma_descr_t dma_SPI_5_TX;
+extern const dma_descr_t dma_SPI_4_TX;
+extern const dma_descr_t dma_SPI_6_TX;
+extern const dma_descr_t dma_SPI_1_TX;
+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)
+
+extern const dma_descr_t dma_ADC_1_RX;
+extern const dma_descr_t dma_ADC_2_RX;
+extern const dma_descr_t dma_SPI_1_RX;
+extern const dma_descr_t dma_I2C_3_TX;
+extern const dma_descr_t dma_ADC_3_RX;
+extern const dma_descr_t dma_SPI_1_TX;
+extern const dma_descr_t dma_I2C_3_RX;
+extern const dma_descr_t dma_DAC_1_TX;
+extern const dma_descr_t dma_SPI_2_RX;
+extern const dma_descr_t dma_I2C_2_TX;
+extern const dma_descr_t dma_DAC_2_TX;
+extern const dma_descr_t dma_SPI_2_TX;
+extern const dma_descr_t dma_I2C_2_RX;
+extern const dma_descr_t dma_I2C_1_TX;
+extern const dma_descr_t dma_I2C_1_RX;
+extern const dma_descr_t dma_SPI_3_RX;
+extern const dma_descr_t dma_SPI_3_TX;
+extern const dma_descr_t dma_SDIO_0_TX;
+extern const dma_descr_t dma_SDIO_0_RX;
+
+#endif
+
+typedef union {
+ uint16_t enabled; // Used to test if both counters are == 0
+ uint8_t counter[2];
+} dma_idle_count_t;
+extern volatile dma_idle_count_t dma_idle;
+#define DMA_IDLE_ENABLED() (dma_idle.enabled != 0)
+
+#define DMA_SYSTICK_MASK 0x0e
+#define DMA_MSECS_PER_SYSTICK (DMA_SYSTICK_MASK + 1)
+#define DMA_IDLE_TICK_MAX (8) // 128 msec
+#define DMA_IDLE_TICK(tick) (((tick) & DMA_SYSTICK_MASK) == 0)
+
+
+void dma_init(DMA_HandleTypeDef *dma, const dma_descr_t *dma_descr, void *data);
+void dma_init_handle(DMA_HandleTypeDef *dma, const dma_descr_t *dma_descr, void *data);
+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
diff --git a/ports/stm32/extint.c b/ports/stm32/extint.c
new file mode 100644
index 000000000..24a68c2a2
--- /dev/null
+++ b/ports/stm32/extint.c
@@ -0,0 +1,508 @@
+/*
+ * 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 <stddef.h>
+#include <string.h>
+
+#include "py/runtime.h"
+#include "py/gc.h"
+#include "py/mphal.h"
+#include "pin.h"
+#include "extint.h"
+#include "irq.h"
+
+/// \moduleref pyb
+/// \class ExtInt - configure I/O pins to interrupt on external events
+///
+/// There are a total of 22 interrupt lines. 16 of these can come from GPIO pins
+/// and the remaining 6 are from internal sources.
+///
+/// For lines 0 thru 15, a given line can map to the corresponding line from an
+/// arbitrary port. So line 0 can map to Px0 where x is A, B, C, ... and
+/// line 1 can map to Px1 where x is A, B, C, ...
+///
+/// def callback(line):
+/// print("line =", line)
+///
+/// Note: ExtInt will automatically configure the gpio line as an input.
+///
+/// extint = pyb.ExtInt(pin, pyb.ExtInt.IRQ_FALLING, pyb.Pin.PULL_UP, callback)
+///
+/// Now every time a falling edge is seen on the X1 pin, the callback will be
+/// called. Caution: mechanical pushbuttons have "bounce" and pushing or
+/// releasing a switch will often generate multiple edges.
+/// See: http://www.eng.utah.edu/~cs5780/debouncing.pdf for a detailed
+/// explanation, along with various techniques for debouncing.
+///
+/// Trying to register 2 callbacks onto the same pin will throw an exception.
+///
+/// If pin is passed as an integer, then it is assumed to map to one of the
+/// internal interrupt sources, and must be in the range 16 thru 22.
+///
+/// All other pin objects go through the pin mapper to come up with one of the
+/// gpio pins.
+///
+/// extint = pyb.ExtInt(pin, mode, pull, callback)
+///
+/// Valid modes are pyb.ExtInt.IRQ_RISING, pyb.ExtInt.IRQ_FALLING,
+/// pyb.ExtInt.IRQ_RISING_FALLING, pyb.ExtInt.EVT_RISING,
+/// pyb.ExtInt.EVT_FALLING, and pyb.ExtInt.EVT_RISING_FALLING.
+///
+/// Only the IRQ_xxx modes have been tested. The EVT_xxx modes have
+/// something to do with sleep mode and the WFE instruction.
+///
+/// Valid pull values are pyb.Pin.PULL_UP, pyb.Pin.PULL_DOWN, pyb.Pin.PULL_NONE.
+///
+/// There is also a C API, so that drivers which require EXTI interrupt lines
+/// can also use this code. See extint.h for the available functions and
+/// usrsw.h for an example of using this.
+
+// TODO Add python method to change callback object.
+
+#define EXTI_OFFSET (EXTI_BASE - PERIPH_BASE)
+
+// Macro used to set/clear the bit corresponding to the line in the IMR/EMR
+// 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)
+// 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.
+#define EXTI_Mode_Interrupt offsetof(EXTI_TypeDef, IMR1)
+#define EXTI_Mode_Event offsetof(EXTI_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)
+#define EXTI_RTSR EXTI->RTSR
+#define EXTI_FTSR EXTI->FTSR
+#endif
+
+#define EXTI_SWIER_BB(line) (*(__IO uint32_t *)(PERIPH_BB_BASE + ((EXTI_OFFSET + offsetof(EXTI_TypeDef, SWIER)) * 32) + ((line) * 4)))
+
+typedef struct {
+ mp_obj_base_t base;
+ mp_int_t line;
+} extint_obj_t;
+
+STATIC uint8_t pyb_extint_mode[EXTI_NUM_VECTORS];
+STATIC bool pyb_extint_hard_irq[EXTI_NUM_VECTORS];
+
+// The callback arg is a small-int or a ROM Pin object, so no need to scan by GC
+STATIC mp_obj_t pyb_extint_callback_arg[EXTI_NUM_VECTORS];
+
+#if !defined(ETH)
+#define ETH_WKUP_IRQn 62 // Some MCUs don't have ETH, but we want a value to put in our table
+#endif
+#if !defined(OTG_HS_WKUP_IRQn)
+#define OTG_HS_WKUP_IRQn 76 // Some MCUs don't have HS, but we want a value to put in our table
+#endif
+#if !defined(OTG_FS_WKUP_IRQn)
+#define OTG_FS_WKUP_IRQn 42 // Some MCUs don't have FS IRQ, but we want a value to put in our table
+#endif
+
+STATIC const uint8_t nvic_irq_channel[EXTI_NUM_VECTORS] = {
+ 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)
+ PVD_PVM_IRQn,
+ #else
+ PVD_IRQn,
+ #endif
+ RTC_Alarm_IRQn,
+ OTG_FS_WKUP_IRQn,
+ ETH_WKUP_IRQn,
+ OTG_HS_WKUP_IRQn,
+ TAMP_STAMP_IRQn,
+ RTC_WKUP_IRQn,
+};
+
+// Set override_callback_obj to true if you want to unconditionally set the
+// callback function.
+uint extint_register(mp_obj_t pin_obj, uint32_t mode, uint32_t pull, mp_obj_t callback_obj, bool override_callback_obj) {
+ const pin_obj_t *pin = NULL;
+ uint v_line;
+
+ if (MP_OBJ_IS_INT(pin_obj)) {
+ // If an integer is passed in, then use it to identify lines 16 thru 22
+ // We expect lines 0 thru 15 to be passed in as a pin, so that we can
+ // get both the port number and line number.
+ v_line = mp_obj_get_int(pin_obj);
+ if (v_line < 16) {
+ nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "ExtInt vector %d < 16, use a Pin object", v_line));
+ }
+ if (v_line >= EXTI_NUM_VECTORS) {
+ nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "ExtInt vector %d >= max of %d", v_line, EXTI_NUM_VECTORS));
+ }
+ } else {
+ pin = pin_find(pin_obj);
+ v_line = pin->pin;
+ }
+ if (mode != GPIO_MODE_IT_RISING &&
+ mode != GPIO_MODE_IT_FALLING &&
+ mode != GPIO_MODE_IT_RISING_FALLING &&
+ mode != GPIO_MODE_EVT_RISING &&
+ mode != GPIO_MODE_EVT_FALLING &&
+ mode != GPIO_MODE_EVT_RISING_FALLING) {
+ nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "invalid ExtInt Mode: %d", mode));
+ }
+ if (pull != GPIO_NOPULL &&
+ pull != GPIO_PULLUP &&
+ pull != GPIO_PULLDOWN) {
+ nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "invalid ExtInt Pull: %d", pull));
+ }
+
+ mp_obj_t *cb = &MP_STATE_PORT(pyb_extint_callback)[v_line];
+ if (!override_callback_obj && *cb != mp_const_none && callback_obj != mp_const_none) {
+ nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "ExtInt vector %d is already in use", v_line));
+ }
+
+ // We need to update callback atomically, so we disable the line
+ // before we update anything.
+
+ extint_disable(v_line);
+
+ *cb = callback_obj;
+ pyb_extint_mode[v_line] = (mode & 0x00010000) ? // GPIO_MODE_IT == 0x00010000
+ EXTI_Mode_Interrupt : EXTI_Mode_Event;
+
+ if (*cb != mp_const_none) {
+ pyb_extint_hard_irq[v_line] = true;
+ pyb_extint_callback_arg[v_line] = MP_OBJ_NEW_SMALL_INT(v_line);
+
+ mp_hal_gpio_clock_enable(pin->gpio);
+ GPIO_InitTypeDef exti;
+ exti.Pin = pin->pin_mask;
+ exti.Mode = mode;
+ exti.Pull = pull;
+ exti.Speed = GPIO_SPEED_FAST;
+ 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);
+ HAL_NVIC_EnableIRQ(nvic_irq_channel[v_line]);
+ }
+ return v_line;
+}
+
+// This function is intended to be used by the Pin.irq() method
+void extint_register_pin(const pin_obj_t *pin, uint32_t mode, bool hard_irq, mp_obj_t callback_obj) {
+ uint32_t line = pin->pin;
+
+ // Check if the ExtInt line is already in use by another Pin/ExtInt
+ mp_obj_t *cb = &MP_STATE_PORT(pyb_extint_callback)[line];
+ if (*cb != mp_const_none && MP_OBJ_FROM_PTR(pin) != pyb_extint_callback_arg[line]) {
+ if (MP_OBJ_IS_SMALL_INT(pyb_extint_callback_arg[line])) {
+ nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError,
+ "ExtInt vector %d is already in use", line));
+ } else {
+ const pin_obj_t *other_pin = (const pin_obj_t*)pyb_extint_callback_arg[line];
+ nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError,
+ "IRQ resource already taken by Pin('%q')", other_pin->name));
+ }
+ }
+
+ extint_disable(line);
+
+ *cb = callback_obj;
+ pyb_extint_mode[line] = (mode & 0x00010000) ? // GPIO_MODE_IT == 0x00010000
+ EXTI_Mode_Interrupt : EXTI_Mode_Event;
+
+ if (*cb != mp_const_none) {
+ // Configure and enable the callback
+
+ pyb_extint_hard_irq[line] = hard_irq;
+ pyb_extint_callback_arg[line] = MP_OBJ_FROM_PTR(pin);
+
+ // Route the GPIO to EXTI
+ __HAL_RCC_SYSCFG_CLK_ENABLE();
+ SYSCFG->EXTICR[line >> 2] =
+ (SYSCFG->EXTICR[line >> 2] & ~(0x0f << (4 * (line & 0x03))))
+ | ((uint32_t)(GPIO_GET_INDEX(pin->gpio)) << (4 * (line & 0x03)));
+
+ // Enable or disable the rising detector
+ if ((mode & GPIO_MODE_IT_RISING) == GPIO_MODE_IT_RISING) {
+ EXTI_RTSR |= 1 << line;
+ } else {
+ EXTI_RTSR &= ~(1 << line);
+ }
+
+ // Enable or disable the falling detector
+ if ((mode & GPIO_MODE_IT_FALLING) == GPIO_MODE_IT_FALLING) {
+ EXTI_FTSR |= 1 << line;
+ } else {
+ EXTI_FTSR &= ~(1 << line);
+ }
+
+ // Configure the NVIC
+ HAL_NVIC_SetPriority(nvic_irq_channel[line], IRQ_PRI_EXTINT, IRQ_SUBPRI_EXTINT);
+ HAL_NVIC_EnableIRQ(nvic_irq_channel[line]);
+
+ // Enable the interrupt
+ extint_enable(line);
+ }
+}
+
+void extint_enable(uint line) {
+ if (line >= EXTI_NUM_VECTORS) {
+ return;
+ }
+ #if defined(MCU_SERIES_F7)
+ // The Cortex-M7 doesn't have bitband support.
+ mp_uint_t irq_state = disable_irq();
+ if (pyb_extint_mode[line] == EXTI_Mode_Interrupt) {
+ EXTI->IMR |= (1 << line);
+ } else {
+ EXTI->EMR |= (1 << line);
+ }
+ enable_irq(irq_state);
+ #else
+ // Since manipulating IMR/EMR is a read-modify-write, and we want this to
+ // be atomic, we use the bit-band area to just affect the bit we're
+ // interested in.
+ EXTI_MODE_BB(pyb_extint_mode[line], line) = 1;
+ #endif
+}
+
+void extint_disable(uint line) {
+ if (line >= EXTI_NUM_VECTORS) {
+ return;
+ }
+
+ #if defined(MCU_SERIES_F7)
+ // The Cortex-M7 doesn't have bitband support.
+ mp_uint_t irq_state = disable_irq();
+ EXTI->IMR &= ~(1 << line);
+ EXTI->EMR &= ~(1 << line);
+ enable_irq(irq_state);
+ #else
+ // Since manipulating IMR/EMR is a read-modify-write, and we want this to
+ // be atomic, we use the bit-band area to just affect the bit we're
+ // interested in.
+ EXTI_MODE_BB(EXTI_Mode_Interrupt, line) = 0;
+ EXTI_MODE_BB(EXTI_Mode_Event, line) = 0;
+ #endif
+}
+
+void extint_swint(uint line) {
+ if (line >= EXTI_NUM_VECTORS) {
+ return;
+ }
+ // we need 0 to 1 transition to trigger the interrupt
+#if defined(MCU_SERIES_L4)
+ EXTI->SWIER1 &= ~(1 << line);
+ EXTI->SWIER1 |= (1 << line);
+#else
+ EXTI->SWIER &= ~(1 << line);
+ EXTI->SWIER |= (1 << line);
+#endif
+}
+
+/// \method line()
+/// Return the line number that the pin is mapped to.
+STATIC mp_obj_t extint_obj_line(mp_obj_t self_in) {
+ extint_obj_t *self = self_in;
+ return MP_OBJ_NEW_SMALL_INT(self->line);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(extint_obj_line_obj, extint_obj_line);
+
+/// \method enable()
+/// Enable a disabled interrupt.
+STATIC mp_obj_t extint_obj_enable(mp_obj_t self_in) {
+ extint_obj_t *self = self_in;
+ extint_enable(self->line);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(extint_obj_enable_obj, extint_obj_enable);
+
+/// \method disable()
+/// Disable the interrupt associated with the ExtInt object.
+/// This could be useful for debouncing.
+STATIC mp_obj_t extint_obj_disable(mp_obj_t self_in) {
+ extint_obj_t *self = self_in;
+ extint_disable(self->line);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(extint_obj_disable_obj, extint_obj_disable);
+
+/// \method swint()
+/// Trigger the callback from software.
+STATIC mp_obj_t extint_obj_swint(mp_obj_t self_in) {
+ extint_obj_t *self = self_in;
+ extint_swint(self->line);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(extint_obj_swint_obj, extint_obj_swint);
+
+// TODO document as a staticmethod
+/// \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);
+ #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);
+ #endif
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_0(extint_regs_fun_obj, extint_regs);
+STATIC MP_DEFINE_CONST_STATICMETHOD_OBJ(extint_regs_obj, (mp_obj_t)&extint_regs_fun_obj);
+
+/// \classmethod \constructor(pin, mode, pull, callback)
+/// Create an ExtInt object:
+///
+/// - `pin` is the pin on which to enable the interrupt (can be a pin object or any valid pin name).
+/// - `mode` can be one of:
+/// - `ExtInt.IRQ_RISING` - trigger on a rising edge;
+/// - `ExtInt.IRQ_FALLING` - trigger on a falling edge;
+/// - `ExtInt.IRQ_RISING_FALLING` - trigger on a rising or falling edge.
+/// - `pull` can be one of:
+/// - `pyb.Pin.PULL_NONE` - no pull up or down resistors;
+/// - `pyb.Pin.PULL_UP` - enable the pull-up resistor;
+/// - `pyb.Pin.PULL_DOWN` - enable the pull-down resistor.
+/// - `callback` is the function to call when the interrupt triggers. The
+/// callback function must accept exactly 1 argument, which is the line that
+/// triggered the interrupt.
+STATIC const mp_arg_t pyb_extint_make_new_args[] = {
+ { MP_QSTR_pin, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+ { MP_QSTR_mode, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} },
+ { MP_QSTR_pull, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} },
+ { MP_QSTR_callback, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+};
+#define PYB_EXTINT_MAKE_NEW_NUM_ARGS MP_ARRAY_SIZE(pyb_extint_make_new_args)
+
+STATIC mp_obj_t extint_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
+ // type_in == extint_obj_type
+
+ // parse args
+ mp_arg_val_t vals[PYB_EXTINT_MAKE_NEW_NUM_ARGS];
+ mp_arg_parse_all_kw_array(n_args, n_kw, args, PYB_EXTINT_MAKE_NEW_NUM_ARGS, pyb_extint_make_new_args, vals);
+
+ extint_obj_t *self = m_new_obj(extint_obj_t);
+ self->base.type = type;
+ self->line = extint_register(vals[0].u_obj, vals[1].u_int, vals[2].u_int, vals[3].u_obj, false);
+
+ return self;
+}
+
+STATIC void extint_obj_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
+ extint_obj_t *self = self_in;
+ mp_printf(print, "<ExtInt line=%u>", self->line);
+}
+
+STATIC const mp_rom_map_elem_t extint_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_line), MP_ROM_PTR(&extint_obj_line_obj) },
+ { MP_ROM_QSTR(MP_QSTR_enable), MP_ROM_PTR(&extint_obj_enable_obj) },
+ { MP_ROM_QSTR(MP_QSTR_disable), MP_ROM_PTR(&extint_obj_disable_obj) },
+ { MP_ROM_QSTR(MP_QSTR_swint), MP_ROM_PTR(&extint_obj_swint_obj) },
+ { MP_ROM_QSTR(MP_QSTR_regs), MP_ROM_PTR(&extint_regs_obj) },
+
+ // class constants
+ /// \constant IRQ_RISING - interrupt on a rising edge
+ /// \constant IRQ_FALLING - interrupt on a falling edge
+ /// \constant IRQ_RISING_FALLING - interrupt on a rising or falling edge
+ { MP_ROM_QSTR(MP_QSTR_IRQ_RISING), MP_ROM_INT(GPIO_MODE_IT_RISING) },
+ { MP_ROM_QSTR(MP_QSTR_IRQ_FALLING), MP_ROM_INT(GPIO_MODE_IT_FALLING) },
+ { MP_ROM_QSTR(MP_QSTR_IRQ_RISING_FALLING), MP_ROM_INT(GPIO_MODE_IT_RISING_FALLING) },
+ { MP_ROM_QSTR(MP_QSTR_EVT_RISING), MP_ROM_INT(GPIO_MODE_EVT_RISING) },
+ { MP_ROM_QSTR(MP_QSTR_EVT_FALLING), MP_ROM_INT(GPIO_MODE_EVT_FALLING) },
+ { MP_ROM_QSTR(MP_QSTR_EVT_RISING_FALLING), MP_ROM_INT(GPIO_MODE_EVT_RISING_FALLING) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(extint_locals_dict, extint_locals_dict_table);
+
+const mp_obj_type_t extint_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_ExtInt,
+ .print = extint_obj_print,
+ .make_new = extint_make_new,
+ .locals_dict = (mp_obj_dict_t*)&extint_locals_dict,
+};
+
+void extint_init0(void) {
+ for (int i = 0; i < PYB_EXTI_NUM_VECTORS; i++) {
+ MP_STATE_PORT(pyb_extint_callback)[i] = mp_const_none;
+ pyb_extint_mode[i] = EXTI_Mode_Interrupt;
+ }
+}
+
+// Interrupt handler
+void Handle_EXTI_Irq(uint32_t line) {
+ if (__HAL_GPIO_EXTI_GET_FLAG(1 << line)) {
+ __HAL_GPIO_EXTI_CLEAR_FLAG(1 << line);
+ if (line < EXTI_NUM_VECTORS) {
+ mp_obj_t *cb = &MP_STATE_PORT(pyb_extint_callback)[line];
+ if (*cb != mp_const_none) {
+ // If it's a soft IRQ handler then just schedule callback for later
+ if (!pyb_extint_hard_irq[line]) {
+ mp_sched_schedule(*cb, pyb_extint_callback_arg[line]);
+ return;
+ }
+
+ mp_sched_lock();
+ // When executing code within a handler we must lock the GC to prevent
+ // any memory allocations. We must also catch any exceptions.
+ gc_lock();
+ nlr_buf_t nlr;
+ if (nlr_push(&nlr) == 0) {
+ mp_call_function_1(*cb, pyb_extint_callback_arg[line]);
+ nlr_pop();
+ } else {
+ // 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);
+ mp_obj_print_exception(&mp_plat_print, (mp_obj_t)nlr.ret_val);
+ }
+ gc_unlock();
+ mp_sched_unlock();
+ }
+ }
+ }
+}
diff --git a/ports/stm32/extint.h b/ports/stm32/extint.h
new file mode 100644
index 000000000..846790b9b
--- /dev/null
+++ b/ports/stm32/extint.h
@@ -0,0 +1,67 @@
+/*
+ * 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.
+ */
+#ifndef MICROPY_INCLUDED_STMHAL_EXTINT_H
+#define MICROPY_INCLUDED_STMHAL_EXTINT_H
+
+// Vectors 0-15 are for regular pins
+// Vectors 16-22 are for internal sources.
+//
+// Use the following constants for the internal sources:
+
+#define EXTI_PVD_OUTPUT (16)
+#define EXTI_RTC_ALARM (17)
+#define EXTI_USB_OTG_FS_WAKEUP (18)
+#define EXTI_ETH_WAKEUP (19)
+#define EXTI_USB_OTG_HS_WAKEUP (20)
+#define EXTI_RTC_TIMESTAMP (21)
+#define EXTI_RTC_WAKEUP (22)
+#if defined(MCU_SERIES_F7)
+#define EXTI_LPTIM1_ASYNC_EVENT (23)
+#endif
+
+#define EXTI_NUM_VECTORS (PYB_EXTI_NUM_VECTORS)
+
+#define EXTI_MODE_INTERRUPT (offsetof(EXTI_TypeDef, IMR))
+#define EXTI_MODE_EVENT (offsetof(EXTI_TypeDef, EMR))
+
+#define EXTI_TRIGGER_RISING (offsetof(EXTI_TypeDef, RTSR))
+#define EXTI_TRIGGER_FALLING (offsetof(EXTI_TypeDef, FTSR))
+#define EXTI_TRIGGER_RISING_FALLING (EXTI_TRIGGER_RISING + EXTI_TRIGGER_FALLING) // just different from RISING or FALLING
+
+void extint_init0(void);
+
+uint extint_register(mp_obj_t pin_obj, uint32_t mode, uint32_t pull, mp_obj_t callback_obj, bool override_callback_obj);
+void extint_register_pin(const pin_obj_t *pin, uint32_t mode, bool hard_irq, mp_obj_t callback_obj);
+
+void extint_enable(uint line);
+void extint_disable(uint line);
+void extint_swint(uint line);
+
+void Handle_EXTI_Irq(uint32_t line);
+
+extern const mp_obj_type_t extint_type;
+
+#endif // MICROPY_INCLUDED_STMHAL_EXTINT_H
diff --git a/ports/stm32/fatfs_port.c b/ports/stm32/fatfs_port.c
new file mode 100644
index 000000000..17ec3f726
--- /dev/null
+++ b/ports/stm32/fatfs_port.c
@@ -0,0 +1,38 @@
+/*
+ * 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 "py/runtime.h"
+#include "lib/oofatfs/ff.h"
+#include "rtc.h"
+
+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);
+ 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
new file mode 100644
index 000000000..bebb3a161
--- /dev/null
+++ b/ports/stm32/flash.c
@@ -0,0 +1,288 @@
+/*
+ * 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 "py/mpconfig.h"
+#include "py/misc.h"
+#include "flash.h"
+
+typedef struct {
+ uint32_t base_address;
+ uint32_t sector_size;
+ uint32_t sector_count;
+} flash_layout_t;
+
+#if defined(MCU_SERIES_F4)
+
+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(MCU_SERIES_F7)
+
+// FLASH_FLAG_PGSERR (Programming Sequence Error) was renamed to
+// FLASH_FLAG_ERSERR (Erasing Sequence Error) in STM32F7
+#define FLASH_FLAG_PGSERR FLASH_FLAG_ERSERR
+
+static const flash_layout_t flash_layout[] = {
+ { 0x08000000, 0x08000, 4 },
+ { 0x08020000, 0x20000, 1 },
+ { 0x08040000, 0x40000, 3 },
+};
+
+#elif defined(MCU_SERIES_L4)
+
+static const flash_layout_t flash_layout[] = {
+ { (uint32_t)FLASH_BASE, (uint32_t)FLASH_PAGE_SIZE, 512 },
+};
+
+#else
+#error Unsupported processor
+#endif
+
+#if defined(MCU_SERIES_L4)
+
+// get the bank of a given flash address
+static uint32_t get_bank(uint32_t addr) {
+ if (READ_BIT(SYSCFG->MEMRMP, SYSCFG_MEMRMP_FB_MODE) == 0) {
+ // no bank swap
+ if (addr < (FLASH_BASE + FLASH_BANK_SIZE)) {
+ return FLASH_BANK_1;
+ } else {
+ return FLASH_BANK_2;
+ }
+ } else {
+ // bank swap
+ if (addr < (FLASH_BASE + FLASH_BANK_SIZE)) {
+ return FLASH_BANK_2;
+ } else {
+ return FLASH_BANK_1;
+ }
+ }
+}
+
+// get the page of a given flash address
+static uint32_t get_page(uint32_t addr) {
+ if (addr < (FLASH_BASE + FLASH_BANK_SIZE)) {
+ // bank 1
+ return (addr - FLASH_BASE) / FLASH_PAGE_SIZE;
+ } else {
+ // bank 2
+ return (addr - (FLASH_BASE + FLASH_BANK_SIZE)) / FLASH_PAGE_SIZE;
+ }
+}
+
+#endif
+
+uint32_t flash_get_sector_info(uint32_t addr, uint32_t *start_addr, uint32_t *size) {
+ 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) {
+ if (start_addr != NULL) {
+ *start_addr = flash_layout[i].base_address
+ + j * flash_layout[i].sector_size;
+ }
+ if (size != NULL) {
+ *size = flash_layout[i].sector_size;
+ }
+ return sector_index;
+ }
+ ++sector_index;
+ }
+ }
+ }
+ return 0;
+}
+
+void flash_erase(uint32_t flash_dest, const uint32_t *src, uint32_t num_word32) {
+ // check there is something to write
+ if (num_word32 == 0) {
+ return;
+ }
+
+ // unlock
+ HAL_FLASH_Unlock();
+
+ FLASH_EraseInitTypeDef EraseInitStruct;
+
+ #if defined(MCU_SERIES_L4)
+ __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_ALL_ERRORS);
+
+ // erase the sector(s)
+ // The sector returned by flash_get_sector_info can not be used
+ // as the flash has on each bank 0/1 pages 0..255
+ EraseInitStruct.TypeErase = FLASH_TYPEERASE_PAGES;
+ EraseInitStruct.Banks = get_bank(flash_dest);
+ EraseInitStruct.Page = get_page(flash_dest);
+ EraseInitStruct.NbPages = get_page(flash_dest + 4 * num_word32 - 1) - EraseInitStruct.Page + 1;;
+ #else
+ // 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)
+ EraseInitStruct.TypeErase = TYPEERASE_SECTORS;
+ EraseInitStruct.VoltageRange = VOLTAGE_RANGE_3; // voltage range needs to be 2.7V to 3.6V
+ 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
+
+ uint32_t SectorError = 0;
+ if (HAL_FLASHEx_Erase(&EraseInitStruct, &SectorError) != HAL_OK) {
+ // error occurred during sector erase
+ HAL_FLASH_Lock(); // lock the flash
+ return;
+ }
+}
+
+/*
+// erase the sector using an interrupt
+void flash_erase_it(uint32_t flash_dest, const uint32_t *src, uint32_t num_word32) {
+ // check there is something to write
+ if (num_word32 == 0) {
+ return;
+ }
+
+ // unlock
+ 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 = 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;
+ if (HAL_FLASHEx_Erase_IT(&EraseInitStruct) != HAL_OK) {
+ // error occurred during sector erase
+ HAL_FLASH_Lock(); // lock the flash
+ return;
+ }
+}
+*/
+
+void flash_write(uint32_t flash_dest, const uint32_t *src, uint32_t num_word32) {
+ #if defined(MCU_SERIES_L4)
+
+ // program the flash uint64 by uint64
+ for (int i = 0; i < num_word32 / 2; i++) {
+ uint64_t val = *(uint64_t*)src;
+ if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, flash_dest, val) != HAL_OK) {
+ // error occurred during flash write
+ HAL_FLASH_Lock(); // lock the flash
+ return;
+ }
+ flash_dest += 8;
+ src += 2;
+ }
+ if ((num_word32 & 0x01) == 1) {
+ uint64_t val = *(uint64_t*)flash_dest;
+ val = (val & 0xffffffff00000000uL) | (*src);
+ if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, flash_dest, val) != HAL_OK) {
+ // error occurred during flash write
+ HAL_FLASH_Lock(); // lock the flash
+ return;
+ }
+ }
+
+ #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) {
+ // error occurred during flash write
+ HAL_FLASH_Lock(); // lock the flash
+ return;
+ }
+ flash_dest += 4;
+ src += 1;
+ }
+
+ #endif
+
+ // lock the flash
+ HAL_FLASH_Lock();
+}
+
+/*
+ use erase, then write
+void flash_erase_and_write(uint32_t flash_dest, const uint32_t *src, uint32_t num_word32) {
+ // check there is something to write
+ if (num_word32 == 0) {
+ return;
+ }
+
+ // unlock
+ 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 = 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;
+ uint32_t SectorError = 0;
+ if (HAL_FLASHEx_Erase(&EraseInitStruct, &SectorError) != HAL_OK) {
+ // error occurred during sector erase
+ HAL_FLASH_Lock(); // lock the flash
+ return;
+ }
+
+ // 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) {
+ // error occurred during flash write
+ HAL_FLASH_Lock(); // lock the flash
+ return;
+ }
+ flash_dest += 4;
+ src += 1;
+ }
+
+ // lock the flash
+ HAL_FLASH_Lock();
+}
+*/
diff --git a/ports/stm32/flash.h b/ports/stm32/flash.h
new file mode 100644
index 000000000..688e70a3c
--- /dev/null
+++ b/ports/stm32/flash.h
@@ -0,0 +1,33 @@
+/*
+ * 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.
+ */
+#ifndef MICROPY_INCLUDED_STMHAL_FLASH_H
+#define MICROPY_INCLUDED_STMHAL_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_write(uint32_t flash_dest, const uint32_t *src, uint32_t num_word32);
+
+#endif // MICROPY_INCLUDED_STMHAL_FLASH_H
diff --git a/ports/stm32/font_petme128_8x8.h b/ports/stm32/font_petme128_8x8.h
new file mode 100644
index 000000000..8b0cc9cb0
--- /dev/null
+++ b/ports/stm32/font_petme128_8x8.h
@@ -0,0 +1,128 @@
+/*
+ * 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.
+ */
+#ifndef MICROPY_INCLUDED_STMHAL_FONT_PETME128_8X8_H
+#define MICROPY_INCLUDED_STMHAL_FONT_PETME128_8X8_H
+
+static const uint8_t font_petme128_8x8[] = {
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // 32=
+ 0x00,0x00,0x00,0x4f,0x4f,0x00,0x00,0x00, // 33=!
+ 0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, // 34="
+ 0x14,0x7f,0x7f,0x14,0x14,0x7f,0x7f,0x14, // 35=#
+ 0x00,0x24,0x2e,0x6b,0x6b,0x3a,0x12,0x00, // 36=$
+ 0x00,0x63,0x33,0x18,0x0c,0x66,0x63,0x00, // 37=%
+ 0x00,0x32,0x7f,0x4d,0x4d,0x77,0x72,0x50, // 38=&
+ 0x00,0x00,0x00,0x04,0x06,0x03,0x01,0x00, // 39='
+ 0x00,0x00,0x1c,0x3e,0x63,0x41,0x00,0x00, // 40=(
+ 0x00,0x00,0x41,0x63,0x3e,0x1c,0x00,0x00, // 41=)
+ 0x08,0x2a,0x3e,0x1c,0x1c,0x3e,0x2a,0x08, // 42=*
+ 0x00,0x08,0x08,0x3e,0x3e,0x08,0x08,0x00, // 43=+
+ 0x00,0x00,0x80,0xe0,0x60,0x00,0x00,0x00, // 44=,
+ 0x00,0x08,0x08,0x08,0x08,0x08,0x08,0x00, // 45=-
+ 0x00,0x00,0x00,0x60,0x60,0x00,0x00,0x00, // 46=.
+ 0x00,0x40,0x60,0x30,0x18,0x0c,0x06,0x02, // 47=/
+ 0x00,0x3e,0x7f,0x49,0x45,0x7f,0x3e,0x00, // 48=0
+ 0x00,0x40,0x44,0x7f,0x7f,0x40,0x40,0x00, // 49=1
+ 0x00,0x62,0x73,0x51,0x49,0x4f,0x46,0x00, // 50=2
+ 0x00,0x22,0x63,0x49,0x49,0x7f,0x36,0x00, // 51=3
+ 0x00,0x18,0x18,0x14,0x16,0x7f,0x7f,0x10, // 52=4
+ 0x00,0x27,0x67,0x45,0x45,0x7d,0x39,0x00, // 53=5
+ 0x00,0x3e,0x7f,0x49,0x49,0x7b,0x32,0x00, // 54=6
+ 0x00,0x03,0x03,0x79,0x7d,0x07,0x03,0x00, // 55=7
+ 0x00,0x36,0x7f,0x49,0x49,0x7f,0x36,0x00, // 56=8
+ 0x00,0x26,0x6f,0x49,0x49,0x7f,0x3e,0x00, // 57=9
+ 0x00,0x00,0x00,0x24,0x24,0x00,0x00,0x00, // 58=:
+ 0x00,0x00,0x80,0xe4,0x64,0x00,0x00,0x00, // 59=;
+ 0x00,0x08,0x1c,0x36,0x63,0x41,0x41,0x00, // 60=<
+ 0x00,0x14,0x14,0x14,0x14,0x14,0x14,0x00, // 61==
+ 0x00,0x41,0x41,0x63,0x36,0x1c,0x08,0x00, // 62=>
+ 0x00,0x02,0x03,0x51,0x59,0x0f,0x06,0x00, // 63=?
+ 0x00,0x3e,0x7f,0x41,0x4d,0x4f,0x2e,0x00, // 64=@
+ 0x00,0x7c,0x7e,0x0b,0x0b,0x7e,0x7c,0x00, // 65=A
+ 0x00,0x7f,0x7f,0x49,0x49,0x7f,0x36,0x00, // 66=B
+ 0x00,0x3e,0x7f,0x41,0x41,0x63,0x22,0x00, // 67=C
+ 0x00,0x7f,0x7f,0x41,0x63,0x3e,0x1c,0x00, // 68=D
+ 0x00,0x7f,0x7f,0x49,0x49,0x41,0x41,0x00, // 69=E
+ 0x00,0x7f,0x7f,0x09,0x09,0x01,0x01,0x00, // 70=F
+ 0x00,0x3e,0x7f,0x41,0x49,0x7b,0x3a,0x00, // 71=G
+ 0x00,0x7f,0x7f,0x08,0x08,0x7f,0x7f,0x00, // 72=H
+ 0x00,0x00,0x41,0x7f,0x7f,0x41,0x00,0x00, // 73=I
+ 0x00,0x20,0x60,0x41,0x7f,0x3f,0x01,0x00, // 74=J
+ 0x00,0x7f,0x7f,0x1c,0x36,0x63,0x41,0x00, // 75=K
+ 0x00,0x7f,0x7f,0x40,0x40,0x40,0x40,0x00, // 76=L
+ 0x00,0x7f,0x7f,0x06,0x0c,0x06,0x7f,0x7f, // 77=M
+ 0x00,0x7f,0x7f,0x0e,0x1c,0x7f,0x7f,0x00, // 78=N
+ 0x00,0x3e,0x7f,0x41,0x41,0x7f,0x3e,0x00, // 79=O
+ 0x00,0x7f,0x7f,0x09,0x09,0x0f,0x06,0x00, // 80=P
+ 0x00,0x1e,0x3f,0x21,0x61,0x7f,0x5e,0x00, // 81=Q
+ 0x00,0x7f,0x7f,0x19,0x39,0x6f,0x46,0x00, // 82=R
+ 0x00,0x26,0x6f,0x49,0x49,0x7b,0x32,0x00, // 83=S
+ 0x00,0x01,0x01,0x7f,0x7f,0x01,0x01,0x00, // 84=T
+ 0x00,0x3f,0x7f,0x40,0x40,0x7f,0x3f,0x00, // 85=U
+ 0x00,0x1f,0x3f,0x60,0x60,0x3f,0x1f,0x00, // 86=V
+ 0x00,0x7f,0x7f,0x30,0x18,0x30,0x7f,0x7f, // 87=W
+ 0x00,0x63,0x77,0x1c,0x1c,0x77,0x63,0x00, // 88=X
+ 0x00,0x07,0x0f,0x78,0x78,0x0f,0x07,0x00, // 89=Y
+ 0x00,0x61,0x71,0x59,0x4d,0x47,0x43,0x00, // 90=Z
+ 0x00,0x00,0x7f,0x7f,0x41,0x41,0x00,0x00, // 91=[
+ 0x00,0x02,0x06,0x0c,0x18,0x30,0x60,0x40, // 92='\'
+ 0x00,0x00,0x41,0x41,0x7f,0x7f,0x00,0x00, // 93=]
+ 0x00,0x08,0x0c,0x06,0x06,0x0c,0x08,0x00, // 94=^
+ 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0, // 95=_
+ 0x00,0x00,0x01,0x03,0x06,0x04,0x00,0x00, // 96=`
+ 0x00,0x20,0x74,0x54,0x54,0x7c,0x78,0x00, // 97=a
+ 0x00,0x7f,0x7f,0x44,0x44,0x7c,0x38,0x00, // 98=b
+ 0x00,0x38,0x7c,0x44,0x44,0x6c,0x28,0x00, // 99=c
+ 0x00,0x38,0x7c,0x44,0x44,0x7f,0x7f,0x00, // 100=d
+ 0x00,0x38,0x7c,0x54,0x54,0x5c,0x58,0x00, // 101=e
+ 0x00,0x08,0x7e,0x7f,0x09,0x03,0x02,0x00, // 102=f
+ 0x00,0x98,0xbc,0xa4,0xa4,0xfc,0x7c,0x00, // 103=g
+ 0x00,0x7f,0x7f,0x04,0x04,0x7c,0x78,0x00, // 104=h
+ 0x00,0x00,0x00,0x7d,0x7d,0x00,0x00,0x00, // 105=i
+ 0x00,0x40,0xc0,0x80,0x80,0xfd,0x7d,0x00, // 106=j
+ 0x00,0x7f,0x7f,0x30,0x38,0x6c,0x44,0x00, // 107=k
+ 0x00,0x00,0x41,0x7f,0x7f,0x40,0x00,0x00, // 108=l
+ 0x00,0x7c,0x7c,0x18,0x30,0x18,0x7c,0x7c, // 109=m
+ 0x00,0x7c,0x7c,0x04,0x04,0x7c,0x78,0x00, // 110=n
+ 0x00,0x38,0x7c,0x44,0x44,0x7c,0x38,0x00, // 111=o
+ 0x00,0xfc,0xfc,0x24,0x24,0x3c,0x18,0x00, // 112=p
+ 0x00,0x18,0x3c,0x24,0x24,0xfc,0xfc,0x00, // 113=q
+ 0x00,0x7c,0x7c,0x04,0x04,0x0c,0x08,0x00, // 114=r
+ 0x00,0x48,0x5c,0x54,0x54,0x74,0x20,0x00, // 115=s
+ 0x04,0x04,0x3f,0x7f,0x44,0x64,0x20,0x00, // 116=t
+ 0x00,0x3c,0x7c,0x40,0x40,0x7c,0x3c,0x00, // 117=u
+ 0x00,0x1c,0x3c,0x60,0x60,0x3c,0x1c,0x00, // 118=v
+ 0x00,0x1c,0x7c,0x30,0x18,0x30,0x7c,0x1c, // 119=w
+ 0x00,0x44,0x6c,0x38,0x38,0x6c,0x44,0x00, // 120=x
+ 0x00,0x9c,0xbc,0xa0,0xa0,0xfc,0x7c,0x00, // 121=y
+ 0x00,0x44,0x64,0x74,0x5c,0x4c,0x44,0x00, // 122=z
+ 0x00,0x08,0x08,0x3e,0x77,0x41,0x41,0x00, // 123={
+ 0x00,0x00,0x00,0xff,0xff,0x00,0x00,0x00, // 124=|
+ 0x00,0x41,0x41,0x77,0x3e,0x08,0x08,0x00, // 125=}
+ 0x00,0x02,0x03,0x01,0x03,0x02,0x03,0x01, // 126=~
+ 0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55, // 127
+};
+
+#endif // MICROPY_INCLUDED_STMHAL_FONT_PETME128_8X8_H
diff --git a/ports/stm32/gccollect.c b/ports/stm32/gccollect.c
new file mode 100644
index 000000000..937fb6f36
--- /dev/null
+++ b/ports/stm32/gccollect.c
@@ -0,0 +1,77 @@
+/*
+ * 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 <stdint.h>
+
+#include "py/mpstate.h"
+#include "py/obj.h"
+#include "py/gc.h"
+#include "py/mpthread.h"
+#include "gccollect.h"
+#include "systick.h"
+
+mp_uint_t gc_helper_get_regs_and_sp(mp_uint_t *regs);
+
+void gc_collect(void) {
+ // get current time, in case we want to time the GC
+ #if 0
+ uint32_t start = mp_hal_ticks_us();
+ #endif
+
+ // start the GC
+ gc_collect_start();
+
+ // get the registers and the sp
+ mp_uint_t regs[10];
+ mp_uint_t sp = gc_helper_get_regs_and_sp(regs);
+
+ // trace the stack, including the registers (since they live on the stack in this function)
+ #if MICROPY_PY_THREAD
+ gc_collect_root((void**)sp, ((uint32_t)MP_STATE_THREAD(stack_top) - sp) / sizeof(uint32_t));
+ #else
+ gc_collect_root((void**)sp, ((uint32_t)&_ram_end - sp) / sizeof(uint32_t));
+ #endif
+
+ // trace root pointers from any threads
+ #if MICROPY_PY_THREAD
+ mp_thread_gc_others();
+ #endif
+
+ // end the GC
+ gc_collect_end();
+
+ #if 0
+ // print GC info
+ uint32_t ticks = mp_hal_ticks_us() - start;
+ gc_info_t info;
+ gc_info(&info);
+ printf("GC@%lu %lums\n", start, ticks);
+ printf(" " UINT_FMT " total\n", info.total);
+ printf(" " UINT_FMT " : " UINT_FMT "\n", info.used, info.free);
+ printf(" 1=" UINT_FMT " 2=" UINT_FMT " m=" UINT_FMT "\n", info.num_1block, info.num_2block, info.max_block);
+ #endif
+}
diff --git a/ports/stm32/gccollect.h b/ports/stm32/gccollect.h
new file mode 100644
index 000000000..1b64a51a6
--- /dev/null
+++ b/ports/stm32/gccollect.h
@@ -0,0 +1,43 @@
+/*
+ * 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.
+ */
+#ifndef MICROPY_INCLUDED_STMHAL_GCCOLLECT_H
+#define MICROPY_INCLUDED_STMHAL_GCCOLLECT_H
+
+// variables defining memory layout
+// (these probably belong somewhere else...)
+extern uint32_t _etext;
+extern uint32_t _sidata;
+extern uint32_t _ram_start;
+extern uint32_t _sdata;
+extern uint32_t _edata;
+extern uint32_t _sbss;
+extern uint32_t _ebss;
+extern uint32_t _heap_start;
+extern uint32_t _heap_end;
+extern uint32_t _estack;
+extern uint32_t _ram_end;
+
+#endif // MICROPY_INCLUDED_STMHAL_GCCOLLECT_H
diff --git a/ports/stm32/gchelper.s b/ports/stm32/gchelper.s
new file mode 100644
index 000000000..6baedcdd0
--- /dev/null
+++ b/ports/stm32/gchelper.s
@@ -0,0 +1,62 @@
+ .syntax unified
+ .cpu cortex-m4
+ .thumb
+ .text
+ .align 2
+
+@ uint gc_helper_get_regs_and_sp(r0=uint regs[10])
+ .global gc_helper_get_regs_and_sp
+ .thumb
+ .thumb_func
+ .type gc_helper_get_regs_and_sp, %function
+gc_helper_get_regs_and_sp:
+ @ store registers into given array
+ str r4, [r0], #4
+ str r5, [r0], #4
+ str r6, [r0], #4
+ str r7, [r0], #4
+ str r8, [r0], #4
+ str r9, [r0], #4
+ str r10, [r0], #4
+ str r11, [r0], #4
+ str r12, [r0], #4
+ str r13, [r0], #4
+
+ @ return the sp
+ mov r0, sp
+ bx lr
+
+
+@ this next function is now obsolete
+
+ .size gc_helper_get_regs_and_clean_stack, .-gc_helper_get_regs_and_clean_stack
+@ void gc_helper_get_regs_and_clean_stack(r0=uint regs[10], r1=heap_end)
+ .global gc_helper_get_regs_and_clean_stack
+ .thumb
+ .thumb_func
+ .type gc_helper_get_regs_and_clean_stack, %function
+gc_helper_get_regs_and_clean_stack:
+ @ store registers into given array
+ str r4, [r0], #4
+ str r5, [r0], #4
+ str r6, [r0], #4
+ str r7, [r0], #4
+ str r8, [r0], #4
+ str r9, [r0], #4
+ str r10, [r0], #4
+ str r11, [r0], #4
+ str r12, [r0], #4
+ str r13, [r0], #4
+
+ @ clean the stack from given pointer up to current sp
+ movs r0, #0
+ mov r2, sp
+ b.n .entry
+.loop:
+ str r0, [r1], #4
+.entry:
+ cmp r1, r2
+ bcc.n .loop
+ bx lr
+
+ .size gc_helper_get_regs_and_clean_stack, .-gc_helper_get_regs_and_clean_stack
diff --git a/ports/stm32/help.c b/ports/stm32/help.c
new file mode 100644
index 000000000..87b2af526
--- /dev/null
+++ b/ports/stm32/help.c
@@ -0,0 +1,71 @@
+/*
+ * 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 "py/builtin.h"
+
+const char *stmhal_help_text =
+"Welcome to MicroPython!\n"
+"\n"
+"For online help please visit http://micropython.org/help/.\n"
+"\n"
+"Quick overview of commands for the board:\n"
+" pyb.info() -- print some general information\n"
+" pyb.delay(n) -- wait for n milliseconds\n"
+" pyb.millis() -- get number of milliseconds since hard reset\n"
+" pyb.Switch() -- create a switch object\n"
+" Switch methods: (), callback(f)\n"
+" pyb.LED(n) -- create an LED object for LED n (n=1,2,3,4)\n"
+" LED methods: on(), off(), toggle(), intensity(<n>)\n"
+" pyb.Pin(pin) -- get a pin, eg pyb.Pin('X1')\n"
+" pyb.Pin(pin, m, [p]) -- get a pin and configure it for IO mode m, pull mode p\n"
+" Pin methods: init(..), value([v]), high(), low()\n"
+" pyb.ExtInt(pin, m, p, callback) -- create an external interrupt object\n"
+" pyb.ADC(pin) -- make an analog object from a pin\n"
+" ADC methods: read(), read_timed(buf, freq)\n"
+" pyb.DAC(port) -- make a DAC object\n"
+" DAC methods: triangle(freq), write(n), write_timed(buf, freq)\n"
+" pyb.RTC() -- make an RTC object; methods: datetime([val])\n"
+" pyb.rng() -- get a 30-bit hardware random number\n"
+" pyb.Servo(n) -- create Servo object for servo n (n=1,2,3,4)\n"
+" Servo methods: calibration(..), angle([x, [t]]), speed([x, [t]])\n"
+" pyb.Accel() -- create an Accelerometer object\n"
+" Accelerometer methods: x(), y(), z(), tilt(), filtered_xyz()\n"
+"\n"
+"Pins are numbered X1-X12, X17-X22, Y1-Y12, or by their MCU name\n"
+"Pin IO modes are: pyb.Pin.IN, pyb.Pin.OUT_PP, pyb.Pin.OUT_OD\n"
+"Pin pull modes are: pyb.Pin.PULL_NONE, pyb.Pin.PULL_UP, pyb.Pin.PULL_DOWN\n"
+"Additional serial bus objects: pyb.I2C(n), pyb.SPI(n), pyb.UART(n)\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/stm32/i2c.c b/ports/stm32/i2c.c
new file mode 100644
index 000000000..d80301081
--- /dev/null
+++ b/ports/stm32/i2c.c
@@ -0,0 +1,1039 @@
+/*
+ * 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/nlr.h"
+#include "py/runtime.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
+
+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(MCU_SERIES_F7) || defined(MCU_SERIES_L4)
+
+// The STM32F0, F3, F7 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 {{100000, 0x40912732}}
+#define MICROPY_HW_I2C_BAUDRATE_DEFAULT (100000)
+#define MICROPY_HW_I2C_BAUDRATE_MAX (100000)
+
+#elif defined(STM32F767xx) || defined(STM32F769xx)
+
+// 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)
+
+#elif defined(MCU_SERIES_L4)
+
+// 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)
+
+#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: %lu", baudrate));
+}
+
+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;
+ }
+ }
+ return 0;
+}
+
+#else
+
+#define MICROPY_HW_I2C_BAUDRATE_DEFAULT (400000)
+#define MICROPY_HW_I2C_BAUDRATE_MAX (400000)
+
+STATIC void i2c_set_baudrate(I2C_InitTypeDef *init, uint32_t baudrate) {
+ init->ClockSpeed = baudrate;
+ init->DutyCycle = I2C_DUTYCYCLE_16_9;
+}
+
+uint32_t i2c_get_baudrate(I2C_InitTypeDef *init) {
+ return init->ClockSpeed;
+}
+
+#endif
+
+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
+}
+
+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;
+ }
+
+ // 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) {
+ __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
+ }
+}
+
+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));
+ }
+
+ *self->use_dma = false;
+
+ // init the I2C bus
+ i2c_deinit(self->i2c);
+ 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);
+ 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(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;
+ }
+ 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(MCU_SERIES_F4)
+
+ 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, 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);
+ }
+ }
+}
+
+/// \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;
+}
+
+/// \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));
+ }
+ }
+
+ // 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++) {
+ for (int i = 0; i < 10; i++) {
+ HAL_StatusTypeDef status = HAL_I2C_IsDeviceReady(self->i2c, addr << 1, 10, 200);
+ if (status == HAL_OK) {
+ mp_obj_list_append(list, mp_obj_new_int(addr));
+ break;
+ }
+ }
+ }
+
+ 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,
+};
diff --git a/ports/stm32/i2c.h b/ports/stm32/i2c.h
new file mode 100644
index 000000000..6affe3973
--- /dev/null
+++ b/ports/stm32/i2c.h
@@ -0,0 +1,55 @@
+/*
+ * 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.
+ */
+#ifndef MICROPY_INCLUDED_STMHAL_I2C_H
+#define MICROPY_INCLUDED_STMHAL_I2C_H
+
+#include "dma.h"
+
+// use this for OwnAddress1 to configure I2C in master mode
+#define PYB_I2C_MASTER_ADDRESS (0xfe)
+
+typedef struct _pyb_i2c_obj_t {
+ mp_obj_base_t base;
+ I2C_HandleTypeDef *i2c;
+ const dma_descr_t *tx_dma_descr;
+ const dma_descr_t *rx_dma_descr;
+ bool *use_dma;
+} pyb_i2c_obj_t;
+
+extern I2C_HandleTypeDef I2CHandle1;
+extern I2C_HandleTypeDef I2CHandle2;
+extern I2C_HandleTypeDef I2CHandle3;
+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 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
diff --git a/ports/stm32/irq.c b/ports/stm32/irq.c
new file mode 100644
index 000000000..d6db8e83d
--- /dev/null
+++ b/ports/stm32/irq.c
@@ -0,0 +1,76 @@
+/*
+ * 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 "py/nlr.h"
+#include "py/obj.h"
+#include "py/mphal.h"
+#include "irq.h"
+
+/// \moduleref pyb
+
+#if IRQ_ENABLE_STATS
+uint32_t irq_stats[FPU_IRQn + 1] = {0};
+#endif
+
+/// \function wfi()
+/// Wait for an interrupt.
+/// This executies a `wfi` instruction which reduces power consumption
+/// of the MCU until an interrupt occurs, at which point execution continues.
+STATIC mp_obj_t pyb_wfi(void) {
+ __WFI();
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_0(pyb_wfi_obj, pyb_wfi);
+
+/// \function disable_irq()
+/// Disable interrupt requests.
+/// Returns the previous IRQ state: `False`/`True` for disabled/enabled IRQs
+/// respectively. This return value can be passed to enable_irq to restore
+/// the IRQ to its original state.
+STATIC mp_obj_t pyb_disable_irq(void) {
+ return mp_obj_new_bool(disable_irq() == IRQ_STATE_ENABLED);
+}
+MP_DEFINE_CONST_FUN_OBJ_0(pyb_disable_irq_obj, pyb_disable_irq);
+
+/// \function enable_irq(state=True)
+/// Enable interrupt requests.
+/// If `state` is `True` (the default value) then IRQs are enabled.
+/// If `state` is `False` then IRQs are disabled. The most common use of
+/// this function is to pass it the value returned by `disable_irq` to
+/// exit a critical section.
+STATIC mp_obj_t pyb_enable_irq(uint n_args, const mp_obj_t *arg) {
+ enable_irq((n_args == 0 || mp_obj_is_true(arg[0])) ? IRQ_STATE_ENABLED : IRQ_STATE_DISABLED);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_enable_irq_obj, 0, 1, pyb_enable_irq);
+
+#if IRQ_ENABLE_STATS
+// return a memoryview of the irq statistics array
+STATIC mp_obj_t pyb_irq_stats(void) {
+ return mp_obj_new_memoryview(0x80 | 'I', MP_ARRAY_SIZE(irq_stats), &irq_stats[0]);
+}
+MP_DEFINE_CONST_FUN_OBJ_0(pyb_irq_stats_obj, pyb_irq_stats);
+#endif
diff --git a/ports/stm32/irq.h b/ports/stm32/irq.h
new file mode 100644
index 000000000..2cf58639e
--- /dev/null
+++ b/ports/stm32/irq.h
@@ -0,0 +1,152 @@
+/*
+ * 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.
+ */
+#ifndef MICROPY_INCLUDED_STMHAL_IRQ_H
+#define MICROPY_INCLUDED_STMHAL_IRQ_H
+
+// these states correspond to values from query_irq, enable_irq and disable_irq
+#define IRQ_STATE_DISABLED (0x00000001)
+#define IRQ_STATE_ENABLED (0x00000000)
+
+// Enable this to get a count for the number of times each irq handler is called,
+// accessible via pyb.irq_stats().
+#define IRQ_ENABLE_STATS (0)
+
+#if IRQ_ENABLE_STATS
+extern uint32_t irq_stats[FPU_IRQn + 1];
+#define IRQ_ENTER(irq) ++irq_stats[irq]
+#define IRQ_EXIT(irq)
+#else
+#define IRQ_ENTER(irq)
+#define IRQ_EXIT(irq)
+#endif
+
+static inline mp_uint_t query_irq(void) {
+ return __get_PRIMASK();
+}
+
+// enable_irq and disable_irq are defined inline in mpconfigport.h
+
+#if __CORTEX_M >= 0x03
+
+// irqs with a priority value greater or equal to "pri" will be disabled
+// "pri" should be between 1 and 15 inclusive
+static inline uint32_t raise_irq_pri(uint32_t pri) {
+ uint32_t basepri = __get_BASEPRI();
+ // If non-zero, the processor does not process any exception with a
+ // priority value greater than or equal to BASEPRI.
+ // When writing to BASEPRI_MAX the write goes to BASEPRI only if either:
+ // - Rn is non-zero and the current BASEPRI value is 0
+ // - Rn is non-zero and less than the current BASEPRI value
+ pri <<= (8 - __NVIC_PRIO_BITS);
+ __ASM volatile ("msr basepri_max, %0" : : "r" (pri) : "memory");
+ return basepri;
+}
+
+// "basepri" should be the value returned from raise_irq_pri
+static inline void restore_irq_pri(uint32_t basepri) {
+ __set_BASEPRI(basepri);
+}
+
+#endif
+
+MP_DECLARE_CONST_FUN_OBJ_0(pyb_wfi_obj);
+MP_DECLARE_CONST_FUN_OBJ_0(pyb_disable_irq_obj);
+MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_enable_irq_obj);
+MP_DECLARE_CONST_FUN_OBJ_0(pyb_irq_stats_obj);
+
+// IRQ priority definitions.
+//
+// Lower number implies higher interrupt priority.
+//
+// The default priority grouping is set to NVIC_PRIORITYGROUP_4 in the
+// HAL_Init function. This corresponds to 4 bits for the priority field
+// and 0 bits for the sub-priority field (which means that for all intensive
+// purposes that the sub-priorities below are ignored).
+//
+// While a given interrupt is being processed, only higher priority (lower number)
+// interrupts will preempt a given interrupt. If sub-priorities are active
+// then the sub-priority determines the order that pending interrupts of
+// a given priority are executed. This is only meaningful if 2 or more
+// interrupts of the same priority are pending at the same time.
+//
+// The priority of the SysTick timer is determined from the TICK_INT_PRIORITY
+// value which is normally set to 0 in the stm32f4xx_hal_conf.h file.
+//
+// The following interrupts are arranged from highest priority to lowest
+// priority to make it a bit easier to figure out.
+
+// Priority Sub-Priority
+// -------- ------------
+//#def IRQ_PRI_SYSTICK 0
+//#def IRQ_SUBPRI_SYSTICK 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
+
+// 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
+
+// SDIO must be higher priority than DMA for SDIO DMA transfers to work.
+#define IRQ_PRI_SDIO 4
+#define IRQ_SUBPRI_SDIO 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_OTG_HS 6
+#define IRQ_SUBPRI_OTG_HS 0
+
+#define IRQ_PRI_TIM5 6
+#define IRQ_SUBPRI_TIM5 0
+
+#define IRQ_PRI_CAN 7
+#define IRQ_SUBPRI_CAN 0
+
+// Interrupt priority for non-special timers.
+#define IRQ_PRI_TIMX 13
+#define IRQ_SUBPRI_TIMX 0
+
+#define IRQ_PRI_EXTINT 14
+#define IRQ_SUBPRI_EXTINT 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_RTC_WKUP 15
+#define IRQ_SUBPRI_RTC_WKUP 0
+
+#endif // MICROPY_INCLUDED_STMHAL_IRQ_H
diff --git a/ports/stm32/lcd.c b/ports/stm32/lcd.c
new file mode 100644
index 000000000..559616b96
--- /dev/null
+++ b/ports/stm32/lcd.c
@@ -0,0 +1,529 @@
+/*
+ * 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/mphal.h"
+#include "py/nlr.h"
+#include "py/runtime.h"
+
+#if MICROPY_HW_HAS_LCD
+
+#include "pin.h"
+#include "genhdr/pins.h"
+#include "bufhelper.h"
+#include "spi.h"
+#include "font_petme128_8x8.h"
+#include "lcd.h"
+
+/// \moduleref pyb
+/// \class LCD - LCD control for the LCD touch-sensor pyskin
+///
+/// The LCD class is used to control the LCD on the LCD touch-sensor pyskin,
+/// LCD32MKv1.0. The LCD is a 128x32 pixel monochrome screen, part NHD-C12832A1Z.
+///
+/// The pyskin must be connected in either the X or Y positions, and then
+/// an LCD object is made using:
+///
+/// lcd = pyb.LCD('X') # if pyskin is in the X position
+/// lcd = pyb.LCD('Y') # if pyskin is in the Y position
+///
+/// Then you can use:
+///
+/// lcd.light(True) # turn the backlight on
+/// lcd.write('Hello world!\n') # print text to the screen
+///
+/// This driver implements a double buffer for setting/getting pixels.
+/// For example, to make a bouncing dot, try:
+///
+/// x = y = 0
+/// dx = dy = 1
+/// while True:
+/// # update the dot's position
+/// x += dx
+/// y += dy
+///
+/// # make the dot bounce of the edges of the screen
+/// if x <= 0 or x >= 127: dx = -dx
+/// if y <= 0 or y >= 31: dy = -dy
+///
+/// lcd.fill(0) # clear the buffer
+/// lcd.pixel(x, y, 1) # draw the dot
+/// lcd.show() # show the buffer
+/// pyb.delay(50) # pause for 50ms
+
+#define LCD_INSTR (0)
+#define LCD_DATA (1)
+
+#define LCD_CHAR_BUF_W (16)
+#define LCD_CHAR_BUF_H (4)
+
+#define LCD_PIX_BUF_W (128)
+#define LCD_PIX_BUF_H (32)
+#define LCD_PIX_BUF_BYTE_SIZE (LCD_PIX_BUF_W * LCD_PIX_BUF_H / 8)
+
+typedef struct _pyb_lcd_obj_t {
+ mp_obj_base_t base;
+
+ // hardware control for the LCD
+ SPI_HandleTypeDef *spi;
+ const pin_obj_t *pin_cs1;
+ const pin_obj_t *pin_rst;
+ const pin_obj_t *pin_a0;
+ const pin_obj_t *pin_bl;
+
+ // character buffer for stdout-like output
+ char char_buffer[LCD_CHAR_BUF_W * LCD_CHAR_BUF_H];
+ int line;
+ int column;
+ int next_line;
+
+ // double buffering for pixel buffer
+ byte pix_buf[LCD_PIX_BUF_BYTE_SIZE];
+ byte pix_buf2[LCD_PIX_BUF_BYTE_SIZE];
+} pyb_lcd_obj_t;
+
+STATIC void lcd_delay(void) {
+ __asm volatile ("nop\nnop");
+}
+
+STATIC void lcd_out(pyb_lcd_obj_t *lcd, int instr_data, uint8_t i) {
+ lcd_delay();
+ mp_hal_pin_low(lcd->pin_cs1); // CS=0; enable
+ if (instr_data == LCD_INSTR) {
+ mp_hal_pin_low(lcd->pin_a0); // A0=0; select instr reg
+ } else {
+ mp_hal_pin_high(lcd->pin_a0); // A0=1; select data reg
+ }
+ lcd_delay();
+ HAL_SPI_Transmit(lcd->spi, &i, 1, 1000);
+ lcd_delay();
+ mp_hal_pin_high(lcd->pin_cs1); // CS=1; disable
+}
+
+// write a string to the LCD at the current cursor location
+// output it straight away (doesn't use the pixel buffer)
+STATIC void lcd_write_strn(pyb_lcd_obj_t *lcd, const char *str, unsigned int len) {
+ int redraw_min = lcd->line * LCD_CHAR_BUF_W + lcd->column;
+ int redraw_max = redraw_min;
+ for (; len > 0; len--, str++) {
+ // move to next line if needed
+ if (lcd->next_line) {
+ if (lcd->line + 1 < LCD_CHAR_BUF_H) {
+ lcd->line += 1;
+ } else {
+ lcd->line = LCD_CHAR_BUF_H - 1;
+ for (int i = 0; i < LCD_CHAR_BUF_W * (LCD_CHAR_BUF_H - 1); i++) {
+ lcd->char_buffer[i] = lcd->char_buffer[i + LCD_CHAR_BUF_W];
+ }
+ for (int i = 0; i < LCD_CHAR_BUF_W; i++) {
+ lcd->char_buffer[LCD_CHAR_BUF_W * (LCD_CHAR_BUF_H - 1) + i] = ' ';
+ }
+ redraw_min = 0;
+ redraw_max = LCD_CHAR_BUF_W * LCD_CHAR_BUF_H;
+ }
+ lcd->next_line = 0;
+ lcd->column = 0;
+ }
+ if (*str == '\n') {
+ lcd->next_line = 1;
+ } else if (*str == '\r') {
+ lcd->column = 0;
+ } else if (*str == '\b') {
+ if (lcd->column > 0) {
+ lcd->column--;
+ redraw_min = 0; // could optimise this to not redraw everything
+ }
+ } else if (lcd->column >= LCD_CHAR_BUF_W) {
+ lcd->next_line = 1;
+ str -= 1;
+ len += 1;
+ } else {
+ lcd->char_buffer[lcd->line * LCD_CHAR_BUF_W + lcd->column] = *str;
+ lcd->column += 1;
+ int max = lcd->line * LCD_CHAR_BUF_W + lcd->column;
+ if (max > redraw_max) {
+ redraw_max = max;
+ }
+ }
+ }
+
+ // we must draw upside down, because the LCD is upside down
+ for (int i = redraw_min; i < redraw_max; i++) {
+ uint page = i / LCD_CHAR_BUF_W;
+ uint offset = 8 * (LCD_CHAR_BUF_W - 1 - (i - (page * LCD_CHAR_BUF_W)));
+ lcd_out(lcd, LCD_INSTR, 0xb0 | page); // page address set
+ lcd_out(lcd, LCD_INSTR, 0x10 | ((offset >> 4) & 0x0f)); // column address set upper
+ lcd_out(lcd, LCD_INSTR, 0x00 | (offset & 0x0f)); // column address set lower
+ int chr = lcd->char_buffer[i];
+ if (chr < 32 || chr > 126) {
+ chr = 127;
+ }
+ const uint8_t *chr_data = &font_petme128_8x8[(chr - 32) * 8];
+ for (int j = 7; j >= 0; j--) {
+ lcd_out(lcd, LCD_DATA, chr_data[j]);
+ }
+ }
+}
+
+/// \classmethod \constructor(skin_position)
+///
+/// Construct an LCD object in the given skin position. `skin_position` can be 'X' or 'Y', and
+/// should match the position where the LCD pyskin is plugged in.
+STATIC mp_obj_t pyb_lcd_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, 1, false);
+
+ // get LCD position
+ const char *lcd_id = mp_obj_str_get_str(args[0]);
+
+ // create lcd object
+ pyb_lcd_obj_t *lcd = m_new_obj(pyb_lcd_obj_t);
+ lcd->base.type = &pyb_lcd_type;
+
+ // 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;
+ } 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;
+ } 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;
+ 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) {
+ // SPI1 is on APB2
+ spi_clock = HAL_RCC_GetPCLK2Freq();
+ } else {
+ // SPI2 and SPI3 are on APB1
+ spi_clock = HAL_RCC_GetPCLK1Freq();
+ }
+ uint br_prescale = spi_clock / 16000000; // datasheet says LCD can run at 20MHz, but we go for 16MHz
+ if (br_prescale <= 2) { init->BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2; }
+ else if (br_prescale <= 4) { init->BaudRatePrescaler = SPI_BAUDRATEPRESCALER_4; }
+ else if (br_prescale <= 8) { init->BaudRatePrescaler = SPI_BAUDRATEPRESCALER_8; }
+ else if (br_prescale <= 16) { init->BaudRatePrescaler = SPI_BAUDRATEPRESCALER_16; }
+ else if (br_prescale <= 32) { init->BaudRatePrescaler = SPI_BAUDRATEPRESCALER_32; }
+ else if (br_prescale <= 64) { init->BaudRatePrescaler = SPI_BAUDRATEPRESCALER_64; }
+ else if (br_prescale <= 128) { init->BaudRatePrescaler = SPI_BAUDRATEPRESCALER_128; }
+ else { init->BaudRatePrescaler = SPI_BAUDRATEPRESCALER_256; }
+
+ // data is sent bigendian, latches on rising clock
+ init->CLKPolarity = SPI_POLARITY_HIGH;
+ init->CLKPhase = SPI_PHASE_2EDGE;
+ init->Direction = SPI_DIRECTION_2LINES;
+ init->DataSize = SPI_DATASIZE_8BIT;
+ init->NSS = SPI_NSS_SOFT;
+ init->FirstBit = SPI_FIRSTBIT_MSB;
+ init->TIMode = SPI_TIMODE_DISABLED;
+ init->CRCCalculation = SPI_CRCCALCULATION_DISABLED;
+ init->CRCPolynomial = 0;
+
+ // init the SPI bus
+ spi_init(lcd->spi, false);
+
+ // set the pins to default values
+ mp_hal_pin_high(lcd->pin_cs1);
+ mp_hal_pin_high(lcd->pin_rst);
+ mp_hal_pin_high(lcd->pin_a0);
+ mp_hal_pin_low(lcd->pin_bl);
+
+ // init the pins to be push/pull outputs
+ mp_hal_pin_output(lcd->pin_cs1);
+ mp_hal_pin_output(lcd->pin_rst);
+ mp_hal_pin_output(lcd->pin_a0);
+ mp_hal_pin_output(lcd->pin_bl);
+
+ // init the LCD
+ mp_hal_delay_ms(1); // wait a bit
+ mp_hal_pin_low(lcd->pin_rst); // RST=0; reset
+ mp_hal_delay_ms(1); // wait for reset; 2us min
+ mp_hal_pin_high(lcd->pin_rst); // RST=1; enable
+ mp_hal_delay_ms(1); // wait for reset; 2us min
+ lcd_out(lcd, LCD_INSTR, 0xa0); // ADC select, normal
+ lcd_out(lcd, LCD_INSTR, 0xc0); // common output mode select, normal (this flips the display)
+ lcd_out(lcd, LCD_INSTR, 0xa2); // LCD bias set, 1/9 bias
+ lcd_out(lcd, LCD_INSTR, 0x2f); // power control set, 0b111=(booster on, vreg on, vfollow on)
+ lcd_out(lcd, LCD_INSTR, 0x21); // v0 voltage regulator internal resistor ratio set, 0b001=small
+ lcd_out(lcd, LCD_INSTR, 0x81); // electronic volume mode set
+ lcd_out(lcd, LCD_INSTR, 0x28); // electronic volume register set
+ lcd_out(lcd, LCD_INSTR, 0x40); // display start line set, 0
+ lcd_out(lcd, LCD_INSTR, 0xaf); // LCD display, on
+
+ // clear LCD RAM
+ for (int page = 0; page < 4; page++) {
+ lcd_out(lcd, LCD_INSTR, 0xb0 | page); // page address set
+ lcd_out(lcd, LCD_INSTR, 0x10); // column address set upper
+ lcd_out(lcd, LCD_INSTR, 0x00); // column address set lower
+ for (int i = 0; i < 128; i++) {
+ lcd_out(lcd, LCD_DATA, 0x00);
+ }
+ }
+
+ // clear local char buffer
+ memset(lcd->char_buffer, ' ', LCD_CHAR_BUF_H * LCD_CHAR_BUF_W);
+ lcd->line = 0;
+ lcd->column = 0;
+ lcd->next_line = 0;
+
+ // clear local pixel buffer
+ memset(lcd->pix_buf, 0, LCD_PIX_BUF_BYTE_SIZE);
+ memset(lcd->pix_buf2, 0, LCD_PIX_BUF_BYTE_SIZE);
+
+ return lcd;
+}
+
+/// \method command(instr_data, buf)
+///
+/// Send an arbitrary command to the LCD. Pass 0 for `instr_data` to send an
+/// instruction, otherwise pass 1 to send data. `buf` is a buffer with the
+/// instructions/data to send.
+STATIC mp_obj_t pyb_lcd_command(mp_obj_t self_in, mp_obj_t instr_data_in, mp_obj_t val) {
+ pyb_lcd_obj_t *self = self_in;
+
+ // get whether instr or data
+ int instr_data = mp_obj_get_int(instr_data_in);
+
+ // get the buffer to send from
+ mp_buffer_info_t bufinfo;
+ uint8_t data[1];
+ pyb_buf_get_for_send(val, &bufinfo, data);
+
+ // send the data
+ for (uint i = 0; i < bufinfo.len; i++) {
+ lcd_out(self, instr_data, ((byte*)bufinfo.buf)[i]);
+ }
+
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_3(pyb_lcd_command_obj, pyb_lcd_command);
+
+/// \method contrast(value)
+///
+/// Set the contrast of the LCD. Valid values are between 0 and 47.
+STATIC mp_obj_t pyb_lcd_contrast(mp_obj_t self_in, mp_obj_t contrast_in) {
+ pyb_lcd_obj_t *self = self_in;
+ int contrast = mp_obj_get_int(contrast_in);
+ if (contrast < 0) {
+ contrast = 0;
+ } else if (contrast > 0x2f) {
+ contrast = 0x2f;
+ }
+ lcd_out(self, LCD_INSTR, 0x81); // electronic volume mode set
+ lcd_out(self, LCD_INSTR, contrast); // electronic volume register set
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(pyb_lcd_contrast_obj, pyb_lcd_contrast);
+
+/// \method light(value)
+///
+/// Turn the backlight on/off. True or 1 turns it on, False or 0 turns it off.
+STATIC mp_obj_t pyb_lcd_light(mp_obj_t self_in, mp_obj_t value) {
+ pyb_lcd_obj_t *self = self_in;
+ if (mp_obj_is_true(value)) {
+ mp_hal_pin_high(self->pin_bl); // set pin high to turn backlight on
+ } else {
+ mp_hal_pin_low(self->pin_bl); // set pin low to turn backlight off
+ }
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(pyb_lcd_light_obj, pyb_lcd_light);
+
+/// \method write(str)
+///
+/// Write the string `str` to the screen. It will appear immediately.
+STATIC mp_obj_t pyb_lcd_write(mp_obj_t self_in, mp_obj_t str) {
+ pyb_lcd_obj_t *self = self_in;
+ size_t len;
+ const char *data = mp_obj_str_get_data(str, &len);
+ lcd_write_strn(self, data, len);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(pyb_lcd_write_obj, pyb_lcd_write);
+
+/// \method fill(colour)
+///
+/// Fill the screen with the given colour (0 or 1 for white or black).
+///
+/// This method writes to the hidden buffer. Use `show()` to show the buffer.
+STATIC mp_obj_t pyb_lcd_fill(mp_obj_t self_in, mp_obj_t col_in) {
+ pyb_lcd_obj_t *self = self_in;
+ int col = mp_obj_get_int(col_in);
+ if (col) {
+ col = 0xff;
+ }
+ memset(self->pix_buf, col, LCD_PIX_BUF_BYTE_SIZE);
+ memset(self->pix_buf2, col, LCD_PIX_BUF_BYTE_SIZE);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(pyb_lcd_fill_obj, pyb_lcd_fill);
+
+/// \method get(x, y)
+///
+/// Get the pixel at the position `(x, y)`. Returns 0 or 1.
+///
+/// This method reads from the visible buffer.
+STATIC mp_obj_t pyb_lcd_get(mp_obj_t self_in, mp_obj_t x_in, mp_obj_t y_in) {
+ pyb_lcd_obj_t *self = self_in;
+ int x = mp_obj_get_int(x_in);
+ int y = mp_obj_get_int(y_in);
+ if (0 <= x && x <= 127 && 0 <= y && y <= 31) {
+ uint byte_pos = x + 128 * ((uint)y >> 3);
+ if (self->pix_buf[byte_pos] & (1 << (y & 7))) {
+ return mp_obj_new_int(1);
+ }
+ }
+ return mp_obj_new_int(0);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_3(pyb_lcd_get_obj, pyb_lcd_get);
+
+/// \method pixel(x, y, colour)
+///
+/// Set the pixel at `(x, y)` to the given colour (0 or 1).
+///
+/// This method writes to the hidden buffer. Use `show()` to show the buffer.
+STATIC mp_obj_t pyb_lcd_pixel(size_t n_args, const mp_obj_t *args) {
+ pyb_lcd_obj_t *self = args[0];
+ int x = mp_obj_get_int(args[1]);
+ int y = mp_obj_get_int(args[2]);
+ if (0 <= x && x <= 127 && 0 <= y && y <= 31) {
+ uint byte_pos = x + 128 * ((uint)y >> 3);
+ if (mp_obj_get_int(args[3]) == 0) {
+ self->pix_buf2[byte_pos] &= ~(1 << (y & 7));
+ } else {
+ self->pix_buf2[byte_pos] |= 1 << (y & 7);
+ }
+ }
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_lcd_pixel_obj, 4, 4, pyb_lcd_pixel);
+
+/// \method text(str, x, y, colour)
+///
+/// Draw the given text to the position `(x, y)` using the given colour (0 or 1).
+///
+/// This method writes to the hidden buffer. Use `show()` to show the buffer.
+STATIC mp_obj_t pyb_lcd_text(size_t n_args, const mp_obj_t *args) {
+ // extract arguments
+ pyb_lcd_obj_t *self = args[0];
+ size_t len;
+ const char *data = mp_obj_str_get_data(args[1], &len);
+ int x0 = mp_obj_get_int(args[2]);
+ int y0 = mp_obj_get_int(args[3]);
+ int col = mp_obj_get_int(args[4]);
+
+ // loop over chars
+ for (const char *top = data + len; data < top; data++) {
+ // get char and make sure its in range of font
+ uint chr = *(byte*)data;
+ if (chr < 32 || chr > 127) {
+ chr = 127;
+ }
+ // get char data
+ const uint8_t *chr_data = &font_petme128_8x8[(chr - 32) * 8];
+ // loop over char data
+ for (uint j = 0; j < 8; j++, x0++) {
+ if (0 <= x0 && x0 < LCD_PIX_BUF_W) { // clip x
+ uint vline_data = chr_data[j]; // each byte of char data is a vertical column of 8 pixels, LSB at top
+ for (int y = y0; vline_data; vline_data >>= 1, y++) { // scan over vertical column
+ if (vline_data & 1) { // only draw if pixel set
+ if (0 <= y && y < LCD_PIX_BUF_H) { // clip y
+ uint byte_pos = x0 + LCD_PIX_BUF_W * ((uint)y >> 3);
+ if (col == 0) {
+ // clear pixel
+ self->pix_buf2[byte_pos] &= ~(1 << (y & 7));
+ } else {
+ // set pixel
+ self->pix_buf2[byte_pos] |= 1 << (y & 7);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_lcd_text_obj, 5, 5, pyb_lcd_text);
+
+/// \method show()
+///
+/// Show the hidden buffer on the screen.
+STATIC mp_obj_t pyb_lcd_show(mp_obj_t self_in) {
+ pyb_lcd_obj_t *self = self_in;
+ memcpy(self->pix_buf, self->pix_buf2, LCD_PIX_BUF_BYTE_SIZE);
+ for (uint page = 0; page < 4; page++) {
+ lcd_out(self, LCD_INSTR, 0xb0 | page); // page address set
+ lcd_out(self, LCD_INSTR, 0x10); // column address set upper; 0
+ lcd_out(self, LCD_INSTR, 0x00); // column address set lower; 0
+ for (uint i = 0; i < 128; i++) {
+ lcd_out(self, LCD_DATA, self->pix_buf[128 * page + 127 - i]);
+ }
+ }
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_lcd_show_obj, pyb_lcd_show);
+
+STATIC const mp_rom_map_elem_t pyb_lcd_locals_dict_table[] = {
+ // instance methods
+ { MP_ROM_QSTR(MP_QSTR_command), MP_ROM_PTR(&pyb_lcd_command_obj) },
+ { MP_ROM_QSTR(MP_QSTR_contrast), MP_ROM_PTR(&pyb_lcd_contrast_obj) },
+ { MP_ROM_QSTR(MP_QSTR_light), MP_ROM_PTR(&pyb_lcd_light_obj) },
+ { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&pyb_lcd_write_obj) },
+ { MP_ROM_QSTR(MP_QSTR_fill), MP_ROM_PTR(&pyb_lcd_fill_obj) },
+ { MP_ROM_QSTR(MP_QSTR_get), MP_ROM_PTR(&pyb_lcd_get_obj) },
+ { MP_ROM_QSTR(MP_QSTR_pixel), MP_ROM_PTR(&pyb_lcd_pixel_obj) },
+ { MP_ROM_QSTR(MP_QSTR_text), MP_ROM_PTR(&pyb_lcd_text_obj) },
+ { MP_ROM_QSTR(MP_QSTR_show), MP_ROM_PTR(&pyb_lcd_show_obj) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(pyb_lcd_locals_dict, pyb_lcd_locals_dict_table);
+
+const mp_obj_type_t pyb_lcd_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_LCD,
+ .make_new = pyb_lcd_make_new,
+ .locals_dict = (mp_obj_dict_t*)&pyb_lcd_locals_dict,
+};
+
+#endif // MICROPY_HW_HAS_LCD
diff --git a/ports/stm32/lcd.h b/ports/stm32/lcd.h
new file mode 100644
index 000000000..c0d9bd97d
--- /dev/null
+++ b/ports/stm32/lcd.h
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ */
+#ifndef MICROPY_INCLUDED_STMHAL_LCD_H
+#define MICROPY_INCLUDED_STMHAL_LCD_H
+
+extern const mp_obj_type_t pyb_lcd_type;
+
+#endif // MICROPY_INCLUDED_STMHAL_LCD_H
diff --git a/ports/stm32/led.c b/ports/stm32/led.c
new file mode 100644
index 000000000..e03781bcf
--- /dev/null
+++ b/ports/stm32/led.c
@@ -0,0 +1,378 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * 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 <stdio.h>
+
+#include "py/nlr.h"
+#include "py/runtime.h"
+#include "py/mphal.h"
+#include "timer.h"
+#include "led.h"
+#include "pin.h"
+#include "genhdr/pins.h"
+
+#if defined(MICROPY_HW_LED1)
+
+/// \moduleref pyb
+/// \class LED - LED object
+///
+/// The LED object controls an individual LED (Light Emitting Diode).
+
+// the default is that LEDs are not inverted, and pin driven high turns them on
+#ifndef MICROPY_HW_LED_INVERTED
+#define MICROPY_HW_LED_INVERTED (0)
+#endif
+
+typedef struct _pyb_led_obj_t {
+ mp_obj_base_t base;
+ mp_uint_t led_id;
+ const pin_obj_t *led_pin;
+} pyb_led_obj_t;
+
+STATIC const pyb_led_obj_t pyb_led_obj[] = {
+ {{&pyb_led_type}, 1, &MICROPY_HW_LED1},
+#if defined(MICROPY_HW_LED2)
+ {{&pyb_led_type}, 2, &MICROPY_HW_LED2},
+#if defined(MICROPY_HW_LED3)
+ {{&pyb_led_type}, 3, &MICROPY_HW_LED3},
+#if defined(MICROPY_HW_LED4)
+ {{&pyb_led_type}, 4, &MICROPY_HW_LED4},
+#endif
+#endif
+#endif
+};
+#define NUM_LEDS MP_ARRAY_SIZE(pyb_led_obj)
+
+void led_init(void) {
+ /* Turn off LEDs and initialize */
+ for (int led = 0; led < NUM_LEDS; led++) {
+ const pin_obj_t *led_pin = pyb_led_obj[led].led_pin;
+ mp_hal_gpio_clock_enable(led_pin->gpio);
+ MICROPY_HW_LED_OFF(led_pin);
+ mp_hal_pin_output(led_pin);
+ }
+}
+
+#if defined(MICROPY_HW_LED1_PWM) \
+ || defined(MICROPY_HW_LED2_PWM) \
+ || defined(MICROPY_HW_LED3_PWM) \
+ || defined(MICROPY_HW_LED4_PWM)
+
+// The following is semi-generic code to control LEDs using PWM.
+// It currently supports TIM1, TIM2 and TIM3, channels 1-4.
+// Configure by defining the relevant MICROPY_HW_LEDx_PWM macros in mpconfigboard.h.
+// If they are not defined then PWM will not be available for that LED.
+
+#define LED_PWM_ENABLED (1)
+
+#ifndef MICROPY_HW_LED1_PWM
+#define MICROPY_HW_LED1_PWM { NULL, 0, 0, 0 }
+#endif
+#ifndef MICROPY_HW_LED2_PWM
+#define MICROPY_HW_LED2_PWM { NULL, 0, 0, 0 }
+#endif
+#ifndef MICROPY_HW_LED3_PWM
+#define MICROPY_HW_LED3_PWM { NULL, 0, 0, 0 }
+#endif
+#ifndef MICROPY_HW_LED4_PWM
+#define MICROPY_HW_LED4_PWM { NULL, 0, 0, 0 }
+#endif
+
+#define LED_PWM_TIM_PERIOD (10000) // TIM runs at 1MHz and fires every 10ms
+
+// this gives the address of the CCR register for channels 1-4
+#define LED_PWM_CCR(pwm_cfg) ((volatile uint32_t*)&(pwm_cfg)->tim->CCR1 + ((pwm_cfg)->tim_channel >> 2))
+
+typedef struct _led_pwm_config_t {
+ TIM_TypeDef *tim;
+ uint8_t tim_id;
+ uint8_t tim_channel;
+ uint8_t alt_func;
+} led_pwm_config_t;
+
+STATIC const led_pwm_config_t led_pwm_config[] = {
+ MICROPY_HW_LED1_PWM,
+ MICROPY_HW_LED2_PWM,
+ MICROPY_HW_LED3_PWM,
+ MICROPY_HW_LED4_PWM,
+};
+
+STATIC uint8_t led_pwm_state = 0;
+
+static inline bool led_pwm_is_enabled(int led) {
+ return (led_pwm_state & (1 << led)) != 0;
+}
+
+// this function has a large stack so it should not be inlined
+STATIC void led_pwm_init(int led) __attribute__((noinline));
+STATIC void led_pwm_init(int led) {
+ const pin_obj_t *led_pin = pyb_led_obj[led - 1].led_pin;
+ const led_pwm_config_t *pwm_cfg = &led_pwm_config[led - 1];
+
+ // GPIO configuration
+ mp_hal_pin_config(led_pin, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, pwm_cfg->alt_func);
+
+ // TIM configuration
+ switch (pwm_cfg->tim_id) {
+ case 1: __TIM1_CLK_ENABLE(); break;
+ case 2: __TIM2_CLK_ENABLE(); break;
+ case 3: __TIM3_CLK_ENABLE(); break;
+ default: assert(0);
+ }
+ TIM_HandleTypeDef tim = {0};
+ tim.Instance = pwm_cfg->tim;
+ tim.Init.Period = LED_PWM_TIM_PERIOD - 1;
+ tim.Init.Prescaler = timer_get_source_freq(pwm_cfg->tim_id) / 1000000 - 1; // TIM runs at 1MHz
+ tim.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
+ tim.Init.CounterMode = TIM_COUNTERMODE_UP;
+ tim.Init.RepetitionCounter = 0;
+ HAL_TIM_PWM_Init(&tim);
+
+ // PWM configuration
+ TIM_OC_InitTypeDef oc_init;
+ oc_init.OCMode = TIM_OCMODE_PWM1;
+ oc_init.Pulse = 0; // off
+ oc_init.OCPolarity = MICROPY_HW_LED_INVERTED ? TIM_OCPOLARITY_LOW : TIM_OCPOLARITY_HIGH;
+ oc_init.OCFastMode = TIM_OCFAST_DISABLE;
+ oc_init.OCNPolarity = TIM_OCNPOLARITY_HIGH; // needed for TIM1 and TIM8
+ oc_init.OCIdleState = TIM_OCIDLESTATE_SET; // needed for TIM1 and TIM8
+ oc_init.OCNIdleState = TIM_OCNIDLESTATE_SET; // needed for TIM1 and TIM8
+ HAL_TIM_PWM_ConfigChannel(&tim, &oc_init, pwm_cfg->tim_channel);
+ HAL_TIM_PWM_Start(&tim, pwm_cfg->tim_channel);
+
+ // indicate that this LED is using PWM
+ led_pwm_state |= 1 << led;
+}
+
+STATIC void led_pwm_deinit(int led) {
+ // make the LED's pin a standard GPIO output pin
+ const pin_obj_t *led_pin = pyb_led_obj[led - 1].led_pin;
+ GPIO_TypeDef *g = led_pin->gpio;
+ uint32_t pin = led_pin->pin;
+ static const int mode = 1; // output
+ static const int alt = 0; // no alt func
+ g->MODER = (g->MODER & ~(3 << (2 * pin))) | (mode << (2 * pin));
+ g->AFR[pin >> 3] = (g->AFR[pin >> 3] & ~(15 << (4 * (pin & 7)))) | (alt << (4 * (pin & 7)));
+ led_pwm_state &= ~(1 << led);
+}
+
+#else
+#define LED_PWM_ENABLED (0)
+#endif
+
+void led_state(pyb_led_t led, int state) {
+ if (led < 1 || led > NUM_LEDS) {
+ return;
+ }
+
+ const pin_obj_t *led_pin = pyb_led_obj[led - 1].led_pin;
+ //printf("led_state(%d,%d)\n", led, state);
+ if (state == 0) {
+ // turn LED off
+ MICROPY_HW_LED_OFF(led_pin);
+ } else {
+ // turn LED on
+ MICROPY_HW_LED_ON(led_pin);
+ }
+
+ #if LED_PWM_ENABLED
+ if (led_pwm_is_enabled(led)) {
+ led_pwm_deinit(led);
+ }
+ #endif
+}
+
+void led_toggle(pyb_led_t led) {
+ if (led < 1 || led > NUM_LEDS) {
+ return;
+ }
+
+ #if LED_PWM_ENABLED
+ if (led_pwm_is_enabled(led)) {
+ // if PWM is enabled then LED has non-zero intensity, so turn it off
+ led_state(led, 0);
+ return;
+ }
+ #endif
+
+ // toggle the output data register to toggle the LED state
+ const pin_obj_t *led_pin = pyb_led_obj[led - 1].led_pin;
+ led_pin->gpio->ODR ^= led_pin->pin_mask;
+}
+
+int led_get_intensity(pyb_led_t led) {
+ if (led < 1 || led > NUM_LEDS) {
+ return 0;
+ }
+
+ #if LED_PWM_ENABLED
+ if (led_pwm_is_enabled(led)) {
+ const led_pwm_config_t *pwm_cfg = &led_pwm_config[led - 1];
+ mp_uint_t i = (*LED_PWM_CCR(pwm_cfg) * 255 + LED_PWM_TIM_PERIOD - 2) / (LED_PWM_TIM_PERIOD - 1);
+ if (i > 255) {
+ i = 255;
+ }
+ return i;
+ }
+ #endif
+
+ const pin_obj_t *led_pin = pyb_led_obj[led - 1].led_pin;
+ GPIO_TypeDef *gpio = led_pin->gpio;
+
+ if (gpio->ODR & led_pin->pin_mask) {
+ // pin is high
+ return MICROPY_HW_LED_INVERTED ? 0 : 255;
+ } else {
+ // pin is low
+ return MICROPY_HW_LED_INVERTED ? 255 : 0;
+ }
+}
+
+void led_set_intensity(pyb_led_t led, mp_int_t intensity) {
+ #if LED_PWM_ENABLED
+ if (intensity > 0 && intensity < 255) {
+ const led_pwm_config_t *pwm_cfg = &led_pwm_config[led - 1];
+ if (pwm_cfg->tim != NULL) {
+ // set intensity using PWM pulse width
+ if (!led_pwm_is_enabled(led)) {
+ led_pwm_init(led);
+ }
+ *LED_PWM_CCR(pwm_cfg) = intensity * (LED_PWM_TIM_PERIOD - 1) / 255;
+ return;
+ }
+ }
+ #endif
+
+ // intensity not supported for this LED; just turn it on/off
+ led_state(led, intensity > 0);
+}
+
+void led_debug(int n, int delay) {
+ led_state(1, n & 1);
+ led_state(2, n & 2);
+ led_state(3, n & 4);
+ led_state(4, n & 8);
+ mp_hal_delay_ms(delay);
+}
+
+/******************************************************************************/
+/* MicroPython bindings */
+
+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);
+}
+
+/// \classmethod \constructor(id)
+/// Create an LED object associated with the given LED:
+///
+/// - `id` is the LED number, 1-4.
+STATIC mp_obj_t led_obj_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, 1, false);
+
+ // get led number
+ mp_int_t led_id = mp_obj_get_int(args[0]);
+
+ // check led number
+ if (!(1 <= led_id && led_id <= NUM_LEDS)) {
+ nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "LED(%d) doesn't exist", led_id));
+ }
+
+ // return static led object
+ return (mp_obj_t)&pyb_led_obj[led_id - 1];
+}
+
+/// \method on()
+/// Turn the LED on.
+mp_obj_t led_obj_on(mp_obj_t self_in) {
+ pyb_led_obj_t *self = self_in;
+ led_state(self->led_id, 1);
+ return mp_const_none;
+}
+
+/// \method off()
+/// Turn the LED off.
+mp_obj_t led_obj_off(mp_obj_t self_in) {
+ pyb_led_obj_t *self = self_in;
+ led_state(self->led_id, 0);
+ return mp_const_none;
+}
+
+/// \method toggle()
+/// Toggle the LED between on and off.
+mp_obj_t led_obj_toggle(mp_obj_t self_in) {
+ pyb_led_obj_t *self = self_in;
+ led_toggle(self->led_id);
+ return mp_const_none;
+}
+
+/// \method intensity([value])
+/// Get or set the LED intensity. Intensity ranges between 0 (off) and 255 (full on).
+/// If no argument is given, return the LED intensity.
+/// If an argument is given, set the LED intensity and return `None`.
+mp_obj_t led_obj_intensity(size_t n_args, const mp_obj_t *args) {
+ pyb_led_obj_t *self = args[0];
+ if (n_args == 1) {
+ return mp_obj_new_int(led_get_intensity(self->led_id));
+ } else {
+ led_set_intensity(self->led_id, mp_obj_get_int(args[1]));
+ return mp_const_none;
+ }
+}
+
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(led_obj_on_obj, led_obj_on);
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(led_obj_off_obj, led_obj_off);
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(led_obj_toggle_obj, led_obj_toggle);
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(led_obj_intensity_obj, 1, 2, led_obj_intensity);
+
+STATIC const mp_rom_map_elem_t led_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_on), MP_ROM_PTR(&led_obj_on_obj) },
+ { MP_ROM_QSTR(MP_QSTR_off), MP_ROM_PTR(&led_obj_off_obj) },
+ { MP_ROM_QSTR(MP_QSTR_toggle), MP_ROM_PTR(&led_obj_toggle_obj) },
+ { MP_ROM_QSTR(MP_QSTR_intensity), MP_ROM_PTR(&led_obj_intensity_obj) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(led_locals_dict, led_locals_dict_table);
+
+const mp_obj_type_t pyb_led_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_LED,
+ .print = led_obj_print,
+ .make_new = led_obj_make_new,
+ .locals_dict = (mp_obj_dict_t*)&led_locals_dict,
+};
+
+#else
+// For boards with no LEDs, we leave an empty function here so that we don't
+// have to put conditionals everywhere.
+void led_init(void) {
+}
+void led_state(pyb_led_t led, int state) {
+}
+void led_toggle(pyb_led_t led) {
+}
+#endif // defined(MICROPY_HW_LED1)
diff --git a/ports/stm32/led.h b/ports/stm32/led.h
new file mode 100644
index 000000000..f1b05d1e2
--- /dev/null
+++ b/ports/stm32/led.h
@@ -0,0 +1,54 @@
+/*
+ * 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.
+ */
+#ifndef MICROPY_INCLUDED_STMHAL_LED_H
+#define MICROPY_INCLUDED_STMHAL_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);
+void led_state(pyb_led_t led, int state);
+void led_toggle(pyb_led_t led);
+void led_debug(int value, int delay);
+
+extern const mp_obj_type_t pyb_led_type;
+
+#endif // MICROPY_INCLUDED_STMHAL_LED_H
diff --git a/ports/stm32/machine_i2c.c b/ports/stm32/machine_i2c.c
new file mode 100644
index 000000000..1be2151e3
--- /dev/null
+++ b/ports/stm32/machine_i2c.c
@@ -0,0 +1,550 @@
+/*
+ * 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 <string.h>
+
+#include "py/runtime.h"
+#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 defined(MCU_SERIES_F4)
+
+// 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.
+*/
+
+typedef struct _machine_hard_i2c_obj_t {
+ mp_obj_base_t base;
+ const pyb_i2c_obj_t *pyb;
+ uint32_t *timeout;
+} 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]},
+};
+
+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;
+}
+
+// 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;
+ }
+ }
+ 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;
+ }
+
+ /* Send slave address */
+ hi2c->Instance->DR = addr_byte;
+
+ /* 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;
+ }
+
+ /* Check for the Timeout */
+ if (Timeout != HAL_MAX_DELAY) {
+ if ((Timeout == 0U)||((HAL_GetTick() - Tickstart ) > Timeout)) {
+ return -MP_ETIMEDOUT;
+ }
+ }
+ }
+
+ return 0;
+}
+
+// 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;
+}
+
+// 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;
+}
+
+#else
+
+// No hardware I2C driver for this MCU so use the software implementation
+
+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},
+ #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},
+ #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},
+ #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},
+ #else
+ {{NULL}, 0, 0, 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, scl=%q, sda=%q, freq=%u, timeout=%u)",
+ self - &machine_hard_i2c_obj[0] + 1,
+ self->scl->name, self->sda->name, 500000 / self->us_delay, self->us_timeout);
+}
+
+STATIC void machine_hard_i2c_init(machine_hard_i2c_obj_t *self, uint32_t freq, uint32_t timeout) {
+ // set parameters
+ if (freq >= 1000000) {
+ // allow fastest possible bit-bang rate
+ self->us_delay = 0;
+ } else {
+ self->us_delay = 500000 / freq;
+ if (self->us_delay == 0) {
+ self->us_delay = 1;
+ }
+ }
+
+ self->us_timeout = timeout;
+
+ // init pins
+ mp_hal_pin_open_drain(self->scl);
+ mp_hal_pin_open_drain(self->sda);
+}
+
+#define machine_hard_i2c_readfrom mp_machine_soft_i2c_readfrom
+#define machine_hard_i2c_writeto mp_machine_soft_i2c_writeto
+
+#endif
+
+/******************************************************************************/
+/* MicroPython bindings for machine API */
+
+mp_obj_t machine_hard_i2c_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
+ // parse args
+ enum { ARG_id, ARG_scl, ARG_sda, ARG_freq, ARG_timeout };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_id, MP_ARG_REQUIRED | MP_ARG_OBJ },
+ { MP_QSTR_scl, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+ { MP_QSTR_sda, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+ { MP_QSTR_freq, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 400000} },
+ { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1000} },
+ };
+ 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);
+
+ // work out i2c bus
+ int i2c_id = 0;
+ if (MP_OBJ_IS_STR(args[ARG_id].u_obj)) {
+ const char *port = mp_obj_str_get_str(args[ARG_id].u_obj);
+ 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[ARG_id].u_obj);
+ if (i2c_id < 1 || i2c_id > MP_ARRAY_SIZE(machine_hard_i2c_obj)
+ || machine_hard_i2c_obj[i2c_id - 1].base.type == NULL) {
+ nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError,
+ "I2C(%d) doesn't exist", i2c_id));
+ }
+ }
+
+ // get static peripheral object
+ machine_hard_i2c_obj_t *self = (machine_hard_i2c_obj_t*)&machine_hard_i2c_obj[i2c_id - 1];
+
+ // here we would check the scl/sda pins and configure them, but it's not implemented
+ if (args[ARG_scl].u_obj != MP_OBJ_NULL || args[ARG_sda].u_obj != MP_OBJ_NULL) {
+ mp_raise_ValueError("explicit choice of scl/sda is not implemented");
+ }
+
+ // initialise the I2C peripheral
+ machine_hard_i2c_init(self, args[ARG_freq].u_int, args[ARG_timeout].u_int);
+
+ return MP_OBJ_FROM_PTR(self);
+}
+
+STATIC const mp_machine_i2c_p_t machine_hard_i2c_p = {
+ .readfrom = machine_hard_i2c_readfrom,
+ .writeto = machine_hard_i2c_writeto,
+};
+
+STATIC const mp_obj_type_t machine_hard_i2c_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_I2C,
+ .print = machine_hard_i2c_print,
+ .make_new = machine_hard_i2c_make_new,
+ .protocol = &machine_hard_i2c_p,
+ .locals_dict = (mp_obj_dict_t*)&mp_machine_soft_i2c_locals_dict,
+};
diff --git a/ports/stm32/main.c b/ports/stm32/main.c
new file mode 100644
index 000000000..16279d073
--- /dev/null
+++ b/ports/stm32/main.c
@@ -0,0 +1,699 @@
+/*
+ * 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/stackctrl.h"
+#include "py/gc.h"
+#include "py/mphal.h"
+#include "lib/mp-readline/readline.h"
+#include "lib/utils/pyexec.h"
+#include "lib/oofatfs/ff.h"
+#include "extmod/vfs.h"
+#include "extmod/vfs_fat.h"
+
+#include "systick.h"
+#include "pendsv.h"
+#include "pybthread.h"
+#include "gccollect.h"
+#include "modmachine.h"
+#include "i2c.h"
+#include "spi.h"
+#include "uart.h"
+#include "timer.h"
+#include "led.h"
+#include "pin.h"
+#include "extint.h"
+#include "usrsw.h"
+#include "usb.h"
+#include "rtc.h"
+#include "storage.h"
+#include "sdcard.h"
+#include "rng.h"
+#include "accel.h"
+#include "servo.h"
+#include "dac.h"
+#include "can.h"
+#include "modnetwork.h"
+
+void SystemClock_Config(void);
+
+pyb_thread_t pyb_thread_main;
+fs_user_mount_t fs_user_mount_flash;
+
+void flash_error(int n) {
+ for (int i = 0; i < n; i++) {
+ led_state(PYB_LED_RED, 1);
+ led_state(PYB_LED_GREEN, 0);
+ mp_hal_delay_ms(250);
+ led_state(PYB_LED_RED, 0);
+ led_state(PYB_LED_GREEN, 1);
+ mp_hal_delay_ms(250);
+ }
+ led_state(PYB_LED_GREEN, 0);
+}
+
+void NORETURN __fatal_error(const char *msg) {
+ for (volatile uint delay = 0; delay < 10000000; delay++) {
+ }
+ led_state(1, 1);
+ led_state(2, 1);
+ led_state(3, 1);
+ led_state(4, 1);
+ mp_hal_stdout_tx_strn("\nFATAL ERROR:\n", 14);
+ mp_hal_stdout_tx_strn(msg, strlen(msg));
+ for (uint i = 0;;) {
+ led_toggle(((i++) & 3) + 1);
+ for (volatile uint delay = 0; delay < 10000000; delay++) {
+ }
+ if (i >= 16) {
+ // to conserve power
+ __WFI();
+ }
+ }
+}
+
+void nlr_jump_fail(void *val) {
+ printf("FATAL: uncaught exception %p\n", val);
+ mp_obj_print_exception(&mp_plat_print, (mp_obj_t)val);
+ __fatal_error("");
+}
+
+#ifndef NDEBUG
+void MP_WEAK __assert_func(const char *file, int line, const char *func, const char *expr) {
+ (void)func;
+ printf("Assertion '%s' failed, at file %s:%d\n", expr, file, line);
+ __fatal_error("");
+}
+#endif
+
+STATIC mp_obj_t pyb_main(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_opt, MP_ARG_INT, {.u_int = 0} }
+ };
+
+ if (MP_OBJ_IS_STR(pos_args[0])) {
+ MP_STATE_PORT(pyb_config_main) = pos_args[0];
+
+ // parse args
+ 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);
+ MP_STATE_VM(mp_optimise_value) = args[0].u_int;
+ }
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_KW(pyb_main_obj, 1, pyb_main);
+
+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"
+"\r\n"
+"import machine\r\n"
+"import pyb\r\n"
+"#pyb.main('main.py') # main script to run after this one\r\n"
+"#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"
+;
+
+static const char fresh_main_py[] =
+"# main.py -- put your code here!\r\n"
+;
+
+static const char fresh_pybcdc_inf[] =
+#include "genhdr/pybcdc_inf.h"
+;
+
+static const char fresh_readme_txt[] =
+"This is a MicroPython board\r\n"
+"\r\n"
+"You can get started right away by writing your Python code in 'main.py'.\r\n"
+"\r\n"
+"For a serial prompt:\r\n"
+" - Windows: you need to go to 'Device manager', right click on the unknown device,\r\n"
+" then update the driver software, using the 'pybcdc.inf' file found on this drive.\r\n"
+" Then use a terminal program like Hyperterminal or putty.\r\n"
+" - Mac OS X: use the command: screen /dev/tty.usbmodem*\r\n"
+" - Linux: use the command: screen /dev/ttyACM0\r\n"
+"\r\n"
+"Please visit http://micropython.org/help/ for further help.\r\n"
+;
+
+// avoid inlining to avoid stack usage within main()
+MP_NOINLINE STATIC bool init_flash_fs(uint reset_mode) {
+ // init the vfs object
+ fs_user_mount_t *vfs_fat = &fs_user_mount_flash;
+ vfs_fat->flags = 0;
+ pyb_flash_init_vfs(vfs_fat);
+
+ // try to mount the flash
+ FRESULT res = f_mount(&vfs_fat->fatfs);
+
+ if (reset_mode == 3 || res == FR_NO_FILESYSTEM) {
+ // no filesystem, or asked to reset it, so create a fresh one
+
+ // LED on to indicate creation of LFS
+ led_state(PYB_LED_GREEN, 1);
+ uint32_t start_tick = HAL_GetTick();
+
+ uint8_t working_buf[_MAX_SS];
+ res = f_mkfs(&vfs_fat->fatfs, FM_FAT, 0, working_buf, sizeof(working_buf));
+ if (res == FR_OK) {
+ // success creating fresh LFS
+ } else {
+ printf("PYB: can't create flash filesystem\n");
+ return false;
+ }
+
+ // set label
+ f_setlabel(&vfs_fat->fatfs, "pybflash");
+
+ // create empty main.py
+ FIL fp;
+ f_open(&vfs_fat->fatfs, &fp, "/main.py", FA_WRITE | FA_CREATE_ALWAYS);
+ UINT n;
+ f_write(&fp, fresh_main_py, sizeof(fresh_main_py) - 1 /* don't count null terminator */, &n);
+ // TODO check we could write n bytes
+ f_close(&fp);
+
+ // create .inf driver file
+ f_open(&vfs_fat->fatfs, &fp, "/pybcdc.inf", FA_WRITE | FA_CREATE_ALWAYS);
+ f_write(&fp, fresh_pybcdc_inf, sizeof(fresh_pybcdc_inf) - 1 /* don't count null terminator */, &n);
+ f_close(&fp);
+
+ // create readme file
+ f_open(&vfs_fat->fatfs, &fp, "/README.txt", FA_WRITE | FA_CREATE_ALWAYS);
+ f_write(&fp, fresh_readme_txt, sizeof(fresh_readme_txt) - 1 /* don't count null terminator */, &n);
+ f_close(&fp);
+
+ // keep LED on for at least 200ms
+ sys_tick_wait_at_least(start_tick, 200);
+ led_state(PYB_LED_GREEN, 0);
+ } else if (res == FR_OK) {
+ // mount sucessful
+ } else {
+ fail:
+ printf("PYB: can't mount flash\n");
+ return false;
+ }
+
+ // mount the flash device (there should be no other devices mounted at this point)
+ // we allocate this structure on the heap because vfs->next is a root pointer
+ mp_vfs_mount_t *vfs = m_new_obj_maybe(mp_vfs_mount_t);
+ if (vfs == NULL) {
+ goto fail;
+ }
+ vfs->str = "/flash";
+ vfs->len = 6;
+ vfs->obj = MP_OBJ_FROM_PTR(vfs_fat);
+ vfs->next = NULL;
+ MP_STATE_VM(vfs_mount_table) = vfs;
+
+ // The current directory is used as the boot up directory.
+ // It is set to the internal flash filesystem by default.
+ MP_STATE_PORT(vfs_cur) = vfs;
+
+ // Make sure we have a /flash/boot.py. Create it if needed.
+ FILINFO fno;
+ res = f_stat(&vfs_fat->fatfs, "/boot.py", &fno);
+ if (res != FR_OK) {
+ // doesn't exist, create fresh file
+
+ // LED on to indicate creation of boot.py
+ led_state(PYB_LED_GREEN, 1);
+ uint32_t start_tick = HAL_GetTick();
+
+ FIL fp;
+ f_open(&vfs_fat->fatfs, &fp, "/boot.py", FA_WRITE | FA_CREATE_ALWAYS);
+ UINT n;
+ f_write(&fp, fresh_boot_py, sizeof(fresh_boot_py) - 1 /* don't count null terminator */, &n);
+ // TODO check we could write n bytes
+ f_close(&fp);
+
+ // keep LED on for at least 200ms
+ sys_tick_wait_at_least(start_tick, 200);
+ led_state(PYB_LED_GREEN, 0);
+ }
+
+ return true;
+}
+
+#if MICROPY_HW_HAS_SDCARD
+STATIC bool init_sdcard_fs(bool first_soft_reset) {
+ bool first_part = true;
+ for (int part_num = 1; part_num <= 4; ++part_num) {
+ // create vfs object
+ fs_user_mount_t *vfs_fat = m_new_obj_maybe(fs_user_mount_t);
+ mp_vfs_mount_t *vfs = m_new_obj_maybe(mp_vfs_mount_t);
+ if (vfs == NULL || vfs_fat == NULL) {
+ break;
+ }
+ vfs_fat->flags = FSUSER_FREE_OBJ;
+ sdcard_init_vfs(vfs_fat, part_num);
+
+ // try to mount the partition
+ FRESULT res = f_mount(&vfs_fat->fatfs);
+
+ if (res != FR_OK) {
+ // couldn't mount
+ m_del_obj(fs_user_mount_t, vfs_fat);
+ m_del_obj(mp_vfs_mount_t, vfs);
+ } else {
+ // mounted via FatFs, now mount the SD partition in the VFS
+ if (first_part) {
+ // the first available partition is traditionally called "sd" for simplicity
+ vfs->str = "/sd";
+ vfs->len = 3;
+ } else {
+ // subsequent partitions are numbered by their index in the partition table
+ if (part_num == 2) {
+ vfs->str = "/sd2";
+ } else if (part_num == 2) {
+ vfs->str = "/sd3";
+ } else {
+ vfs->str = "/sd4";
+ }
+ vfs->len = 4;
+ }
+ vfs->obj = MP_OBJ_FROM_PTR(vfs_fat);
+ vfs->next = NULL;
+ for (mp_vfs_mount_t **m = &MP_STATE_VM(vfs_mount_table);; m = &(*m)->next) {
+ if (*m == NULL) {
+ *m = vfs;
+ break;
+ }
+ }
+
+ if (first_soft_reset) {
+ // use SD card as medium for the USB MSD
+ #if defined(USE_DEVICE_MODE)
+ pyb_usb_storage_medium = PYB_USB_STORAGE_MEDIUM_SDCARD;
+ #endif
+ }
+
+ #if defined(USE_DEVICE_MODE)
+ // 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
+ {
+ if (first_part) {
+ // use SD card as current directory
+ MP_STATE_PORT(vfs_cur) = vfs;
+ }
+ }
+ first_part = false;
+ }
+ }
+
+ if (first_part) {
+ printf("PYB: can't mount SD card\n");
+ return false;
+ } else {
+ return true;
+ }
+}
+#endif
+
+STATIC uint update_reset_mode(uint reset_mode) {
+#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)
+ for (uint i = 0; i < 3000; i++) {
+ if (!switch_get()) {
+ break;
+ }
+ mp_hal_delay_ms(20);
+ if (i % 30 == 29) {
+ if (++reset_mode > 3) {
+ reset_mode = 1;
+ }
+ led_state(2, reset_mode & 1);
+ led_state(3, reset_mode & 2);
+ led_state(4, reset_mode & 4);
+ }
+ }
+ // flash the selected reset mode
+ for (uint i = 0; i < 6; i++) {
+ led_state(2, 0);
+ led_state(3, 0);
+ led_state(4, 0);
+ mp_hal_delay_ms(50);
+ led_state(2, reset_mode & 1);
+ led_state(3, reset_mode & 2);
+ led_state(4, reset_mode & 4);
+ mp_hal_delay_ms(50);
+ }
+ mp_hal_delay_ms(400);
+
+#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
+ for (uint i = 0; i < 10; i++) {
+ led_state(1, 0);
+ for (uint j = 0; j < reset_mode; j++) {
+ if (!switch_get()) {
+ break;
+ }
+ led_state(1, 1);
+ mp_hal_delay_ms(100);
+ led_state(1, 0);
+ mp_hal_delay_ms(200);
+ }
+ mp_hal_delay_ms(400);
+ if (!switch_get()) {
+ break;
+ }
+ if (++reset_mode > 3) {
+ reset_mode = 1;
+ }
+ }
+ // Flash the selected reset mode
+ for (uint i = 0; i < 2; i++) {
+ for (uint j = 0; j < reset_mode; j++) {
+ led_state(1, 1);
+ mp_hal_delay_ms(100);
+ led_state(1, 0);
+ mp_hal_delay_ms(200);
+ }
+ mp_hal_delay_ms(400);
+ }
+#else
+#error Need a reset mode update method
+#endif
+ }
+#endif
+ return reset_mode;
+}
+
+int main(void) {
+ // TODO disable JTAG
+
+ /* 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();
+
+ // set the system clock to be HSE
+ SystemClock_Config();
+
+ // enable GPIO clocks
+ __GPIOA_CLK_ENABLE();
+ __GPIOB_CLK_ENABLE();
+ __GPIOC_CLK_ENABLE();
+ __GPIOD_CLK_ENABLE();
+
+ #if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7)
+ #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.
+ __HAL_RCC_DTCMRAMEN_CLK_ENABLE();
+ #elif defined(CCMDATARAM_BASE)
+ // enable the CCM RAM
+ __HAL_RCC_CCMDATARAMEN_CLK_ENABLE();
+ #endif
+ #endif
+
+ #if defined(MICROPY_BOARD_EARLY_INIT)
+ MICROPY_BOARD_EARLY_INIT();
+ #endif
+
+ // basic sub-system init
+ #if MICROPY_PY_THREAD
+ pyb_thread_init(&pyb_thread_main);
+ #endif
+ pendsv_init();
+ led_init();
+#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;
+
+soft_reset:
+
+ // check if user switch held to select the reset mode
+#if defined(MICROPY_HW_LED2)
+ led_state(1, 0);
+ led_state(2, 1);
+#else
+ led_state(1, 1);
+ led_state(2, 0);
+#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();
+ }
+
+ // Python threading init
+ #if MICROPY_PY_THREAD
+ mp_thread_init();
+ #endif
+
+ // Stack limit should be less than real stack size, so we have a chance
+ // to recover from limit hit. (Limit is measured in bytes.)
+ // Note: stack control relies on main thread being initialised above
+ mp_stack_set_top(&_estack);
+ mp_stack_set_limit((char*)&_estack - (char*)&_heap_end - 1024);
+
+ // GC init
+ gc_init(&_heap_start, &_heap_end);
+
+ // MicroPython init
+ mp_init();
+ mp_obj_list_init(mp_sys_path, 0);
+ mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR_)); // current dir (or base dir of the script)
+ mp_obj_list_init(mp_sys_argv, 0);
+
+ // Initialise low-level sub-systems. Here we need to very basic things like
+ // zeroing out memory and resetting any of the sub-systems. Following this
+ // we can run Python scripts (eg boot.py), but anything that is configurable
+ // by boot.py must be set after boot.py is run.
+
+ readline_init0();
+ pin_init0();
+ extint_init0();
+ timer_init0();
+ uart_init0();
+
+ // 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)
+ {
+ 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);
+ }
+#else
+ MP_STATE_PORT(pyb_stdio_uart) = NULL;
+#endif
+
+#if MICROPY_HW_ENABLE_CAN
+ can_init0();
+#endif
+
+#if MICROPY_HW_ENABLE_RNG
+ rng_init0();
+#endif
+
+ i2c_init0();
+ spi_init0();
+ pyb_usb_init0();
+
+ // 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_sdcard = false;
+#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);
+ }
+ }
+#endif
+
+ // set sys.path based on mounted filesystems (/sd is first so it can override /flash)
+ if (mounted_sdcard) {
+ mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR__slash_sd));
+ mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR__slash_sd_slash_lib));
+ }
+ if (mounted_flash) {
+ mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR__slash_flash));
+ mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR__slash_flash_slash_lib));
+ }
+
+ // reset config variables; they should be set by boot.py
+ MP_STATE_PORT(pyb_config_main) = MP_OBJ_NULL;
+
+ // run boot.py, if it exists
+ // TODO perhaps have pyb.reboot([bootpy]) function to soft-reboot and execute custom boot.py
+ if (reset_mode == 1 || reset_mode == 3) {
+ const char *boot_py = "boot.py";
+ mp_import_stat_t stat = mp_import_stat(boot_py);
+ if (stat == MP_IMPORT_STAT_FILE) {
+ int ret = pyexec_file(boot_py);
+ if (ret & PYEXEC_FORCED_EXIT) {
+ goto soft_reset_exit;
+ }
+ if (!ret) {
+ flash_error(4);
+ }
+ }
+ }
+
+ // turn boot-up LEDs off
+#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
+ led_state(2, 0);
+ led_state(3, 0);
+ led_state(4, 0);
+
+ // Now we initialise sub-systems that need configuration from boot.py,
+ // or whose initialisation can be safely deferred until after running
+ // boot.py.
+
+#if defined(USE_DEVICE_MODE)
+ // 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
+
+#if MICROPY_HW_HAS_MMA7660
+ // MMA accel: init and reset
+ accel_init();
+#endif
+
+#if MICROPY_HW_ENABLE_SERVO
+ // servo
+ servo_init();
+#endif
+
+#if MICROPY_HW_ENABLE_DAC
+ // DAC
+ dac_init();
+#endif
+
+#if MICROPY_PY_NETWORK
+ mod_network_init();
+#endif
+
+ // At this point everything is fully configured and initialised.
+
+ // Run the main script from the current directory.
+ if ((reset_mode == 1 || reset_mode == 3) && pyexec_mode_kind == PYEXEC_MODE_FRIENDLY_REPL) {
+ const char *main_py;
+ if (MP_STATE_PORT(pyb_config_main) == MP_OBJ_NULL) {
+ main_py = "main.py";
+ } else {
+ main_py = mp_obj_str_get_str(MP_STATE_PORT(pyb_config_main));
+ }
+ mp_import_stat_t stat = mp_import_stat(main_py);
+ if (stat == MP_IMPORT_STAT_FILE) {
+ int ret = pyexec_file(main_py);
+ if (ret & PYEXEC_FORCED_EXIT) {
+ goto soft_reset_exit;
+ }
+ if (!ret) {
+ flash_error(3);
+ }
+ }
+ }
+
+ // Main script is finished, so now go into REPL mode.
+ // The REPL mode can change, or it can request a soft reset.
+ for (;;) {
+ if (pyexec_mode_kind == PYEXEC_MODE_RAW_REPL) {
+ if (pyexec_raw_repl() != 0) {
+ break;
+ }
+ } else {
+ if (pyexec_friendly_repl() != 0) {
+ break;
+ }
+ }
+ }
+
+soft_reset_exit:
+
+ // soft reset
+
+ printf("PYB: sync filesystems\n");
+ storage_flush();
+
+ printf("PYB: soft reboot\n");
+ timer_deinit();
+ uart_deinit();
+#if MICROPY_HW_ENABLE_CAN
+ can_deinit();
+#endif
+
+ #if MICROPY_PY_THREAD
+ pyb_thread_deinit();
+ #endif
+
+ first_soft_reset = false;
+ goto soft_reset;
+}
diff --git a/ports/stm32/make-stmconst.py b/ports/stm32/make-stmconst.py
new file mode 100644
index 000000000..0b5666b9c
--- /dev/null
+++ b/ports/stm32/make-stmconst.py
@@ -0,0 +1,261 @@
+"""
+Read in the cmsis/devinc/stm32f405xx.h header, extract relevant constants,
+and create modstmconst.c.
+
+This is not part of the automatic build process because stm32f405xx.h isn't
+expected to change. After generating the file, some manual intervention is
+needed to copy the new qstr definitions to qstrdefsport.h.
+"""
+
+from __future__ import print_function
+
+import argparse
+import re
+
+# Python 2/3 compatibility
+import platform
+if platform.python_version_tuple()[0] == '2':
+ def convert_bytes_to_str(b):
+ return b
+elif platform.python_version_tuple()[0] == '3':
+ def convert_bytes_to_str(b):
+ try:
+ return str(b, 'utf8')
+ except ValueError:
+ # some files have invalid utf8 bytes, so filter them out
+ return ''.join(chr(l) for l in b if l <= 126)
+# end compatibility code
+
+# given a list of (name,regex) pairs, find the first one that matches the given line
+def re_match_first(regexs, line):
+ for name, regex in regexs:
+ match = re.match(regex, line)
+ if match:
+ return name, match
+ return None, None
+
+class LexerError(Exception):
+ def __init__(self, line):
+ self.line = line
+
+class Lexer:
+ re_io_reg = r'__IO uint(?P<bits>8|16|32)_t +(?P<reg>[A-Z0-9]+)'
+ re_comment = r'(?P<comment>[A-Za-z0-9 \-/_()&]+)'
+ re_addr_offset = r'Address offset: (?P<offset>0x[0-9A-Z]{2,3})'
+ regexs = (
+ ('#define hex', re.compile(r'#define +(?P<id>[A-Z0-9_]+) +(?:\(\(uint32_t\))?(?P<hex>0x[0-9A-F]+)U?(?:\))?($| +/\*)')),
+ ('#define X', re.compile(r'#define +(?P<id>[A-Z0-9_]+) +(?P<id2>[A-Z0-9_]+)($| +/\*)')),
+ ('#define X+hex', re.compile(r'#define +(?P<id>[A-Za-z0-9_]+) +\((?P<id2>[A-Z0-9_]+) \+ (?P<hex>0x[0-9A-F]+)U?\)($| +/\*)')),
+ ('#define typedef', re.compile(r'#define +(?P<id>[A-Z0-9_]+(ext)?) +\(\([A-Za-z0-9_]+_TypeDef \*\) (?P<id2>[A-Za-z0-9_]+)\)($| +/\*)')),
+ ('typedef struct', re.compile(r'typedef struct$')),
+ ('{', re.compile(r'{$')),
+ ('}', re.compile(r'}$')),
+ ('} TypeDef', re.compile(r'} *(?P<id>[A-Z][A-Za-z0-9_]+)_(?P<global>([A-Za-z0-9_]+)?)TypeDef;$')),
+ ('IO reg', re.compile(re_io_reg + r'; +/\*!< ' + re_comment + r', +' + re_addr_offset + r' *\*/')),
+ ('IO reg array', re.compile(re_io_reg + r'\[(?P<array>[2-8])\]; +/\*!< ' + re_comment + r', +' + re_addr_offset + r'-(0x[0-9A-Z]{2,3}) *\*/')),
+ )
+
+ def __init__(self, filename):
+ self.file = open(filename, 'rb')
+ self.line_number = 0
+
+ def next_match(self, strictly_next=False):
+ while True:
+ line = self.file.readline()
+ line = convert_bytes_to_str(line)
+ self.line_number += 1
+ if len(line) == 0:
+ return ('EOF', None)
+ match = re_match_first(Lexer.regexs, line.strip())
+ if strictly_next or match[0] is not None:
+ return match
+
+ def must_match(self, kind):
+ match = self.next_match(strictly_next=True)
+ if match[0] != kind:
+ raise LexerError(self.line_number)
+ return match
+
+def parse_file(filename):
+ lexer = Lexer(filename)
+
+ reg_defs = {}
+ consts = {}
+ periphs = []
+ while True:
+ m = lexer.next_match()
+ if m[0] == 'EOF':
+ break
+ elif m[0] == '#define hex':
+ d = m[1].groupdict()
+ consts[d['id']] = int(d['hex'], base=16)
+ elif m[0] == '#define X':
+ d = m[1].groupdict()
+ if d['id2'] in consts:
+ consts[d['id']] = consts[d['id2']]
+ elif m[0] == '#define X+hex':
+ d = m[1].groupdict()
+ if d['id2'] in consts:
+ consts[d['id']] = consts[d['id2']] + int(d['hex'], base=16)
+ elif m[0] == '#define typedef':
+ d = m[1].groupdict()
+ if d['id2'] in consts:
+ periphs.append((d['id'], consts[d['id2']]))
+ elif m[0] == 'typedef struct':
+ lexer.must_match('{')
+ m = lexer.next_match()
+ regs = []
+ while m[0] in ('IO reg', 'IO reg array'):
+ d = m[1].groupdict()
+ reg = d['reg']
+ offset = int(d['offset'], base=16)
+ bits = int(d['bits'])
+ comment = d['comment']
+ if m[0] == 'IO reg':
+ regs.append((reg, offset, bits, comment))
+ else:
+ for i in range(int(d['array'])):
+ regs.append((reg + str(i), offset + i * bits // 8, bits, comment))
+ m = lexer.next_match()
+ if m[0] == '}':
+ pass
+ elif m[0] == '} TypeDef':
+ reg_defs[m[1].groupdict()['id']] = regs
+ else:
+ raise LexerError(lexer.line_number)
+
+ return periphs, reg_defs
+
+def print_int_obj(val, needed_mpzs):
+ if -0x40000000 <= val < 0x40000000:
+ print('MP_ROM_INT(%#x)' % val, end='')
+ else:
+ print('MP_ROM_PTR(&mpz_%08x)' % val, end='')
+ needed_mpzs.add(val)
+
+def print_periph(periph_name, periph_val, needed_qstrs, needed_mpzs):
+ qstr = periph_name.upper()
+ print('{ MP_ROM_QSTR(MP_QSTR_%s), ' % qstr, end='')
+ print_int_obj(periph_val, needed_mpzs)
+ print(' },')
+ needed_qstrs.add(qstr)
+
+def print_regs(reg_name, reg_defs, needed_qstrs, needed_mpzs):
+ reg_name = reg_name.upper()
+ for r in reg_defs:
+ qstr = reg_name + '_' + r[0]
+ print('{ MP_ROM_QSTR(MP_QSTR_%s), ' % qstr, end='')
+ print_int_obj(r[1], needed_mpzs)
+ print(' }, // %s-bits, %s' % (r[2], r[3]))
+ needed_qstrs.add(qstr)
+
+# This version of print regs groups registers together into submodules (eg GPIO submodule).
+# This makes the qstrs shorter, and makes the list of constants more manageable (since
+# they are not all in one big module) but it is then harder to compile the constants, and
+# is more cumbersome to access.
+# As such, we don't use this version.
+# And for the number of constants we have, this function seems to use about the same amount
+# of ROM as print_regs.
+def print_regs_as_submodules(reg_name, reg_defs, modules, needed_qstrs):
+ mod_name_lower = reg_name.lower() + '_'
+ mod_name_upper = mod_name_lower.upper()
+ modules.append((mod_name_lower, mod_name_upper))
+
+ print("""
+STATIC const mp_rom_map_elem_t stm_%s_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_%s) },
+""" % (mod_name_lower, mod_name_upper))
+ needed_qstrs.add(mod_name_upper)
+
+ for r in reg_defs:
+ print(' { MP_ROM_QSTR(MP_QSTR_%s), MP_ROM_INT(%#x) }, // %s-bits, %s' % (r[0], r[1], r[2], r[3]))
+ needed_qstrs.add(r[0])
+
+ print("""};
+
+STATIC MP_DEFINE_CONST_DICT(stm_%s_globals, stm_%s_globals_table);
+
+const mp_obj_module_t stm_%s_obj = {
+ .base = { &mp_type_module },
+ .name = MP_QSTR_%s,
+ .globals = (mp_obj_dict_t*)&stm_%s_globals,
+};
+""" % (mod_name_lower, mod_name_lower, mod_name_lower, mod_name_upper, mod_name_lower))
+
+def main():
+ cmd_parser = argparse.ArgumentParser(description='Extract ST constants from a C header file.')
+ cmd_parser.add_argument('file', nargs=1, help='input file')
+ cmd_parser.add_argument('-q', '--qstr', dest='qstr_filename', default='build/stmconst_qstr.h',
+ help='Specified the name of the generated qstr header file')
+ cmd_parser.add_argument('--mpz', dest='mpz_filename', default='build/stmconst_mpz.h',
+ help='the destination file of the generated mpz header')
+ args = cmd_parser.parse_args()
+
+ periphs, reg_defs = parse_file(args.file[0])
+
+ # add legacy GPIO constants that were removed when upgrading CMSIS
+ if 'GPIO' in reg_defs and 'stm32f4' in args.file[0]:
+ reg_defs['GPIO'].append(['BSRRL', 0x18, 16, 'legacy register'])
+ reg_defs['GPIO'].append(['BSRRH', 0x1a, 16, 'legacy register'])
+
+ modules = []
+ needed_qstrs = set()
+ needed_mpzs = set()
+
+ print("// Automatically generated from %s by make-stmconst.py" % args.file[0])
+ print("")
+
+ for periph_name, periph_val in periphs:
+ print_periph(periph_name, periph_val, needed_qstrs, needed_mpzs)
+
+ for reg in (
+ 'ADC',
+ #'ADC_Common',
+ #'CAN_TxMailBox',
+ #'CAN_FIFOMailBox',
+ #'CAN_FilterRegister',
+ #'CAN',
+ 'CRC',
+ 'DAC',
+ 'DBGMCU',
+ 'DMA_Stream',
+ 'DMA',
+ 'EXTI',
+ 'FLASH',
+ 'GPIO',
+ 'SYSCFG',
+ 'I2C',
+ 'IWDG',
+ 'PWR',
+ 'RCC',
+ 'RTC',
+ #'SDIO',
+ 'SPI',
+ 'TIM',
+ 'USART',
+ 'WWDG',
+ 'RNG',
+ ):
+ if reg in reg_defs:
+ print_regs(reg, reg_defs[reg], needed_qstrs, needed_mpzs)
+ #print_regs_as_submodules(reg, reg_defs[reg], modules, needed_qstrs)
+
+ #print("#define MOD_STM_CONST_MODULES \\")
+ #for mod_lower, mod_upper in modules:
+ # print(" { MP_ROM_QSTR(MP_QSTR_%s), MP_ROM_PTR(&stm_%s_obj) }, \\" % (mod_upper, mod_lower))
+
+ print("")
+
+ with open(args.qstr_filename, 'wt') as qstr_file:
+ for qstr in sorted(needed_qstrs):
+ print('Q({})'.format(qstr), file=qstr_file)
+
+ with open(args.mpz_filename, 'wt') as mpz_file:
+ for mpz in sorted(needed_mpzs):
+ assert 0 <= mpz <= 0xffffffff
+ print('STATIC const mp_obj_int_t mpz_%08x = {{&mp_type_int}, '
+ '{.neg=0, .fixed_dig=1, .alloc=2, .len=2, ' '.dig=(uint16_t[]){%#x, %#x}}};'
+ % (mpz, mpz & 0xffff, (mpz >> 16) & 0xffff), file=mpz_file)
+
+if __name__ == "__main__":
+ main()
diff --git a/ports/stm32/modmachine.c b/ports/stm32/modmachine.c
new file mode 100644
index 000000000..8c59758fa
--- /dev/null
+++ b/ports/stm32/modmachine.c
@@ -0,0 +1,593 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2013-2015 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 "modmachine.h"
+#include "py/gc.h"
+#include "py/runtime.h"
+#include "py/mphal.h"
+#include "extmod/machine_mem.h"
+#include "extmod/machine_signal.h"
+#include "extmod/machine_pulse.h"
+#include "extmod/machine_i2c.h"
+#include "lib/utils/pyexec.h"
+#include "lib/oofatfs/ff.h"
+#include "extmod/vfs.h"
+#include "extmod/vfs_fat.h"
+#include "gccollect.h"
+#include "irq.h"
+#include "pybthread.h"
+#include "rng.h"
+#include "storage.h"
+#include "pin.h"
+#include "timer.h"
+#include "usb.h"
+#include "rtc.h"
+#include "i2c.h"
+#include "spi.h"
+#include "uart.h"
+#include "wdt.h"
+#include "genhdr/pllfreqtable.h"
+
+#if defined(MCU_SERIES_L4)
+// L4 does not have a POR, so use BOR instead
+#define RCC_CSR_PORRSTF RCC_CSR_BORRSTF
+#endif
+
+#define PYB_RESET_SOFT (0)
+#define PYB_RESET_POWER_ON (1)
+#define PYB_RESET_HARD (2)
+#define PYB_RESET_WDT (3)
+#define PYB_RESET_DEEPSLEEP (4)
+
+STATIC uint32_t reset_cause;
+
+void machine_init(void) {
+ #if defined(MCU_SERIES_F4)
+ 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)
+ if (PWR->CSR1 & PWR_CSR1_SBF) {
+ // came out of standby
+ reset_cause = PYB_RESET_DEEPSLEEP;
+ PWR->CR1 |= PWR_CR1_CSBF;
+ } else
+ #endif
+ {
+ // get reset cause from RCC flags
+ uint32_t state = RCC->CSR;
+ if (state & RCC_CSR_IWDGRSTF || state & RCC_CSR_WWDGRSTF) {
+ reset_cause = PYB_RESET_WDT;
+ } else if (state & RCC_CSR_PORRSTF || state & RCC_CSR_BORRSTF) {
+ reset_cause = PYB_RESET_POWER_ON;
+ } else if (state & RCC_CSR_PINRSTF) {
+ reset_cause = PYB_RESET_HARD;
+ } else {
+ // default is soft reset
+ reset_cause = PYB_RESET_SOFT;
+ }
+ }
+ // clear RCC reset flags
+ RCC->CSR |= RCC_CSR_RMVF;
+}
+
+// machine.info([dump_alloc_table])
+// Print out lots of information about the board.
+STATIC mp_obj_t machine_info(size_t n_args, const mp_obj_t *args) {
+ // get and print unique id; 96 bits
+ {
+ byte *id = (byte*)MP_HAL_UNIQUE_ID_ADDRESS;
+ printf("ID=%02x%02x%02x%02x:%02x%02x%02x%02x:%02x%02x%02x%02x\n", id[0], id[1], id[2], id[3], id[4], id[5], id[6], id[7], id[8], id[9], id[10], id[11]);
+ }
+
+ // 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());
+ }
+
+ // to print info about memory
+ {
+ printf("_etext=%p\n", &_etext);
+ printf("_sidata=%p\n", &_sidata);
+ printf("_sdata=%p\n", &_sdata);
+ printf("_edata=%p\n", &_edata);
+ printf("_sbss=%p\n", &_sbss);
+ printf("_ebss=%p\n", &_ebss);
+ printf("_estack=%p\n", &_estack);
+ printf("_ram_start=%p\n", &_ram_start);
+ printf("_heap_start=%p\n", &_heap_start);
+ printf("_heap_end=%p\n", &_heap_end);
+ printf("_ram_end=%p\n", &_ram_end);
+ }
+
+ // qstr info
+ {
+ mp_uint_t n_pool, n_qstr, n_str_data_bytes, n_total_bytes;
+ qstr_pool_info(&n_pool, &n_qstr, &n_str_data_bytes, &n_total_bytes);
+ printf("qstr:\n n_pool=" UINT_FMT "\n n_qstr=" UINT_FMT "\n n_str_data_bytes=" UINT_FMT "\n n_total_bytes=" UINT_FMT "\n", n_pool, n_qstr, n_str_data_bytes, n_total_bytes);
+ }
+
+ // GC info
+ {
+ gc_info_t info;
+ gc_info(&info);
+ printf("GC:\n");
+ printf(" " UINT_FMT " total\n", info.total);
+ printf(" " UINT_FMT " : " UINT_FMT "\n", info.used, info.free);
+ printf(" 1=" UINT_FMT " 2=" UINT_FMT " m=" UINT_FMT "\n", info.num_1block, info.num_2block, info.max_block);
+ }
+
+ // free space on flash
+ {
+ 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
+ fs_user_mount_t *vfs_fat = MP_OBJ_TO_PTR(vfs->obj);
+ DWORD nclst;
+ f_getfree(&vfs_fat->fatfs, &nclst);
+ printf("LFS free: %u bytes\n", (uint)(nclst * vfs_fat->fatfs.csize * 512));
+ break;
+ }
+ }
+ }
+
+ #if MICROPY_PY_THREAD
+ pyb_thread_dump();
+ #endif
+
+ if (n_args == 1) {
+ // arg given means dump gc allocation table
+ gc_dump_alloc_table();
+ }
+
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_info_obj, 0, 1, machine_info);
+
+// Returns a string of 12 bytes (96 bits), which is the unique ID for the MCU.
+STATIC mp_obj_t machine_unique_id(void) {
+ byte *id = (byte*)MP_HAL_UNIQUE_ID_ADDRESS;
+ return mp_obj_new_bytes(id, 12);
+}
+MP_DEFINE_CONST_FUN_OBJ_0(machine_unique_id_obj, machine_unique_id);
+
+// Resets the pyboard in a manner similar to pushing the external RESET button.
+STATIC mp_obj_t machine_reset(void) {
+ NVIC_SystemReset();
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_0(machine_reset_obj, machine_reset);
+
+STATIC mp_obj_t machine_soft_reset(void) {
+ pyexec_system_exit = PYEXEC_FORCED_EXIT;
+ nlr_raise(mp_obj_new_exception(&mp_type_SystemExit));
+}
+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) {
+ pyb_usb_dev_deinit();
+ storage_flush();
+
+ HAL_RCC_DeInit();
+ HAL_DeInit();
+
+ #if (__MPU_PRESENT == 1)
+ // MPU must be disabled for bootloader to function correctly
+ HAL_MPU_Disable();
+ #endif
+
+#if defined(MCU_SERIES_F7)
+ // 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));
+ __ASM volatile ("movw r3, #0x0000\nmovt r3, #0x1FF0\nldr r3, [r3, #0]\nMSR msp, r3\n" : : : "r3", "sp");
+
+ ((void (*)(void)) *((uint32_t*) 0x1FF00004))();
+#else
+ __HAL_REMAPMEMORY_SYSTEMFLASH();
+
+ // 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*) 0x00000000));
+ __ASM volatile ("movs r3, #0\nldr r3, [r3, #0]\nMSR msp, r3\n" : : : "r3", "sp");
+
+ ((void (*)(void)) *((uint32_t*) 0x00000004))();
+#endif
+
+ while (1);
+}
+MP_DEFINE_CONST_FUN_OBJ_0(machine_bootloader_obj, machine_bootloader);
+
+// 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; }
+ else if (wanted_div <= 2) { return RCC_SYSCLK_DIV2; }
+ else if (wanted_div <= 4) { return RCC_SYSCLK_DIV4; }
+ else if (wanted_div <= 8) { return RCC_SYSCLK_DIV8; }
+ else if (wanted_div <= 16) { return RCC_SYSCLK_DIV16; }
+ else if (wanted_div <= 64) { return RCC_SYSCLK_DIV64; }
+ else if (wanted_div <= 128) { return RCC_SYSCLK_DIV128; }
+ else if (wanted_div <= 256) { return RCC_SYSCLK_DIV256; }
+ else { return RCC_SYSCLK_DIV512; }
+}
+STATIC mp_uint_t machine_freq_calc_apb_div(mp_uint_t wanted_div) {
+ if (wanted_div <= 1) { return RCC_HCLK_DIV1; }
+ else if (wanted_div <= 2) { return RCC_HCLK_DIV2; }
+ else if (wanted_div <= 4) { return RCC_HCLK_DIV4; }
+ else if (wanted_div <= 8) { return RCC_HCLK_DIV8; }
+ else { return RCC_SYSCLK_DIV16; }
+}
+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_new_int(HAL_RCC_GetSysClockFreq()),
+ mp_obj_new_int(HAL_RCC_GetHCLKFreq()),
+ mp_obj_new_int(HAL_RCC_GetPCLK1Freq()),
+ mp_obj_new_int(HAL_RCC_GetPCLK2Freq()),
+ };
+ return mp_obj_new_tuple(4, tuple);
+ } else {
+ // set
+ mp_int_t wanted_sysclk = mp_obj_get_int(args[0]) / 1000000;
+
+ #if defined(MCU_SERIES_L4)
+ mp_raise_NotImplementedError("machine.freq set not supported yet");
+ #endif
+
+ // default PLL parameters that give 48MHz on PLL48CK
+ uint32_t m = HSE_VALUE / 1000000, n = 336, p = 2, q = 7;
+ uint32_t sysclk_source;
+
+ // search for a valid PLL configuration that keeps USB at 48MHz
+ for (const uint16_t *pll = &pll_freq_table[MP_ARRAY_SIZE(pll_freq_table) - 1]; pll >= &pll_freq_table[0]; --pll) {
+ uint32_t sys = *pll & 0xff;
+ if (sys <= wanted_sysclk) {
+ m = (*pll >> 10) & 0x3f;
+ p = ((*pll >> 7) & 0x6) + 2;
+ if (m == 0) {
+ // special entry for using HSI directly
+ sysclk_source = RCC_SYSCLKSOURCE_HSI;
+ goto set_clk;
+ } else if (m == 1) {
+ // special entry for using HSE directly
+ sysclk_source = RCC_SYSCLKSOURCE_HSE;
+ goto set_clk;
+ } else {
+ // use PLL
+ sysclk_source = RCC_SYSCLKSOURCE_PLLCLK;
+ uint32_t vco_out = sys * p;
+ n = vco_out * m / (HSE_VALUE / 1000000);
+ q = vco_out / 48;
+ goto set_clk;
+ }
+ }
+ }
+ mp_raise_ValueError("can't make valid freq");
+
+ set_clk:
+ //printf("%lu %lu %lu %lu %lu\n", sysclk_source, m, n, p, q);
+
+ // let the USB CDC have a chance to process before we change the clock
+ mp_hal_delay_ms(5);
+
+ // desired system clock source is in sysclk_source
+ RCC_ClkInitTypeDef RCC_ClkInitStruct;
+ RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2);
+ if (sysclk_source == RCC_SYSCLKSOURCE_PLLCLK) {
+ // set HSE as system clock source to allow modification of the PLL configuration
+ // we then change to PLL after re-configuring PLL
+ RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSE;
+ } else {
+ // directly set the system clock source as desired
+ RCC_ClkInitStruct.SYSCLKSource = sysclk_source;
+ }
+ wanted_sysclk *= 1000000;
+ if (n_args >= 2) {
+ // note: AHB freq required to be >= 14.2MHz for USB operation
+ RCC_ClkInitStruct.AHBCLKDivider = machine_freq_calc_ahb_div(wanted_sysclk / mp_obj_get_int(args[1]));
+ } else {
+ RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
+ }
+ if (n_args >= 3) {
+ RCC_ClkInitStruct.APB1CLKDivider = machine_freq_calc_apb_div(wanted_sysclk / mp_obj_get_int(args[2]));
+ } else {
+ RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
+ }
+ if (n_args >= 4) {
+ RCC_ClkInitStruct.APB2CLKDivider = machine_freq_calc_apb_div(wanted_sysclk / mp_obj_get_int(args[3]));
+ } else {
+ RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
+ }
+ #if defined(MICROPY_HW_CLK_LAST_FREQ) && MICROPY_HW_CLK_LAST_FREQ
+ uint32_t h = RCC_ClkInitStruct.AHBCLKDivider >> 4;
+ uint32_t b1 = RCC_ClkInitStruct.APB1CLKDivider >> 10;
+ uint32_t b2 = RCC_ClkInitStruct.APB2CLKDivider >> 10;
+ #endif
+ if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1) != HAL_OK) {
+ goto fail;
+ }
+
+ // re-configure PLL
+ // 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.PLL.PLLState = RCC_PLL_ON;
+ RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
+ RCC_OscInitStruct.PLL.PLLM = m;
+ RCC_OscInitStruct.PLL.PLLN = n;
+ RCC_OscInitStruct.PLL.PLLP = p;
+ RCC_OscInitStruct.PLL.PLLQ = q;
+ if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {
+ goto fail;
+ }
+
+ // set PLL as system clock source if wanted
+ if (sysclk_source == RCC_SYSCLKSOURCE_PLLCLK) {
+ #if defined(MCU_SERIES_F7)
+ // if possible, scale down the internal voltage regulator to save power
+ uint32_t volt_scale;
+ if (wanted_sysclk <= 151000000) {
+ volt_scale = PWR_REGULATOR_VOLTAGE_SCALE3;
+ } else if (wanted_sysclk <= 180000000) {
+ volt_scale = PWR_REGULATOR_VOLTAGE_SCALE2;
+ } else {
+ volt_scale = PWR_REGULATOR_VOLTAGE_SCALE1;
+ }
+ if (HAL_PWREx_ControlVoltageScaling(volt_scale) != HAL_OK) {
+ goto fail;
+ }
+ #endif
+
+ #if !defined(MICROPY_HW_FLASH_LATENCY)
+ #define MICROPY_HW_FLASH_LATENCY FLASH_LATENCY_5
+ #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) {
+ goto fail;
+ }
+ }
+
+ #if defined(MICROPY_HW_CLK_LAST_FREQ) && MICROPY_HW_CLK_LAST_FREQ
+ #if defined(MCU_SERIES_F7)
+ #define FREQ_BKP BKP31R
+ #else
+ #define FREQ_BKP BKP19R
+ #endif
+ // qqqqqqqq pppppppp nnnnnnnn nnmmmmmm
+ // qqqqQQQQ ppppppPP nNNNNNNN NNMMMMMM
+ // 222111HH HHQQQQPP nNNNNNNN NNMMMMMM
+ p = (p / 2) - 1;
+ RTC->FREQ_BKP = m
+ | (n << 6) | (p << 16) | (q << 18)
+ | (h << 22)
+ | (b1 << 26)
+ | (b2 << 29);
+ #endif
+
+ return mp_const_none;
+
+ fail:;
+ void NORETURN __fatal_error(const char *msg);
+ __fatal_error("can't change freq");
+ }
+}
+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)
+
+ // Enter Stop 1 mode
+ __HAL_RCC_WAKEUPSTOP_CLK_CONFIG(RCC_STOP_WAKEUPCLOCK_MSI);
+ HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI);
+
+ // reconfigure system clock after wakeup
+ // Enable Power Control clock
+ __HAL_RCC_PWR_CLK_ENABLE();
+
+ // Get the Oscillators configuration according to the internal RCC registers
+ RCC_OscInitTypeDef RCC_OscInitStruct = {0};
+ HAL_RCC_GetOscConfig(&RCC_OscInitStruct);
+ RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_MSI;
+ RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
+ HAL_RCC_OscConfig(&RCC_OscInitStruct);
+
+ // Get the Clocks configuration according to the internal RCC registers
+ RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
+ uint32_t pFLatency = 0;
+ HAL_RCC_GetClockConfig(&RCC_ClkInitStruct, &pFLatency);
+
+ // Select PLL as system clock source and configure the HCLK, PCLK1 and PCLK2 clock dividers
+ RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK;
+ RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
+ HAL_RCC_ClockConfig(&RCC_ClkInitStruct, pFLatency);
+
+ #else
+
+ // takes longer to wake but reduces stop current
+ HAL_PWREx_EnableFlashPowerDown();
+
+ # if defined(MCU_SERIES_F7)
+ 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);
+ #endif
+
+ // reconfigure the system clock after waking up
+
+ // enable HSE
+ __HAL_RCC_HSE_CONFIG(RCC_HSE_ON);
+ while (!__HAL_RCC_GET_FLAG(RCC_FLAG_HSERDY)) {
+ }
+
+ // enable PLL
+ __HAL_RCC_PLL_ENABLE();
+ while (!__HAL_RCC_GET_FLAG(RCC_FLAG_PLLRDY)) {
+ }
+
+ // select PLL as system clock source
+ MODIFY_REG(RCC->CFGR, RCC_CFGR_SW, RCC_SYSCLKSOURCE_PLLCLK);
+ while (__HAL_RCC_GET_SYSCLK_SOURCE() != RCC_CFGR_SWS_PLL) {
+ }
+
+ #endif
+
+ return mp_const_none;
+}
+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)
+ printf("machine.deepsleep not supported yet\n");
+#else
+ // We need to clear the PWR wake-up-flag before entering standby, since
+ // the flag may have been set by a previous wake-up event. Furthermore,
+ // we need to disable the wake-up sources while clearing this flag, so
+ // that if a source is active it does actually wake the device.
+ // See section 5.3.7 of RM0090.
+
+ // 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;
+
+ // save RTC interrupts
+ uint32_t save_irq_bits = RTC->CR & irq_bits;
+
+ // disable RTC interrupts
+ RTC->CR &= ~irq_bits;
+
+ // clear RTC wake-up flags
+ RTC->ISR &= ~(RTC_ISR_ALRAF | RTC_ISR_ALRBF | RTC_ISR_WUTF | RTC_ISR_TSF);
+
+ #if defined(MCU_SERIES_F7)
+ // 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;
+ #else
+ // clear global wake-up flag
+ PWR->CR |= PWR_CR_CWUF;
+ #endif
+
+ // enable previously-enabled RTC interrupts
+ RTC->CR |= save_irq_bits;
+
+ // enter standby mode
+ HAL_PWR_EnterSTANDBYMode();
+ // we never return; MCU is reset on exit from standby
+#endif
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_0(machine_deepsleep_obj, machine_deepsleep);
+
+STATIC mp_obj_t machine_reset_cause(void) {
+ return MP_OBJ_NEW_SMALL_INT(reset_cause);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_reset_cause_obj, machine_reset_cause);
+
+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_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_reset), MP_ROM_PTR(&machine_reset_obj) },
+ { MP_ROM_QSTR(MP_QSTR_soft_reset), MP_ROM_PTR(&machine_soft_reset_obj) },
+ { MP_ROM_QSTR(MP_QSTR_bootloader), MP_ROM_PTR(&machine_bootloader_obj) },
+ { MP_ROM_QSTR(MP_QSTR_freq), MP_ROM_PTR(&machine_freq_obj) },
+#if MICROPY_HW_ENABLE_RNG
+ { MP_ROM_QSTR(MP_QSTR_rng), MP_ROM_PTR(&pyb_rng_get_obj) },
+#endif
+ { MP_ROM_QSTR(MP_QSTR_idle), MP_ROM_PTR(&pyb_wfi_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_reset_cause), MP_ROM_PTR(&machine_reset_cause_obj) },
+#if 0
+ { MP_ROM_QSTR(MP_QSTR_wake_reason), MP_ROM_PTR(&machine_wake_reason_obj) },
+#endif
+
+ { MP_ROM_QSTR(MP_QSTR_disable_irq), MP_ROM_PTR(&pyb_disable_irq_obj) },
+ { MP_ROM_QSTR(MP_QSTR_enable_irq), MP_ROM_PTR(&pyb_enable_irq_obj) },
+
+ { MP_ROM_QSTR(MP_QSTR_time_pulse_us), MP_ROM_PTR(&machine_time_pulse_us_obj) },
+
+ { 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_Pin), MP_ROM_PTR(&pin_type) },
+ { MP_ROM_QSTR(MP_QSTR_Signal), MP_ROM_PTR(&machine_signal_type) },
+
+#if 0
+ { 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
+ { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&machine_i2c_type) },
+ { 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) },
+#if 0
+ { MP_ROM_QSTR(MP_QSTR_Timer), MP_ROM_PTR(&pyb_timer_type) },
+ { MP_ROM_QSTR(MP_QSTR_HeartBeat), MP_ROM_PTR(&pyb_heartbeat_type) },
+ { MP_ROM_QSTR(MP_QSTR_SD), MP_ROM_PTR(&pyb_sd_type) },
+
+ // class constants
+ { MP_ROM_QSTR(MP_QSTR_IDLE), MP_ROM_INT(PYB_PWR_MODE_ACTIVE) },
+ { MP_ROM_QSTR(MP_QSTR_SLEEP), MP_ROM_INT(PYB_PWR_MODE_LPDS) },
+ { MP_ROM_QSTR(MP_QSTR_DEEPSLEEP), MP_ROM_INT(PYB_PWR_MODE_HIBERNATE) },
+#endif
+ { MP_ROM_QSTR(MP_QSTR_PWRON_RESET), MP_ROM_INT(PYB_RESET_POWER_ON) },
+ { MP_ROM_QSTR(MP_QSTR_HARD_RESET), MP_ROM_INT(PYB_RESET_HARD) },
+ { MP_ROM_QSTR(MP_QSTR_WDT_RESET), MP_ROM_INT(PYB_RESET_WDT) },
+ { MP_ROM_QSTR(MP_QSTR_DEEPSLEEP_RESET), MP_ROM_INT(PYB_RESET_DEEPSLEEP) },
+ { MP_ROM_QSTR(MP_QSTR_SOFT_RESET), MP_ROM_INT(PYB_RESET_SOFT) },
+#if 0
+ { MP_ROM_QSTR(MP_QSTR_WLAN_WAKE), MP_ROM_INT(PYB_SLP_WAKED_BY_WLAN) },
+ { MP_ROM_QSTR(MP_QSTR_PIN_WAKE), MP_ROM_INT(PYB_SLP_WAKED_BY_GPIO) },
+ { MP_ROM_QSTR(MP_QSTR_RTC_WAKE), MP_ROM_INT(PYB_SLP_WAKED_BY_RTC) },
+#endif
+};
+
+STATIC MP_DEFINE_CONST_DICT(machine_module_globals, machine_module_globals_table);
+
+const mp_obj_module_t machine_module = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t*)&machine_module_globals,
+};
+
diff --git a/ports/stm32/modmachine.h b/ports/stm32/modmachine.h
new file mode 100644
index 000000000..ac39f854e
--- /dev/null
+++ b/ports/stm32/modmachine.h
@@ -0,0 +1,43 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2013-2015 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_STMHAL_MODMACHINE_H
+#define MICROPY_INCLUDED_STMHAL_MODMACHINE_H
+
+#include "py/mpstate.h"
+#include "py/nlr.h"
+#include "py/obj.h"
+
+void machine_init(void);
+
+MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(machine_info_obj);
+MP_DECLARE_CONST_FUN_OBJ_0(machine_unique_id_obj);
+MP_DECLARE_CONST_FUN_OBJ_0(machine_reset_obj);
+MP_DECLARE_CONST_FUN_OBJ_0(machine_bootloader_obj);
+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
diff --git a/ports/stm32/modnetwork.c b/ports/stm32/modnetwork.c
new file mode 100644
index 000000000..6b4949a0d
--- /dev/null
+++ b/ports/stm32/modnetwork.c
@@ -0,0 +1,94 @@
+/*
+ * 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.
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+
+#include "py/nlr.h"
+#include "py/objlist.h"
+#include "py/runtime.h"
+#include "modnetwork.h"
+
+#if MICROPY_PY_NETWORK
+
+/// \module network - network configuration
+///
+/// This module provides network drivers and routing configuration.
+
+void mod_network_init(void) {
+ mp_obj_list_init(&MP_STATE_PORT(mod_network_nic_list), 0);
+}
+
+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) {
+ // nic already registered
+ return;
+ }
+ }
+ // nic not registered so add to list
+ mp_obj_list_append(&MP_STATE_PORT(mod_network_nic_list), nic);
+}
+
+mp_obj_t mod_network_find_nic(const uint8_t *ip) {
+ // find a NIC that is suited to given IP address
+ for (mp_uint_t i = 0; i < MP_STATE_PORT(mod_network_nic_list).len; i++) {
+ mp_obj_t nic = MP_STATE_PORT(mod_network_nic_list).items[i];
+ // TODO check IP suitability here
+ //mod_network_nic_type_t *nic_type = (mod_network_nic_type_t*)mp_obj_get_type(nic);
+ return nic;
+ }
+
+ nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "no available NIC"));
+}
+
+STATIC mp_obj_t network_route(void) {
+ return &MP_STATE_PORT(mod_network_nic_list);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_0(network_route_obj, network_route);
+
+STATIC const mp_rom_map_elem_t mp_module_network_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_network) },
+
+ #if MICROPY_PY_WIZNET5K
+ { MP_ROM_QSTR(MP_QSTR_WIZNET5K), MP_ROM_PTR(&mod_network_nic_type_wiznet5k) },
+ #endif
+ #if MICROPY_PY_CC3K
+ { MP_ROM_QSTR(MP_QSTR_CC3K), MP_ROM_PTR(&mod_network_nic_type_cc3k) },
+ #endif
+
+ { MP_ROM_QSTR(MP_QSTR_route), MP_ROM_PTR(&network_route_obj) },
+};
+
+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,
+};
+
+#endif // MICROPY_PY_NETWORK
diff --git a/ports/stm32/modnetwork.h b/ports/stm32/modnetwork.h
new file mode 100644
index 000000000..ecda94da4
--- /dev/null
+++ b/ports/stm32/modnetwork.h
@@ -0,0 +1,83 @@
+/*
+ * 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.
+ */
+#ifndef MICROPY_INCLUDED_STMHAL_MODNETWORK_H
+#define MICROPY_INCLUDED_STMHAL_MODNETWORK_H
+
+#define MOD_NETWORK_IPADDR_BUF_SIZE (4)
+
+#define MOD_NETWORK_AF_INET (2)
+#define MOD_NETWORK_AF_INET6 (10)
+
+#define MOD_NETWORK_SOCK_STREAM (1)
+#define MOD_NETWORK_SOCK_DGRAM (2)
+#define MOD_NETWORK_SOCK_RAW (3)
+
+struct _mod_network_socket_obj_t;
+
+typedef struct _mod_network_nic_type_t {
+ mp_obj_type_t base;
+
+ // API for non-socket operations
+ int (*gethostbyname)(mp_obj_t nic, const char *name, mp_uint_t len, uint8_t *ip_out);
+
+ // API for socket operations; return -1 on error
+ int (*socket)(struct _mod_network_socket_obj_t *socket, int *_errno);
+ void (*close)(struct _mod_network_socket_obj_t *socket);
+ int (*bind)(struct _mod_network_socket_obj_t *socket, byte *ip, mp_uint_t port, int *_errno);
+ int (*listen)(struct _mod_network_socket_obj_t *socket, mp_int_t backlog, int *_errno);
+ int (*accept)(struct _mod_network_socket_obj_t *socket, struct _mod_network_socket_obj_t *socket2, byte *ip, mp_uint_t *port, int *_errno);
+ int (*connect)(struct _mod_network_socket_obj_t *socket, byte *ip, mp_uint_t port, int *_errno);
+ mp_uint_t (*send)(struct _mod_network_socket_obj_t *socket, const byte *buf, mp_uint_t len, int *_errno);
+ mp_uint_t (*recv)(struct _mod_network_socket_obj_t *socket, byte *buf, mp_uint_t len, int *_errno);
+ mp_uint_t (*sendto)(struct _mod_network_socket_obj_t *socket, const byte *buf, mp_uint_t len, byte *ip, mp_uint_t port, int *_errno);
+ mp_uint_t (*recvfrom)(struct _mod_network_socket_obj_t *socket, byte *buf, mp_uint_t len, byte *ip, mp_uint_t *port, int *_errno);
+ int (*setsockopt)(struct _mod_network_socket_obj_t *socket, mp_uint_t level, mp_uint_t opt, const void *optval, mp_uint_t optlen, int *_errno);
+ int (*settimeout)(struct _mod_network_socket_obj_t *socket, mp_uint_t timeout_ms, int *_errno);
+ int (*ioctl)(struct _mod_network_socket_obj_t *socket, mp_uint_t request, mp_uint_t arg, int *_errno);
+} mod_network_nic_type_t;
+
+typedef struct _mod_network_socket_obj_t {
+ mp_obj_base_t base;
+ mp_obj_t nic;
+ mod_network_nic_type_t *nic_type;
+ union {
+ struct {
+ uint8_t domain;
+ uint8_t type;
+ int8_t fileno;
+ } u_param;
+ mp_uint_t u_state;
+ };
+} 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;
+
+void mod_network_init(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
diff --git a/ports/stm32/modnwcc3k.c b/ports/stm32/modnwcc3k.c
new file mode 100644
index 000000000..2be5d6c22
--- /dev/null
+++ b/ports/stm32/modnwcc3k.c
@@ -0,0 +1,602 @@
+/*
+ * 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.
+ */
+
+#include <string.h>
+#include <stdarg.h>
+
+// CC3000 defines its own ENOBUFS (different to standard one!)
+#undef ENOBUFS
+
+#include "py/nlr.h"
+#include "py/objtuple.h"
+#include "py/objlist.h"
+#include "py/stream.h"
+#include "py/runtime.h"
+#include "py/mperrno.h"
+#include "py/mphal.h"
+#include "lib/netutils/netutils.h"
+#include "modnetwork.h"
+#include "pin.h"
+#include "genhdr/pins.h"
+#include "spi.h"
+
+#include "hci.h"
+#include "socket.h"
+#include "inet_ntop.h"
+#include "inet_pton.h"
+#include "ccspi.h"
+#include "wlan.h"
+#include "nvmem.h"
+#include "netapp.h"
+#include "patch_prog.h"
+
+#define MAX_ADDRSTRLEN (128)
+#define MAX_RX_PACKET (CC3000_RX_BUFFER_SIZE-CC3000_MINIMAL_RX_SIZE-1)
+#define MAX_TX_PACKET (CC3000_TX_BUFFER_SIZE-CC3000_MINIMAL_TX_SIZE-1)
+
+#define MAKE_SOCKADDR(addr, ip, port) \
+ sockaddr addr; \
+ addr.sa_family = AF_INET; \
+ addr.sa_data[0] = port >> 8; \
+ addr.sa_data[1] = port; \
+ addr.sa_data[2] = ip[0]; \
+ addr.sa_data[3] = ip[1]; \
+ addr.sa_data[4] = ip[2]; \
+ addr.sa_data[5] = ip[3];
+
+#define UNPACK_SOCKADDR(addr, ip, port) \
+ port = (addr.sa_data[0] << 8) | addr.sa_data[1]; \
+ ip[0] = addr.sa_data[2]; \
+ ip[1] = addr.sa_data[3]; \
+ ip[2] = addr.sa_data[4]; \
+ ip[3] = addr.sa_data[5];
+
+STATIC int cc3k_socket_ioctl(mod_network_socket_obj_t *socket, mp_uint_t request, mp_uint_t arg, int *_errno);
+
+int CC3000_EXPORT(errno); // for cc3000 driver
+
+STATIC volatile uint32_t fd_closed_state = 0;
+STATIC volatile bool wlan_connected = false;
+STATIC volatile bool ip_obtained = false;
+
+STATIC int cc3k_get_fd_closed_state(int fd) {
+ return fd_closed_state & (1 << fd);
+}
+
+STATIC void cc3k_set_fd_closed_state(int fd) {
+ fd_closed_state |= 1 << fd;
+}
+
+STATIC void cc3k_reset_fd_closed_state(int fd) {
+ fd_closed_state &= ~(1 << fd);
+}
+
+STATIC void cc3k_callback(long event_type, char *data, unsigned char length) {
+ switch (event_type) {
+ case HCI_EVNT_WLAN_UNSOL_CONNECT:
+ wlan_connected = true;
+ break;
+ case HCI_EVNT_WLAN_UNSOL_DISCONNECT:
+ // link down
+ wlan_connected = false;
+ ip_obtained = false;
+ break;
+ case HCI_EVNT_WLAN_UNSOL_DHCP:
+ ip_obtained = true;
+ break;
+ case HCI_EVNT_BSD_TCP_CLOSE_WAIT:
+ // mark socket for closure
+ cc3k_set_fd_closed_state(data[0]);
+ break;
+ }
+}
+
+STATIC int cc3k_gethostbyname(mp_obj_t nic, const char *name, mp_uint_t len, uint8_t *out_ip) {
+ uint32_t ip;
+ // CC3000 gethostbyname is unreliable and usually returns -95 on first call
+ for (int retry = 5; CC3000_EXPORT(gethostbyname)((char*)name, len, &ip) < 0; retry--) {
+ if (retry == 0 || CC3000_EXPORT(errno) != -95) {
+ return CC3000_EXPORT(errno);
+ }
+ mp_hal_delay_ms(50);
+ }
+
+ if (ip == 0) {
+ // unknown host
+ return MP_ENOENT;
+ }
+
+ out_ip[0] = ip >> 24;
+ out_ip[1] = ip >> 16;
+ out_ip[2] = ip >> 8;
+ out_ip[3] = ip;
+
+ return 0;
+}
+
+STATIC int cc3k_socket_socket(mod_network_socket_obj_t *socket, int *_errno) {
+ if (socket->u_param.domain != MOD_NETWORK_AF_INET) {
+ *_errno = MP_EAFNOSUPPORT;
+ return -1;
+ }
+
+ mp_uint_t type;
+ switch (socket->u_param.type) {
+ case MOD_NETWORK_SOCK_STREAM: type = SOCK_STREAM; break;
+ case MOD_NETWORK_SOCK_DGRAM: type = SOCK_DGRAM; break;
+ case MOD_NETWORK_SOCK_RAW: type = SOCK_RAW; break;
+ default: *_errno = MP_EINVAL; return -1;
+ }
+
+ // open socket
+ int fd = CC3000_EXPORT(socket)(AF_INET, type, 0);
+ if (fd < 0) {
+ *_errno = CC3000_EXPORT(errno);
+ return -1;
+ }
+
+ // clear socket state
+ cc3k_reset_fd_closed_state(fd);
+
+ // store state of this socket
+ socket->u_state = fd;
+
+ // make accept blocking by default
+ int optval = SOCK_OFF;
+ socklen_t optlen = sizeof(optval);
+ CC3000_EXPORT(setsockopt)(socket->u_state, SOL_SOCKET, SOCKOPT_ACCEPT_NONBLOCK, &optval, optlen);
+
+ return 0;
+}
+
+STATIC void cc3k_socket_close(mod_network_socket_obj_t *socket) {
+ CC3000_EXPORT(closesocket)(socket->u_state);
+}
+
+STATIC int cc3k_socket_bind(mod_network_socket_obj_t *socket, byte *ip, mp_uint_t port, int *_errno) {
+ MAKE_SOCKADDR(addr, ip, port)
+ int ret = CC3000_EXPORT(bind)(socket->u_state, &addr, sizeof(addr));
+ if (ret != 0) {
+ *_errno = ret;
+ return -1;
+ }
+ return 0;
+}
+
+STATIC int cc3k_socket_listen(mod_network_socket_obj_t *socket, mp_int_t backlog, int *_errno) {
+ int ret = CC3000_EXPORT(listen)(socket->u_state, backlog);
+ if (ret != 0) {
+ *_errno = ret;
+ return -1;
+ }
+ return 0;
+}
+
+STATIC int cc3k_socket_accept(mod_network_socket_obj_t *socket, mod_network_socket_obj_t *socket2, byte *ip, mp_uint_t *port, int *_errno) {
+ // accept incoming connection
+ int fd;
+ sockaddr addr;
+ socklen_t addr_len = sizeof(addr);
+ if ((fd = CC3000_EXPORT(accept)(socket->u_state, &addr, &addr_len)) < 0) {
+ if (fd == SOC_IN_PROGRESS) {
+ *_errno = MP_EAGAIN;
+ } else {
+ *_errno = -fd;
+ }
+ return -1;
+ }
+
+ // clear socket state
+ cc3k_reset_fd_closed_state(fd);
+
+ // store state in new socket object
+ socket2->u_state = fd;
+
+ // return ip and port
+ // it seems CC3000 returns little endian for accept??
+ //UNPACK_SOCKADDR(addr, ip, *port);
+ *port = (addr.sa_data[1] << 8) | addr.sa_data[0];
+ ip[3] = addr.sa_data[2];
+ ip[2] = addr.sa_data[3];
+ ip[1] = addr.sa_data[4];
+ ip[0] = addr.sa_data[5];
+
+ return 0;
+}
+
+STATIC int cc3k_socket_connect(mod_network_socket_obj_t *socket, byte *ip, mp_uint_t port, int *_errno) {
+ MAKE_SOCKADDR(addr, ip, port)
+ int ret = CC3000_EXPORT(connect)(socket->u_state, &addr, sizeof(addr));
+ if (ret != 0) {
+ *_errno = CC3000_EXPORT(errno);
+ return -1;
+ }
+ return 0;
+}
+
+STATIC mp_uint_t cc3k_socket_send(mod_network_socket_obj_t *socket, const byte *buf, mp_uint_t len, int *_errno) {
+ if (cc3k_get_fd_closed_state(socket->u_state)) {
+ CC3000_EXPORT(closesocket)(socket->u_state);
+ *_errno = MP_EPIPE;
+ return -1;
+ }
+
+ // CC3K does not handle fragmentation, and will overflow,
+ // split the packet into smaller ones and send them out.
+ mp_int_t bytes = 0;
+ while (bytes < len) {
+ int n = MIN((len - bytes), MAX_TX_PACKET);
+ n = CC3000_EXPORT(send)(socket->u_state, (uint8_t*)buf + bytes, n, 0);
+ if (n <= 0) {
+ *_errno = CC3000_EXPORT(errno);
+ return -1;
+ }
+ bytes += n;
+ }
+
+ return bytes;
+}
+
+STATIC mp_uint_t cc3k_socket_recv(mod_network_socket_obj_t *socket, byte *buf, mp_uint_t len, int *_errno) {
+ // check the socket is open
+ if (cc3k_get_fd_closed_state(socket->u_state)) {
+ // socket is closed, but CC3000 may have some data remaining in buffer, so check
+ fd_set rfds;
+ FD_ZERO(&rfds);
+ FD_SET(socket->u_state, &rfds);
+ cc3000_timeval tv;
+ tv.tv_sec = 0;
+ tv.tv_usec = 1;
+ int nfds = CC3000_EXPORT(select)(socket->u_state + 1, &rfds, NULL, NULL, &tv);
+ if (nfds == -1 || !FD_ISSET(socket->u_state, &rfds)) {
+ // no data waiting, so close socket and return 0 data
+ CC3000_EXPORT(closesocket)(socket->u_state);
+ return 0;
+ }
+ }
+
+ // cap length at MAX_RX_PACKET
+ len = MIN(len, MAX_RX_PACKET);
+
+ // do the recv
+ int ret = CC3000_EXPORT(recv)(socket->u_state, buf, len, 0);
+ if (ret < 0) {
+ *_errno = CC3000_EXPORT(errno);
+ return -1;
+ }
+
+ return ret;
+}
+
+STATIC mp_uint_t cc3k_socket_sendto(mod_network_socket_obj_t *socket, const byte *buf, mp_uint_t len, byte *ip, mp_uint_t port, int *_errno) {
+ MAKE_SOCKADDR(addr, ip, port)
+ int ret = CC3000_EXPORT(sendto)(socket->u_state, (byte*)buf, len, 0, (sockaddr*)&addr, sizeof(addr));
+ if (ret < 0) {
+ *_errno = CC3000_EXPORT(errno);
+ return -1;
+ }
+ return ret;
+}
+
+STATIC mp_uint_t cc3k_socket_recvfrom(mod_network_socket_obj_t *socket, byte *buf, mp_uint_t len, byte *ip, mp_uint_t *port, int *_errno) {
+ sockaddr addr;
+ socklen_t addr_len = sizeof(addr);
+ mp_int_t ret = CC3000_EXPORT(recvfrom)(socket->u_state, buf, len, 0, &addr, &addr_len);
+ if (ret < 0) {
+ *_errno = CC3000_EXPORT(errno);
+ return -1;
+ }
+ UNPACK_SOCKADDR(addr, ip, *port);
+ return ret;
+}
+
+STATIC int cc3k_socket_setsockopt(mod_network_socket_obj_t *socket, mp_uint_t level, mp_uint_t opt, const void *optval, mp_uint_t optlen, int *_errno) {
+ int ret = CC3000_EXPORT(setsockopt)(socket->u_state, level, opt, optval, optlen);
+ if (ret < 0) {
+ *_errno = CC3000_EXPORT(errno);
+ return -1;
+ }
+ return 0;
+}
+
+STATIC int cc3k_socket_settimeout(mod_network_socket_obj_t *socket, mp_uint_t timeout_ms, int *_errno) {
+ int ret;
+ if (timeout_ms == 0 || timeout_ms == -1) {
+ int optval;
+ socklen_t optlen = sizeof(optval);
+ if (timeout_ms == 0) {
+ // set non-blocking mode
+ optval = SOCK_ON;
+ } else {
+ // set blocking mode
+ optval = SOCK_OFF;
+ }
+ ret = CC3000_EXPORT(setsockopt)(socket->u_state, SOL_SOCKET, SOCKOPT_RECV_NONBLOCK, &optval, optlen);
+ if (ret == 0) {
+ ret = CC3000_EXPORT(setsockopt)(socket->u_state, SOL_SOCKET, SOCKOPT_ACCEPT_NONBLOCK, &optval, optlen);
+ }
+ } else {
+ // set timeout
+ socklen_t optlen = sizeof(timeout_ms);
+ ret = CC3000_EXPORT(setsockopt)(socket->u_state, SOL_SOCKET, SOCKOPT_RECV_TIMEOUT, &timeout_ms, optlen);
+ }
+
+ if (ret != 0) {
+ *_errno = CC3000_EXPORT(errno);
+ return -1;
+ }
+
+ return 0;
+}
+
+STATIC int cc3k_socket_ioctl(mod_network_socket_obj_t *socket, mp_uint_t request, mp_uint_t arg, int *_errno) {
+ mp_uint_t ret;
+ if (request == MP_STREAM_POLL) {
+ mp_uint_t flags = arg;
+ ret = 0;
+ int fd = socket->u_state;
+
+ // init fds
+ fd_set rfds, wfds, xfds;
+ FD_ZERO(&rfds);
+ FD_ZERO(&wfds);
+ FD_ZERO(&xfds);
+
+ // set fds if needed
+ if (flags & MP_STREAM_POLL_RD) {
+ FD_SET(fd, &rfds);
+
+ // A socked that just closed is available for reading. A call to
+ // recv() returns 0 which is consistent with BSD.
+ if (cc3k_get_fd_closed_state(fd)) {
+ ret |= MP_STREAM_POLL_RD;
+ }
+ }
+ if (flags & MP_STREAM_POLL_WR) {
+ FD_SET(fd, &wfds);
+ }
+ if (flags & MP_STREAM_POLL_HUP) {
+ FD_SET(fd, &xfds);
+ }
+
+ // call cc3000 select with minimum timeout
+ cc3000_timeval tv;
+ tv.tv_sec = 0;
+ tv.tv_usec = 1;
+ int nfds = CC3000_EXPORT(select)(fd + 1, &rfds, &wfds, &xfds, &tv);
+
+ // check for error
+ if (nfds == -1) {
+ *_errno = CC3000_EXPORT(errno);
+ return -1;
+ }
+
+ // check return of select
+ if (FD_ISSET(fd, &rfds)) {
+ ret |= MP_STREAM_POLL_RD;
+ }
+ if (FD_ISSET(fd, &wfds)) {
+ ret |= MP_STREAM_POLL_WR;
+ }
+ if (FD_ISSET(fd, &xfds)) {
+ ret |= MP_STREAM_POLL_HUP;
+ }
+ } else {
+ *_errno = MP_EINVAL;
+ ret = -1;
+ }
+ return ret;
+}
+
+/******************************************************************************/
+// MicroPython bindings; CC3K class
+
+typedef struct _cc3k_obj_t {
+ mp_obj_base_t base;
+} cc3k_obj_t;
+
+STATIC const cc3k_obj_t cc3k_obj = {{(mp_obj_type_t*)&mod_network_nic_type_cc3k}};
+
+// \classmethod \constructor(spi, pin_cs, pin_en, pin_irq)
+// Initialise the CC3000 using the given SPI bus and pins and return a CC3K object.
+//
+// Note: pins were originally hard-coded to:
+// PYBv1.0: init(pyb.SPI(2), pyb.Pin.board.Y5, pyb.Pin.board.Y4, pyb.Pin.board.Y3)
+// [SPI on Y position; Y6=B13=SCK, Y7=B14=MISO, Y8=B15=MOSI]
+//
+// STM32F4DISC: init(pyb.SPI(2), pyb.Pin.cpu.A15, pyb.Pin.cpu.B10, pyb.Pin.cpu.B11)
+STATIC mp_obj_t cc3k_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, 4, 4, false);
+
+ // set the pins to use
+ SpiInit(
+ spi_get_handle(args[0]),
+ pin_find(args[1]),
+ pin_find(args[2]),
+ pin_find(args[3])
+ );
+
+ // initialize and start the module
+ wlan_init(cc3k_callback, NULL, NULL, NULL,
+ ReadWlanInterruptPin, SpiResumeSpi, SpiPauseSpi, WriteWlanPin);
+
+ if (wlan_start(0) != 0) {
+ nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "failed to init CC3000 module"));
+ }
+
+ // set connection policy. this should be called explicitly by the user
+ // wlan_ioctl_set_connection_policy(0, 0, 0);
+
+ // Mask out all non-required events from the CC3000
+ wlan_set_event_mask(HCI_EVNT_WLAN_KEEPALIVE|
+ HCI_EVNT_WLAN_UNSOL_INIT|
+ HCI_EVNT_WLAN_ASYNC_PING_REPORT|
+ HCI_EVNT_WLAN_ASYNC_SIMPLE_CONFIG_DONE);
+
+ // register with network module
+ mod_network_register_nic((mp_obj_t)&cc3k_obj);
+
+ return (mp_obj_t)&cc3k_obj;
+}
+
+// method connect(ssid, key=None, *, security=WPA2, bssid=None)
+STATIC mp_obj_t cc3k_connect(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_ssid, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+ { MP_QSTR_key, MP_ARG_OBJ, {.u_obj = mp_const_none} },
+ { MP_QSTR_security, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = WLAN_SEC_WPA2} },
+ { MP_QSTR_bssid, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
+ };
+
+ // parse args
+ 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 ssid
+ size_t ssid_len;
+ const char *ssid = mp_obj_str_get_data(args[0].u_obj, &ssid_len);
+
+ // get key and sec
+ size_t key_len = 0;
+ const char *key = NULL;
+ mp_uint_t sec = WLAN_SEC_UNSEC;
+ if (args[1].u_obj != mp_const_none) {
+ key = mp_obj_str_get_data(args[1].u_obj, &key_len);
+ sec = args[2].u_int;
+ }
+
+ // get bssid
+ const char *bssid = NULL;
+ if (args[3].u_obj != mp_const_none) {
+ bssid = mp_obj_str_get_str(args[3].u_obj);
+ }
+
+ // connect to AP
+ if (wlan_connect(sec, (char*)ssid, ssid_len, (uint8_t*)bssid, (uint8_t*)key, key_len) != 0) {
+ nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, "could not connect to ssid=%s, sec=%d, key=%s\n", ssid, sec, key));
+ }
+
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(cc3k_connect_obj, 1, cc3k_connect);
+
+STATIC mp_obj_t cc3k_disconnect(mp_obj_t self_in) {
+ // should we check return value?
+ wlan_disconnect();
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(cc3k_disconnect_obj, cc3k_disconnect);
+
+STATIC mp_obj_t cc3k_isconnected(mp_obj_t self_in) {
+ return mp_obj_new_bool(wlan_connected && ip_obtained);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(cc3k_isconnected_obj, cc3k_isconnected);
+
+STATIC mp_obj_t cc3k_ifconfig(mp_obj_t self_in) {
+ tNetappIpconfigRetArgs ipconfig;
+ netapp_ipconfig(&ipconfig);
+
+ // render MAC address
+ VSTR_FIXED(mac_vstr, 18);
+ const uint8_t *mac = ipconfig.uaMacAddr;
+ vstr_printf(&mac_vstr, "%02x:%02x:%02x:%02x:%02x:%02x", mac[5], mac[4], mac[3], mac[2], mac[1], mac[0]);
+
+ // create and return tuple with ifconfig info
+ mp_obj_t tuple[7] = {
+ netutils_format_ipv4_addr(ipconfig.aucIP, NETUTILS_LITTLE),
+ netutils_format_ipv4_addr(ipconfig.aucSubnetMask, NETUTILS_LITTLE),
+ 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),
+ };
+ return mp_obj_new_tuple(MP_ARRAY_SIZE(tuple), tuple);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(cc3k_ifconfig_obj, cc3k_ifconfig);
+
+STATIC mp_obj_t cc3k_patch_version(mp_obj_t self_in) {
+ uint8_t pver[2];
+ mp_obj_tuple_t *t_pver;
+
+ nvmem_read_sp_version(pver);
+ t_pver = mp_obj_new_tuple(2, NULL);
+ t_pver->items[0] = mp_obj_new_int(pver[0]);
+ t_pver->items[1] = mp_obj_new_int(pver[1]);
+ return t_pver;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(cc3k_patch_version_obj, cc3k_patch_version);
+
+STATIC mp_obj_t cc3k_patch_program(mp_obj_t self_in, mp_obj_t key_in) {
+ const char *key = mp_obj_str_get_str(key_in);
+ if (key[0] == 'p' && key[1] == 'g' && key[2] == 'm' && key[3] == '\0') {
+ patch_prog_start();
+ } else {
+ mp_print_str(&mp_plat_print, "pass 'pgm' as argument in order to program\n");
+ }
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(cc3k_patch_program_obj, cc3k_patch_program);
+
+STATIC const mp_rom_map_elem_t cc3k_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_connect), MP_ROM_PTR(&cc3k_connect_obj) },
+ { MP_ROM_QSTR(MP_QSTR_disconnect), MP_ROM_PTR(&cc3k_disconnect_obj) },
+ { MP_ROM_QSTR(MP_QSTR_isconnected), MP_ROM_PTR(&cc3k_isconnected_obj) },
+ { MP_ROM_QSTR(MP_QSTR_ifconfig), MP_ROM_PTR(&cc3k_ifconfig_obj) },
+ { MP_ROM_QSTR(MP_QSTR_patch_version), MP_ROM_PTR(&cc3k_patch_version_obj) },
+ { MP_ROM_QSTR(MP_QSTR_patch_program), MP_ROM_PTR(&cc3k_patch_program_obj) },
+
+ // class constants
+ { MP_ROM_QSTR(MP_QSTR_WEP), MP_ROM_INT(WLAN_SEC_WEP) },
+ { MP_ROM_QSTR(MP_QSTR_WPA), MP_ROM_INT(WLAN_SEC_WPA) },
+ { MP_ROM_QSTR(MP_QSTR_WPA2), MP_ROM_INT(WLAN_SEC_WPA2) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(cc3k_locals_dict, cc3k_locals_dict_table);
+
+const mod_network_nic_type_t mod_network_nic_type_cc3k = {
+ .base = {
+ { &mp_type_type },
+ .name = MP_QSTR_CC3K,
+ .make_new = cc3k_make_new,
+ .locals_dict = (mp_obj_dict_t*)&cc3k_locals_dict,
+ },
+ .gethostbyname = cc3k_gethostbyname,
+ .socket = cc3k_socket_socket,
+ .close = cc3k_socket_close,
+ .bind = cc3k_socket_bind,
+ .listen = cc3k_socket_listen,
+ .accept = cc3k_socket_accept,
+ .connect = cc3k_socket_connect,
+ .send = cc3k_socket_send,
+ .recv = cc3k_socket_recv,
+ .sendto = cc3k_socket_sendto,
+ .recvfrom = cc3k_socket_recvfrom,
+ .setsockopt = cc3k_socket_setsockopt,
+ .settimeout = cc3k_socket_settimeout,
+ .ioctl = cc3k_socket_ioctl,
+};
diff --git a/ports/stm32/modnwwiznet5k.c b/ports/stm32/modnwwiznet5k.c
new file mode 100644
index 000000000..ffc383524
--- /dev/null
+++ b/ports/stm32/modnwwiznet5k.c
@@ -0,0 +1,464 @@
+/*
+ * 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.
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+
+#include "py/nlr.h"
+#include "py/objlist.h"
+#include "py/runtime.h"
+#include "py/mperrno.h"
+#include "py/mphal.h"
+#include "lib/netutils/netutils.h"
+#include "modnetwork.h"
+#include "pin.h"
+#include "genhdr/pins.h"
+#include "spi.h"
+
+#include "ethernet/wizchip_conf.h"
+#include "ethernet/socket.h"
+#include "internet/dns/dns.h"
+
+/// \moduleref network
+
+typedef struct _wiznet5k_obj_t {
+ mp_obj_base_t base;
+ mp_uint_t cris_state;
+ SPI_HandleTypeDef *spi;
+ const pin_obj_t *cs;
+ const pin_obj_t *rst;
+ uint8_t socket_used;
+} wiznet5k_obj_t;
+
+STATIC wiznet5k_obj_t wiznet5k_obj;
+
+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, 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);
+ (void)status;
+}
+
+STATIC int wiznet5k_gethostbyname(mp_obj_t nic, const char *name, mp_uint_t len, uint8_t *out_ip) {
+ uint8_t dns_ip[MOD_NETWORK_IPADDR_BUF_SIZE] = {8, 8, 8, 8};
+ uint8_t *buf = m_new(uint8_t, MAX_DNS_BUF_SIZE);
+ DNS_init(0, buf);
+ mp_int_t ret = DNS_run(dns_ip, (uint8_t*)name, out_ip);
+ m_del(uint8_t, buf, MAX_DNS_BUF_SIZE);
+ if (ret == 1) {
+ // success
+ return 0;
+ } else {
+ // failure
+ return MP_ENOENT;
+ }
+}
+
+STATIC int wiznet5k_socket_socket(mod_network_socket_obj_t *socket, int *_errno) {
+ if (socket->u_param.domain != MOD_NETWORK_AF_INET) {
+ *_errno = MP_EAFNOSUPPORT;
+ return -1;
+ }
+
+ switch (socket->u_param.type) {
+ case MOD_NETWORK_SOCK_STREAM: socket->u_param.type = Sn_MR_TCP; break;
+ case MOD_NETWORK_SOCK_DGRAM: socket->u_param.type = Sn_MR_UDP; break;
+ default: *_errno = MP_EINVAL; return -1;
+ }
+
+ if (socket->u_param.fileno == -1) {
+ // get first unused socket number
+ for (mp_uint_t sn = 0; sn < _WIZCHIP_SOCK_NUM_; sn++) {
+ if ((wiznet5k_obj.socket_used & (1 << sn)) == 0) {
+ wiznet5k_obj.socket_used |= (1 << sn);
+ socket->u_param.fileno = sn;
+ break;
+ }
+ }
+ if (socket->u_param.fileno == -1) {
+ // too many open sockets
+ *_errno = MP_EMFILE;
+ return -1;
+ }
+ }
+
+ // WIZNET does not have a concept of pure "open socket". You need to know
+ // if it's a server or client at the time of creation of the socket.
+ // So, we defer the open until we know what kind of socket we want.
+
+ // use "domain" to indicate that this socket has not yet been opened
+ socket->u_param.domain = 0;
+
+ return 0;
+}
+
+STATIC void wiznet5k_socket_close(mod_network_socket_obj_t *socket) {
+ uint8_t sn = (uint8_t)socket->u_param.fileno;
+ if (sn < _WIZCHIP_SOCK_NUM_) {
+ wiznet5k_obj.socket_used &= ~(1 << sn);
+ WIZCHIP_EXPORT(close)(sn);
+ }
+}
+
+STATIC int wiznet5k_socket_bind(mod_network_socket_obj_t *socket, byte *ip, mp_uint_t port, int *_errno) {
+ // open the socket in server mode (if port != 0)
+ mp_int_t ret = WIZCHIP_EXPORT(socket)(socket->u_param.fileno, socket->u_param.type, port, 0);
+ if (ret < 0) {
+ wiznet5k_socket_close(socket);
+ *_errno = -ret;
+ return -1;
+ }
+
+ // indicate that this socket has been opened
+ socket->u_param.domain = 1;
+
+ // success
+ return 0;
+}
+
+STATIC int wiznet5k_socket_listen(mod_network_socket_obj_t *socket, mp_int_t backlog, int *_errno) {
+ mp_int_t ret = WIZCHIP_EXPORT(listen)(socket->u_param.fileno);
+ if (ret < 0) {
+ wiznet5k_socket_close(socket);
+ *_errno = -ret;
+ return -1;
+ }
+ return 0;
+}
+
+STATIC int wiznet5k_socket_accept(mod_network_socket_obj_t *socket, mod_network_socket_obj_t *socket2, byte *ip, mp_uint_t *port, int *_errno) {
+ for (;;) {
+ int sr = getSn_SR((uint8_t)socket->u_param.fileno);
+ if (sr == SOCK_ESTABLISHED) {
+ socket2->u_param = socket->u_param;
+ // TODO need to populate this with the correct values
+ ip[0] = 0;
+ ip[1] = 0;
+ ip[2] = 0;
+ ip[3] = 0;
+ *port = getSn_PORT(socket2->u_param.fileno);
+
+ // WIZnet turns the listening socket into the client socket, so we
+ // need to re-bind and re-listen on another socket for the server.
+ // TODO handle errors, especially no-more-sockets error
+ socket->u_param.domain = MOD_NETWORK_AF_INET;
+ socket->u_param.fileno = -1;
+ int _errno2;
+ if (wiznet5k_socket_socket(socket, &_errno2) != 0) {
+ //printf("(bad resocket %d)\n", _errno2);
+ } else if (wiznet5k_socket_bind(socket, NULL, *port, &_errno2) != 0) {
+ //printf("(bad rebind %d)\n", _errno2);
+ } else if (wiznet5k_socket_listen(socket, 0, &_errno2) != 0) {
+ //printf("(bad relisten %d)\n", _errno2);
+ }
+
+ return 0;
+ }
+ if (sr == SOCK_CLOSED || sr == SOCK_CLOSE_WAIT) {
+ wiznet5k_socket_close(socket);
+ *_errno = MP_ENOTCONN; // ??
+ return -1;
+ }
+ mp_hal_delay_ms(1);
+ }
+}
+
+STATIC int wiznet5k_socket_connect(mod_network_socket_obj_t *socket, byte *ip, mp_uint_t port, int *_errno) {
+ // use "bind" function to open the socket in client mode
+ if (wiznet5k_socket_bind(socket, ip, 0, _errno) != 0) {
+ return -1;
+ }
+
+ // now connect
+ mp_int_t ret = WIZCHIP_EXPORT(connect)(socket->u_param.fileno, ip, port);
+ if (ret < 0) {
+ wiznet5k_socket_close(socket);
+ *_errno = -ret;
+ return -1;
+ }
+
+ // success
+ return 0;
+}
+
+STATIC mp_uint_t wiznet5k_socket_send(mod_network_socket_obj_t *socket, const byte *buf, mp_uint_t len, int *_errno) {
+ mp_int_t ret = WIZCHIP_EXPORT(send)(socket->u_param.fileno, (byte*)buf, len);
+ // TODO convert Wiz errno's to POSIX ones
+ if (ret < 0) {
+ wiznet5k_socket_close(socket);
+ *_errno = -ret;
+ return -1;
+ }
+ return ret;
+}
+
+STATIC mp_uint_t wiznet5k_socket_recv(mod_network_socket_obj_t *socket, byte *buf, mp_uint_t len, int *_errno) {
+ mp_int_t ret = WIZCHIP_EXPORT(recv)(socket->u_param.fileno, buf, len);
+ // TODO convert Wiz errno's to POSIX ones
+ if (ret < 0) {
+ wiznet5k_socket_close(socket);
+ *_errno = -ret;
+ return -1;
+ }
+ return ret;
+}
+
+STATIC mp_uint_t wiznet5k_socket_sendto(mod_network_socket_obj_t *socket, const byte *buf, mp_uint_t len, byte *ip, mp_uint_t port, int *_errno) {
+ if (socket->u_param.domain == 0) {
+ // socket not opened; use "bind" function to open the socket in client mode
+ if (wiznet5k_socket_bind(socket, ip, 0, _errno) != 0) {
+ return -1;
+ }
+ }
+
+ mp_int_t ret = WIZCHIP_EXPORT(sendto)(socket->u_param.fileno, (byte*)buf, len, ip, port);
+ if (ret < 0) {
+ wiznet5k_socket_close(socket);
+ *_errno = -ret;
+ return -1;
+ }
+ return ret;
+}
+
+STATIC mp_uint_t wiznet5k_socket_recvfrom(mod_network_socket_obj_t *socket, byte *buf, mp_uint_t len, byte *ip, mp_uint_t *port, int *_errno) {
+ uint16_t port2;
+ mp_int_t ret = WIZCHIP_EXPORT(recvfrom)(socket->u_param.fileno, buf, len, ip, &port2);
+ *port = port2;
+ if (ret < 0) {
+ wiznet5k_socket_close(socket);
+ *_errno = -ret;
+ return -1;
+ }
+ return ret;
+}
+
+STATIC int wiznet5k_socket_setsockopt(mod_network_socket_obj_t *socket, mp_uint_t level, mp_uint_t opt, const void *optval, mp_uint_t optlen, int *_errno) {
+ // TODO
+ *_errno = MP_EINVAL;
+ return -1;
+}
+
+STATIC int wiznet5k_socket_settimeout(mod_network_socket_obj_t *socket, mp_uint_t timeout_ms, int *_errno) {
+ // TODO
+ *_errno = MP_EINVAL;
+ return -1;
+
+ /*
+ if (timeout_ms == 0) {
+ // set non-blocking mode
+ uint8_t arg = SOCK_IO_NONBLOCK;
+ WIZCHIP_EXPORT(ctlsocket)(socket->u_param.fileno, CS_SET_IOMODE, &arg);
+ }
+ */
+}
+
+STATIC int wiznet5k_socket_ioctl(mod_network_socket_obj_t *socket, mp_uint_t request, mp_uint_t arg, int *_errno) {
+ // TODO
+ *_errno = MP_EINVAL;
+ return -1;
+}
+
+#if 0
+STATIC void wiznet5k_socket_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
+ wiznet5k_socket_obj_t *self = self_in;
+ print(env, "<WIZNET5K.socket sn=%u MR=0x%02x>", self->sn, getSn_MR(self->sn));
+}
+
+STATIC mp_obj_t wiznet5k_socket_disconnect(mp_obj_t self_in) {
+ mp_int_t ret = WIZCHIP_EXPORT(disconnect)(self->sn);
+ return 0;
+}
+#endif
+
+/******************************************************************************/
+// MicroPython bindings
+
+/// \classmethod \constructor(spi, pin_cs, pin_rst)
+/// Create and return a WIZNET5K object.
+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);
+
+ // 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.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_4; // 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_init(wiznet5k_obj.spi, false);
+
+ mp_hal_pin_output(wiznet5k_obj.cs);
+ mp_hal_pin_output(wiznet5k_obj.rst);
+
+ 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(160); // datasheet says 150ms
+
+ 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);
+
+ uint8_t sn_size[16] = {2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2}; // 2k buffer for each socket
+ ctlwizchip(CW_INIT_WIZCHIP, sn_size);
+
+ // set some sensible default values; they are configurable using ifconfig method
+ wiz_NetInfo netinfo = {
+ .mac = {0x00, 0x08, 0xdc, 0xab, 0xcd, 0xef},
+ .ip = {192, 168, 0, 18},
+ .sn = {255, 255, 255, 0},
+ .gw = {192, 168, 0, 1},
+ .dns = {8, 8, 8, 8}, // Google public DNS
+ .dhcp = NETINFO_STATIC,
+ };
+ ctlnetwork(CN_SET_NETINFO, (void*)&netinfo);
+
+ // seems we need a small delay after init
+ mp_hal_delay_ms(250);
+
+ // register with network module
+ mod_network_register_nic(&wiznet5k_obj);
+
+ // return wiznet5k object
+ return &wiznet5k_obj;
+}
+
+/// \method regs()
+/// Dump WIZNET5K registers.
+STATIC mp_obj_t wiznet5k_regs(mp_obj_t self_in) {
+ //wiznet5k_obj_t *self = self_in;
+ printf("Wiz CREG:");
+ for (int i = 0; i < 0x50; ++i) {
+ if (i % 16 == 0) {
+ printf("\n %04x:", i);
+ }
+ printf(" %02x", WIZCHIP_READ(i));
+ }
+ 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);
+ }
+ printf(" %02x", WIZCHIP_READ(WIZCHIP_SREG_ADDR(sn, i)));
+ }
+ }
+ printf("\n");
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(wiznet5k_regs_obj, wiznet5k_regs);
+
+/// \method ifconfig([(ip, subnet, gateway, dns)])
+/// Get/set IP address, subnet mask, gateway and DNS.
+STATIC mp_obj_t wiznet5k_ifconfig(size_t n_args, const mp_obj_t *args) {
+ wiz_NetInfo netinfo;
+ ctlnetwork(CN_GET_NETINFO, &netinfo);
+ if (n_args == 1) {
+ // get
+ mp_obj_t tuple[4] = {
+ netutils_format_ipv4_addr(netinfo.ip, NETUTILS_BIG),
+ netutils_format_ipv4_addr(netinfo.sn, NETUTILS_BIG),
+ netutils_format_ipv4_addr(netinfo.gw, NETUTILS_BIG),
+ netutils_format_ipv4_addr(netinfo.dns, 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], netinfo.ip, NETUTILS_BIG);
+ netutils_parse_ipv4_addr(items[1], netinfo.sn, NETUTILS_BIG);
+ netutils_parse_ipv4_addr(items[2], netinfo.gw, NETUTILS_BIG);
+ netutils_parse_ipv4_addr(items[3], netinfo.dns, NETUTILS_BIG);
+ ctlnetwork(CN_SET_NETINFO, &netinfo);
+ return mp_const_none;
+ }
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(wiznet5k_ifconfig_obj, 1, 2, wiznet5k_ifconfig);
+
+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_ifconfig), MP_ROM_PTR(&wiznet5k_ifconfig_obj) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(wiznet5k_locals_dict, wiznet5k_locals_dict_table);
+
+const mod_network_nic_type_t mod_network_nic_type_wiznet5k = {
+ .base = {
+ { &mp_type_type },
+ .name = MP_QSTR_WIZNET5K,
+ .make_new = wiznet5k_make_new,
+ .locals_dict = (mp_obj_dict_t*)&wiznet5k_locals_dict,
+ },
+ .gethostbyname = wiznet5k_gethostbyname,
+ .socket = wiznet5k_socket_socket,
+ .close = wiznet5k_socket_close,
+ .bind = wiznet5k_socket_bind,
+ .listen = wiznet5k_socket_listen,
+ .accept = wiznet5k_socket_accept,
+ .connect = wiznet5k_socket_connect,
+ .send = wiznet5k_socket_send,
+ .recv = wiznet5k_socket_recv,
+ .sendto = wiznet5k_socket_sendto,
+ .recvfrom = wiznet5k_socket_recvfrom,
+ .setsockopt = wiznet5k_socket_setsockopt,
+ .settimeout = wiznet5k_socket_settimeout,
+ .ioctl = wiznet5k_socket_ioctl,
+};
diff --git a/ports/stm32/modpyb.c b/ports/stm32/modpyb.c
new file mode 100644
index 000000000..5dc28e132
--- /dev/null
+++ b/ports/stm32/modpyb.c
@@ -0,0 +1,214 @@
+/*
+ * 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 <stdint.h>
+#include <stdio.h>
+
+#include "py/mpstate.h"
+#include "py/nlr.h"
+#include "py/obj.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 "stm32_it.h"
+#include "irq.h"
+#include "systick.h"
+#include "led.h"
+#include "pin.h"
+#include "timer.h"
+#include "extint.h"
+#include "usrsw.h"
+#include "rng.h"
+#include "rtc.h"
+#include "i2c.h"
+#include "spi.h"
+#include "uart.h"
+#include "can.h"
+#include "adc.h"
+#include "storage.h"
+#include "sdcard.h"
+#include "accel.h"
+#include "servo.h"
+#include "dac.h"
+#include "lcd.h"
+#include "usb.h"
+#include "portmodules.h"
+#include "modmachine.h"
+#include "extmod/vfs.h"
+#include "extmod/utime_mphal.h"
+
+STATIC mp_obj_t pyb_fault_debug(mp_obj_t value) {
+ pyb_hard_fault_debug = mp_obj_is_true(value);
+ return mp_const_none;
+}
+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
+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();
+ return MP_OBJ_NEW_SMALL_INT((currMillis - startMillis) & 0x3fffffff);
+}
+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
+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();
+ return MP_OBJ_NEW_SMALL_INT((currMicros - startMicros) & 0x3fffffff);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_elapsed_micros_obj, pyb_elapsed_micros);
+
+MP_DECLARE_CONST_FUN_OBJ_KW(pyb_main_obj); // defined in main.c
+
+STATIC const mp_rom_map_elem_t pyb_module_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_pyb) },
+
+ { MP_ROM_QSTR(MP_QSTR_fault_debug), MP_ROM_PTR(&pyb_fault_debug_obj) },
+
+ { 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) },
+ { 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) },
+ { MP_ROM_QSTR(MP_QSTR_disable_irq), MP_ROM_PTR(&pyb_disable_irq_obj) },
+ { MP_ROM_QSTR(MP_QSTR_enable_irq), MP_ROM_PTR(&pyb_enable_irq_obj) },
+ #if IRQ_ENABLE_STATS
+ { MP_ROM_QSTR(MP_QSTR_irq_stats), MP_ROM_PTR(&pyb_irq_stats_obj) },
+ #endif
+
+ { MP_ROM_QSTR(MP_QSTR_stop), MP_ROM_PTR(&machine_sleep_obj) },
+ { MP_ROM_QSTR(MP_QSTR_standby), MP_ROM_PTR(&machine_deepsleep_obj) },
+ { MP_ROM_QSTR(MP_QSTR_main), MP_ROM_PTR(&pyb_main_obj) },
+ { MP_ROM_QSTR(MP_QSTR_repl_uart), MP_ROM_PTR(&mod_os_dupterm_obj) },
+
+ { 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) },
+ // 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) },
+
+ { 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) },
+ { MP_ROM_QSTR(MP_QSTR_elapsed_micros), MP_ROM_PTR(&pyb_elapsed_micros_obj) },
+ { MP_ROM_QSTR(MP_QSTR_delay), MP_ROM_PTR(&mp_utime_sleep_ms_obj) },
+ { 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) },
+
+ { MP_ROM_QSTR(MP_QSTR_Timer), MP_ROM_PTR(&pyb_timer_type) },
+
+#if MICROPY_HW_ENABLE_RNG
+ { MP_ROM_QSTR(MP_QSTR_rng), MP_ROM_PTR(&pyb_rng_get_obj) },
+#endif
+
+#if MICROPY_HW_ENABLE_RTC
+ { MP_ROM_QSTR(MP_QSTR_RTC), MP_ROM_PTR(&pyb_rtc_type) },
+#endif
+
+ { MP_ROM_QSTR(MP_QSTR_Pin), MP_ROM_PTR(&pin_type) },
+ { MP_ROM_QSTR(MP_QSTR_ExtInt), MP_ROM_PTR(&extint_type) },
+
+#if MICROPY_HW_ENABLE_SERVO
+ { MP_ROM_QSTR(MP_QSTR_pwm), MP_ROM_PTR(&pyb_pwm_set_obj) },
+ { MP_ROM_QSTR(MP_QSTR_servo), MP_ROM_PTR(&pyb_servo_set_obj) },
+ { MP_ROM_QSTR(MP_QSTR_Servo), MP_ROM_PTR(&pyb_servo_type) },
+#endif
+
+#if MICROPY_HW_HAS_SWITCH
+ { MP_ROM_QSTR(MP_QSTR_Switch), MP_ROM_PTR(&pyb_switch_type) },
+#endif
+
+#if MICROPY_HW_HAS_FLASH
+ { MP_ROM_QSTR(MP_QSTR_Flash), MP_ROM_PTR(&pyb_flash_type) },
+#endif
+
+#if MICROPY_HW_HAS_SDCARD
+ { MP_ROM_QSTR(MP_QSTR_SD), MP_ROM_PTR(&pyb_sdcard_obj) }, // now obsolete
+ { 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
+ { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&pyb_i2c_type) },
+ { 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
+
+ { 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) },
+
+#if MICROPY_HW_ENABLE_DAC
+ { MP_ROM_QSTR(MP_QSTR_DAC), MP_ROM_PTR(&pyb_dac_type) },
+#endif
+
+#if MICROPY_HW_HAS_MMA7660
+ { MP_ROM_QSTR(MP_QSTR_Accel), MP_ROM_PTR(&pyb_accel_type) },
+#endif
+
+#if MICROPY_HW_HAS_LCD
+ { MP_ROM_QSTR(MP_QSTR_LCD), MP_ROM_PTR(&pyb_lcd_type) },
+#endif
+};
+
+STATIC MP_DEFINE_CONST_DICT(pyb_module_globals, pyb_module_globals_table);
+
+const mp_obj_module_t pyb_module = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t*)&pyb_module_globals,
+};
diff --git a/ports/stm32/modstm.c b/ports/stm32/modstm.c
new file mode 100644
index 000000000..2084c0aa0
--- /dev/null
+++ b/ports/stm32/modstm.c
@@ -0,0 +1,51 @@
+/*
+ * 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 <stdint.h>
+
+#include "py/obj.h"
+#include "py/objint.h"
+#include "extmod/machine_mem.h"
+#include "genhdr/modstm_mpz.h"
+#include "portmodules.h"
+
+STATIC const mp_rom_map_elem_t stm_module_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_stm) },
+
+ { 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) },
+
+#include "genhdr/modstm_const.h"
+};
+
+STATIC MP_DEFINE_CONST_DICT(stm_module_globals, stm_module_globals_table);
+
+const mp_obj_module_t stm_module = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t*)&stm_module_globals,
+};
diff --git a/ports/stm32/modules/lcd160cr.py b/ports/stm32/modules/lcd160cr.py
new file mode 120000
index 000000000..c0e180714
--- /dev/null
+++ b/ports/stm32/modules/lcd160cr.py
@@ -0,0 +1 @@
+../../drivers/display/lcd160cr.py \ No newline at end of file
diff --git a/ports/stm32/modules/lcd160cr_test.py b/ports/stm32/modules/lcd160cr_test.py
new file mode 120000
index 000000000..56f091351
--- /dev/null
+++ b/ports/stm32/modules/lcd160cr_test.py
@@ -0,0 +1 @@
+../../drivers/display/lcd160cr_test.py \ No newline at end of file
diff --git a/ports/stm32/modules/onewire.py b/ports/stm32/modules/onewire.py
new file mode 120000
index 000000000..f6ec745e8
--- /dev/null
+++ b/ports/stm32/modules/onewire.py
@@ -0,0 +1 @@
+../../drivers/onewire/onewire.py \ No newline at end of file
diff --git a/ports/stm32/moduos.c b/ports/stm32/moduos.c
new file mode 100644
index 000000000..82ee61726
--- /dev/null
+++ b/ports/stm32/moduos.c
@@ -0,0 +1,169 @@
+/*
+ * 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 <stdint.h>
+#include <string.h>
+
+#include "py/mpstate.h"
+#include "py/runtime.h"
+#include "py/objtuple.h"
+#include "py/objstr.h"
+#include "lib/timeutils/timeutils.h"
+#include "lib/oofatfs/ff.h"
+#include "lib/oofatfs/diskio.h"
+#include "extmod/vfs.h"
+#include "extmod/vfs_fat.h"
+#include "genhdr/mpversion.h"
+#include "rng.h"
+#include "uart.h"
+#include "portmodules.h"
+
+/// \module os - basic "operating system" services
+///
+/// The `os` module contains functions for filesystem access and `urandom`.
+///
+/// The filesystem has `/` as the root directory, and the available physical
+/// drives are accessible from here. They are currently:
+///
+/// /flash -- the internal flash filesystem
+/// /sd -- the SD card (if it exists)
+///
+/// On boot up, the current directory is `/flash` if no SD card is inserted,
+/// otherwise it is `/sd`.
+
+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, "pyboard");
+STATIC const MP_DEFINE_STR_OBJ(os_uname_info_nodename_obj, "pyboard");
+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);
+
+/// \function sync()
+/// Sync all filesystems.
+STATIC mp_obj_t os_sync(void) {
+ 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);
+ }
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_0(mod_os_sync_obj, os_sync);
+
+#if MICROPY_HW_ENABLE_RNG
+/// \function urandom(n)
+/// Return a bytes object with n random bytes, generated by the hardware
+/// random number generator.
+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);
+ for (int i = 0; i < n; i++) {
+ vstr.buf[i] = rng_get();
+ }
+ return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(os_urandom_obj, os_urandom);
+#endif
+
+// Get or set the UART object that the REPL is repeated on.
+// TODO should accept any object with read/write methods.
+STATIC mp_obj_t os_dupterm(size_t n_args, const mp_obj_t *args) {
+ if (n_args == 0) {
+ if (MP_STATE_PORT(pyb_stdio_uart) == NULL) {
+ return mp_const_none;
+ } else {
+ return MP_STATE_PORT(pyb_stdio_uart);
+ }
+ } else {
+ if (args[0] == mp_const_none) {
+ 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];
+ } else {
+ mp_raise_ValueError("need a UART object");
+ }
+ return mp_const_none;
+ }
+}
+MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_os_dupterm_obj, 0, 1, os_dupterm);
+
+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_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_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_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_rmdir), MP_ROM_PTR(&mp_vfs_rmdir_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_unlink), MP_ROM_PTR(&mp_vfs_remove_obj) }, // unlink aliases to remove
+
+ { MP_ROM_QSTR(MP_QSTR_sync), MP_ROM_PTR(&mod_os_sync_obj) },
+
+ /// \constant sep - separation character used in paths
+ { MP_ROM_QSTR(MP_QSTR_sep), MP_ROM_QSTR(MP_QSTR__slash_) },
+
+#if MICROPY_HW_ENABLE_RNG
+ { MP_ROM_QSTR(MP_QSTR_urandom), MP_ROM_PTR(&os_urandom_obj) },
+#endif
+
+ // these are MicroPython extensions
+ { MP_ROM_QSTR(MP_QSTR_dupterm), MP_ROM_PTR(&mod_os_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) },
+ { MP_ROM_QSTR(MP_QSTR_VfsFat), MP_ROM_PTR(&mp_fat_vfs_type) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(os_module_globals, os_module_globals_table);
+
+const mp_obj_module_t mp_module_uos = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t*)&os_module_globals,
+};
diff --git a/ports/stm32/modusocket.c b/ports/stm32/modusocket.c
new file mode 100644
index 000000000..32dad5ced
--- /dev/null
+++ b/ports/stm32/modusocket.c
@@ -0,0 +1,452 @@
+/*
+ * 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.
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include "py/nlr.h"
+#include "py/objtuple.h"
+#include "py/objlist.h"
+#include "py/runtime.h"
+#include "py/mperrno.h"
+#include "lib/netutils/netutils.h"
+#include "modnetwork.h"
+
+#if MICROPY_PY_USOCKET
+
+/******************************************************************************/
+// socket class
+
+STATIC const mp_obj_type_t socket_type;
+
+// constructor socket(family=AF_INET, type=SOCK_STREAM, proto=0, fileno=None)
+STATIC mp_obj_t socket_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, 0, 4, false);
+
+ // create socket object (not bound to any NIC yet)
+ mod_network_socket_obj_t *s = m_new_obj_with_finaliser(mod_network_socket_obj_t);
+ s->base.type = (mp_obj_t)&socket_type;
+ s->nic = MP_OBJ_NULL;
+ s->nic_type = NULL;
+ s->u_param.domain = MOD_NETWORK_AF_INET;
+ s->u_param.type = MOD_NETWORK_SOCK_STREAM;
+ s->u_param.fileno = -1;
+ if (n_args >= 1) {
+ s->u_param.domain = mp_obj_get_int(args[0]);
+ if (n_args >= 2) {
+ s->u_param.type = mp_obj_get_int(args[1]);
+ if (n_args >= 4) {
+ s->u_param.fileno = mp_obj_get_int(args[3]);
+ }
+ }
+ }
+
+ return s;
+}
+
+STATIC void socket_select_nic(mod_network_socket_obj_t *self, const byte *ip) {
+ if (self->nic == MP_OBJ_NULL) {
+ // select NIC based on IP
+ self->nic = mod_network_find_nic(ip);
+ self->nic_type = (mod_network_nic_type_t*)mp_obj_get_type(self->nic);
+
+ // call the NIC to open the socket
+ int _errno;
+ if (self->nic_type->socket(self, &_errno) != 0) {
+ mp_raise_OSError(_errno);
+ }
+ }
+}
+// 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) {
+ mod_network_socket_obj_t *self = self_in;
+
+ // get address
+ uint8_t ip[MOD_NETWORK_IPADDR_BUF_SIZE];
+ mp_uint_t port = netutils_parse_inet_addr(addr_in, ip, NETUTILS_BIG);
+
+ // check if we need to select a NIC
+ socket_select_nic(self, ip);
+
+ // call the NIC to bind the socket
+ int _errno;
+ if (self->nic_type->bind(self, ip, port, &_errno) != 0) {
+ mp_raise_OSError(_errno);
+ }
+
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_bind_obj, socket_bind);
+
+// method socket.listen(backlog)
+STATIC mp_obj_t socket_listen(mp_obj_t self_in, mp_obj_t backlog) {
+ mod_network_socket_obj_t *self = self_in;
+
+ if (self->nic == MP_OBJ_NULL) {
+ // not connected
+ // TODO I think we can listen even if not bound...
+ mp_raise_OSError(MP_ENOTCONN);
+ }
+
+ int _errno;
+ if (self->nic_type->listen(self, mp_obj_get_int(backlog), &_errno) != 0) {
+ mp_raise_OSError(_errno);
+ }
+
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_listen_obj, socket_listen);
+
+// method socket.accept()
+STATIC mp_obj_t socket_accept(mp_obj_t self_in) {
+ mod_network_socket_obj_t *self = self_in;
+
+ // create new socket object
+ // starts with empty NIC so that finaliser doesn't run close() method if accept() fails
+ mod_network_socket_obj_t *socket2 = m_new_obj_with_finaliser(mod_network_socket_obj_t);
+ socket2->base.type = (mp_obj_t)&socket_type;
+ socket2->nic = MP_OBJ_NULL;
+ socket2->nic_type = NULL;
+
+ // accept incoming connection
+ uint8_t ip[MOD_NETWORK_IPADDR_BUF_SIZE];
+ mp_uint_t port;
+ int _errno;
+ if (self->nic_type->accept(self, socket2, ip, &port, &_errno) != 0) {
+ mp_raise_OSError(_errno);
+ }
+
+ // new socket has valid state, so set the NIC to the same as parent
+ socket2->nic = self->nic;
+ socket2->nic_type = self->nic_type;
+
+ // make the return value
+ mp_obj_tuple_t *client = mp_obj_new_tuple(2, NULL);
+ client->items[0] = socket2;
+ 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);
+
+// method socket.connect(address)
+STATIC mp_obj_t socket_connect(mp_obj_t self_in, mp_obj_t addr_in) {
+ mod_network_socket_obj_t *self = self_in;
+
+ // get address
+ uint8_t ip[MOD_NETWORK_IPADDR_BUF_SIZE];
+ mp_uint_t port = netutils_parse_inet_addr(addr_in, ip, NETUTILS_BIG);
+
+ // check if we need to select a NIC
+ socket_select_nic(self, ip);
+
+ // call the NIC to connect the socket
+ int _errno;
+ if (self->nic_type->connect(self, ip, port, &_errno) != 0) {
+ mp_raise_OSError(_errno);
+ }
+
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_connect_obj, socket_connect);
+
+// method socket.send(bytes)
+STATIC mp_obj_t socket_send(mp_obj_t self_in, mp_obj_t buf_in) {
+ mod_network_socket_obj_t *self = self_in;
+ if (self->nic == MP_OBJ_NULL) {
+ // not connected
+ mp_raise_OSError(MP_EPIPE);
+ }
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_READ);
+ int _errno;
+ mp_uint_t ret = self->nic_type->send(self, bufinfo.buf, bufinfo.len, &_errno);
+ if (ret == -1) {
+ mp_raise_OSError(_errno);
+ }
+ return mp_obj_new_int_from_uint(ret);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_send_obj, socket_send);
+
+// method socket.recv(bufsize)
+STATIC mp_obj_t socket_recv(mp_obj_t self_in, mp_obj_t len_in) {
+ mod_network_socket_obj_t *self = self_in;
+ if (self->nic == MP_OBJ_NULL) {
+ // not connected
+ mp_raise_OSError(MP_ENOTCONN);
+ }
+ mp_int_t len = mp_obj_get_int(len_in);
+ vstr_t vstr;
+ vstr_init_len(&vstr, len);
+ int _errno;
+ mp_uint_t ret = self->nic_type->recv(self, (byte*)vstr.buf, len, &_errno);
+ if (ret == -1) {
+ mp_raise_OSError(_errno);
+ }
+ if (ret == 0) {
+ return mp_const_empty_bytes;
+ }
+ vstr.len = ret;
+ return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_recv_obj, socket_recv);
+
+// method socket.sendto(bytes, address)
+STATIC mp_obj_t socket_sendto(mp_obj_t self_in, mp_obj_t data_in, mp_obj_t addr_in) {
+ mod_network_socket_obj_t *self = self_in;
+
+ // get the data
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(data_in, &bufinfo, MP_BUFFER_READ);
+
+ // get address
+ uint8_t ip[MOD_NETWORK_IPADDR_BUF_SIZE];
+ mp_uint_t port = netutils_parse_inet_addr(addr_in, ip, NETUTILS_BIG);
+
+ // check if we need to select a NIC
+ socket_select_nic(self, ip);
+
+ // call the NIC to sendto
+ int _errno;
+ mp_int_t ret = self->nic_type->sendto(self, bufinfo.buf, bufinfo.len, ip, port, &_errno);
+ if (ret == -1) {
+ mp_raise_OSError(_errno);
+ }
+
+ return mp_obj_new_int(ret);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_3(socket_sendto_obj, socket_sendto);
+
+// method socket.recvfrom(bufsize)
+STATIC mp_obj_t socket_recvfrom(mp_obj_t self_in, mp_obj_t len_in) {
+ mod_network_socket_obj_t *self = self_in;
+ if (self->nic == MP_OBJ_NULL) {
+ // not connected
+ mp_raise_OSError(MP_ENOTCONN);
+ }
+ vstr_t vstr;
+ vstr_init_len(&vstr, mp_obj_get_int(len_in));
+ byte ip[4];
+ mp_uint_t port;
+ int _errno;
+ mp_int_t ret = self->nic_type->recvfrom(self, (byte*)vstr.buf, vstr.len, ip, &port, &_errno);
+ if (ret == -1) {
+ mp_raise_OSError(_errno);
+ }
+ mp_obj_t tuple[2];
+ if (ret == 0) {
+ tuple[0] = mp_const_empty_bytes;
+ } else {
+ vstr.len = ret;
+ tuple[0] = mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
+ }
+ 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);
+
+// method socket.setsockopt(level, optname, value)
+STATIC mp_obj_t socket_setsockopt(size_t n_args, const mp_obj_t *args) {
+ mod_network_socket_obj_t *self = args[0];
+
+ mp_int_t level = mp_obj_get_int(args[1]);
+ mp_int_t opt = mp_obj_get_int(args[2]);
+
+ const void *optval;
+ mp_uint_t optlen;
+ mp_int_t val;
+ if (mp_obj_is_integer(args[3])) {
+ val = mp_obj_get_int_truncated(args[3]);
+ optval = &val;
+ optlen = sizeof(val);
+ } else {
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(args[3], &bufinfo, MP_BUFFER_READ);
+ optval = bufinfo.buf;
+ optlen = bufinfo.len;
+ }
+
+ int _errno;
+ if (self->nic_type->setsockopt(self, level, opt, optval, optlen, &_errno) != 0) {
+ mp_raise_OSError(_errno);
+ }
+
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(socket_setsockopt_obj, 4, 4, socket_setsockopt);
+
+// method socket.settimeout(value)
+// timeout=0 means non-blocking
+// timeout=None means blocking
+// otherwise, timeout is in seconds
+STATIC mp_obj_t socket_settimeout(mp_obj_t self_in, mp_obj_t timeout_in) {
+ mod_network_socket_obj_t *self = self_in;
+ if (self->nic == MP_OBJ_NULL) {
+ // not connected
+ mp_raise_OSError(MP_ENOTCONN);
+ }
+ mp_uint_t timeout;
+ if (timeout_in == mp_const_none) {
+ timeout = -1;
+ } else {
+ #if MICROPY_PY_BUILTINS_FLOAT
+ timeout = 1000 * mp_obj_get_float(timeout_in);
+ #else
+ timeout = 1000 * mp_obj_get_int(timeout_in);
+ #endif
+ }
+ int _errno;
+ if (self->nic_type->settimeout(self, timeout, &_errno) != 0) {
+ mp_raise_OSError(_errno);
+ }
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_settimeout_obj, socket_settimeout);
+
+// method socket.setblocking(flag)
+STATIC mp_obj_t socket_setblocking(mp_obj_t self_in, mp_obj_t blocking) {
+ if (mp_obj_is_true(blocking)) {
+ return socket_settimeout(self_in, mp_const_none);
+ } else {
+ return socket_settimeout(self_in, MP_OBJ_NEW_SMALL_INT(0));
+ }
+}
+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_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_recv), MP_ROM_PTR(&socket_recv_obj) },
+ { MP_ROM_QSTR(MP_QSTR_sendto), MP_ROM_PTR(&socket_sendto_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) },
+};
+
+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;
+ return self->nic_type->ioctl(self, request, arg, errcode);
+}
+
+STATIC const mp_stream_p_t socket_stream_p = {
+ .ioctl = socket_ioctl,
+ .is_text = false,
+};
+
+STATIC const mp_obj_type_t socket_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_socket,
+ .make_new = socket_make_new,
+ .protocol = &socket_stream_p,
+ .locals_dict = (mp_obj_dict_t*)&socket_locals_dict,
+};
+
+/******************************************************************************/
+// usocket module
+
+// function usocket.getaddrinfo(host, port)
+STATIC mp_obj_t mod_usocket_getaddrinfo(mp_obj_t host_in, mp_obj_t port_in) {
+ size_t hlen;
+ const char *host = mp_obj_str_get_data(host_in, &hlen);
+ mp_int_t port = mp_obj_get_int(port_in);
+
+ // find a NIC that can do a name lookup
+ for (mp_uint_t i = 0; i < MP_STATE_PORT(mod_network_nic_list).len; i++) {
+ mp_obj_t nic = MP_STATE_PORT(mod_network_nic_list).items[i];
+ mod_network_nic_type_t *nic_type = (mod_network_nic_type_t*)mp_obj_get_type(nic);
+ if (nic_type->gethostbyname != NULL) {
+ uint8_t out_ip[MOD_NETWORK_IPADDR_BUF_SIZE];
+ int ret = nic_type->gethostbyname(nic, host, hlen, out_ip);
+ if (ret != 0) {
+ // TODO CPython raises: socket.gaierror: [Errno -2] Name or service not known
+ mp_raise_OSError(ret);
+ }
+ mp_obj_tuple_t *tuple = mp_obj_new_tuple(5, NULL);
+ tuple->items[0] = MP_OBJ_NEW_SMALL_INT(MOD_NETWORK_AF_INET);
+ tuple->items[1] = MP_OBJ_NEW_SMALL_INT(MOD_NETWORK_SOCK_STREAM);
+ tuple->items[2] = MP_OBJ_NEW_SMALL_INT(0);
+ tuple->items[3] = MP_OBJ_NEW_QSTR(MP_QSTR_);
+ tuple->items[4] = netutils_format_inet_addr(out_ip, port, NETUTILS_BIG);
+ return mp_obj_new_list(1, (mp_obj_t*)&tuple);
+ }
+ }
+
+ nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "no available NIC"));
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_usocket_getaddrinfo_obj, mod_usocket_getaddrinfo);
+
+STATIC const mp_rom_map_elem_t mp_module_usocket_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_usocket) },
+
+ { MP_ROM_QSTR(MP_QSTR_socket), MP_ROM_PTR(&socket_type) },
+ { MP_ROM_QSTR(MP_QSTR_getaddrinfo), MP_ROM_PTR(&mod_usocket_getaddrinfo_obj) },
+
+ // class constants
+ { MP_ROM_QSTR(MP_QSTR_AF_INET), MP_ROM_INT(MOD_NETWORK_AF_INET) },
+ { MP_ROM_QSTR(MP_QSTR_AF_INET6), MP_ROM_INT(MOD_NETWORK_AF_INET6) },
+
+ { MP_ROM_QSTR(MP_QSTR_SOCK_STREAM), MP_ROM_INT(MOD_NETWORK_SOCK_STREAM) },
+ { MP_ROM_QSTR(MP_QSTR_SOCK_DGRAM), MP_ROM_INT(MOD_NETWORK_SOCK_DGRAM) },
+ { MP_ROM_QSTR(MP_QSTR_SOCK_RAW), MP_ROM_INT(MOD_NETWORK_SOCK_RAW) },
+
+ /*
+ { MP_ROM_QSTR(MP_QSTR_IPPROTO_IP), MP_ROM_INT(MOD_NETWORK_IPPROTO_IP) },
+ { MP_ROM_QSTR(MP_QSTR_IPPROTO_ICMP), MP_ROM_INT(MOD_NETWORK_IPPROTO_ICMP) },
+ { MP_ROM_QSTR(MP_QSTR_IPPROTO_IPV4), MP_ROM_INT(MOD_NETWORK_IPPROTO_IPV4) },
+ { MP_ROM_QSTR(MP_QSTR_IPPROTO_TCP), MP_ROM_INT(MOD_NETWORK_IPPROTO_TCP) },
+ { MP_ROM_QSTR(MP_QSTR_IPPROTO_UDP), MP_ROM_INT(MOD_NETWORK_IPPROTO_UDP) },
+ { MP_ROM_QSTR(MP_QSTR_IPPROTO_IPV6), MP_ROM_INT(MOD_NETWORK_IPPROTO_IPV6) },
+ { MP_ROM_QSTR(MP_QSTR_IPPROTO_RAW), MP_ROM_INT(MOD_NETWORK_IPPROTO_RAW) },
+ */
+};
+
+STATIC MP_DEFINE_CONST_DICT(mp_module_usocket_globals, mp_module_usocket_globals_table);
+
+const mp_obj_module_t mp_module_usocket = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t*)&mp_module_usocket_globals,
+};
+
+#endif // MICROPY_PY_USOCKET
diff --git a/ports/stm32/modutime.c b/ports/stm32/modutime.c
new file mode 100644
index 000000000..54045f4c5
--- /dev/null
+++ b/ports/stm32/modutime.c
@@ -0,0 +1,153 @@
+/*
+ * 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/smallint.h"
+#include "py/obj.h"
+#include "lib/timeutils/timeutils.h"
+#include "extmod/utime_mphal.h"
+#include "systick.h"
+#include "portmodules.h"
+#include "rtc.h"
+
+/// \module time - time related functions
+///
+/// The `time` module provides functions for getting the current time and date,
+/// and for sleeping.
+
+/// \function localtime([secs])
+/// Convert a time expressed in seconds since Jan 1, 2000 into an 8-tuple which
+/// contains: (year, month, mday, hour, minute, second, weekday, yearday)
+/// If secs is not provided or None, then the current time from the RTC is used.
+/// year includes the century (for example 2014)
+/// month is 1-12
+/// mday is 1-31
+/// hour is 0-23
+/// minute is 0-59
+/// second is 0-59
+/// weekday is 0-6 for Mon-Sun.
+/// yearday is 1-366
+STATIC mp_obj_t time_localtime(size_t n_args, const mp_obj_t *args) {
+ if (n_args == 0 || args[0] == mp_const_none) {
+ // get current date and time
+ // note: need to call get time then get date to correctly access the registers
+ rtc_init_finalise();
+ RTC_DateTypeDef date;
+ RTC_TimeTypeDef time;
+ HAL_RTC_GetTime(&RTCHandle, &time, FORMAT_BIN);
+ HAL_RTC_GetDate(&RTCHandle, &date, FORMAT_BIN);
+ mp_obj_t tuple[8] = {
+ mp_obj_new_int(2000 + date.Year),
+ mp_obj_new_int(date.Month),
+ mp_obj_new_int(date.Date),
+ mp_obj_new_int(time.Hours),
+ mp_obj_new_int(time.Minutes),
+ mp_obj_new_int(time.Seconds),
+ mp_obj_new_int(date.WeekDay - 1),
+ mp_obj_new_int(timeutils_year_day(2000 + date.Year, date.Month, date.Date)),
+ };
+ return mp_obj_new_tuple(8, tuple);
+ } else {
+ mp_int_t seconds = mp_obj_get_int(args[0]);
+ timeutils_struct_time_t tm;
+ 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);
+ }
+}
+MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(time_localtime_obj, 0, 1, time_localtime);
+
+
+/// \function mktime()
+/// This is inverse function of localtime. It's argument is a full 8-tuple
+/// which expresses a time as per localtime. It returns an integer which is
+/// the number of seconds since Jan 1, 2000.
+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])));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(time_mktime_obj, time_mktime);
+
+/// \function time()
+/// Returns the number of seconds, as an integer, since 1/1/2000.
+STATIC mp_obj_t time_time(void) {
+ // get date and time
+ // note: need to call get time then get date to correctly access the registers
+ rtc_init_finalise();
+ RTC_DateTypeDef date;
+ RTC_TimeTypeDef time;
+ HAL_RTC_GetTime(&RTCHandle, &time, FORMAT_BIN);
+ HAL_RTC_GetDate(&RTCHandle, &date, 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);
+
+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 mp_module_utime = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t*)&time_module_globals,
+};
diff --git a/ports/stm32/mpconfigport.h b/ports/stm32/mpconfigport.h
new file mode 100644
index 000000000..326aa2c20
--- /dev/null
+++ b/ports/stm32/mpconfigport.h
@@ -0,0 +1,348 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2013-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.
+ */
+
+// Options to control how MicroPython is built for this port,
+// overriding defaults in py/mpconfig.h.
+
+// board specific definitions
+#include "mpconfigboard.h"
+
+// memory allocation policies
+#define MICROPY_ALLOC_PATH_MAX (128)
+
+// emitters
+#define MICROPY_PERSISTENT_CODE_LOAD (1)
+#ifndef MICROPY_EMIT_THUMB
+#define MICROPY_EMIT_THUMB (1)
+#endif
+#ifndef MICROPY_EMIT_INLINE_THUMB
+#define MICROPY_EMIT_INLINE_THUMB (1)
+#endif
+
+// compiler configuration
+#define MICROPY_COMP_MODULE_CONST (1)
+#define MICROPY_COMP_TRIPLE_TUPLE_ASSIGN (1)
+#define MICROPY_COMP_RETURN_IF_EXPR (1)
+
+// optimisations
+#define MICROPY_OPT_COMPUTED_GOTO (1)
+#define MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE (0)
+#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_EMERGENCY_EXCEPTION_BUF_SIZE (0)
+#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)
+#ifndef MICROPY_FLOAT_IMPL // can be configured by each board via mpconfigboard.mk
+#define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_FLOAT)
+#endif
+#define MICROPY_STREAMS_NON_BLOCK (1)
+#define MICROPY_MODULE_WEAK_LINKS (1)
+#define MICROPY_CAN_OVERRIDE_BUILTINS (1)
+#define MICROPY_USE_INTERNAL_ERRNO (1)
+#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_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_MEMORYVIEW (1)
+#define MICROPY_PY_BUILTINS_FROZENSET (1)
+#define MICROPY_PY_BUILTINS_SLICE_ATTRS (1)
+#define MICROPY_PY_ALL_SPECIAL_METHODS (1)
+#define MICROPY_PY_BUILTINS_COMPILE (1)
+#define MICROPY_PY_BUILTINS_EXECFILE (1)
+#define MICROPY_PY_BUILTINS_INPUT (1)
+#define MICROPY_PY_BUILTINS_POW3 (1)
+#define MICROPY_PY_BUILTINS_HELP (1)
+#define MICROPY_PY_BUILTINS_HELP_TEXT stmhal_help_text
+#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_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_SYS_MAXSIZE (1)
+#define MICROPY_PY_SYS_EXIT (1)
+#define MICROPY_PY_SYS_STDFILES (1)
+#define MICROPY_PY_SYS_STDIO_BUFFER (1)
+#ifndef MICROPY_PY_SYS_PLATFORM // let boards override it if they want
+#define MICROPY_PY_SYS_PLATFORM "pyboard"
+#endif
+#define MICROPY_PY_UERRNO (1)
+#ifndef MICROPY_PY_THREAD
+#define MICROPY_PY_THREAD (0)
+#endif
+
+// 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_UHASHLIB (1)
+#define MICROPY_PY_UBINASCII (1)
+#define MICROPY_PY_URANDOM (1)
+#define MICROPY_PY_URANDOM_EXTRA_FUNCS (1)
+#define MICROPY_PY_USELECT (1)
+#define MICROPY_PY_UTIMEQ (1)
+#define MICROPY_PY_UTIME_MP_HAL (1)
+#define MICROPY_PY_MACHINE (1)
+#define MICROPY_PY_MACHINE_PULSE (1)
+#define MICROPY_PY_MACHINE_PIN_MAKE_NEW mp_pin_make_new
+#define MICROPY_PY_MACHINE_I2C (1)
+#define MICROPY_PY_MACHINE_I2C_MAKE_NEW machine_hard_i2c_make_new
+#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_PY_FRAMEBUF (1)
+#ifndef MICROPY_PY_USOCKET
+#define MICROPY_PY_USOCKET (1)
+#endif
+#ifndef MICROPY_PY_NETWORK
+#define MICROPY_PY_NETWORK (1)
+#endif
+
+// fatfs configuration used in ffconf.h
+#define MICROPY_FATFS_ENABLE_LFN (1)
+#define MICROPY_FATFS_LFN_CODE_PAGE (437) /* 1=SFN/ANSI 437=LFN/U.S.(OEM) */
+#define MICROPY_FATFS_USE_LABEL (1)
+#define MICROPY_FATFS_RPATH (2)
+#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
+
+// 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_ROM_QSTR(MP_QSTR_open), MP_ROM_PTR(&mp_builtin_open_obj) },
+
+// extra built in modules to add to the list of known ones
+extern const struct _mp_obj_module_t machine_module;
+extern const struct _mp_obj_module_t pyb_module;
+extern const struct _mp_obj_module_t stm_module;
+extern const struct _mp_obj_module_t mp_module_ubinascii;
+extern const struct _mp_obj_module_t mp_module_ure;
+extern const struct _mp_obj_module_t mp_module_uzlib;
+extern const struct _mp_obj_module_t mp_module_ujson;
+extern const struct _mp_obj_module_t mp_module_uheapq;
+extern const struct _mp_obj_module_t mp_module_uhashlib;
+extern const struct _mp_obj_module_t mp_module_uos;
+extern const struct _mp_obj_module_t mp_module_utime;
+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
+#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) },
+#else
+#define SOCKET_BUILTIN_MODULE
+#define SOCKET_BUILTIN_MODULE_WEAK_LINKS
+#endif
+
+#if MICROPY_PY_NETWORK
+#define NETWORK_BUILTIN_MODULE { MP_ROM_QSTR(MP_QSTR_network), MP_ROM_PTR(&mp_module_network) },
+#else
+#define NETWORK_BUILTIN_MODULE
+#endif
+
+#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) }, \
+ { 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 \
+ NETWORK_BUILTIN_MODULE \
+ { MP_ROM_QSTR(MP_QSTR__onewire), MP_ROM_PTR(&mp_module_onewire) }, \
+
+#define MICROPY_PORT_BUILTIN_MODULE_WEAK_LINKS \
+ { MP_ROM_QSTR(MP_QSTR_binascii), MP_ROM_PTR(&mp_module_ubinascii) }, \
+ { MP_ROM_QSTR(MP_QSTR_collections), MP_ROM_PTR(&mp_module_collections) }, \
+ { MP_ROM_QSTR(MP_QSTR_re), MP_ROM_PTR(&mp_module_ure) }, \
+ { MP_ROM_QSTR(MP_QSTR_zlib), MP_ROM_PTR(&mp_module_uzlib) }, \
+ { MP_ROM_QSTR(MP_QSTR_json), MP_ROM_PTR(&mp_module_ujson) }, \
+ { MP_ROM_QSTR(MP_QSTR_heapq), MP_ROM_PTR(&mp_module_uheapq) }, \
+ { MP_ROM_QSTR(MP_QSTR_hashlib), MP_ROM_PTR(&mp_module_uhashlib) }, \
+ { MP_ROM_QSTR(MP_QSTR_io), MP_ROM_PTR(&mp_module_io) }, \
+ { MP_ROM_QSTR(MP_QSTR_os), MP_ROM_PTR(&mp_module_uos) }, \
+ { MP_ROM_QSTR(MP_QSTR_random), MP_ROM_PTR(&mp_module_urandom) }, \
+ { MP_ROM_QSTR(MP_QSTR_time), MP_ROM_PTR(&mp_module_utime) }, \
+ { MP_ROM_QSTR(MP_QSTR_select), MP_ROM_PTR(&mp_module_uselect) }, \
+ SOCKET_BUILTIN_MODULE_WEAK_LINKS \
+ { MP_ROM_QSTR(MP_QSTR_struct), MP_ROM_PTR(&mp_module_ustruct) }, \
+ { MP_ROM_QSTR(MP_QSTR_machine), MP_ROM_PTR(&machine_module) }, \
+ { MP_ROM_QSTR(MP_QSTR_errno), MP_ROM_PTR(&mp_module_uerrno) }, \
+
+// extra constants
+#define MICROPY_PORT_CONSTANTS \
+ { 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_UART (8)
+#else
+#define PYB_EXTI_NUM_VECTORS (23)
+#define MICROPY_HW_MAX_UART (6)
+#endif
+
+#define MP_STATE_PORT MP_STATE_VM
+
+#define MICROPY_PORT_ROOT_POINTERS \
+ const char *readline_hist[8]; \
+ \
+ mp_obj_t pyb_hid_report_desc; \
+ \
+ mp_obj_t pyb_config_main; \
+ \
+ mp_obj_t pyb_switch_callback; \
+ \
+ mp_obj_t pin_class_mapper; \
+ mp_obj_t pin_class_map_dict; \
+ \
+ mp_obj_t pyb_extint_callback[PYB_EXTI_NUM_VECTORS]; \
+ \
+ /* Used to do callbacks to Python code on interrupt */ \
+ struct _pyb_timer_obj_t *pyb_timer_obj_all[14]; \
+ \
+ /* stdio is repeated on this UART object if it's not null */ \
+ struct _pyb_uart_obj_t *pyb_stdio_uart; \
+ \
+ /* pointers to all UART objects (if they have been created) */ \
+ struct _pyb_uart_obj_t *pyb_uart_obj_all[MICROPY_HW_MAX_UART]; \
+ \
+ /* pointers to all CAN objects (if they have been created) */ \
+ struct _pyb_can_obj_t *pyb_can_obj_all[2]; \
+ \
+ /* list of registered NICs */ \
+ mp_obj_list_t mod_network_nic_list; \
+
+// type definitions for the specific machine
+
+#define MICROPY_MAKE_POINTER_CALLABLE(p) ((void*)((mp_uint_t)(p) | 1))
+
+#define MP_SSIZE_MAX (0x7fffffff)
+
+#define UINT_FMT "%u"
+#define INT_FMT "%d"
+
+typedef int mp_int_t; // must be pointer size
+typedef unsigned int mp_uint_t; // must be pointer size
+typedef long mp_off_t;
+
+#define MP_PLAT_PRINT_STRN(str, len) mp_hal_stdout_tx_strn_cooked(str, len)
+
+// We have inlined IRQ functions for efficiency (they are generally
+// 1 machine instruction).
+//
+// Note on IRQ state: you should not need to know the specific
+// value of the state variable, but rather just pass the return
+// 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);
+}
+
+static inline mp_uint_t disable_irq(void) {
+ mp_uint_t state = __get_PRIMASK();
+ __disable_irq();
+ return state;
+}
+
+#define MICROPY_BEGIN_ATOMIC_SECTION() disable_irq()
+#define MICROPY_END_ATOMIC_SECTION(state) enable_irq(state)
+
+#if MICROPY_PY_THREAD
+#define MICROPY_EVENT_POLL_HOOK \
+ do { \
+ extern void mp_handle_pending(void); \
+ mp_handle_pending(); \
+ if (pyb_thread_enabled) { \
+ MP_THREAD_GIL_EXIT(); \
+ pyb_thread_yield(); \
+ MP_THREAD_GIL_ENTER(); \
+ } else { \
+ __WFI(); \
+ } \
+ } while (0);
+#else
+#define MICROPY_EVENT_POLL_HOOK \
+ do { \
+ extern void mp_handle_pending(void); \
+ mp_handle_pending(); \
+ __WFI(); \
+ } while (0);
+#endif
+
+// There is no classical C heap in bare-metal ports, only Python
+// garbage-collected heap. For completeness, emulate C heap via
+// GC heap. Note that MicroPython core never uses malloc() and friends,
+// so these defines are mostly to help extension module writers.
+#define malloc(n) m_malloc(n)
+#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_stmhal.h"
diff --git a/ports/stm32/mpconfigport.mk b/ports/stm32/mpconfigport.mk
new file mode 100644
index 000000000..64145383e
--- /dev/null
+++ b/ports/stm32/mpconfigport.mk
@@ -0,0 +1,7 @@
+# Enable/disable extra modules
+
+# wiznet5k module for ethernet support
+MICROPY_PY_WIZNET5K ?= 0
+
+# cc3k module for wifi support
+MICROPY_PY_CC3K ?= 0
diff --git a/ports/stm32/mphalport.c b/ports/stm32/mphalport.c
new file mode 100644
index 000000000..dff781ff2
--- /dev/null
+++ b/ports/stm32/mphalport.c
@@ -0,0 +1,156 @@
+#include <string.h>
+
+#include "py/mpstate.h"
+#include "py/runtime.h"
+#include "py/mperrno.h"
+#include "py/mphal.h"
+#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,
+ [HAL_ERROR] = MP_EIO,
+ [HAL_BUSY] = MP_EBUSY,
+ [HAL_TIMEOUT] = MP_ETIMEDOUT,
+};
+
+NORETURN void mp_hal_raise(HAL_StatusTypeDef status) {
+ mp_raise_OSError(mp_hal_status_to_errno_table[status]);
+}
+
+int mp_hal_stdin_rx_chr(void) {
+ for (;;) {
+#if 0
+#ifdef USE_HOST_MODE
+ pyb_usb_host_process();
+ int c = pyb_usb_host_get_keyboard();
+ if (c != 0) {
+ return c;
+ }
+#endif
+#endif
+
+ 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))) {
+ return uart_rx_char(MP_STATE_PORT(pyb_stdio_uart));
+ }
+ MICROPY_EVENT_POLL_HOOK
+ }
+}
+
+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, size_t len) {
+ if (MP_STATE_PORT(pyb_stdio_uart) != NULL) {
+ uart_tx_strn(MP_STATE_PORT(pyb_stdio_uart), str, len);
+ }
+#if 0 && defined(USE_HOST_MODE) && MICROPY_HW_HAS_LCD
+ lcd_print_strn(str, len);
+#endif
+ if (usb_vcp_is_enabled()) {
+ usb_vcp_send_strn(str, len);
+ }
+}
+
+void mp_hal_stdout_tx_strn_cooked(const char *str, size_t len) {
+ // send stdout to UART and USB CDC VCP
+ if (MP_STATE_PORT(pyb_stdio_uart) != NULL) {
+ uart_tx_strn_cooked(MP_STATE_PORT(pyb_stdio_uart), str, len);
+ }
+ if (usb_vcp_is_enabled()) {
+ usb_vcp_send_strn_cooked(str, len);
+ }
+}
+
+void mp_hal_ticks_cpu_enable(void) {
+ if (!mp_hal_ticks_cpu_enabled) {
+ 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
+ DWT->LAR = 0xc5acce55;
+ #endif
+ DWT->CYCCNT = 0;
+ DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
+ mp_hal_ticks_cpu_enabled = true;
+ }
+}
+
+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)
+ // 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();
+ #endif
+ }
+}
+
+void mp_hal_pin_config(mp_hal_pin_obj_t pin_obj, uint32_t mode, uint32_t pull, uint32_t alt) {
+ GPIO_TypeDef *gpio = pin_obj->gpio;
+ uint32_t pin = pin_obj->pin;
+ mp_hal_gpio_clock_enable(gpio);
+ 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)));
+}
+
+bool mp_hal_pin_config_alt(mp_hal_pin_obj_t pin, uint32_t mode, uint32_t pull, uint8_t fn, uint8_t unit) {
+ const pin_af_obj_t *af = pin_find_af(pin, fn, unit);
+ if (af == NULL) {
+ return false;
+ }
+ mp_hal_pin_config(pin, mode, pull, af->idx);
+ return true;
+}
diff --git a/ports/stm32/mphalport.h b/ports/stm32/mphalport.h
new file mode 100644
index 000000000..8dd95c470
--- /dev/null
+++ b/ports/stm32/mphalport.h
@@ -0,0 +1,75 @@
+// We use the ST Cube HAL library for most hardware peripherals
+#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);
+void mp_hal_set_interrupt_char(int c); // -1 to disable
+
+// timing functions
+
+#include "stmhal/irq.h"
+
+#define mp_hal_quiet_timing_enter() raise_irq_pri(1)
+#define mp_hal_quiet_timing_exit(irq_state) restore_irq_pri(irq_state)
+#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) {
+ mp_hal_ticks_cpu_enable();
+ }
+ return DWT->CYCCNT;
+}
+
+// C-level pin HAL
+
+#include "stmhal/pin.h"
+
+#define MP_HAL_PIN_FMT "%q"
+#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 const pin_obj_t*
+#define mp_hal_get_pin_obj(o) pin_find(o)
+#define mp_hal_pin_name(p) ((p)->name)
+#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_high(p) (((p)->gpio->BSRR) = (p)->pin_mask)
+#define mp_hal_pin_low(p) (((p)->gpio->BSRR) = ((p)->pin_mask << 16))
+#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)
+#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_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);
diff --git a/ports/stm32/mpthreadport.c b/ports/stm32/mpthreadport.c
new file mode 100644
index 000000000..d7c5b569b
--- /dev/null
+++ b/ports/stm32/mpthreadport.c
@@ -0,0 +1,94 @@
+/*
+ * 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 "py/mpconfig.h"
+#include "py/mpstate.h"
+#include "py/gc.h"
+#include "py/mpthread.h"
+#include "gccollect.h"
+
+#if MICROPY_PY_THREAD
+
+// the mutex controls access to the linked list
+STATIC mp_thread_mutex_t thread_mutex;
+
+void mp_thread_init(void) {
+ mp_thread_mutex_init(&thread_mutex);
+ mp_thread_set_state(&mp_state_ctx.thread);
+}
+
+void mp_thread_gc_others(void) {
+ mp_thread_mutex_lock(&thread_mutex, 1);
+ for (pyb_thread_t *th = pyb_thread_all; th != NULL; th = th->all_next) {
+ gc_collect_root((void**)&th, 1);
+ gc_collect_root(&th->arg, 1);
+ gc_collect_root(&th->stack, 1);
+ if (th != pyb_thread_cur) {
+ gc_collect_root(th->stack, th->stack_len);
+ }
+ }
+ mp_thread_mutex_unlock(&thread_mutex);
+}
+
+void mp_thread_create(void *(*entry)(void*), void *arg, size_t *stack_size) {
+ if (*stack_size == 0) {
+ *stack_size = 4096; // default stack size
+ } else if (*stack_size < 2048) {
+ *stack_size = 2048; // minimum stack size
+ }
+
+ // round stack size to a multiple of the word size
+ size_t stack_len = *stack_size / sizeof(uint32_t);
+ *stack_size = stack_len * sizeof(uint32_t);
+
+ // allocate stack and linked-list node (must be done outside thread_mutex lock)
+ uint32_t *stack = m_new(uint32_t, stack_len);
+ pyb_thread_t *th = m_new_obj(pyb_thread_t);
+
+ mp_thread_mutex_lock(&thread_mutex, 1);
+
+ // create thread
+ uint32_t id = pyb_thread_new(th, stack, stack_len, entry, arg);
+ if (id == 0) {
+ mp_thread_mutex_unlock(&thread_mutex);
+ nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "can't create thread"));
+ }
+
+ mp_thread_mutex_unlock(&thread_mutex);
+
+ // adjust stack_size to provide room to recover from hitting the limit
+ *stack_size -= 1024;
+}
+
+void mp_thread_start(void) {
+}
+
+void mp_thread_finish(void) {
+}
+
+#endif // MICROPY_PY_THREAD
diff --git a/ports/stm32/mpthreadport.h b/ports/stm32/mpthreadport.h
new file mode 100644
index 000000000..8e2372dcb
--- /dev/null
+++ b/ports/stm32/mpthreadport.h
@@ -0,0 +1,53 @@
+/*
+ * 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 "py/mpthread.h"
+#include "pybthread.h"
+
+typedef pyb_mutex_t mp_thread_mutex_t;
+
+void mp_thread_init(void);
+void mp_thread_gc_others(void);
+
+static inline void mp_thread_set_state(void *state) {
+ pyb_thread_set_local(state);
+}
+
+static inline struct _mp_state_thread_t *mp_thread_get_state(void) {
+ return pyb_thread_get_local();
+}
+
+static inline void mp_thread_mutex_init(mp_thread_mutex_t *m) {
+ pyb_mutex_init(m);
+}
+
+static inline int mp_thread_mutex_lock(mp_thread_mutex_t *m, int wait) {
+ return pyb_mutex_lock(m, wait);
+}
+
+static inline void mp_thread_mutex_unlock(mp_thread_mutex_t *m) {
+ pyb_mutex_unlock(m);
+}
diff --git a/ports/stm32/pendsv.c b/ports/stm32/pendsv.c
new file mode 100644
index 000000000..00ea12f46
--- /dev/null
+++ b/ports/stm32/pendsv.c
@@ -0,0 +1,152 @@
+/*
+ * 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 <stdlib.h>
+
+#include "py/mpstate.h"
+#include "py/runtime.h"
+#include "lib/utils/interrupt_char.h"
+#include "pendsv.h"
+#include "irq.h"
+
+// This variable is used to save the exception object between a ctrl-C and the
+// PENDSV call that actually raises the exception. It must be non-static
+// otherwise gcc-5 optimises it away. It can point to the heap but is not
+// traced by GC. This is okay because we only ever set it to
+// mp_kbd_exception which is in the root-pointer set.
+void *pendsv_object;
+
+void pendsv_init(void) {
+ // set PendSV interrupt at lowest priority
+ HAL_NVIC_SetPriority(PendSV_IRQn, IRQ_PRI_PENDSV, IRQ_SUBPRI_PENDSV);
+}
+
+// Call this function to raise a pending exception during an interrupt.
+// It will first try to raise the exception "softly" by setting the
+// mp_pending_exception variable and hoping that the VM will notice it.
+// If this function is called a second time (ie with the mp_pending_exception
+// variable already set) then it will force the exception by using the hardware
+// PENDSV feature. This will wait until all interrupts are finished then raise
+// the given exception object using nlr_jump in the context of the top-level
+// thread.
+void pendsv_kbd_intr(void) {
+ if (MP_STATE_VM(mp_pending_exception) == MP_OBJ_NULL) {
+ mp_keyboard_interrupt();
+ } else {
+ MP_STATE_VM(mp_pending_exception) = MP_OBJ_NULL;
+ pendsv_object = &MP_STATE_VM(mp_kbd_exception);
+ SCB->ICSR = SCB_ICSR_PENDSVSET_Msk;
+ }
+}
+
+void pendsv_isr_handler(void) {
+ // re-jig the stack so that when we return from this interrupt handler
+ // it returns instead to nlr_jump with argument pendsv_object
+ // note that stack has a different layout if DEBUG is enabled
+ //
+ // on entry to this (naked) function, stack has the following layout:
+ //
+ // stack layout with DEBUG disabled:
+ // sp[6]: pc=r15
+ // sp[5]: lr=r14
+ // sp[4]: r12
+ // sp[3]: r3
+ // sp[2]: r2
+ // sp[1]: r1
+ // sp[0]: r0
+ //
+ // stack layout with DEBUG enabled:
+ // sp[8]: pc=r15
+ // sp[7]: lr=r14
+ // sp[6]: r12
+ // sp[5]: r3
+ // sp[4]: r2
+ // sp[3]: r1
+ // sp[2]: r0
+ // sp[1]: 0xfffffff9
+ // sp[0]: ?
+
+#if MICROPY_PY_THREAD
+ __asm volatile (
+ "ldr r1, pendsv_object_ptr\n"
+ "ldr r0, [r1]\n"
+ "cmp r0, 0\n"
+ "beq .no_obj\n"
+ "str r0, [sp, #0]\n" // store to r0 on stack
+ "mov r0, #0\n"
+ "str r0, [r1]\n" // clear pendsv_object
+ "ldr r0, nlr_jump_ptr\n"
+ "str r0, [sp, #24]\n" // store to pc on stack
+ "bx lr\n" // return from interrupt; will return to nlr_jump
+
+ ".no_obj:\n" // pendsv_object==NULL
+ "push {r4-r11, lr}\n"
+ "vpush {s16-s31}\n"
+ "mrs r5, primask\n" // save PRIMASK in r5
+ "cpsid i\n" // disable interrupts while we change stacks
+ "mov r0, sp\n" // pass sp to save
+ "mov r4, lr\n" // save lr because we are making a call
+ "bl pyb_thread_next\n" // get next thread to execute
+ "mov lr, r4\n" // restore lr
+ "mov sp, r0\n" // switch stacks
+ "msr primask, r5\n" // reenable interrupts
+ "vpop {s16-s31}\n"
+ "pop {r4-r11, lr}\n"
+ "bx lr\n" // return from interrupt; will return to new thread
+ ".align 2\n"
+ "pendsv_object_ptr: .word pendsv_object\n"
+ "nlr_jump_ptr: .word nlr_jump\n"
+ );
+#else
+ __asm volatile (
+ "ldr r0, pendsv_object_ptr\n"
+ "ldr r0, [r0]\n"
+#if defined(PENDSV_DEBUG)
+ "str r0, [sp, #8]\n"
+#else
+ "str r0, [sp, #0]\n"
+#endif
+ "ldr r0, nlr_jump_ptr\n"
+#if defined(PENDSV_DEBUG)
+ "str r0, [sp, #32]\n"
+#else
+ "str r0, [sp, #24]\n"
+#endif
+ "bx lr\n"
+ ".align 2\n"
+ "pendsv_object_ptr: .word pendsv_object\n"
+ "nlr_jump_ptr: .word nlr_jump\n"
+ );
+#endif
+
+ /*
+ uint32_t x[2] = {0x424242, 0xdeaddead};
+ printf("PendSV: %p\n", x);
+ for (uint32_t *p = (uint32_t*)(((uint32_t)x - 15) & 0xfffffff0), i = 64; i > 0; p += 4, i -= 4) {
+ printf(" %p: %08x %08x %08x %08x\n", p, (uint)p[0], (uint)p[1], (uint)p[2], (uint)p[3]);
+ }
+ */
+}
diff --git a/ports/stm32/pendsv.h b/ports/stm32/pendsv.h
new file mode 100644
index 000000000..6a9eb0d79
--- /dev/null
+++ b/ports/stm32/pendsv.h
@@ -0,0 +1,36 @@
+/*
+ * 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.
+ */
+#ifndef MICROPY_INCLUDED_STMHAL_PENDSV_H
+#define MICROPY_INCLUDED_STMHAL_PENDSV_H
+
+void pendsv_init(void);
+void pendsv_kbd_intr(void);
+
+// since we play tricks with the stack, the compiler must not generate a
+// prelude for this function
+void pendsv_isr_handler(void) __attribute__((naked));
+
+#endif // MICROPY_INCLUDED_STMHAL_PENDSV_H
diff --git a/ports/stm32/pin.c b/ports/stm32/pin.c
new file mode 100644
index 000000000..b7a2302b0
--- /dev/null
+++ b/ports/stm32/pin.c
@@ -0,0 +1,675 @@
+/*
+ * 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 <stdint.h>
+#include <string.h>
+
+#include "py/nlr.h"
+#include "py/runtime.h"
+#include "py/mphal.h"
+#include "extmod/virtpin.h"
+#include "pin.h"
+#include "extint.h"
+
+/// \moduleref pyb
+/// \class Pin - control I/O pins
+///
+/// A pin is the basic object to control I/O pins. It has methods to set
+/// the mode of the pin (input, output, etc) and methods to get and set the
+/// digital logic level. For analog control of a pin, see the ADC class.
+///
+/// Usage Model:
+///
+/// All Board Pins are predefined as pyb.Pin.board.Name
+///
+/// x1_pin = pyb.Pin.board.X1
+///
+/// g = pyb.Pin(pyb.Pin.board.X1, pyb.Pin.IN)
+///
+/// CPU pins which correspond to the board pins are available
+/// as `pyb.cpu.Name`. For the CPU pins, the names are the port letter
+/// followed by the pin number. On the PYBv1.0, `pyb.Pin.board.X1` and
+/// `pyb.Pin.cpu.B6` are the same pin.
+///
+/// You can also use strings:
+///
+/// g = pyb.Pin('X1', pyb.Pin.OUT_PP)
+///
+/// Users can add their own names:
+///
+/// MyMapperDict = { 'LeftMotorDir' : pyb.Pin.cpu.C12 }
+/// pyb.Pin.dict(MyMapperDict)
+/// g = pyb.Pin("LeftMotorDir", pyb.Pin.OUT_OD)
+///
+/// and can query mappings
+///
+/// pin = pyb.Pin("LeftMotorDir")
+///
+/// Users can also add their own mapping function:
+///
+/// def MyMapper(pin_name):
+/// if pin_name == "LeftMotorDir":
+/// return pyb.Pin.cpu.A0
+///
+/// pyb.Pin.mapper(MyMapper)
+///
+/// So, if you were to call: `pyb.Pin("LeftMotorDir", pyb.Pin.OUT_PP)`
+/// then `"LeftMotorDir"` is passed directly to the mapper function.
+///
+/// To summarise, the following order determines how things get mapped into
+/// an ordinal pin number:
+///
+/// 1. Directly specify a pin object
+/// 2. User supplied mapping function
+/// 3. User supplied mapping (object must be usable as a dictionary key)
+/// 4. Supply a string which matches a board pin
+/// 5. Supply a string which matches a CPU port/pin
+///
+/// You can set `pyb.Pin.debug(True)` to get some debug information about
+/// how a particular object gets mapped to a pin.
+
+// Pin class variables
+STATIC bool pin_class_debug;
+
+void pin_init0(void) {
+ MP_STATE_PORT(pin_class_mapper) = mp_const_none;
+ MP_STATE_PORT(pin_class_map_dict) = mp_const_none;
+ pin_class_debug = false;
+}
+
+// C API used to convert a user-supplied pin name into an ordinal pin number.
+const pin_obj_t *pin_find(mp_obj_t user_obj) {
+ const pin_obj_t *pin_obj;
+
+ // If a pin was provided, then use it
+ if (MP_OBJ_IS_TYPE(user_obj, &pin_type)) {
+ pin_obj = user_obj;
+ if (pin_class_debug) {
+ printf("Pin map passed pin ");
+ mp_obj_print((mp_obj_t)pin_obj, PRINT_STR);
+ printf("\n");
+ }
+ return pin_obj;
+ }
+
+ if (MP_STATE_PORT(pin_class_mapper) != mp_const_none) {
+ pin_obj = mp_call_function_1(MP_STATE_PORT(pin_class_mapper), user_obj);
+ if (pin_obj != mp_const_none) {
+ if (!MP_OBJ_IS_TYPE(pin_obj, &pin_type)) {
+ mp_raise_ValueError("Pin.mapper didn't return a Pin object");
+ }
+ if (pin_class_debug) {
+ printf("Pin.mapper maps ");
+ mp_obj_print(user_obj, PRINT_REPR);
+ printf(" to ");
+ mp_obj_print((mp_obj_t)pin_obj, PRINT_STR);
+ printf("\n");
+ }
+ return pin_obj;
+ }
+ // The pin mapping function returned mp_const_none, fall through to
+ // other lookup methods.
+ }
+
+ if (MP_STATE_PORT(pin_class_map_dict) != mp_const_none) {
+ mp_map_t *pin_map_map = mp_obj_dict_get_map(MP_STATE_PORT(pin_class_map_dict));
+ mp_map_elem_t *elem = mp_map_lookup(pin_map_map, user_obj, MP_MAP_LOOKUP);
+ if (elem != NULL && elem->value != NULL) {
+ pin_obj = elem->value;
+ if (pin_class_debug) {
+ printf("Pin.map_dict maps ");
+ mp_obj_print(user_obj, PRINT_REPR);
+ printf(" to ");
+ mp_obj_print((mp_obj_t)pin_obj, PRINT_STR);
+ printf("\n");
+ }
+ return pin_obj;
+ }
+ }
+
+ // See if the pin name matches a board pin
+ pin_obj = pin_find_named_pin(&pin_board_pins_locals_dict, user_obj);
+ if (pin_obj) {
+ if (pin_class_debug) {
+ printf("Pin.board maps ");
+ mp_obj_print(user_obj, PRINT_REPR);
+ printf(" to ");
+ mp_obj_print((mp_obj_t)pin_obj, PRINT_STR);
+ printf("\n");
+ }
+ return pin_obj;
+ }
+
+ // See if the pin name matches a cpu pin
+ pin_obj = pin_find_named_pin(&pin_cpu_pins_locals_dict, user_obj);
+ if (pin_obj) {
+ if (pin_class_debug) {
+ printf("Pin.cpu maps ");
+ mp_obj_print(user_obj, PRINT_REPR);
+ printf(" to ");
+ mp_obj_print((mp_obj_t)pin_obj, PRINT_STR);
+ printf("\n");
+ }
+ return pin_obj;
+ }
+
+ nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "Pin(%s) doesn't exist", mp_obj_str_get_str(user_obj)));
+}
+
+/// \method __str__()
+/// Return a string describing the pin object.
+STATIC void pin_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
+ pin_obj_t *self = self_in;
+
+ // pin name
+ mp_printf(print, "Pin(Pin.cpu.%q, mode=Pin.", self->name);
+
+ uint32_t mode = pin_get_mode(self);
+
+ if (mode == GPIO_MODE_ANALOG) {
+ // analog
+ mp_print_str(print, "ANALOG)");
+
+ } else {
+ // IO mode
+ bool af = false;
+ qstr mode_qst;
+ if (mode == GPIO_MODE_INPUT) {
+ mode_qst = MP_QSTR_IN;
+ } else if (mode == GPIO_MODE_OUTPUT_PP) {
+ mode_qst = MP_QSTR_OUT;
+ } else if (mode == GPIO_MODE_OUTPUT_OD) {
+ mode_qst = MP_QSTR_OPEN_DRAIN;
+ } else {
+ af = true;
+ if (mode == GPIO_MODE_AF_PP) {
+ mode_qst = MP_QSTR_ALT;
+ } else {
+ mode_qst = MP_QSTR_ALT_OPEN_DRAIN;
+ }
+ }
+ mp_print_str(print, qstr_str(mode_qst));
+
+ // pull mode
+ qstr pull_qst = MP_QSTR_NULL;
+ uint32_t pull = pin_get_pull(self);
+ if (pull == GPIO_PULLUP) {
+ pull_qst = MP_QSTR_PULL_UP;
+ } else if (pull == GPIO_PULLDOWN) {
+ pull_qst = MP_QSTR_PULL_DOWN;
+ }
+ if (pull_qst != MP_QSTR_NULL) {
+ mp_printf(print, ", pull=Pin.%q", pull_qst);
+ }
+
+ // AF mode
+ if (af) {
+ mp_uint_t af_idx = pin_get_af(self);
+ const pin_af_obj_t *af_obj = pin_find_af_by_index(self, af_idx);
+ if (af_obj == NULL) {
+ mp_printf(print, ", af=%d)", af_idx);
+ } else {
+ mp_printf(print, ", af=Pin.%q)", af_obj->name);
+ }
+ } else {
+ mp_print_str(print, ")");
+ }
+ }
+}
+
+STATIC mp_obj_t pin_obj_init_helper(const pin_obj_t *pin, size_t n_args, const mp_obj_t *args, mp_map_t *kw_args);
+
+/// \classmethod \constructor(id, ...)
+/// Create a new Pin object associated with the id. If additional arguments are given,
+/// they are used to initialise the pin. See `init`.
+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);
+
+ // Run an argument through the mapper and return the result.
+ const pin_obj_t *pin = pin_find(args[0]);
+
+ 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);
+ pin_obj_init_helper(pin, n_args - 1, args + 1, &kw_args);
+ }
+
+ return (mp_obj_t)pin;
+}
+
+// fast method for getting/setting pin value
+STATIC mp_obj_t 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);
+ pin_obj_t *self = self_in;
+ if (n_args == 0) {
+ // get pin
+ return MP_OBJ_NEW_SMALL_INT(mp_hal_pin_read(self));
+ } else {
+ // set pin
+ mp_hal_pin_write(self, mp_obj_is_true(args[0]));
+ return mp_const_none;
+ }
+}
+
+/// \classmethod mapper([fun])
+/// Get or set the pin mapper function.
+STATIC mp_obj_t pin_mapper(size_t n_args, const mp_obj_t *args) {
+ if (n_args > 1) {
+ MP_STATE_PORT(pin_class_mapper) = args[1];
+ return mp_const_none;
+ }
+ return MP_STATE_PORT(pin_class_mapper);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pin_mapper_fun_obj, 1, 2, pin_mapper);
+STATIC MP_DEFINE_CONST_CLASSMETHOD_OBJ(pin_mapper_obj, (mp_obj_t)&pin_mapper_fun_obj);
+
+/// \classmethod dict([dict])
+/// Get or set the pin mapper dictionary.
+STATIC mp_obj_t pin_map_dict(size_t n_args, const mp_obj_t *args) {
+ if (n_args > 1) {
+ MP_STATE_PORT(pin_class_map_dict) = args[1];
+ return mp_const_none;
+ }
+ return MP_STATE_PORT(pin_class_map_dict);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pin_map_dict_fun_obj, 1, 2, pin_map_dict);
+STATIC MP_DEFINE_CONST_CLASSMETHOD_OBJ(pin_map_dict_obj, (mp_obj_t)&pin_map_dict_fun_obj);
+
+/// \classmethod af_list()
+/// Returns an array of alternate functions available for this pin.
+STATIC mp_obj_t pin_af_list(mp_obj_t self_in) {
+ pin_obj_t *self = self_in;
+ mp_obj_t result = mp_obj_new_list(0, NULL);
+
+ const pin_af_obj_t *af = self->af;
+ for (mp_uint_t i = 0; i < self->num_af; i++, af++) {
+ mp_obj_list_append(result, (mp_obj_t)af);
+ }
+ return result;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(pin_af_list_obj, pin_af_list);
+
+/// \classmethod debug([state])
+/// Get or set the debugging state (`True` or `False` for on or off).
+STATIC mp_obj_t pin_debug(size_t n_args, const mp_obj_t *args) {
+ if (n_args > 1) {
+ pin_class_debug = mp_obj_is_true(args[1]);
+ return mp_const_none;
+ }
+ return mp_obj_new_bool(pin_class_debug);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pin_debug_fun_obj, 1, 2, pin_debug);
+STATIC MP_DEFINE_CONST_CLASSMETHOD_OBJ(pin_debug_obj, (mp_obj_t)&pin_debug_fun_obj);
+
+// init(mode, pull=None, af=-1, *, value, alt)
+STATIC mp_obj_t pin_obj_init_helper(const pin_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_REQUIRED | MP_ARG_INT },
+ { MP_QSTR_pull, MP_ARG_OBJ, {.u_obj = mp_const_none}},
+ { MP_QSTR_af, MP_ARG_INT, {.u_int = -1}}, // legacy
+ { MP_QSTR_value, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL}},
+ { MP_QSTR_alt, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1}},
+ };
+
+ // 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);
+
+ // get io mode
+ uint mode = args[0].u_int;
+ if (!IS_GPIO_MODE(mode)) {
+ nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "invalid pin mode: %d", mode));
+ }
+
+ // get pull mode
+ uint pull = GPIO_NOPULL;
+ if (args[1].u_obj != mp_const_none) {
+ pull = mp_obj_get_int(args[1].u_obj);
+ }
+ if (!IS_GPIO_PULL(pull)) {
+ nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "invalid pin pull: %d", pull));
+ }
+
+ // get af (alternate function); alt-arg overrides af-arg
+ mp_int_t af = args[4].u_int;
+ if (af == -1) {
+ af = args[2].u_int;
+ }
+ if ((mode == GPIO_MODE_AF_PP || mode == GPIO_MODE_AF_OD) && !IS_GPIO_AF(af)) {
+ nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "invalid pin af: %d", af));
+ }
+
+ // enable the peripheral clock for the port of this pin
+ mp_hal_gpio_clock_enable(self->gpio);
+
+ // if given, set the pin value before initialising to prevent glitches
+ if (args[3].u_obj != MP_OBJ_NULL) {
+ mp_hal_pin_write(self, mp_obj_is_true(args[3].u_obj));
+ }
+
+ // configure the GPIO as requested
+ GPIO_InitTypeDef GPIO_InitStructure;
+ GPIO_InitStructure.Pin = self->pin_mask;
+ GPIO_InitStructure.Mode = mode;
+ GPIO_InitStructure.Pull = pull;
+ GPIO_InitStructure.Speed = GPIO_SPEED_FAST;
+ GPIO_InitStructure.Alternate = af;
+ HAL_GPIO_Init(self->gpio, &GPIO_InitStructure);
+
+ return mp_const_none;
+}
+
+STATIC mp_obj_t pin_obj_init(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
+ return pin_obj_init_helper(args[0], n_args - 1, args + 1, kw_args);
+}
+MP_DEFINE_CONST_FUN_OBJ_KW(pin_init_obj, 1, pin_obj_init);
+
+/// \method value([value])
+/// Get or set the digital logic level of the pin:
+///
+/// - With no argument, return 0 or 1 depending on the logic level of the pin.
+/// - With `value` given, set the logic level of the pin. `value` can be
+/// anything that converts to a boolean. If it converts to `True`, the pin
+/// is set high, otherwise it is set low.
+STATIC mp_obj_t pin_value(size_t n_args, const mp_obj_t *args) {
+ return pin_call(args[0], n_args - 1, 0, args + 1);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pin_value_obj, 1, 2, pin_value);
+
+STATIC mp_obj_t pin_off(mp_obj_t self_in) {
+ pin_obj_t *self = self_in;
+ mp_hal_pin_low(self);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(pin_off_obj, pin_off);
+
+STATIC mp_obj_t pin_on(mp_obj_t self_in) {
+ pin_obj_t *self = self_in;
+ mp_hal_pin_high(self);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(pin_on_obj, pin_on);
+
+// pin.irq(handler=None, trigger=IRQ_FALLING|IRQ_RISING, hard=False)
+STATIC mp_obj_t pin_irq(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum { ARG_handler, ARG_trigger, ARG_hard };
+ 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_MODE_IT_RISING | GPIO_MODE_IT_FALLING} },
+ { MP_QSTR_hard, MP_ARG_BOOL, {.u_bool = false} },
+ };
+ 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
+ extint_register_pin(self, args[ARG_trigger].u_int,
+ args[ARG_hard].u_bool, args[ARG_handler].u_obj);
+ }
+
+ // TODO should return an IRQ object
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pin_irq_obj, 1, pin_irq);
+
+/// \method name()
+/// Get the pin name.
+STATIC mp_obj_t pin_name(mp_obj_t self_in) {
+ pin_obj_t *self = self_in;
+ return MP_OBJ_NEW_QSTR(self->name);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(pin_name_obj, pin_name);
+
+/// \method names()
+/// Returns the cpu and board names for this pin.
+STATIC mp_obj_t pin_names(mp_obj_t self_in) {
+ pin_obj_t *self = self_in;
+ mp_obj_t result = mp_obj_new_list(0, NULL);
+ mp_obj_list_append(result, MP_OBJ_NEW_QSTR(self->name));
+
+ mp_map_t *map = mp_obj_dict_get_map((mp_obj_t)&pin_board_pins_locals_dict);
+ mp_map_elem_t *elem = map->table;
+
+ for (mp_uint_t i = 0; i < map->used; i++, elem++) {
+ if (elem->value == self) {
+ mp_obj_list_append(result, elem->key);
+ }
+ }
+ return result;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(pin_names_obj, pin_names);
+
+/// \method port()
+/// Get the pin port.
+STATIC mp_obj_t pin_port(mp_obj_t self_in) {
+ pin_obj_t *self = self_in;
+ return MP_OBJ_NEW_SMALL_INT(self->port);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(pin_port_obj, pin_port);
+
+/// \method pin()
+/// Get the pin number.
+STATIC mp_obj_t pin_pin(mp_obj_t self_in) {
+ pin_obj_t *self = self_in;
+ return MP_OBJ_NEW_SMALL_INT(self->pin);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(pin_pin_obj, pin_pin);
+
+/// \method gpio()
+/// Returns the base address of the GPIO block associated with this pin.
+STATIC mp_obj_t pin_gpio(mp_obj_t self_in) {
+ pin_obj_t *self = self_in;
+ return MP_OBJ_NEW_SMALL_INT((mp_int_t)self->gpio);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(pin_gpio_obj, pin_gpio);
+
+/// \method mode()
+/// Returns the currently configured mode of the pin. The integer returned
+/// will match one of the allowed constants for the mode argument to the init
+/// function.
+STATIC mp_obj_t pin_mode(mp_obj_t self_in) {
+ return MP_OBJ_NEW_SMALL_INT(pin_get_mode(self_in));
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(pin_mode_obj, pin_mode);
+
+/// \method pull()
+/// Returns the currently configured pull of the pin. The integer returned
+/// will match one of the allowed constants for the pull argument to the init
+/// function.
+STATIC mp_obj_t pin_pull(mp_obj_t self_in) {
+ return MP_OBJ_NEW_SMALL_INT(pin_get_pull(self_in));
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(pin_pull_obj, pin_pull);
+
+/// \method af()
+/// Returns the currently configured alternate-function of the pin. The
+/// integer returned will match one of the allowed constants for the af
+/// argument to the init function.
+STATIC mp_obj_t pin_af(mp_obj_t self_in) {
+ return MP_OBJ_NEW_SMALL_INT(pin_get_af(self_in));
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(pin_af_obj, pin_af);
+
+STATIC const mp_rom_map_elem_t pin_locals_dict_table[] = {
+ // instance methods
+ { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&pin_init_obj) },
+ { MP_ROM_QSTR(MP_QSTR_value), MP_ROM_PTR(&pin_value_obj) },
+ { MP_ROM_QSTR(MP_QSTR_off), MP_ROM_PTR(&pin_off_obj) },
+ { MP_ROM_QSTR(MP_QSTR_on), MP_ROM_PTR(&pin_on_obj) },
+ { MP_ROM_QSTR(MP_QSTR_irq), MP_ROM_PTR(&pin_irq_obj) },
+
+ // Legacy names as used by pyb.Pin
+ { MP_ROM_QSTR(MP_QSTR_low), MP_ROM_PTR(&pin_off_obj) },
+ { MP_ROM_QSTR(MP_QSTR_high), MP_ROM_PTR(&pin_on_obj) },
+ { MP_ROM_QSTR(MP_QSTR_name), MP_ROM_PTR(&pin_name_obj) },
+ { MP_ROM_QSTR(MP_QSTR_names), MP_ROM_PTR(&pin_names_obj) },
+ { MP_ROM_QSTR(MP_QSTR_af_list), MP_ROM_PTR(&pin_af_list_obj) },
+ { MP_ROM_QSTR(MP_QSTR_port), MP_ROM_PTR(&pin_port_obj) },
+ { MP_ROM_QSTR(MP_QSTR_pin), MP_ROM_PTR(&pin_pin_obj) },
+ { MP_ROM_QSTR(MP_QSTR_gpio), MP_ROM_PTR(&pin_gpio_obj) },
+ { MP_ROM_QSTR(MP_QSTR_mode), MP_ROM_PTR(&pin_mode_obj) },
+ { MP_ROM_QSTR(MP_QSTR_pull), MP_ROM_PTR(&pin_pull_obj) },
+ { MP_ROM_QSTR(MP_QSTR_af), MP_ROM_PTR(&pin_af_obj) },
+
+ // class methods
+ { MP_ROM_QSTR(MP_QSTR_mapper), MP_ROM_PTR(&pin_mapper_obj) },
+ { MP_ROM_QSTR(MP_QSTR_dict), MP_ROM_PTR(&pin_map_dict_obj) },
+ { MP_ROM_QSTR(MP_QSTR_debug), MP_ROM_PTR(&pin_debug_obj) },
+
+ // class attributes
+ { MP_ROM_QSTR(MP_QSTR_board), MP_ROM_PTR(&pin_board_pins_obj_type) },
+ { MP_ROM_QSTR(MP_QSTR_cpu), MP_ROM_PTR(&pin_cpu_pins_obj_type) },
+
+ // 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_OUTPUT_PP) },
+ { MP_ROM_QSTR(MP_QSTR_OPEN_DRAIN), MP_ROM_INT(GPIO_MODE_OUTPUT_OD) },
+ { MP_ROM_QSTR(MP_QSTR_ALT), MP_ROM_INT(GPIO_MODE_AF_PP) },
+ { MP_ROM_QSTR(MP_QSTR_ALT_OPEN_DRAIN), MP_ROM_INT(GPIO_MODE_AF_OD) },
+ { MP_ROM_QSTR(MP_QSTR_ANALOG), MP_ROM_INT(GPIO_MODE_ANALOG) },
+ { MP_ROM_QSTR(MP_QSTR_PULL_UP), MP_ROM_INT(GPIO_PULLUP) },
+ { MP_ROM_QSTR(MP_QSTR_PULL_DOWN), MP_ROM_INT(GPIO_PULLDOWN) },
+ { MP_ROM_QSTR(MP_QSTR_IRQ_RISING), MP_ROM_INT(GPIO_MODE_IT_RISING) },
+ { MP_ROM_QSTR(MP_QSTR_IRQ_FALLING), MP_ROM_INT(GPIO_MODE_IT_FALLING) },
+
+ // legacy class constants
+ { MP_ROM_QSTR(MP_QSTR_OUT_PP), MP_ROM_INT(GPIO_MODE_OUTPUT_PP) },
+ { MP_ROM_QSTR(MP_QSTR_OUT_OD), MP_ROM_INT(GPIO_MODE_OUTPUT_OD) },
+ { MP_ROM_QSTR(MP_QSTR_AF_PP), MP_ROM_INT(GPIO_MODE_AF_PP) },
+ { MP_ROM_QSTR(MP_QSTR_AF_OD), MP_ROM_INT(GPIO_MODE_AF_OD) },
+ { MP_ROM_QSTR(MP_QSTR_PULL_NONE), MP_ROM_INT(GPIO_NOPULL) },
+
+#include "genhdr/pins_af_const.h"
+};
+
+STATIC MP_DEFINE_CONST_DICT(pin_locals_dict, pin_locals_dict_table);
+
+STATIC mp_uint_t pin_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) {
+ (void)errcode;
+ pin_obj_t *self = self_in;
+
+ switch (request) {
+ case MP_PIN_READ: {
+ return mp_hal_pin_read(self);
+ }
+ case MP_PIN_WRITE: {
+ mp_hal_pin_write(self, arg);
+ return 0;
+ }
+ }
+ return -1;
+}
+
+STATIC const mp_pin_p_t pin_pin_p = {
+ .ioctl = pin_ioctl,
+};
+
+const mp_obj_type_t pin_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_Pin,
+ .print = pin_print,
+ .make_new = mp_pin_make_new,
+ .call = pin_call,
+ .protocol = &pin_pin_p,
+ .locals_dict = (mp_obj_dict_t*)&pin_locals_dict,
+};
+
+/// \moduleref pyb
+/// \class PinAF - Pin Alternate Functions
+///
+/// A Pin represents a physical pin on the microcprocessor. Each pin
+/// can have a variety of functions (GPIO, I2C SDA, etc). Each PinAF
+/// object represents a particular function for a pin.
+///
+/// Usage Model:
+///
+/// x3 = pyb.Pin.board.X3
+/// x3_af = x3.af_list()
+///
+/// x3_af will now contain an array of PinAF objects which are availble on
+/// pin X3.
+///
+/// For the pyboard, x3_af would contain:
+/// [Pin.AF1_TIM2, Pin.AF2_TIM5, Pin.AF3_TIM9, Pin.AF7_USART2]
+///
+/// Normally, each peripheral would configure the af automatically, but sometimes
+/// the same function is available on multiple pins, and having more control
+/// is desired.
+///
+/// To configure X3 to expose TIM2_CH3, you could use:
+/// pin = pyb.Pin(pyb.Pin.board.X3, mode=pyb.Pin.AF_PP, af=pyb.Pin.AF1_TIM2)
+/// or:
+/// pin = pyb.Pin(pyb.Pin.board.X3, mode=pyb.Pin.AF_PP, af=1)
+
+/// \method __str__()
+/// Return a string describing the alternate function.
+STATIC void pin_af_obj_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
+ pin_af_obj_t *self = self_in;
+ mp_printf(print, "Pin.%q", self->name);
+}
+
+/// \method index()
+/// Return the alternate function index.
+STATIC mp_obj_t pin_af_index(mp_obj_t self_in) {
+ pin_af_obj_t *af = self_in;
+ return MP_OBJ_NEW_SMALL_INT(af->idx);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(pin_af_index_obj, pin_af_index);
+
+/// \method name()
+/// Return the name of the alternate function.
+STATIC mp_obj_t pin_af_name(mp_obj_t self_in) {
+ pin_af_obj_t *af = self_in;
+ return MP_OBJ_NEW_QSTR(af->name);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(pin_af_name_obj, pin_af_name);
+
+/// \method reg()
+/// Return the base register associated with the peripheral assigned to this
+/// alternate function. For example, if the alternate function were TIM2_CH3
+/// this would return stm.TIM2
+STATIC mp_obj_t pin_af_reg(mp_obj_t self_in) {
+ pin_af_obj_t *af = self_in;
+ return MP_OBJ_NEW_SMALL_INT((mp_uint_t)af->reg);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(pin_af_reg_obj, pin_af_reg);
+
+STATIC const mp_rom_map_elem_t pin_af_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_index), MP_ROM_PTR(&pin_af_index_obj) },
+ { MP_ROM_QSTR(MP_QSTR_name), MP_ROM_PTR(&pin_af_name_obj) },
+ { MP_ROM_QSTR(MP_QSTR_reg), MP_ROM_PTR(&pin_af_reg_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(pin_af_locals_dict, pin_af_locals_dict_table);
+
+const mp_obj_type_t pin_af_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_PinAF,
+ .print = pin_af_obj_print,
+ .locals_dict = (mp_obj_dict_t*)&pin_af_locals_dict,
+};
diff --git a/ports/stm32/pin.h b/ports/stm32/pin.h
new file mode 100644
index 000000000..90de79e5c
--- /dev/null
+++ b/ports/stm32/pin.h
@@ -0,0 +1,100 @@
+/*
+ * 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.
+ */
+#ifndef MICROPY_INCLUDED_STMHAL_PIN_H
+#define MICROPY_INCLUDED_STMHAL_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
+
+#include MICROPY_PIN_DEFS_PORT_H
+#include "py/obj.h"
+
+typedef struct {
+ mp_obj_base_t base;
+ qstr name;
+ uint8_t idx;
+ uint8_t fn;
+ uint8_t unit;
+ uint8_t type;
+
+ union {
+ void *reg;
+
+ PIN_DEFS_PORT_AF_UNION
+ };
+} pin_af_obj_t;
+
+typedef struct {
+ mp_obj_base_t base;
+ qstr name;
+ uint32_t port : 4;
+ uint32_t pin : 5; // Some ARM processors use 32 bits/PORT
+ uint32_t num_af : 4;
+ uint32_t adc_channel : 5; // Some ARM processors use 32 bits/PORT
+ uint32_t adc_num : 3; // 1 bit per ADC
+ uint32_t pin_mask;
+ pin_gpio_t *gpio;
+ const pin_af_obj_t *af;
+} pin_obj_t;
+
+extern const mp_obj_type_t pin_type;
+extern const mp_obj_type_t pin_af_type;
+
+typedef struct {
+ const char *name;
+ const pin_obj_t *pin;
+} pin_named_pin_t;
+
+extern const pin_named_pin_t pin_board_pins[];
+extern const pin_named_pin_t pin_cpu_pins[];
+
+//extern pin_map_obj_t pin_map_obj;
+
+typedef struct {
+ mp_obj_base_t base;
+ qstr name;
+ const pin_named_pin_t *named_pins;
+} pin_named_pins_obj_t;
+
+extern const mp_obj_type_t pin_board_pins_obj_type;
+extern const mp_obj_type_t pin_cpu_pins_obj_type;
+
+extern const mp_obj_dict_t pin_cpu_pins_locals_dict;
+extern const mp_obj_dict_t pin_board_pins_locals_dict;
+
+MP_DECLARE_CONST_FUN_OBJ_KW(pin_init_obj);
+
+void pin_init0(void);
+uint32_t pin_get_mode(const pin_obj_t *pin);
+uint32_t pin_get_pull(const pin_obj_t *pin);
+uint32_t pin_get_af(const pin_obj_t *pin);
+const pin_obj_t *pin_find(mp_obj_t user_obj);
+const pin_obj_t *pin_find_named_pin(const mp_obj_dict_t *named_pins, mp_obj_t name);
+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
diff --git a/ports/stm32/pin_defs_stmhal.c b/ports/stm32/pin_defs_stmhal.c
new file mode 100644
index 000000000..0aef5f95f
--- /dev/null
+++ b/ports/stm32/pin_defs_stmhal.c
@@ -0,0 +1,31 @@
+#include "py/obj.h"
+#include "pin.h"
+
+// Returns the pin mode. This value returned by this macro should be one of:
+// GPIO_MODE_INPUT, GPIO_MODE_OUTPUT_PP, GPIO_MODE_OUTPUT_OD,
+// GPIO_MODE_AF_PP, GPIO_MODE_AF_OD, or GPIO_MODE_ANALOG.
+
+uint32_t pin_get_mode(const pin_obj_t *pin) {
+ GPIO_TypeDef *gpio = pin->gpio;
+ uint32_t mode = (gpio->MODER >> (pin->pin * 2)) & 3;
+ if (mode != GPIO_MODE_ANALOG) {
+ if (gpio->OTYPER & pin->pin_mask) {
+ mode |= 1 << 4;
+ }
+ }
+ return mode;
+}
+
+// Returns the pin pullup/pulldown. The value returned by this macro should
+// be one of GPIO_NOPULL, GPIO_PULLUP, or GPIO_PULLDOWN.
+
+uint32_t pin_get_pull(const pin_obj_t *pin) {
+ return (pin->gpio->PUPDR >> (pin->pin * 2)) & 3;
+}
+
+// Returns the af (alternate function) index currently set for a pin.
+
+uint32_t pin_get_af(const pin_obj_t *pin) {
+ return (pin->gpio->AFR[pin->pin >> 3] >> ((pin->pin & 7) * 4)) & 0xf;
+}
+
diff --git a/ports/stm32/pin_defs_stmhal.h b/ports/stm32/pin_defs_stmhal.h
new file mode 100644
index 000000000..6cf3b1b83
--- /dev/null
+++ b/ports/stm32/pin_defs_stmhal.h
@@ -0,0 +1,131 @@
+/*
+ * 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.
+ */
+
+// This file contains pin definitions that are specific to the stmhal port.
+// This file should only ever be #included by pin.h and not directly.
+
+enum {
+ PORT_A,
+ PORT_B,
+ PORT_C,
+ PORT_D,
+ PORT_E,
+ PORT_F,
+ PORT_G,
+ PORT_H,
+ PORT_I,
+ PORT_J,
+ PORT_K,
+};
+
+enum {
+ AF_FN_TIM,
+ AF_FN_I2C,
+ AF_FN_USART,
+ AF_FN_UART = AF_FN_USART,
+ AF_FN_SPI,
+ AF_FN_I2S,
+ AF_FN_SDMMC,
+};
+
+enum {
+ AF_PIN_TYPE_TIM_CH1 = 0,
+ AF_PIN_TYPE_TIM_CH2,
+ AF_PIN_TYPE_TIM_CH3,
+ AF_PIN_TYPE_TIM_CH4,
+ AF_PIN_TYPE_TIM_CH1N,
+ AF_PIN_TYPE_TIM_CH2N,
+ AF_PIN_TYPE_TIM_CH3N,
+ AF_PIN_TYPE_TIM_CH1_ETR,
+ AF_PIN_TYPE_TIM_ETR,
+ AF_PIN_TYPE_TIM_BKIN,
+
+ AF_PIN_TYPE_I2C_SDA = 0,
+ AF_PIN_TYPE_I2C_SCL,
+
+ AF_PIN_TYPE_USART_TX = 0,
+ AF_PIN_TYPE_USART_RX,
+ AF_PIN_TYPE_USART_CTS,
+ AF_PIN_TYPE_USART_RTS,
+ AF_PIN_TYPE_USART_CK,
+ AF_PIN_TYPE_UART_TX = AF_PIN_TYPE_USART_TX,
+ AF_PIN_TYPE_UART_RX = AF_PIN_TYPE_USART_RX,
+ AF_PIN_TYPE_UART_CTS = AF_PIN_TYPE_USART_CTS,
+ AF_PIN_TYPE_UART_RTS = AF_PIN_TYPE_USART_RTS,
+
+ AF_PIN_TYPE_SPI_MOSI = 0,
+ AF_PIN_TYPE_SPI_MISO,
+ AF_PIN_TYPE_SPI_SCK,
+ AF_PIN_TYPE_SPI_NSS,
+
+ AF_PIN_TYPE_I2S_CK = 0,
+ AF_PIN_TYPE_I2S_MCK,
+ AF_PIN_TYPE_I2S_SD,
+ AF_PIN_TYPE_I2S_WS,
+ AF_PIN_TYPE_I2S_EXTSD,
+
+ AF_PIN_TYPE_SDMMC_CK = 0,
+ AF_PIN_TYPE_SDMMC_CMD,
+ AF_PIN_TYPE_SDMMC_D0,
+ AF_PIN_TYPE_SDMMC_D1,
+ AF_PIN_TYPE_SDMMC_D2,
+ AF_PIN_TYPE_SDMMC_D3,
+};
+
+// The HAL uses a slightly different naming than we chose, so we provide
+// some #defines to massage things. Also I2S and SPI share the same
+// peripheral.
+
+#define GPIO_AF5_I2S2 GPIO_AF5_SPI2
+#define GPIO_AF5_I2S3 GPIO_AF5_I2S3ext
+#define GPIO_AF6_I2S2 GPIO_AF6_I2S2ext
+#define GPIO_AF6_I2S3 GPIO_AF6_SPI3
+#define GPIO_AF7_I2S2 GPIO_AF7_SPI2
+#define GPIO_AF7_I2S3 GPIO_AF7_I2S3ext
+
+#define I2S2 SPI2
+#define I2S3 SPI3
+
+enum {
+ PIN_ADC1 = (1 << 0),
+ PIN_ADC2 = (1 << 1),
+ 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/pin_named_pins.c b/ports/stm32/pin_named_pins.c
new file mode 100644
index 000000000..726da54dd
--- /dev/null
+++ b/ports/stm32/pin_named_pins.c
@@ -0,0 +1,85 @@
+/*
+ * 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 "pin.h"
+
+const mp_obj_type_t pin_cpu_pins_obj_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_cpu,
+ .locals_dict = (mp_obj_t)&pin_cpu_pins_locals_dict,
+};
+
+const mp_obj_type_t pin_board_pins_obj_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_board,
+ .locals_dict = (mp_obj_t)&pin_board_pins_locals_dict,
+};
+
+const pin_obj_t *pin_find_named_pin(const mp_obj_dict_t *named_pins, mp_obj_t name) {
+ mp_map_t *named_map = mp_obj_dict_get_map((mp_obj_t)named_pins);
+ mp_map_elem_t *named_elem = mp_map_lookup(named_map, name, MP_MAP_LOOKUP);
+ if (named_elem != NULL && named_elem->value != NULL) {
+ return named_elem->value;
+ }
+ return NULL;
+}
+
+const pin_af_obj_t *pin_find_af(const pin_obj_t *pin, uint8_t fn, uint8_t unit) {
+ const pin_af_obj_t *af = pin->af;
+ for (mp_uint_t i = 0; i < pin->num_af; i++, af++) {
+ if (af->fn == fn && af->unit == unit) {
+ return af;
+ }
+ }
+ return NULL;
+}
+
+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 *af = pin->af;
+ for (mp_uint_t i = 0; i < pin->num_af; i++, af++) {
+ if (af->idx == af_idx) {
+ return af;
+ }
+ }
+ return NULL;
+}
+
+/* unused
+const pin_af_obj_t *pin_find_af_by_name(const pin_obj_t *pin, const char *name) {
+ const pin_af_obj_t *af = pin->af;
+ for (mp_uint_t i = 0; i < pin->num_af; i++, af++) {
+ if (strcmp(name, qstr_str(af->name)) == 0) {
+ return af;
+ }
+ }
+ return NULL;
+}
+*/
diff --git a/ports/stm32/portmodules.h b/ports/stm32/portmodules.h
new file mode 100644
index 000000000..b575109b8
--- /dev/null
+++ b/ports/stm32/portmodules.h
@@ -0,0 +1,43 @@
+/*
+ * 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.
+ */
+#ifndef MICROPY_INCLUDED_STMHAL_PORTMODULES_H
+#define MICROPY_INCLUDED_STMHAL_PORTMODULES_H
+
+extern const mp_obj_module_t pyb_module;
+extern const mp_obj_module_t stm_module;
+extern const mp_obj_module_t mp_module_uos;
+extern const mp_obj_module_t mp_module_utime;
+extern const mp_obj_module_t mp_module_usocket;
+
+// additional helper functions exported by the modules
+
+MP_DECLARE_CONST_FUN_OBJ_1(time_sleep_ms_obj);
+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
diff --git a/ports/stm32/pybcdc.inf_template b/ports/stm32/pybcdc.inf_template
new file mode 100644
index 000000000..85279ada3
--- /dev/null
+++ b/ports/stm32/pybcdc.inf_template
@@ -0,0 +1,92 @@
+; Windows USB CDC ACM Setup File
+; Based on INF files which were:
+; Copyright (c) 2000 Microsoft Corporation
+; Copyright (C) 2007 Microchip Technology Inc.
+; Likely to be covered by the MLPL as found at:
+; <http://msdn.microsoft.com/en-us/cc300389.aspx#MLPL>.
+
+[Version]
+Signature="$Windows NT$"
+Class=Ports
+ClassGuid={4D36E978-E325-11CE-BFC1-08002BE10318}
+Provider=%MFGNAME%
+LayoutFile=layout.inf
+DriverVer=03/11/2010,5.1.2600.3
+
+[Manufacturer]
+%MFGNAME%=DeviceList, NTamd64
+
+[DestinationDirs]
+DefaultDestDir=12
+
+;---------------------------------------------------------------------
+; Windows 2000/XP/Server2003/Vista/Server2008/7 - 32bit Sections
+
+[DriverInstall.nt]
+include=mdmcpq.inf
+CopyFiles=DriverCopyFiles.nt
+AddReg=DriverInstall.nt.AddReg
+
+[DriverCopyFiles.nt]
+usbser.sys,,,0x20
+
+[DriverInstall.nt.AddReg]
+HKR,,DevLoader,,*ntkern
+HKR,,NTMPDriver,,usbser.sys
+HKR,,EnumPropPages32,,"MsPorts.dll,SerialPortPropPageProvider"
+
+[DriverInstall.nt.Services]
+AddService=usbser, 0x00000002, DriverService.nt
+
+[DriverService.nt]
+DisplayName=%SERVICE%
+ServiceType=1
+StartType=3
+ErrorControl=1
+ServiceBinary=%12%\usbser.sys
+
+;---------------------------------------------------------------------
+; Windows XP/Server2003/Vista/Server2008/7 - 64bit Sections
+
+[DriverInstall.NTamd64]
+include=mdmcpq.inf
+CopyFiles=DriverCopyFiles.NTamd64
+AddReg=DriverInstall.NTamd64.AddReg
+
+[DriverCopyFiles.NTamd64]
+usbser.sys,,,0x20
+
+[DriverInstall.NTamd64.AddReg]
+HKR,,DevLoader,,*ntkern
+HKR,,NTMPDriver,,usbser.sys
+HKR,,EnumPropPages32,,"MsPorts.dll,SerialPortPropPageProvider"
+
+[DriverInstall.NTamd64.Services]
+AddService=usbser, 0x00000002, DriverService.NTamd64
+
+[DriverService.NTamd64]
+DisplayName=%SERVICE%
+ServiceType=1
+StartType=3
+ErrorControl=1
+ServiceBinary=%12%\usbser.sys
+
+;---------------------------------------------------------------------
+; Vendor and Product ID Definitions
+
+[SourceDisksFiles]
+[SourceDisksNames]
+[DeviceList]
+%DESCRIPTION%=DriverInstall, USB\VID_${USB_VID}&PID_${USB_PID_CDC_MSC}&MI_00, USB\VID_${USB_VID}&PID_${USB_PID_CDC_MSC}&MI_01, USB\VID_${USB_VID}&PID_${USB_PID_CDC_HID}&MI_00, USB\VID_${USB_VID}&PID_${USB_PID_CDC_HID}&MI_01, USB\VID_${USB_VID}&PID_${USB_PID_CDC}
+
+[DeviceList.NTamd64]
+%DESCRIPTION%=DriverInstall, USB\VID_${USB_VID}&PID_${USB_PID_CDC_MSC}&MI_00, USB\VID_${USB_VID}&PID_${USB_PID_CDC_MSC}&MI_01, USB\VID_${USB_VID}&PID_${USB_PID_CDC_HID}&MI_00, USB\VID_${USB_VID}&PID_${USB_PID_CDC_HID}&MI_01, USB\VID_${USB_VID}&PID_${USB_PID_CDC}
+
+;---------------------------------------------------------------------
+; String Definitions
+
+[Strings]
+MFGFILENAME="pybcdc"
+MFGNAME="MicroPython"
+DESCRIPTION="Pyboard USB Comm Port"
+SERVICE="USB Serial Driver"
diff --git a/ports/stm32/pybthread.c b/ports/stm32/pybthread.c
new file mode 100644
index 000000000..6baf88f66
--- /dev/null
+++ b/ports/stm32/pybthread.c
@@ -0,0 +1,237 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 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 <string.h>
+#include <stdio.h>
+
+#include "py/obj.h"
+#include "gccollect.h"
+#include "irq.h"
+#include "pybthread.h"
+
+#if MICROPY_PY_THREAD
+
+#define PYB_MUTEX_UNLOCKED ((void*)0)
+#define PYB_MUTEX_LOCKED ((void*)1)
+
+// These macros are used when we only need to protect against a thread
+// switch; other interrupts are still allowed to proceed.
+#define RAISE_IRQ_PRI() raise_irq_pri(IRQ_PRI_PENDSV)
+#define RESTORE_IRQ_PRI(state) restore_irq_pri(state)
+
+extern void __fatal_error(const char*);
+
+volatile int pyb_thread_enabled;
+pyb_thread_t *volatile pyb_thread_all;
+pyb_thread_t *volatile pyb_thread_cur;
+
+static inline void pyb_thread_add_to_runable(pyb_thread_t *thread) {
+ thread->run_prev = pyb_thread_cur->run_prev;
+ thread->run_next = pyb_thread_cur;
+ pyb_thread_cur->run_prev->run_next = thread;
+ pyb_thread_cur->run_prev = thread;
+}
+
+static inline void pyb_thread_remove_from_runable(pyb_thread_t *thread) {
+ if (thread->run_next == thread) {
+ __fatal_error("deadlock");
+ }
+ thread->run_prev->run_next = thread->run_next;
+ thread->run_next->run_prev = thread->run_prev;
+}
+
+void pyb_thread_init(pyb_thread_t *thread) {
+ pyb_thread_enabled = 0;
+ pyb_thread_all = thread;
+ pyb_thread_cur = thread;
+ thread->sp = NULL; // will be set when this thread switches out
+ thread->local_state = 0; // will be set by mp_thread_init
+ thread->arg = NULL;
+ thread->stack = &_heap_end;
+ thread->stack_len = ((uint32_t)&_estack - (uint32_t)&_heap_end) / sizeof(uint32_t);
+ thread->all_next = NULL;
+ thread->run_prev = thread;
+ thread->run_next = thread;
+ thread->queue_next = NULL;
+}
+
+void pyb_thread_deinit() {
+ uint32_t irq_state = disable_irq();
+ pyb_thread_enabled = 0;
+ pyb_thread_all = pyb_thread_cur;
+ pyb_thread_cur->all_next = NULL;
+ pyb_thread_cur->run_prev = pyb_thread_cur;
+ pyb_thread_cur->run_next = pyb_thread_cur;
+ enable_irq(irq_state);
+}
+
+STATIC void pyb_thread_terminate(void) {
+ uint32_t irq_state = disable_irq();
+ pyb_thread_t *thread = pyb_thread_cur;
+ // take current thread off the run list
+ pyb_thread_remove_from_runable(thread);
+ // take current thread off the list of all threads
+ for (pyb_thread_t **n = (pyb_thread_t**)&pyb_thread_all;; n = &(*n)->all_next) {
+ if (*n == thread) {
+ *n = thread->all_next;
+ break;
+ }
+ }
+ // clean pointers as much as possible to help GC
+ thread->all_next = NULL;
+ thread->queue_next = NULL;
+ thread->stack = NULL;
+ if (pyb_thread_all->all_next == NULL) {
+ // only 1 thread left
+ pyb_thread_enabled = 0;
+ }
+ // thread switch will occur after we enable irqs
+ SCB->ICSR = SCB_ICSR_PENDSVSET_Msk;
+ enable_irq(irq_state);
+ // should not return
+ __fatal_error("could not terminate");
+}
+
+uint32_t pyb_thread_new(pyb_thread_t *thread, void *stack, size_t stack_len, void *entry, void *arg) {
+ uint32_t *stack_top = (uint32_t*)stack + stack_len; // stack is full descending
+ *--stack_top = 0x01000000; // xPSR (thumb bit set)
+ *--stack_top = (uint32_t)entry & 0xfffffffe; // pc (must have bit 0 cleared, even for thumb code)
+ *--stack_top = (uint32_t)pyb_thread_terminate; // lr
+ *--stack_top = 0; // r12
+ *--stack_top = 0; // r3
+ *--stack_top = 0; // r2
+ *--stack_top = 0; // r1
+ *--stack_top = (uint32_t)arg; // r0
+ *--stack_top = 0xfffffff9; // lr (return to thread mode, non-FP, use MSP)
+ stack_top -= 8; // r4-r11
+ stack_top -= 16; // s16-s31 (we assume all threads use FP registers)
+ thread->sp = stack_top;
+ thread->local_state = 0;
+ thread->arg = arg;
+ thread->stack = stack;
+ thread->stack_len = stack_len;
+ thread->queue_next = NULL;
+ uint32_t irq_state = disable_irq();
+ pyb_thread_enabled = 1;
+ thread->all_next = pyb_thread_all;
+ pyb_thread_all = thread;
+ pyb_thread_add_to_runable(thread);
+ enable_irq(irq_state);
+ return (uint32_t)thread; // success
+}
+
+void pyb_thread_dump(void) {
+ if (!pyb_thread_enabled) {
+ printf("THREAD: only main thread\n");
+ } else {
+ printf("THREAD:\n");
+ for (pyb_thread_t *th = pyb_thread_all; th != NULL; th = th->all_next) {
+ bool runable = false;
+ for (pyb_thread_t *th2 = pyb_thread_cur;; th2 = th2->run_next) {
+ if (th == th2) {
+ runable = true;
+ break;
+ }
+ if (th2->run_next == pyb_thread_cur) {
+ break;
+ }
+ }
+ printf(" id=%p sp=%p sz=%u", th, th->stack, th->stack_len);
+ if (runable) {
+ printf(" (runable)");
+ }
+ printf("\n");
+ }
+ }
+}
+
+// should only be called from pendsv_isr_handler
+void *pyb_thread_next(void *sp) {
+ pyb_thread_cur->sp = sp;
+ pyb_thread_cur = pyb_thread_cur->run_next;
+ pyb_thread_cur->timeslice = 4; // in milliseconds
+ return pyb_thread_cur->sp;
+}
+
+void pyb_mutex_init(pyb_mutex_t *m) {
+ *m = PYB_MUTEX_UNLOCKED;
+}
+
+int pyb_mutex_lock(pyb_mutex_t *m, int wait) {
+ uint32_t irq_state = RAISE_IRQ_PRI();
+ if (*m == PYB_MUTEX_UNLOCKED) {
+ // mutex is available
+ *m = PYB_MUTEX_LOCKED;
+ RESTORE_IRQ_PRI(irq_state);
+ } else {
+ // mutex is locked
+ if (!wait) {
+ RESTORE_IRQ_PRI(irq_state);
+ return 0; // failed to lock mutex
+ }
+ if (*m == PYB_MUTEX_LOCKED) {
+ *m = pyb_thread_cur;
+ } else {
+ for (pyb_thread_t *n = *m;; n = n->queue_next) {
+ if (n->queue_next == NULL) {
+ n->queue_next = pyb_thread_cur;
+ break;
+ }
+ }
+ }
+ pyb_thread_cur->queue_next = NULL;
+ // take current thread off the run list
+ pyb_thread_remove_from_runable(pyb_thread_cur);
+ // thread switch will occur after we enable irqs
+ SCB->ICSR = SCB_ICSR_PENDSVSET_Msk;
+ RESTORE_IRQ_PRI(irq_state);
+ // when we come back we have the mutex
+ }
+ return 1; // have mutex
+}
+
+void pyb_mutex_unlock(pyb_mutex_t *m) {
+ uint32_t irq_state = RAISE_IRQ_PRI();
+ if (*m == PYB_MUTEX_LOCKED) {
+ // no threads are blocked on the mutex
+ *m = PYB_MUTEX_UNLOCKED;
+ } else {
+ // at least one thread is blocked on this mutex
+ pyb_thread_t *th = *m;
+ if (th->queue_next == NULL) {
+ // no other threads are blocked
+ *m = PYB_MUTEX_LOCKED;
+ } else {
+ // at least one other thread is still blocked
+ *m = th->queue_next;
+ }
+ // put unblocked thread on runable list
+ pyb_thread_add_to_runable(th);
+ }
+ RESTORE_IRQ_PRI(irq_state);
+}
+
+#endif // MICROPY_PY_THREAD
diff --git a/ports/stm32/pybthread.h b/ports/stm32/pybthread.h
new file mode 100644
index 000000000..f628f934b
--- /dev/null
+++ b/ports/stm32/pybthread.h
@@ -0,0 +1,77 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 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.
+ */
+#ifndef MICROPY_INCLUDED_STMHAL_PYBTHREAD_H
+#define MICROPY_INCLUDED_STMHAL_PYBTHREAD_H
+
+typedef struct _pyb_thread_t {
+ void *sp;
+ uint32_t local_state;
+ void *arg; // thread Python args, a GC root pointer
+ void *stack; // pointer to the stack
+ size_t stack_len; // number of words in the stack
+ uint32_t timeslice;
+ struct _pyb_thread_t *all_next;
+ struct _pyb_thread_t *run_prev;
+ struct _pyb_thread_t *run_next;
+ struct _pyb_thread_t *queue_next;
+} pyb_thread_t;
+
+typedef pyb_thread_t *pyb_mutex_t;
+
+extern volatile int pyb_thread_enabled;
+extern pyb_thread_t *volatile pyb_thread_all;
+extern pyb_thread_t *volatile pyb_thread_cur;
+
+void pyb_thread_init(pyb_thread_t *th);
+void pyb_thread_deinit();
+uint32_t pyb_thread_new(pyb_thread_t *th, void *stack, size_t stack_len, void *entry, void *arg);
+void pyb_thread_dump(void);
+
+static inline uint32_t pyb_thread_get_id(void) {
+ return (uint32_t)pyb_thread_cur;
+}
+
+static inline void pyb_thread_set_local(void *value) {
+ pyb_thread_cur->local_state = (uint32_t)value;
+}
+
+static inline void *pyb_thread_get_local(void) {
+ return (void*)pyb_thread_cur->local_state;
+}
+
+static inline void pyb_thread_yield(void) {
+ if (pyb_thread_cur->run_next == pyb_thread_cur) {
+ __WFI();
+ } else {
+ SCB->ICSR = SCB_ICSR_PENDSVSET_Msk;
+ }
+}
+
+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
diff --git a/ports/stm32/qstrdefsport.h b/ports/stm32/qstrdefsport.h
new file mode 100644
index 000000000..31220c5a4
--- /dev/null
+++ b/ports/stm32/qstrdefsport.h
@@ -0,0 +1,47 @@
+/*
+ * 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.
+ */
+
+// qstrs specific to this port
+
+Q(boot.py)
+Q(main.py)
+// Entries for sys.path
+Q(/flash)
+Q(/flash/lib)
+Q(/sd)
+Q(/sd/lib)
+// for usb modes
+Q(MSC+HID)
+Q(VCP+MSC)
+Q(VCP+HID)
+Q(CDC+MSC)
+Q(CDC+HID)
+Q(/)
+
+
+// The following qstrings not referenced from anywhere in the sources
+Q(CDC)
+Q(flash)
diff --git a/ports/stm32/rng.c b/ports/stm32/rng.c
new file mode 100644
index 000000000..c0c5e9aeb
--- /dev/null
+++ b/ports/stm32/rng.c
@@ -0,0 +1,67 @@
+/*
+ * 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 <string.h>
+
+#include "py/obj.h"
+#include "rng.h"
+
+#if MICROPY_HW_ENABLE_RNG
+
+/// \moduleref pyb
+
+STATIC RNG_HandleTypeDef RNGHandle = {.Instance = NULL};
+
+void rng_init0(void) {
+ // reset the RNG handle
+ memset(&RNGHandle, 0, sizeof(RNG_HandleTypeDef));
+ RNGHandle.Instance = RNG;
+}
+
+void rng_init(void) {
+ __RNG_CLK_ENABLE();
+ HAL_RNG_Init(&RNGHandle);
+}
+
+uint32_t rng_get(void) {
+ if (RNGHandle.State == HAL_RNG_STATE_RESET) {
+ rng_init();
+ }
+ return HAL_RNG_GetRandomNumber(&RNGHandle);
+}
+
+/// \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);
+}
+
+MP_DEFINE_CONST_FUN_OBJ_0(pyb_rng_get_obj, pyb_rng_get);
+
+#endif // MICROPY_HW_ENABLE_RNG
diff --git a/ports/stm32/rng.h b/ports/stm32/rng.h
new file mode 100644
index 000000000..43e49fe72
--- /dev/null
+++ b/ports/stm32/rng.h
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ */
+#ifndef MICROPY_INCLUDED_STMHAL_RNG_H
+#define MICROPY_INCLUDED_STMHAL_RNG_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
diff --git a/ports/stm32/rtc.c b/ports/stm32/rtc.c
new file mode 100644
index 000000000..73272d363
--- /dev/null
+++ b/ports/stm32/rtc.c
@@ -0,0 +1,730 @@
+/*
+ * 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 "py/runtime.h"
+#include "rtc.h"
+#include "irq.h"
+
+/// \moduleref pyb
+/// \class RTC - real time clock
+///
+/// The RTC is and independent clock that keeps track of the date
+/// and time.
+///
+/// Example usage:
+///
+/// rtc = pyb.RTC()
+/// rtc.datetime((2014, 5, 1, 4, 13, 0, 0, 0))
+/// print(rtc.datetime())
+
+RTC_HandleTypeDef RTCHandle;
+
+// rtc_info indicates various things about RTC startup
+// it's a bit of a hack at the moment
+static mp_uint_t rtc_info;
+
+// Note: LSI is around (32KHz), these dividers should work either way
+// ck_spre(1Hz) = RTCCLK(LSE) /(uwAsynchPrediv + 1)*(uwSynchPrediv + 1)
+// modify RTC_ASYNCH_PREDIV & RTC_SYNCH_PREDIV in board/<BN>/mpconfigport.h to change sub-second ticks
+// default is 3906.25 µs, min is ~30.52 µs (will increas Ivbat by ~500nA)
+#ifndef RTC_ASYNCH_PREDIV
+#define RTC_ASYNCH_PREDIV (0x7f)
+#endif
+#ifndef RTC_SYNCH_PREDIV
+#define RTC_SYNCH_PREDIV (0x00ff)
+#endif
+
+STATIC HAL_StatusTypeDef PYB_RTC_Init(RTC_HandleTypeDef *hrtc);
+STATIC void PYB_RTC_MspInit_Kick(RTC_HandleTypeDef *hrtc, bool rtc_use_lse);
+STATIC HAL_StatusTypeDef PYB_RTC_MspInit_Finalise(RTC_HandleTypeDef *hrtc);
+STATIC void RTC_CalendarConfig(void);
+
+#if defined(MICROPY_HW_RTC_USE_LSE) && MICROPY_HW_RTC_USE_LSE
+STATIC bool rtc_use_lse = true;
+#else
+STATIC bool rtc_use_lse = false;
+#endif
+STATIC uint32_t rtc_startup_tick;
+STATIC bool rtc_need_init_finalise = false;
+
+// check if LSE exists
+// not well tested, should probably be removed
+STATIC bool lse_magic(void) {
+#if 0
+ uint32_t mode_in = GPIOC->MODER & 0x3fffffff;
+ uint32_t mode_out = mode_in | 0x40000000;
+ GPIOC->MODER = mode_out;
+ GPIOC->OTYPER &= 0x7fff;
+ GPIOC->BSRRH = 0x8000;
+ GPIOC->OSPEEDR &= 0x3fffffff;
+ GPIOC->PUPDR &= 0x3fffffff;
+ int i = 0xff0;
+ __IO int d = 0;
+ uint32_t tc = 0;
+ __IO uint32_t j;
+ while (i) {
+ GPIOC->MODER = mode_out;
+ GPIOC->MODER = mode_in;
+ for (j = 0; j < d; j++) ;
+ i--;
+ if ((GPIOC->IDR & 0x8000) == 0) {
+ tc++;
+ }
+ }
+ return (tc < 0xff0)?true:false;
+#else
+ return false;
+#endif
+}
+
+void rtc_init_start(bool force_init) {
+ RTCHandle.Instance = RTC;
+
+ /* Configure RTC prescaler and RTC data registers */
+ /* RTC configured as follow:
+ - Hour Format = Format 24
+ - Asynch Prediv = Value according to source clock
+ - Synch Prediv = Value according to source clock
+ - OutPut = Output Disable
+ - OutPutPolarity = High Polarity
+ - OutPutType = Open Drain */
+ RTCHandle.Init.HourFormat = RTC_HOURFORMAT_24;
+ RTCHandle.Init.AsynchPrediv = RTC_ASYNCH_PREDIV;
+ RTCHandle.Init.SynchPrediv = RTC_SYNCH_PREDIV;
+ RTCHandle.Init.OutPut = RTC_OUTPUT_DISABLE;
+ RTCHandle.Init.OutPutPolarity = RTC_OUTPUT_POLARITY_HIGH;
+ RTCHandle.Init.OutPutType = RTC_OUTPUT_TYPE_OPENDRAIN;
+
+ rtc_need_init_finalise = false;
+
+ if (!force_init) {
+ if ((RCC->BDCR & (RCC_BDCR_LSEON | RCC_BDCR_LSERDY)) == (RCC_BDCR_LSEON | RCC_BDCR_LSERDY)) {
+ // LSE is enabled & ready --> no need to (re-)init RTC
+ // remove Backup Domain write protection
+ HAL_PWR_EnableBkUpAccess();
+ // Clear source Reset Flag
+ __HAL_RCC_CLEAR_RESET_FLAGS();
+ // 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
+ // remove Backup Domain write protection
+ HAL_PWR_EnableBkUpAccess();
+ // Clear source Reset Flag
+ __HAL_RCC_CLEAR_RESET_FLAGS();
+ RCC->CSR |= 1;
+ // provide some status information
+ rtc_info |= 0x80000 | (RCC->BDCR & 7) | (RCC->CSR & 3) << 8;
+ return;
+ }
+ }
+
+ rtc_startup_tick = HAL_GetTick();
+ rtc_info = 0x3f000000 | (rtc_startup_tick & 0xffffff);
+ if (rtc_use_lse) {
+ if (lse_magic()) {
+ // don't even try LSE
+ rtc_use_lse = false;
+ rtc_info &= ~0x01000000;
+ }
+ }
+ PYB_RTC_MspInit_Kick(&RTCHandle, rtc_use_lse);
+}
+
+void rtc_init_finalise() {
+ if (!rtc_need_init_finalise) {
+ return;
+ }
+
+ rtc_info = 0x20000000 | (rtc_use_lse << 28);
+ if (PYB_RTC_Init(&RTCHandle) != HAL_OK) {
+ if (rtc_use_lse) {
+ // fall back to LSI...
+ rtc_use_lse = false;
+ rtc_startup_tick = HAL_GetTick();
+ PYB_RTC_MspInit_Kick(&RTCHandle, rtc_use_lse);
+ HAL_PWR_EnableBkUpAccess();
+ RTCHandle.State = HAL_RTC_STATE_RESET;
+ if (PYB_RTC_Init(&RTCHandle) != HAL_OK) {
+ rtc_info = 0x0100ffff; // indicate error
+ return;
+ }
+ } else {
+ // init error
+ rtc_info = 0xffff; // indicate error
+ return;
+ }
+ }
+
+ // 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(__HAL_RCC_GET_FLAG(RCC_FLAG_BORRST) != RESET) {
+ #else
+ if(__HAL_RCC_GET_FLAG(RCC_FLAG_PORRST) != RESET) {
+ #endif
+ // power on reset occurred
+ rtc_info |= 0x10000;
+ }
+ if(__HAL_RCC_GET_FLAG(RCC_FLAG_PINRST) != RESET) {
+ // external reset occurred
+ rtc_info |= 0x20000;
+ }
+ // Clear source Reset Flag
+ __HAL_RCC_CLEAR_RESET_FLAGS();
+ rtc_need_init_finalise = false;
+}
+
+STATIC HAL_StatusTypeDef PYB_RCC_OscConfig(RCC_OscInitTypeDef *RCC_OscInitStruct) {
+ /*------------------------------ LSI Configuration -------------------------*/
+ if ((RCC_OscInitStruct->OscillatorType & RCC_OSCILLATORTYPE_LSI) == RCC_OSCILLATORTYPE_LSI) {
+ // Check the LSI State
+ if (RCC_OscInitStruct->LSIState != RCC_LSI_OFF) {
+ // Enable the Internal Low Speed oscillator (LSI).
+ __HAL_RCC_LSI_ENABLE();
+ } else {
+ // Disable the Internal Low Speed oscillator (LSI).
+ __HAL_RCC_LSI_DISABLE();
+ }
+ }
+
+ /*------------------------------ LSE Configuration -------------------------*/
+ if ((RCC_OscInitStruct->OscillatorType & RCC_OSCILLATORTYPE_LSE) == RCC_OSCILLATORTYPE_LSE) {
+ // Enable Power Clock
+ __PWR_CLK_ENABLE();
+ HAL_PWR_EnableBkUpAccess();
+ uint32_t tickstart = HAL_GetTick();
+
+ #if defined(MCU_SERIES_F7) || defined(MCU_SERIES_L4)
+ //__HAL_RCC_PWR_CLK_ENABLE();
+ // Enable write access to Backup domain
+ //PWR->CR1 |= PWR_CR1_DBP;
+ // Wait for Backup domain Write protection disable
+ while ((PWR->CR1 & PWR_CR1_DBP) == RESET) {
+ if (HAL_GetTick() - tickstart > RCC_DBP_TIMEOUT_VALUE) {
+ return HAL_TIMEOUT;
+ }
+ }
+ #else
+ // Enable write access to Backup domain
+ //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) {
+ return HAL_TIMEOUT;
+ }
+ }
+ #endif
+
+ // Set the new LSE configuration
+ __HAL_RCC_LSE_CONFIG(RCC_OscInitStruct->LSEState);
+ }
+
+ return HAL_OK;
+}
+
+STATIC HAL_StatusTypeDef PYB_RTC_Init(RTC_HandleTypeDef *hrtc) {
+ // Check the RTC peripheral state
+ if (hrtc == NULL) {
+ return HAL_ERROR;
+ }
+ if (hrtc->State == HAL_RTC_STATE_RESET) {
+ // Allocate lock resource and initialize it
+ hrtc->Lock = HAL_UNLOCKED;
+ // Initialize RTC MSP
+ if (PYB_RTC_MspInit_Finalise(hrtc) != HAL_OK) {
+ return HAL_ERROR;
+ }
+ }
+
+ // Set RTC state
+ hrtc->State = HAL_RTC_STATE_BUSY;
+
+ // Disable the write protection for RTC registers
+ __HAL_RTC_WRITEPROTECTION_DISABLE(hrtc);
+
+ // Set Initialization mode
+ if (RTC_EnterInitMode(hrtc) != HAL_OK) {
+ // Enable the write protection for RTC registers
+ __HAL_RTC_WRITEPROTECTION_ENABLE(hrtc);
+
+ // Set RTC state
+ hrtc->State = HAL_RTC_STATE_ERROR;
+
+ return HAL_ERROR;
+ } else {
+ // Clear RTC_CR FMT, OSEL and POL Bits
+ hrtc->Instance->CR &= ((uint32_t)~(RTC_CR_FMT | RTC_CR_OSEL | RTC_CR_POL));
+ // Set RTC_CR register
+ hrtc->Instance->CR |= (uint32_t)(hrtc->Init.HourFormat | hrtc->Init.OutPut | hrtc->Init.OutPutPolarity);
+
+ // Configure the RTC PRER
+ hrtc->Instance->PRER = (uint32_t)(hrtc->Init.SynchPrediv);
+ hrtc->Instance->PRER |= (uint32_t)(hrtc->Init.AsynchPrediv << 16);
+
+ // Exit Initialization mode
+ hrtc->Instance->ISR &= (uint32_t)~RTC_ISR_INIT;
+
+ #if defined(MCU_SERIES_L4)
+ hrtc->Instance->OR &= (uint32_t)~RTC_OR_ALARMOUTTYPE;
+ hrtc->Instance->OR |= (uint32_t)(hrtc->Init.OutPutType);
+ #elif defined(MCU_SERIES_F7)
+ hrtc->Instance->OR &= (uint32_t)~RTC_OR_ALARMTYPE;
+ hrtc->Instance->OR |= (uint32_t)(hrtc->Init.OutPutType);
+ #else
+ hrtc->Instance->TAFCR &= (uint32_t)~RTC_TAFCR_ALARMOUTTYPE;
+ hrtc->Instance->TAFCR |= (uint32_t)(hrtc->Init.OutPutType);
+ #endif
+
+ // Enable the write protection for RTC registers
+ __HAL_RTC_WRITEPROTECTION_ENABLE(hrtc);
+
+ // Set RTC state
+ hrtc->State = HAL_RTC_STATE_READY;
+
+ return HAL_OK;
+ }
+}
+
+STATIC void PYB_RTC_MspInit_Kick(RTC_HandleTypeDef *hrtc, bool rtc_use_lse) {
+ /* To change the source clock of the RTC feature (LSE, LSI), You have to:
+ - Enable the power clock using __PWR_CLK_ENABLE()
+ - Enable write access using HAL_PWR_EnableBkUpAccess() function before to
+ configure the RTC clock source (to be done once after reset).
+ - Reset the Back up Domain using __HAL_RCC_BACKUPRESET_FORCE() and
+ __HAL_RCC_BACKUPRESET_RELEASE().
+ - Configure the needed RTc clock source */
+
+ // RTC clock source uses LSE (external crystal) only if relevant
+ // configuration variable is set. Otherwise it uses LSI (internal osc).
+
+ RCC_OscInitTypeDef RCC_OscInitStruct;
+ RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSI | RCC_OSCILLATORTYPE_LSE;
+ RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
+ if (rtc_use_lse) {
+ RCC_OscInitStruct.LSEState = RCC_LSE_ON;
+ RCC_OscInitStruct.LSIState = RCC_LSI_OFF;
+ } else {
+ RCC_OscInitStruct.LSEState = RCC_LSE_OFF;
+ RCC_OscInitStruct.LSIState = RCC_LSI_ON;
+ }
+ PYB_RCC_OscConfig(&RCC_OscInitStruct);
+
+ // now ramp up osc. in background and flag calendear init needed
+ rtc_need_init_finalise = true;
+}
+
+#define PYB_LSE_TIMEOUT_VALUE 1000 // ST docs spec 2000 ms LSE startup, seems to be too pessimistic
+#define PYB_LSI_TIMEOUT_VALUE 500 // this is way too pessimistic, typ. < 1ms
+
+STATIC HAL_StatusTypeDef PYB_RTC_MspInit_Finalise(RTC_HandleTypeDef *hrtc) {
+ // we already had a kick so now wait for the corresponding ready state...
+ if (rtc_use_lse) {
+ // we now have to wait for LSE ready or timeout
+ uint32_t tickstart = rtc_startup_tick;
+ while (__HAL_RCC_GET_FLAG(RCC_FLAG_LSERDY) == RESET) {
+ if ((HAL_GetTick() - tickstart ) > PYB_LSE_TIMEOUT_VALUE) {
+ return HAL_TIMEOUT;
+ }
+ }
+ } else {
+ // we now have to wait for LSI ready or timeout
+ uint32_t tickstart = rtc_startup_tick;
+ while (__HAL_RCC_GET_FLAG(RCC_FLAG_LSIRDY) == RESET) {
+ if ((HAL_GetTick() - tickstart ) > PYB_LSI_TIMEOUT_VALUE) {
+ return HAL_TIMEOUT;
+ }
+ }
+ }
+
+ RCC_PeriphCLKInitTypeDef PeriphClkInitStruct;
+ PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_RTC;
+ if (rtc_use_lse) {
+ PeriphClkInitStruct.RTCClockSelection = RCC_RTCCLKSOURCE_LSE;
+ } else {
+ PeriphClkInitStruct.RTCClockSelection = RCC_RTCCLKSOURCE_LSI;
+ }
+ if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK) {
+ //Error_Handler();
+ return HAL_ERROR;
+ }
+
+ // enable RTC peripheral clock
+ __HAL_RCC_RTC_ENABLE();
+ return HAL_OK;
+}
+
+STATIC void RTC_CalendarConfig(void) {
+ // set the date to 1st Jan 2015
+ RTC_DateTypeDef date;
+ date.Year = 15;
+ date.Month = 1;
+ date.Date = 1;
+ date.WeekDay = RTC_WEEKDAY_THURSDAY;
+
+ if(HAL_RTC_SetDate(&RTCHandle, &date, FORMAT_BIN) != HAL_OK) {
+ // init error
+ return;
+ }
+
+ // set the time to 00:00:00
+ RTC_TimeTypeDef time;
+ time.Hours = 0;
+ time.Minutes = 0;
+ time.Seconds = 0;
+ time.TimeFormat = RTC_HOURFORMAT12_AM;
+ time.DayLightSaving = RTC_DAYLIGHTSAVING_NONE;
+ time.StoreOperation = RTC_STOREOPERATION_RESET;
+
+ if (HAL_RTC_SetTime(&RTCHandle, &time, FORMAT_BIN) != HAL_OK) {
+ // init error
+ return;
+ }
+}
+
+/******************************************************************************/
+// MicroPython bindings
+
+typedef struct _pyb_rtc_obj_t {
+ mp_obj_base_t base;
+} pyb_rtc_obj_t;
+
+STATIC const pyb_rtc_obj_t pyb_rtc_obj = {{&pyb_rtc_type}};
+
+/// \classmethod \constructor()
+/// Create an RTC object.
+STATIC mp_obj_t pyb_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)&pyb_rtc_obj;
+}
+
+// force rtc to re-initialise
+mp_obj_t pyb_rtc_init(mp_obj_t self_in) {
+ rtc_init_start(true);
+ rtc_init_finalise();
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_1(pyb_rtc_init_obj, pyb_rtc_init);
+
+/// \method info()
+/// Get information about the startup time and reset source.
+///
+/// - The lower 0xffff are the number of milliseconds the RTC took to
+/// start up.
+/// - Bit 0x10000 is set if a power-on reset occurred.
+/// - Bit 0x20000 is set if an external reset occurred
+mp_obj_t pyb_rtc_info(mp_obj_t self_in) {
+ return mp_obj_new_int(rtc_info);
+}
+MP_DEFINE_CONST_FUN_OBJ_1(pyb_rtc_info_obj, pyb_rtc_info);
+
+/// \method datetime([datetimetuple])
+/// Get or set the date and time of the RTC.
+///
+/// With no arguments, this method returns an 8-tuple with the current
+/// date and time. With 1 argument (being an 8-tuple) it sets the date
+/// and time.
+///
+/// The 8-tuple has the following format:
+///
+/// (year, month, day, weekday, hours, minutes, seconds, subseconds)
+///
+/// `weekday` is 1-7 for Monday through Sunday.
+///
+/// `subseconds` counts down from 255 to 0
+
+#define MEG_DIV_64 (1000000 / 64)
+#define MEG_DIV_SCALE ((RTC_SYNCH_PREDIV + 1) / 64)
+
+#if defined(MICROPY_HW_RTC_USE_US) && MICROPY_HW_RTC_USE_US
+uint32_t rtc_subsec_to_us(uint32_t ss) {
+ return ((RTC_SYNCH_PREDIV - ss) * MEG_DIV_64) / MEG_DIV_SCALE;
+}
+
+uint32_t rtc_us_to_subsec(uint32_t us) {
+ return RTC_SYNCH_PREDIV - (us * MEG_DIV_SCALE / MEG_DIV_64);
+}
+#else
+#define rtc_us_to_subsec
+#define rtc_subsec_to_us
+#endif
+
+mp_obj_t pyb_rtc_datetime(size_t n_args, const mp_obj_t *args) {
+ rtc_init_finalise();
+ if (n_args == 1) {
+ // get date and time
+ // 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);
+ mp_obj_t tuple[8] = {
+ mp_obj_new_int(2000 + date.Year),
+ mp_obj_new_int(date.Month),
+ mp_obj_new_int(date.Date),
+ mp_obj_new_int(date.WeekDay),
+ mp_obj_new_int(time.Hours),
+ mp_obj_new_int(time.Minutes),
+ mp_obj_new_int(time.Seconds),
+ mp_obj_new_int(rtc_subsec_to_us(time.SubSeconds)),
+ };
+ return mp_obj_new_tuple(8, tuple);
+ } else {
+ // set date and time
+ mp_obj_t *items;
+ mp_obj_get_array_fixed_n(args[1], 8, &items);
+
+ RTC_DateTypeDef date;
+ date.Year = mp_obj_get_int(items[0]) - 2000;
+ 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);
+
+ 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);
+
+ return mp_const_none;
+ }
+}
+MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_rtc_datetime_obj, 1, 2, pyb_rtc_datetime);
+
+// wakeup(None)
+// wakeup(ms, callback=None)
+// wakeup(wucksel, wut, callback)
+mp_obj_t pyb_rtc_wakeup(size_t n_args, const mp_obj_t *args) {
+ // wut is wakeup counter start value, wucksel is clock source
+ // counter is decremented at wucksel rate, and wakes the MCU when it gets to 0
+ // wucksel=0b000 is RTC/16 (RTC runs at 32768Hz)
+ // wucksel=0b001 is RTC/8
+ // wucksel=0b010 is RTC/4
+ // wucksel=0b011 is RTC/2
+ // wucksel=0b100 is 1Hz clock
+ // wucksel=0b110 is 1Hz clock with 0x10000 added to wut
+ // so a 1 second wakeup could be wut=2047, wucksel=0b000, or wut=4095, wucksel=0b001, etc
+
+ rtc_init_finalise();
+
+ // disable wakeup IRQ while we configure it
+ HAL_NVIC_DisableIRQ(RTC_WKUP_IRQn);
+
+ bool enable = false;
+ mp_int_t wucksel;
+ mp_int_t wut;
+ mp_obj_t callback = mp_const_none;
+ if (n_args <= 3) {
+ if (args[1] == mp_const_none) {
+ // disable wakeup
+ } else {
+ // time given in ms
+ mp_int_t ms = mp_obj_get_int(args[1]);
+ mp_int_t div = 2;
+ wucksel = 3;
+ while (div <= 16 && ms > 2000 * div) {
+ div *= 2;
+ wucksel -= 1;
+ }
+ if (div <= 16) {
+ wut = 32768 / div * ms / 1000;
+ } else {
+ // use 1Hz clock
+ wucksel = 4;
+ wut = ms / 1000;
+ if (wut > 0x10000) {
+ // wut too large for 16-bit register, try to offset by 0x10000
+ wucksel = 6;
+ wut -= 0x10000;
+ if (wut > 0x10000) {
+ // wut still too large
+ mp_raise_ValueError("wakeup value too large");
+ }
+ }
+ }
+ // wut register should be 1 less than desired value, but guard against wut=0
+ if (wut > 0) {
+ wut -= 1;
+ }
+ enable = true;
+ }
+ if (n_args == 3) {
+ callback = args[2];
+ }
+ } else {
+ // config values given directly
+ wucksel = mp_obj_get_int(args[1]);
+ wut = mp_obj_get_int(args[2]);
+ callback = args[3];
+ enable = true;
+ }
+
+ // set the callback
+ MP_STATE_PORT(pyb_extint_callback)[22] = callback;
+
+ // disable register write protection
+ RTC->WPR = 0xca;
+ RTC->WPR = 0x53;
+
+ // clear WUTE
+ RTC->CR &= ~(1 << 10);
+
+ // wait until WUTWF is set
+ while (!(RTC->ISR & (1 << 2))) {
+ }
+
+ if (enable) {
+ // program WUT
+ RTC->WUTR = wut;
+
+ // set WUTIE to enable wakeup interrupts
+ // set WUTE to enable wakeup
+ // program WUCKSEL
+ RTC->CR = (RTC->CR & ~7) | (1 << 14) | (1 << 10) | (wucksel & 7);
+
+ // enable register write protection
+ RTC->WPR = 0xff;
+
+ // enable external interrupts on line 22
+ #if defined(MCU_SERIES_L4)
+ EXTI->IMR1 |= 1 << 22;
+ EXTI->RTSR1 |= 1 << 22;
+ #else
+ EXTI->IMR |= 1 << 22;
+ EXTI->RTSR |= 1 << 22;
+ #endif
+
+ // clear interrupt flags
+ RTC->ISR &= ~(1 << 10);
+ #if defined(MCU_SERIES_L4)
+ EXTI->PR1 = 1 << 22;
+ #else
+ EXTI->PR = 1 << 22;
+ #endif
+
+ HAL_NVIC_SetPriority(RTC_WKUP_IRQn, IRQ_PRI_RTC_WKUP, IRQ_SUBPRI_RTC_WKUP);
+ HAL_NVIC_EnableIRQ(RTC_WKUP_IRQn);
+
+ //printf("wut=%d wucksel=%d\n", wut, wucksel);
+ } else {
+ // clear WUTIE to disable interrupts
+ RTC->CR &= ~(1 << 14);
+
+ // enable register write protection
+ RTC->WPR = 0xff;
+
+ // disable external interrupts on line 22
+ #if defined(MCU_SERIES_L4)
+ EXTI->IMR1 &= ~(1 << 22);
+ #else
+ EXTI->IMR &= ~(1 << 22);
+ #endif
+ }
+
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_rtc_wakeup_obj, 2, 4, pyb_rtc_wakeup);
+
+// calibration(None)
+// calibration(cal)
+// When an integer argument is provided, check that it falls in the range [-511 to 512]
+// and set the calibration value; otherwise return calibration value
+mp_obj_t pyb_rtc_calibration(size_t n_args, const mp_obj_t *args) {
+ rtc_init_finalise();
+ mp_int_t cal;
+ if (n_args == 2) {
+ cal = mp_obj_get_int(args[1]);
+ mp_uint_t cal_p, cal_m;
+ if (cal < -511 || cal > 512) {
+#if defined(MICROPY_HW_RTC_USE_CALOUT) && MICROPY_HW_RTC_USE_CALOUT
+ if ((cal & 0xfffe) == 0x0ffe) {
+ // turn on/off X18 (PC13) 512Hz output
+ // Note:
+ // Output will stay active even in VBAT mode (and inrease current)
+ if (cal & 1) {
+ HAL_RTCEx_SetCalibrationOutPut(&RTCHandle, RTC_CALIBOUTPUT_512HZ);
+ } else {
+ HAL_RTCEx_DeactivateCalibrationOutPut(&RTCHandle);
+ }
+ return mp_obj_new_int(cal & 1);
+ } else {
+ mp_raise_ValueError("calibration value out of range");
+ }
+#else
+ mp_raise_ValueError("calibration value out of range");
+#endif
+ }
+ if (cal > 0) {
+ cal_p = RTC_SMOOTHCALIB_PLUSPULSES_SET;
+ cal_m = 512 - cal;
+ } else {
+ cal_p = RTC_SMOOTHCALIB_PLUSPULSES_RESET;
+ cal_m = -cal;
+ }
+ HAL_RTCEx_SetSmoothCalib(&RTCHandle, RTC_SMOOTHCALIB_PERIOD_32SEC, cal_p, cal_m);
+ return mp_const_none;
+ } else {
+ // printf("CALR = 0x%x\n", (mp_uint_t) RTCHandle.Instance->CALR); // DEBUG
+ // Test if CALP bit is set in CALR:
+ if (RTCHandle.Instance->CALR & 0x8000) {
+ cal = 512 - (RTCHandle.Instance->CALR & 0x1ff);
+ } else {
+ cal = -(RTCHandle.Instance->CALR & 0x1ff);
+ }
+ return mp_obj_new_int(cal);
+ }
+}
+MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_rtc_calibration_obj, 1, 2, pyb_rtc_calibration);
+
+STATIC const mp_rom_map_elem_t pyb_rtc_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&pyb_rtc_init_obj) },
+ { MP_ROM_QSTR(MP_QSTR_info), MP_ROM_PTR(&pyb_rtc_info_obj) },
+ { MP_ROM_QSTR(MP_QSTR_datetime), MP_ROM_PTR(&pyb_rtc_datetime_obj) },
+ { MP_ROM_QSTR(MP_QSTR_wakeup), MP_ROM_PTR(&pyb_rtc_wakeup_obj) },
+ { MP_ROM_QSTR(MP_QSTR_calibration), MP_ROM_PTR(&pyb_rtc_calibration_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(pyb_rtc_locals_dict, pyb_rtc_locals_dict_table);
+
+const mp_obj_type_t pyb_rtc_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_RTC,
+ .make_new = pyb_rtc_make_new,
+ .locals_dict = (mp_obj_dict_t*)&pyb_rtc_locals_dict,
+};
diff --git a/ports/stm32/rtc.h b/ports/stm32/rtc.h
new file mode 100644
index 000000000..09ab2aedf
--- /dev/null
+++ b/ports/stm32/rtc.h
@@ -0,0 +1,35 @@
+/*
+ * 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.
+ */
+#ifndef MICROPY_INCLUDED_STMHAL_RTC_H
+#define MICROPY_INCLUDED_STMHAL_RTC_H
+
+extern RTC_HandleTypeDef RTCHandle;
+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
diff --git a/ports/stm32/sdcard.c b/ports/stm32/sdcard.c
new file mode 100644
index 000000000..27276332a
--- /dev/null
+++ b/ports/stm32/sdcard.c
@@ -0,0 +1,547 @@
+/*
+ * 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 <string.h>
+
+#include "py/nlr.h"
+#include "py/runtime.h"
+#include "py/mphal.h"
+#include "lib/oofatfs/ff.h"
+#include "extmod/vfs_fat.h"
+
+#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)
+
+// 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
+// is used, otherwise SDMMC1 is used.
+
+#if defined(MICROPY_HW_SDMMC2_CK)
+#define SDIO SDMMC2
+#define SDMMC_CLK_ENABLE() __HAL_RCC_SDMMC2_CLK_ENABLE()
+#define SDMMC_CLK_DISABLE() __HAL_RCC_SDMMC2_CLK_DISABLE()
+#define SDMMC_IRQn SDMMC2_IRQn
+#define SDMMC_TX_DMA dma_SDMMC_2_TX
+#define SDMMC_RX_DMA dma_SDMMC_2_RX
+#else
+#define SDIO SDMMC1
+#define SDMMC_CLK_ENABLE() __HAL_RCC_SDMMC1_CLK_ENABLE()
+#define SDMMC_CLK_DISABLE() __HAL_RCC_SDMMC1_CLK_DISABLE()
+#define SDMMC_IRQn SDMMC1_IRQn
+#define SDMMC_TX_DMA dma_SDIO_0_TX
+#define SDMMC_RX_DMA dma_SDIO_0_RX
+#endif
+
+// The F7 & L4 series calls the peripheral SDMMC rather than SDIO, so provide some
+// #defines for backwards compatability.
+
+#define SDIO_CLOCK_EDGE_RISING SDMMC_CLOCK_EDGE_RISING
+#define SDIO_CLOCK_EDGE_FALLING SDMMC_CLOCK_EDGE_FALLING
+
+#define SDIO_CLOCK_BYPASS_DISABLE SDMMC_CLOCK_BYPASS_DISABLE
+#define SDIO_CLOCK_BYPASS_ENABLE SDMMC_CLOCK_BYPASS_ENABLE
+
+#define SDIO_CLOCK_POWER_SAVE_DISABLE SDMMC_CLOCK_POWER_SAVE_DISABLE
+#define SDIO_CLOCK_POWER_SAVE_ENABLE SDMMC_CLOCK_POWER_SAVE_ENABLE
+
+#define SDIO_BUS_WIDE_1B SDMMC_BUS_WIDE_1B
+#define SDIO_BUS_WIDE_4B SDMMC_BUS_WIDE_4B
+#define SDIO_BUS_WIDE_8B SDMMC_BUS_WIDE_8B
+
+#define SDIO_HARDWARE_FLOW_CONTROL_DISABLE SDMMC_HARDWARE_FLOW_CONTROL_DISABLE
+#define SDIO_HARDWARE_FLOW_CONTROL_ENABLE SDMMC_HARDWARE_FLOW_CONTROL_ENABLE
+
+#define SDIO_TRANSFER_CLK_DIV SDMMC_TRANSFER_CLK_DIV
+
+#else
+
+// These are definitions for F4 MCUs so there is a common macro across all MCUs.
+
+#define SDMMC_CLK_ENABLE() __SDIO_CLK_ENABLE()
+#define SDMMC_CLK_DISABLE() __SDIO_CLK_DISABLE()
+#define SDMMC_IRQn SDIO_IRQn
+#define SDMMC_TX_DMA dma_SDIO_0_TX
+#define SDMMC_RX_DMA dma_SDIO_0_RX
+
+#endif
+
+// If no custom SDIO pins defined, use the default ones
+#ifndef MICROPY_HW_SDMMC_CK
+
+#define MICROPY_HW_SDMMC_D0 (pin_C8)
+#define MICROPY_HW_SDMMC_D1 (pin_C9)
+#define MICROPY_HW_SDMMC_D2 (pin_C10)
+#define MICROPY_HW_SDMMC_D3 (pin_C11)
+#define MICROPY_HW_SDMMC_CK (pin_C12)
+#define MICROPY_HW_SDMMC_CMD (pin_D2)
+
+#endif
+
+// TODO: Since SDIO is fundamentally half-duplex, we really only need to
+// tie up one DMA channel. However, the HAL DMA API doesn't
+// seem to provide a convenient way to change the direction. I believe that
+// its as simple as changing the CR register and the Init.Direction field
+// and make DMA_SetConfig public.
+
+// TODO: I think that as an optimization, we can allocate these dynamically
+// 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;
+static DMA_HandleTypeDef sd_rx_dma, sd_tx_dma;
+
+void sdcard_init(void) {
+ // invalidate the sd_handle
+ sd_handle.Instance = NULL;
+
+ // configure SD GPIO
+ // we do this here an not in HAL_SD_MspInit because it apparently
+ // makes it more robust to have the pins always pulled high
+ // Note: the mp_hal_pin_config function will configure the GPIO in
+ // fast mode which can do up to 50MHz. This should be plenty for SDIO
+ // 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);
+ #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);
+ #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);
+}
+
+void HAL_SD_MspInit(SD_HandleTypeDef *hsd) {
+ // enable SDIO clock
+ SDMMC_CLK_ENABLE();
+
+ // NVIC configuration for SDIO interrupts
+ HAL_NVIC_SetPriority(SDMMC_IRQn, IRQ_PRI_SDIO, IRQ_SUBPRI_SDIO);
+ HAL_NVIC_EnableIRQ(SDMMC_IRQn);
+
+ // GPIO have already been initialised by sdcard_init
+}
+
+void HAL_SD_MspDeInit(SD_HandleTypeDef *hsd) {
+ HAL_NVIC_DisableIRQ(SDMMC_IRQn);
+ SDMMC_CLK_DISABLE();
+}
+
+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;
+}
+
+bool sdcard_power_on(void) {
+ if (!sdcard_is_present()) {
+ return false;
+ }
+ if (sd_handle.Instance) {
+ return true;
+ }
+
+ // SD device interface configuration
+ sd_handle.Instance = SDIO;
+ sd_handle.Init.ClockEdge = SDIO_CLOCK_EDGE_RISING;
+ sd_handle.Init.ClockBypass = SDIO_CLOCK_BYPASS_DISABLE;
+ 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;
+ sd_handle.Init.ClockDiv = SDIO_TRANSFER_CLK_DIV;
+
+ // init the SD interface, with retry if it's not ready yet
+ for (int retry = 10; HAL_SD_Init(&sd_handle) != HAL_OK; retry--) {
+ if (retry == 0) {
+ goto error;
+ }
+ mp_hal_delay_ms(50);
+ }
+
+ // configure the SD bus width for wide operation
+ if (HAL_SD_ConfigWideBusOperation(&sd_handle, SDIO_BUS_WIDE_4B) != HAL_OK) {
+ HAL_SD_DeInit(&sd_handle);
+ goto error;
+ }
+
+ return true;
+
+error:
+ sd_handle.Instance = NULL;
+ return false;
+}
+
+void sdcard_power_off(void) {
+ if (!sd_handle.Instance) {
+ return;
+ }
+ HAL_SD_DeInit(&sd_handle);
+ sd_handle.Instance = NULL;
+}
+
+uint64_t sdcard_get_capacity_in_bytes(void) {
+ if (sd_handle.Instance == NULL) {
+ return 0;
+ }
+ HAL_SD_CardInfoTypeDef cardinfo;
+ HAL_SD_GetCardInfo(&sd_handle, &cardinfo);
+ return (uint64_t)cardinfo.LogBlockNbr * (uint64_t)cardinfo.LogBlockSize;
+}
+
+void SDIO_IRQHandler(void) {
+ IRQ_ENTER(SDIO_IRQn);
+ HAL_SD_IRQHandler(&sd_handle);
+ IRQ_EXIT(SDIO_IRQn);
+}
+
+#if defined(MCU_SERIES_F7)
+void SDMMC2_IRQHandler(void) {
+ IRQ_ENTER(SDMMC2_IRQn);
+ HAL_SD_IRQHandler(&sd_handle);
+ IRQ_EXIT(SDMMC2_IRQn);
+}
+#endif
+
+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) {
+ 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);
+ if (state == HAL_SD_CARD_TRANSFER) {
+ return HAL_OK;
+ }
+ if (!(state == HAL_SD_CARD_SENDING || state == HAL_SD_CARD_RECEIVING || state == HAL_SD_CARD_PROGRAMMING)) {
+ return HAL_ERROR;
+ }
+ if (HAL_GetTick() - start >= timeout) {
+ return HAL_TIMEOUT;
+ }
+ }
+ return HAL_OK;
+}
+
+mp_uint_t sdcard_read_blocks(uint8_t *dest, uint32_t block_num, uint32_t num_blocks) {
+ // check that SD card is initialised
+ if (sd_handle.Instance == NULL) {
+ return HAL_ERROR;
+ }
+
+ HAL_StatusTypeDef err = HAL_OK;
+
+ // check that dest pointer is aligned on a 4-byte boundary
+ uint8_t *orig_dest = NULL;
+ uint32_t saved_word;
+ if (((uint32_t)dest & 3) != 0) {
+ // Pointer is not aligned so it needs fixing.
+ // We could allocate a temporary block of RAM (as sdcard_write_blocks
+ // does) but instead we are going to use the dest buffer inplace. We
+ // are going to align the pointer, save the initial word at the aligned
+ // location, read into the aligned memory, move the memory back to the
+ // unaligned location, then restore the initial bytes at the aligned
+ // location. We should have no trouble doing this as those initial
+ // bytes at the aligned location should be able to be changed for the
+ // duration of this function call.
+ orig_dest = dest;
+ dest = (uint8_t*)((uint32_t)dest & ~3);
+ saved_word = *(uint32_t*)dest;
+ }
+
+ if (query_irq() == IRQ_STATE_ENABLED) {
+ // we must disable USB irqs to prevent MSC contention with SD card
+ uint32_t basepri = raise_irq_pri(IRQ_PRI_OTG_FS);
+
+ dma_init(&sd_rx_dma, &SDMMC_RX_DMA, &sd_handle);
+ sd_handle.hdmarx = &sd_rx_dma;
+
+ // make sure cache is flushed and invalidated so when DMA updates the RAM
+ // from reading the peripheral the CPU then reads the new data
+ MP_HAL_CLEANINVALIDATE_DCACHE(dest, num_blocks * SDCARD_BLOCK_SIZE);
+
+ err = HAL_SD_ReadBlocks_DMA(&sd_handle, dest, block_num, num_blocks);
+ if (err == HAL_OK) {
+ err = sdcard_wait_finished(&sd_handle, 60000);
+ }
+
+ dma_deinit(&SDMMC_RX_DMA);
+ sd_handle.hdmarx = NULL;
+
+ restore_irq_pri(basepri);
+ } else {
+ err = HAL_SD_ReadBlocks(&sd_handle, dest, block_num, num_blocks, 60000);
+ if (err == HAL_OK) {
+ err = sdcard_wait_finished(&sd_handle, 60000);
+ }
+ }
+
+ if (orig_dest != NULL) {
+ // move the read data to the non-aligned position, and restore the initial bytes
+ memmove(orig_dest, dest, num_blocks * SDCARD_BLOCK_SIZE);
+ memcpy(dest, &saved_word, orig_dest - dest);
+ }
+
+ return err;
+}
+
+mp_uint_t sdcard_write_blocks(const uint8_t *src, uint32_t block_num, uint32_t num_blocks) {
+ // check that SD card is initialised
+ if (sd_handle.Instance == NULL) {
+ return HAL_ERROR;
+ }
+
+ HAL_StatusTypeDef err = HAL_OK;
+
+ // check that src pointer is aligned on a 4-byte boundary
+ if (((uint32_t)src & 3) != 0) {
+ // pointer is not aligned, so allocate a temporary block to do the write
+ uint8_t *src_aligned = m_new_maybe(uint8_t, SDCARD_BLOCK_SIZE);
+ if (src_aligned == NULL) {
+ return HAL_ERROR;
+ }
+ for (size_t i = 0; i < num_blocks; ++i) {
+ memcpy(src_aligned, src + i * SDCARD_BLOCK_SIZE, SDCARD_BLOCK_SIZE);
+ err = sdcard_write_blocks(src_aligned, block_num + i, 1);
+ if (err != HAL_OK) {
+ break;
+ }
+ }
+ m_del(uint8_t, src_aligned, SDCARD_BLOCK_SIZE);
+ return err;
+ }
+
+ if (query_irq() == IRQ_STATE_ENABLED) {
+ // we must disable USB irqs to prevent MSC contention with SD card
+ uint32_t basepri = raise_irq_pri(IRQ_PRI_OTG_FS);
+
+ dma_init(&sd_tx_dma, &SDMMC_TX_DMA, &sd_handle);
+ sd_handle.hdmatx = &sd_tx_dma;
+
+ // 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);
+
+ err = HAL_SD_WriteBlocks_DMA(&sd_handle, (uint8_t*)src, block_num, num_blocks);
+ if (err == HAL_OK) {
+ err = sdcard_wait_finished(&sd_handle, 60000);
+ }
+ dma_deinit(&SDMMC_TX_DMA);
+ sd_handle.hdmatx = NULL;
+
+ restore_irq_pri(basepri);
+ } else {
+ err = HAL_SD_WriteBlocks(&sd_handle, (uint8_t*)src, block_num, num_blocks, 60000);
+ if (err == HAL_OK) {
+ err = sdcard_wait_finished(&sd_handle, 60000);
+ }
+ }
+
+ return err;
+}
+
+/******************************************************************************/
+// MicroPython bindings
+//
+// Expose the SD card as an object with the block protocol.
+
+// there is a singleton SDCard object
+const mp_obj_base_t pyb_sdcard_obj = {&pyb_sdcard_type};
+
+STATIC mp_obj_t pyb_sdcard_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 singleton object
+ return (mp_obj_t)&pyb_sdcard_obj;
+}
+
+STATIC mp_obj_t sd_present(mp_obj_t self) {
+ return mp_obj_new_bool(sdcard_is_present());
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(sd_present_obj, sd_present);
+
+STATIC mp_obj_t sd_power(mp_obj_t self, mp_obj_t state) {
+ bool result;
+ if (mp_obj_is_true(state)) {
+ result = sdcard_power_on();
+ } else {
+ sdcard_power_off();
+ result = true;
+ }
+ return mp_obj_new_bool(result);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(sd_power_obj, sd_power);
+
+STATIC mp_obj_t sd_info(mp_obj_t self) {
+ if (sd_handle.Instance == NULL) {
+ return mp_const_none;
+ }
+ HAL_SD_CardInfoTypeDef cardinfo;
+ HAL_SD_GetCardInfo(&sd_handle, &cardinfo);
+ // cardinfo.SD_csd and cardinfo.SD_cid have lots of info but we don't use them
+ mp_obj_t tuple[3] = {
+ mp_obj_new_int_from_ull((uint64_t)cardinfo.LogBlockNbr * (uint64_t)cardinfo.LogBlockSize),
+ mp_obj_new_int_from_uint(cardinfo.LogBlockSize),
+ mp_obj_new_int(cardinfo.CardType),
+ };
+ return mp_obj_new_tuple(3, tuple);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(sd_info_obj, sd_info);
+
+// now obsolete, kept for backwards compatibility
+STATIC mp_obj_t sd_read(mp_obj_t self, mp_obj_t block_num) {
+ uint8_t *dest = m_new(uint8_t, SDCARD_BLOCK_SIZE);
+ mp_uint_t ret = sdcard_read_blocks(dest, mp_obj_get_int(block_num), 1);
+
+ if (ret != 0) {
+ m_del(uint8_t, dest, SDCARD_BLOCK_SIZE);
+ nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_Exception, "sdcard_read_blocks failed [%u]", ret));
+ }
+
+ return mp_obj_new_bytearray_by_ref(SDCARD_BLOCK_SIZE, dest);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(sd_read_obj, sd_read);
+
+// now obsolete, kept for backwards compatibility
+STATIC mp_obj_t sd_write(mp_obj_t self, mp_obj_t block_num, mp_obj_t data) {
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(data, &bufinfo, MP_BUFFER_READ);
+ if (bufinfo.len % SDCARD_BLOCK_SIZE != 0) {
+ nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "writes must be a multiple of %d bytes", SDCARD_BLOCK_SIZE));
+ }
+
+ mp_uint_t ret = sdcard_write_blocks(bufinfo.buf, mp_obj_get_int(block_num), bufinfo.len / SDCARD_BLOCK_SIZE);
+
+ if (ret != 0) {
+ nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_Exception, "sdcard_write_blocks failed [%u]", ret));
+ }
+
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_3(sd_write_obj, sd_write);
+
+STATIC mp_obj_t pyb_sdcard_readblocks(mp_obj_t self, mp_obj_t block_num, mp_obj_t buf) {
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(buf, &bufinfo, MP_BUFFER_WRITE);
+ mp_uint_t ret = sdcard_read_blocks(bufinfo.buf, mp_obj_get_int(block_num), bufinfo.len / SDCARD_BLOCK_SIZE);
+ return mp_obj_new_bool(ret == 0);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_3(pyb_sdcard_readblocks_obj, pyb_sdcard_readblocks);
+
+STATIC mp_obj_t pyb_sdcard_writeblocks(mp_obj_t self, mp_obj_t block_num, mp_obj_t buf) {
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(buf, &bufinfo, MP_BUFFER_READ);
+ mp_uint_t ret = sdcard_write_blocks(bufinfo.buf, mp_obj_get_int(block_num), bufinfo.len / SDCARD_BLOCK_SIZE);
+ return mp_obj_new_bool(ret == 0);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_3(pyb_sdcard_writeblocks_obj, pyb_sdcard_writeblocks);
+
+STATIC mp_obj_t pyb_sdcard_ioctl(mp_obj_t self, mp_obj_t cmd_in, mp_obj_t arg_in) {
+ mp_int_t cmd = mp_obj_get_int(cmd_in);
+ switch (cmd) {
+ case BP_IOCTL_INIT:
+ if (!sdcard_power_on()) {
+ return MP_OBJ_NEW_SMALL_INT(-1); // error
+ }
+ return MP_OBJ_NEW_SMALL_INT(0); // success
+
+ case BP_IOCTL_DEINIT:
+ sdcard_power_off();
+ return MP_OBJ_NEW_SMALL_INT(0); // success
+
+ case BP_IOCTL_SYNC:
+ // nothing to do
+ return MP_OBJ_NEW_SMALL_INT(0); // success
+
+ case BP_IOCTL_SEC_COUNT:
+ return MP_OBJ_NEW_SMALL_INT(0); // TODO
+
+ case BP_IOCTL_SEC_SIZE:
+ return MP_OBJ_NEW_SMALL_INT(SDCARD_BLOCK_SIZE);
+
+ default: // unknown command
+ return MP_OBJ_NEW_SMALL_INT(-1); // error
+ }
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_3(pyb_sdcard_ioctl_obj, pyb_sdcard_ioctl);
+
+STATIC const mp_rom_map_elem_t pyb_sdcard_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_present), MP_ROM_PTR(&sd_present_obj) },
+ { MP_ROM_QSTR(MP_QSTR_power), MP_ROM_PTR(&sd_power_obj) },
+ { MP_ROM_QSTR(MP_QSTR_info), MP_ROM_PTR(&sd_info_obj) },
+ { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&sd_read_obj) },
+ { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&sd_write_obj) },
+ // block device protocol
+ { MP_ROM_QSTR(MP_QSTR_readblocks), MP_ROM_PTR(&pyb_sdcard_readblocks_obj) },
+ { MP_ROM_QSTR(MP_QSTR_writeblocks), MP_ROM_PTR(&pyb_sdcard_writeblocks_obj) },
+ { MP_ROM_QSTR(MP_QSTR_ioctl), MP_ROM_PTR(&pyb_sdcard_ioctl_obj) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(pyb_sdcard_locals_dict, pyb_sdcard_locals_dict_table);
+
+const mp_obj_type_t pyb_sdcard_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_SDCard,
+ .make_new = pyb_sdcard_make_new,
+ .locals_dict = (mp_obj_dict_t*)&pyb_sdcard_locals_dict,
+};
+
+void sdcard_init_vfs(fs_user_mount_t *vfs, int part) {
+ vfs->base.type = &mp_fat_vfs_type;
+ vfs->flags |= FSUSER_NATIVE | FSUSER_HAVE_IOCTL;
+ vfs->fatfs.drv = vfs;
+ vfs->fatfs.part = part;
+ vfs->readblocks[0] = (mp_obj_t)&pyb_sdcard_readblocks_obj;
+ vfs->readblocks[1] = (mp_obj_t)&pyb_sdcard_obj;
+ vfs->readblocks[2] = (mp_obj_t)sdcard_read_blocks; // native version
+ vfs->writeblocks[0] = (mp_obj_t)&pyb_sdcard_writeblocks_obj;
+ vfs->writeblocks[1] = (mp_obj_t)&pyb_sdcard_obj;
+ vfs->writeblocks[2] = (mp_obj_t)sdcard_write_blocks; // native version
+ vfs->u.ioctl[0] = (mp_obj_t)&pyb_sdcard_ioctl_obj;
+ vfs->u.ioctl[1] = (mp_obj_t)&pyb_sdcard_obj;
+}
+
+#endif // MICROPY_HW_HAS_SDCARD
diff --git a/ports/stm32/sdcard.h b/ports/stm32/sdcard.h
new file mode 100644
index 000000000..8c698fc2f
--- /dev/null
+++ b/ports/stm32/sdcard.h
@@ -0,0 +1,48 @@
+/*
+ * 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.
+ */
+#ifndef MICROPY_INCLUDED_STMHAL_SDCARD_H
+#define MICROPY_INCLUDED_STMHAL_SDCARD_H
+
+// this is a fixed size and should not be changed
+#define SDCARD_BLOCK_SIZE (512)
+
+void sdcard_init(void);
+bool sdcard_is_present(void);
+bool sdcard_power_on(void);
+void sdcard_power_off(void);
+uint64_t sdcard_get_capacity_in_bytes(void);
+
+// these return 0 on success, non-zero on error
+mp_uint_t sdcard_read_blocks(uint8_t *dest, uint32_t block_num, uint32_t num_blocks);
+mp_uint_t sdcard_write_blocks(const uint8_t *src, uint32_t block_num, uint32_t num_blocks);
+
+extern const struct _mp_obj_type_t pyb_sdcard_type;
+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
diff --git a/ports/stm32/servo.c b/ports/stm32/servo.c
new file mode 100644
index 000000000..0e54b4d0a
--- /dev/null
+++ b/ports/stm32/servo.c
@@ -0,0 +1,334 @@
+/*
+ * 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 "py/runtime.h"
+#include "py/mphal.h"
+#include "pin.h"
+#include "genhdr/pins.h"
+#include "timer.h"
+#include "servo.h"
+
+#if MICROPY_HW_ENABLE_SERVO
+
+// This file implements the pyb.Servo class which controls standard hobby servo
+// motors that have 3-wires (ground, power, signal).
+//
+// The driver uses hardware PWM to drive servos on pins X1, X2, X3, X4 which are
+// assumed to be on PA0, PA1, PA2, PA3 but not necessarily in that order (the
+// pins PA0-PA3 are used directly if the X pins are not defined).
+//
+// TIM2 and TIM5 have CH1-CH4 on PA0-PA3 respectively. They are both 32-bit
+// counters with 16-bit prescaler. TIM5 is used by this driver.
+
+#define PYB_SERVO_NUM (4)
+
+typedef struct _pyb_servo_obj_t {
+ mp_obj_base_t base;
+ const pin_obj_t *pin;
+ uint8_t pulse_min; // units of 10us
+ uint8_t pulse_max; // units of 10us
+ uint8_t pulse_centre; // units of 10us
+ uint8_t pulse_angle_90; // units of 10us; pulse at 90 degrees, minus pulse_centre
+ uint8_t pulse_speed_100; // units of 10us; pulse at 100% forward speed, minus pulse_centre
+ uint16_t pulse_cur; // units of 10us
+ uint16_t pulse_dest; // units of 10us
+ int16_t pulse_accum;
+ uint16_t time_left;
+} pyb_servo_obj_t;
+
+STATIC pyb_servo_obj_t pyb_servo_obj[PYB_SERVO_NUM];
+
+void servo_init(void) {
+ timer_tim5_init();
+
+ // reset servo objects
+ for (int i = 0; i < PYB_SERVO_NUM; i++) {
+ pyb_servo_obj[i].base.type = &pyb_servo_type;
+ pyb_servo_obj[i].pulse_min = 64;
+ pyb_servo_obj[i].pulse_max = 242;
+ pyb_servo_obj[i].pulse_centre = 150;
+ pyb_servo_obj[i].pulse_angle_90 = 97;
+ pyb_servo_obj[i].pulse_speed_100 = 70;
+ pyb_servo_obj[i].pulse_cur = 150;
+ pyb_servo_obj[i].pulse_dest = 0;
+ pyb_servo_obj[i].time_left = 0;
+ }
+
+ // 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;
+ #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;
+ #endif
+}
+
+void servo_timer_irq_callback(void) {
+ bool need_it = false;
+ for (int i = 0; i < PYB_SERVO_NUM; i++) {
+ pyb_servo_obj_t *s = &pyb_servo_obj[i];
+ if (s->pulse_cur != s->pulse_dest) {
+ // clamp pulse to within min/max
+ if (s->pulse_dest < s->pulse_min) {
+ s->pulse_dest = s->pulse_min;
+ } else if (s->pulse_dest > s->pulse_max) {
+ s->pulse_dest = s->pulse_max;
+ }
+ // adjust cur to get closer to dest
+ if (s->time_left <= 1) {
+ s->pulse_cur = s->pulse_dest;
+ s->time_left = 0;
+ } else {
+ s->pulse_accum += s->pulse_dest - s->pulse_cur;
+ s->pulse_cur += s->pulse_accum / s->time_left;
+ s->pulse_accum %= s->time_left;
+ s->time_left--;
+ need_it = true;
+ }
+ // set the pulse width
+ *(&TIM5->CCR1 + s->pin->pin) = s->pulse_cur;
+ }
+ }
+ if (need_it) {
+ __HAL_TIM_ENABLE_IT(&TIM5_Handle, TIM_IT_UPDATE);
+ } else {
+ __HAL_TIM_DISABLE_IT(&TIM5_Handle, TIM_IT_UPDATE);
+ }
+}
+
+STATIC void servo_init_channel(pyb_servo_obj_t *s) {
+ static const uint8_t channel_table[4] =
+ {TIM_CHANNEL_1, TIM_CHANNEL_2, TIM_CHANNEL_3, TIM_CHANNEL_4};
+ uint32_t channel = channel_table[s->pin->pin];
+
+ // GPIO configuration
+ mp_hal_pin_config(s->pin, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, GPIO_AF2_TIM5);
+
+ // PWM mode configuration
+ TIM_OC_InitTypeDef oc_init;
+ oc_init.OCMode = TIM_OCMODE_PWM1;
+ oc_init.Pulse = s->pulse_cur; // units of 10us
+ oc_init.OCPolarity = TIM_OCPOLARITY_HIGH;
+ oc_init.OCFastMode = TIM_OCFAST_DISABLE;
+ HAL_TIM_PWM_ConfigChannel(&TIM5_Handle, &oc_init, channel);
+
+ // start PWM
+ HAL_TIM_PWM_Start(&TIM5_Handle, channel);
+}
+
+/******************************************************************************/
+// MicroPython bindings
+
+STATIC mp_obj_t pyb_servo_set(mp_obj_t port, mp_obj_t value) {
+ int p = mp_obj_get_int(port);
+ int v = mp_obj_get_int(value);
+ if (v < 50) { v = 50; }
+ if (v > 250) { v = 250; }
+ switch (p) {
+ case 1: TIM5->CCR1 = v; break;
+ case 2: TIM5->CCR2 = v; break;
+ case 3: TIM5->CCR3 = v; break;
+ case 4: TIM5->CCR4 = v; break;
+ }
+ return mp_const_none;
+}
+
+MP_DEFINE_CONST_FUN_OBJ_2(pyb_servo_set_obj, pyb_servo_set);
+
+STATIC mp_obj_t pyb_pwm_set(mp_obj_t period, mp_obj_t pulse) {
+ int pe = mp_obj_get_int(period);
+ int pu = mp_obj_get_int(pulse);
+ TIM5->ARR = pe;
+ TIM5->CCR3 = pu;
+ return mp_const_none;
+}
+
+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);
+}
+
+/// \classmethod \constructor(id)
+/// Create a servo object. `id` is 1-4.
+STATIC mp_obj_t pyb_servo_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, 1, false);
+
+ // get servo number
+ mp_int_t servo_id = mp_obj_get_int(args[0]) - 1;
+
+ // check servo number
+ if (!(0 <= servo_id && servo_id < PYB_SERVO_NUM)) {
+ nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "Servo(%d) doesn't exist", servo_id + 1));
+ }
+
+ // get and init servo object
+ pyb_servo_obj_t *s = &pyb_servo_obj[servo_id];
+ s->pulse_dest = s->pulse_cur;
+ s->time_left = 0;
+ servo_init_channel(s);
+
+ return s;
+}
+
+/// \method pulse_width([value])
+/// Get or set the pulse width in milliseconds.
+STATIC mp_obj_t pyb_servo_pulse_width(size_t n_args, const mp_obj_t *args) {
+ pyb_servo_obj_t *self = args[0];
+ if (n_args == 1) {
+ // get pulse width, in us
+ return mp_obj_new_int(10 * self->pulse_cur);
+ } else {
+ // set pulse width, in us
+ self->pulse_dest = mp_obj_get_int(args[1]) / 10;
+ self->time_left = 0;
+ servo_timer_irq_callback();
+ return mp_const_none;
+ }
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_servo_pulse_width_obj, 1, 2, pyb_servo_pulse_width);
+
+/// \method calibration([pulse_min, pulse_max, pulse_centre, [pulse_angle_90, pulse_speed_100]])
+/// Get or set the calibration of the servo timing.
+// TODO should accept 1 arg, a 5-tuple of values to set
+STATIC mp_obj_t pyb_servo_calibration(size_t n_args, const mp_obj_t *args) {
+ pyb_servo_obj_t *self = args[0];
+ if (n_args == 1) {
+ // get calibration values
+ mp_obj_t tuple[5];
+ tuple[0] = mp_obj_new_int(10 * self->pulse_min);
+ tuple[1] = mp_obj_new_int(10 * self->pulse_max);
+ tuple[2] = mp_obj_new_int(10 * self->pulse_centre);
+ tuple[3] = mp_obj_new_int(10 * (self->pulse_angle_90 + self->pulse_centre));
+ tuple[4] = mp_obj_new_int(10 * (self->pulse_speed_100 + self->pulse_centre));
+ return mp_obj_new_tuple(5, tuple);
+ } else if (n_args >= 4) {
+ // set min, max, centre
+ self->pulse_min = mp_obj_get_int(args[1]) / 10;
+ self->pulse_max = mp_obj_get_int(args[2]) / 10;
+ self->pulse_centre = mp_obj_get_int(args[3]) / 10;
+ if (n_args == 4) {
+ return mp_const_none;
+ } else if (n_args == 6) {
+ self->pulse_angle_90 = mp_obj_get_int(args[4]) / 10 - self->pulse_centre;
+ self->pulse_speed_100 = mp_obj_get_int(args[5]) / 10 - self->pulse_centre;
+ return mp_const_none;
+ }
+ }
+
+ // bad number of arguments
+ nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "calibration expecting 1, 4 or 6 arguments, got %d", n_args));
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_servo_calibration_obj, 1, 6, pyb_servo_calibration);
+
+/// \method angle([angle, time=0])
+/// Get or set the angle of the servo.
+///
+/// - `angle` is the angle to move to in degrees.
+/// - `time` is the number of milliseconds to take to get to the specified angle.
+STATIC mp_obj_t pyb_servo_angle(size_t n_args, const mp_obj_t *args) {
+ pyb_servo_obj_t *self = args[0];
+ if (n_args == 1) {
+ // get angle
+ return mp_obj_new_int((self->pulse_cur - self->pulse_centre) * 90 / self->pulse_angle_90);
+ } else {
+#if MICROPY_PY_BUILTINS_FLOAT
+ self->pulse_dest = self->pulse_centre + self->pulse_angle_90 * mp_obj_get_float(args[1]) / 90.0;
+#else
+ self->pulse_dest = self->pulse_centre + self->pulse_angle_90 * mp_obj_get_int(args[1]) / 90;
+#endif
+ if (n_args == 2) {
+ // set angle immediately
+ self->time_left = 0;
+ } else {
+ // set angle over a given time (given in milli seconds)
+ self->time_left = mp_obj_get_int(args[2]) / 20;
+ self->pulse_accum = 0;
+ }
+ servo_timer_irq_callback();
+ return mp_const_none;
+ }
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_servo_angle_obj, 1, 3, pyb_servo_angle);
+
+/// \method speed([speed, time=0])
+/// Get or set the speed of a continuous rotation servo.
+///
+/// - `speed` is the speed to move to change to, between -100 and 100.
+/// - `time` is the number of milliseconds to take to get to the specified speed.
+STATIC mp_obj_t pyb_servo_speed(size_t n_args, const mp_obj_t *args) {
+ pyb_servo_obj_t *self = args[0];
+ if (n_args == 1) {
+ // get speed
+ return mp_obj_new_int((self->pulse_cur - self->pulse_centre) * 100 / self->pulse_speed_100);
+ } else {
+#if MICROPY_PY_BUILTINS_FLOAT
+ self->pulse_dest = self->pulse_centre + self->pulse_speed_100 * mp_obj_get_float(args[1]) / 100.0;
+#else
+ self->pulse_dest = self->pulse_centre + self->pulse_speed_100 * mp_obj_get_int(args[1]) / 100;
+#endif
+ if (n_args == 2) {
+ // set speed immediately
+ self->time_left = 0;
+ } else {
+ // set speed over a given time (given in milli seconds)
+ self->time_left = mp_obj_get_int(args[2]) / 20;
+ self->pulse_accum = 0;
+ }
+ servo_timer_irq_callback();
+ return mp_const_none;
+ }
+}
+
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_servo_speed_obj, 1, 3, pyb_servo_speed);
+
+STATIC const mp_rom_map_elem_t pyb_servo_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_pulse_width), MP_ROM_PTR(&pyb_servo_pulse_width_obj) },
+ { MP_ROM_QSTR(MP_QSTR_calibration), MP_ROM_PTR(&pyb_servo_calibration_obj) },
+ { MP_ROM_QSTR(MP_QSTR_angle), MP_ROM_PTR(&pyb_servo_angle_obj) },
+ { MP_ROM_QSTR(MP_QSTR_speed), MP_ROM_PTR(&pyb_servo_speed_obj) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(pyb_servo_locals_dict, pyb_servo_locals_dict_table);
+
+const mp_obj_type_t pyb_servo_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_Servo,
+ .print = pyb_servo_print,
+ .make_new = pyb_servo_make_new,
+ .locals_dict = (mp_obj_dict_t*)&pyb_servo_locals_dict,
+};
+
+#endif // MICROPY_HW_ENABLE_SERVO
diff --git a/ports/stm32/servo.h b/ports/stm32/servo.h
new file mode 100644
index 000000000..c602a07da
--- /dev/null
+++ b/ports/stm32/servo.h
@@ -0,0 +1,37 @@
+/*
+ * 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.
+ */
+#ifndef MICROPY_INCLUDED_STMHAL_SERVO_H
+#define MICROPY_INCLUDED_STMHAL_SERVO_H
+
+void servo_init(void);
+void servo_timer_irq_callback(void);
+
+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
diff --git a/ports/stm32/spi.c b/ports/stm32/spi.c
new file mode 100644
index 000000000..654a1327d
--- /dev/null
+++ b/ports/stm32/spi.c
@@ -0,0 +1,956 @@
+/*
+ * 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/nlr.h"
+#include "py/runtime.h"
+#include "py/mphal.h"
+#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
+/// \class SPI - a master-driven serial protocol
+///
+/// SPI is a serial protocol that is driven by a master. At the physical level
+/// there are 3 lines: SCK, MOSI, MISO.
+///
+/// See usage model of I2C; SPI is very similar. Main difference is
+/// parameters to init the SPI bus:
+///
+/// from pyb import SPI
+/// spi = SPI(1, SPI.MASTER, baudrate=600000, polarity=1, phase=0, crc=0x7)
+///
+/// Only required parameter is mode, SPI.MASTER or SPI.SLAVE. Polarity can be
+/// 0 or 1, and is the level the idle clock line sits at. Phase can be 0 or 1
+/// to sample data on the first or second clock edge respectively. Crc can be
+/// None for no CRC, or a polynomial specifier.
+///
+/// Additional method for SPI:
+///
+/// data = spi.send_recv(b'1234') # send 4 bytes and receive 4 bytes
+/// buf = bytearray(4)
+/// spi.send_recv(b'1234', buf) # send 4 bytes and receive 4 into buf
+/// spi.send_recv(buf, buf) # send/recv 4 bytes from/to buf
+
+// Possible DMA configurations for SPI busses:
+// SPI1_TX: DMA2_Stream3.CHANNEL_3 or DMA2_Stream5.CHANNEL_3
+// SPI1_RX: DMA2_Stream0.CHANNEL_3 or DMA2_Stream2.CHANNEL_3
+// SPI2_TX: DMA1_Stream4.CHANNEL_0
+// SPI2_RX: DMA1_Stream3.CHANNEL_0
+// SPI3_TX: DMA1_Stream5.CHANNEL_0 or DMA1_Stream7.CHANNEL_0
+// SPI3_RX: DMA1_Stream0.CHANNEL_0 or DMA1_Stream2.CHANNEL_0
+// SPI4_TX: DMA2_Stream4.CHANNEL_5 or DMA2_Stream1.CHANNEL_4
+// SPI4_RX: DMA2_Stream3.CHANNEL_5 or DMA2_Stream0.CHANNEL_4
+// SPI5_TX: DMA2_Stream4.CHANNEL_2 or DMA2_Stream6.CHANNEL_7
+// SPI5_RX: DMA2_Stream3.CHANNEL_2 or DMA2_Stream5.CHANNEL_7
+// 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
+#if defined(MICROPY_HW_SPI2_SCK)
+SPI_HandleTypeDef SPIHandle2 = {.Instance = NULL};
+#endif
+#if defined(MICROPY_HW_SPI3_SCK)
+SPI_HandleTypeDef SPIHandle3 = {.Instance = NULL};
+#endif
+#if defined(MICROPY_HW_SPI4_SCK)
+SPI_HandleTypeDef SPIHandle4 = {.Instance = NULL};
+#endif
+#if defined(MICROPY_HW_SPI5_SCK)
+SPI_HandleTypeDef SPIHandle5 = {.Instance = NULL};
+#endif
+#if defined(MICROPY_HW_SPI6_SCK)
+SPI_HandleTypeDef SPIHandle6 = {.Instance = NULL};
+#endif
+
+STATIC const pyb_spi_obj_t pyb_spi_obj[] = {
+ #if defined(MICROPY_HW_SPI1_SCK)
+ {{&pyb_spi_type}, &SPIHandle1, &dma_SPI_1_TX, &dma_SPI_1_RX},
+ #else
+ {{&pyb_spi_type}, NULL, NULL, NULL},
+ #endif
+ #if defined(MICROPY_HW_SPI2_SCK)
+ {{&pyb_spi_type}, &SPIHandle2, &dma_SPI_2_TX, &dma_SPI_2_RX},
+ #else
+ {{&pyb_spi_type}, NULL, NULL, NULL},
+ #endif
+ #if defined(MICROPY_HW_SPI3_SCK)
+ {{&pyb_spi_type}, &SPIHandle3, &dma_SPI_3_TX, &dma_SPI_3_RX},
+ #else
+ {{&pyb_spi_type}, NULL, NULL, NULL},
+ #endif
+ #if defined(MICROPY_HW_SPI4_SCK)
+ {{&pyb_spi_type}, &SPIHandle4, &dma_SPI_4_TX, &dma_SPI_4_RX},
+ #else
+ {{&pyb_spi_type}, NULL, NULL, NULL},
+ #endif
+ #if defined(MICROPY_HW_SPI5_SCK)
+ {{&pyb_spi_type}, &SPIHandle5, &dma_SPI_5_TX, &dma_SPI_5_RX},
+ #else
+ {{&pyb_spi_type}, NULL, NULL, NULL},
+ #endif
+ #if defined(MICROPY_HW_SPI6_SCK)
+ {{&pyb_spi_type}, &SPIHandle6, &dma_SPI_6_TX, &dma_SPI_6_RX},
+ #else
+ {{&pyb_spi_type}, NULL, NULL, NULL},
+ #endif
+};
+
+void spi_init0(void) {
+ // reset the SPI handles
+ #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
+}
+
+STATIC int spi_find(mp_obj_t id) {
+ if (MP_OBJ_IS_STR(id)) {
+ // given a string id
+ const char *port = mp_obj_str_get_str(id);
+ if (0) {
+ #ifdef MICROPY_HW_SPI1_NAME
+ } else if (strcmp(port, MICROPY_HW_SPI1_NAME) == 0) {
+ return 1;
+ #endif
+ #ifdef MICROPY_HW_SPI2_NAME
+ } else if (strcmp(port, MICROPY_HW_SPI2_NAME) == 0) {
+ return 2;
+ #endif
+ #ifdef MICROPY_HW_SPI3_NAME
+ } else if (strcmp(port, MICROPY_HW_SPI3_NAME) == 0) {
+ return 3;
+ #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) {
+ return spi_id;
+ }
+ nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError,
+ "SPI(%d) doesn't exist", spi_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,
+ int32_t polarity, int32_t phase, int32_t bits, int32_t firstbit) {
+ 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 (spi->Instance == SPI2 || spi->Instance == SPI3) {
+ // SPI2 and SPI3 are on APB1
+ spi_clock = HAL_RCC_GetPCLK1Freq();
+ } else {
+ // SPI1, SPI4, SPI5 and SPI6 are on APB2
+ spi_clock = HAL_RCC_GetPCLK2Freq();
+ }
+ prescale = spi_clock / baudrate;
+ }
+ if (prescale <= 2) { init->BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2; }
+ else if (prescale <= 4) { init->BaudRatePrescaler = SPI_BAUDRATEPRESCALER_4; }
+ else if (prescale <= 8) { init->BaudRatePrescaler = SPI_BAUDRATEPRESCALER_8; }
+ else if (prescale <= 16) { init->BaudRatePrescaler = SPI_BAUDRATEPRESCALER_16; }
+ else if (prescale <= 32) { init->BaudRatePrescaler = SPI_BAUDRATEPRESCALER_32; }
+ else if (prescale <= 64) { init->BaudRatePrescaler = SPI_BAUDRATEPRESCALER_64; }
+ else if (prescale <= 128) { init->BaudRatePrescaler = SPI_BAUDRATEPRESCALER_128; }
+ else { init->BaudRatePrescaler = SPI_BAUDRATEPRESCALER_256; }
+ }
+
+ if (polarity != -1) {
+ init->CLKPolarity = polarity == 0 ? SPI_POLARITY_LOW : SPI_POLARITY_HIGH;
+ }
+
+ if (phase != -1) {
+ init->CLKPhase = phase == 0 ? SPI_PHASE_1EDGE : SPI_PHASE_2EDGE;
+ }
+
+ if (bits != -1) {
+ init->DataSize = (bits == 16) ? SPI_DATASIZE_16BIT : SPI_DATASIZE_8BIT;
+ }
+
+ if (firstbit != -1) {
+ init->FirstBit = firstbit;
+ }
+}
+
+// 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;
+
+ 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;
+ #endif
+ pins[1] = &MICROPY_HW_SPI1_SCK;
+ pins[2] = &MICROPY_HW_SPI1_MISO;
+ pins[3] = &MICROPY_HW_SPI1_MOSI;
+ // enable the SPI clock
+ __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;
+ #endif
+ pins[1] = &MICROPY_HW_SPI2_SCK;
+ pins[2] = &MICROPY_HW_SPI2_MISO;
+ pins[3] = &MICROPY_HW_SPI2_MOSI;
+ // enable the SPI clock
+ __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;
+ #endif
+ pins[1] = &MICROPY_HW_SPI3_SCK;
+ pins[2] = &MICROPY_HW_SPI3_MISO;
+ pins[3] = &MICROPY_HW_SPI3_MOSI;
+ // enable the SPI clock
+ __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;
+ #endif
+ pins[1] = &MICROPY_HW_SPI4_SCK;
+ pins[2] = &MICROPY_HW_SPI4_MISO;
+ pins[3] = &MICROPY_HW_SPI4_MOSI;
+ // enable the SPI clock
+ __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;
+ #endif
+ pins[1] = &MICROPY_HW_SPI5_SCK;
+ pins[2] = &MICROPY_HW_SPI5_MISO;
+ pins[3] = &MICROPY_HW_SPI5_MOSI;
+ // enable the SPI clock
+ __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;
+ #endif
+ pins[1] = &MICROPY_HW_SPI6_SCK;
+ pins[2] = &MICROPY_HW_SPI6_MISO;
+ pins[3] = &MICROPY_HW_SPI6_MOSI;
+ // enable the SPI clock
+ __SPI6_CLK_ENABLE();
+ #endif
+ } else {
+ // SPI 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;
+ 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);
+ }
+
+ // init the SPI device
+ if (HAL_SPI_Init(spi) != 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_SPI_Init failed\n");
+ return;
+ }
+
+ // After calling HAL_SPI_Init() it seems that the DMA gets disconnected if
+ // it was previously configured. So we invalidate the DMA channel to force
+ // an initialisation the next time we use it.
+ dma_invalidate_channel(self->tx_dma_descr);
+ dma_invalidate_channel(self->rx_dma_descr);
+}
+
+void spi_deinit(SPI_HandleTypeDef *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();
+ #endif
+ #if defined(MICROPY_HW_SPI2_SCK)
+ } else if (spi->Instance == SPI2) {
+ __SPI2_FORCE_RESET();
+ __SPI2_RELEASE_RESET();
+ __SPI2_CLK_DISABLE();
+ #endif
+ #if defined(MICROPY_HW_SPI3_SCK)
+ } else if (spi->Instance == SPI3) {
+ __SPI3_FORCE_RESET();
+ __SPI3_RELEASE_RESET();
+ __SPI3_CLK_DISABLE();
+ #endif
+ #if defined(MICROPY_HW_SPI4_SCK)
+ } else if (spi->Instance == SPI4) {
+ __SPI4_FORCE_RESET();
+ __SPI4_RELEASE_RESET();
+ __SPI4_CLK_DISABLE();
+ #endif
+ #if defined(MICROPY_HW_SPI5_SCK)
+ } else if (spi->Instance == SPI5) {
+ __SPI5_FORCE_RESET();
+ __SPI5_RELEASE_RESET();
+ __SPI5_CLK_DISABLE();
+ #endif
+ #if defined(MICROPY_HW_SPI6_SCK)
+ } else if (spi->Instance == SPI6) {
+ __SPI6_FORCE_RESET();
+ __SPI6_RELEASE_RESET();
+ __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) {
+ return HAL_TIMEOUT;
+ }
+ }
+ return HAL_OK;
+}
+
+// A transfer of "len" bytes should take len*8*1000/baudrate milliseconds.
+// To simplify the calculation we assume the baudrate is never less than 8kHz
+// 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) {
+ // 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.
+
+ HAL_StatusTypeDef status;
+
+ if (dest == NULL) {
+ // send only
+ if (len == 1 || query_irq() == IRQ_STATE_DISABLED) {
+ status = HAL_SPI_Transmit(self->spi, (uint8_t*)src, len, timeout);
+ } else {
+ DMA_HandleTypeDef tx_dma;
+ dma_init(&tx_dma, self->tx_dma_descr, self->spi);
+ 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);
+ }
+ dma_deinit(self->tx_dma_descr);
+ }
+ } else if (src == NULL) {
+ // receive only
+ if (len == 1 || query_irq() == IRQ_STATE_DISABLED) {
+ status = HAL_SPI_Receive(self->spi, dest, len, timeout);
+ } else {
+ DMA_HandleTypeDef tx_dma, rx_dma;
+ if (self->spi->Init.Mode == SPI_MODE_MASTER) {
+ // in master mode the HAL actually does a TransmitReceive call
+ dma_init(&tx_dma, self->tx_dma_descr, self->spi);
+ self->spi->hdmatx = &tx_dma;
+ } else {
+ self->spi->hdmatx = NULL;
+ }
+ 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);
+ }
+ if (self->spi->hdmatx != NULL) {
+ dma_deinit(self->tx_dma_descr);
+ }
+ dma_deinit(self->rx_dma_descr);
+ }
+ } else {
+ // send and receive
+ if (len == 1 || query_irq() == IRQ_STATE_DISABLED) {
+ status = HAL_SPI_TransmitReceive(self->spi, (uint8_t*)src, dest, len, timeout);
+ } else {
+ DMA_HandleTypeDef tx_dma, rx_dma;
+ dma_init(&tx_dma, self->tx_dma_descr, self->spi);
+ self->spi->hdmatx = &tx_dma;
+ dma_init(&rx_dma, self->rx_dma_descr, self->spi);
+ 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);
+ }
+ dma_deinit(self->tx_dma_descr);
+ dma_deinit(self->rx_dma_descr);
+ }
+ }
+
+ if (status != HAL_OK) {
+ mp_hal_raise(status);
+ }
+}
+
+STATIC void spi_print(const mp_print_t *print, SPI_HandleTypeDef *spi, bool legacy) {
+ uint spi_num = 1; // default to SPI1
+ if (spi->Instance == SPI2) { spi_num = 2; }
+ else if (spi->Instance == SPI3) { spi_num = 3; }
+ #if defined(SPI4)
+ else if (spi->Instance == SPI4) { spi_num = 4; }
+ #endif
+ #if defined(SPI5)
+ else if (spi->Instance == SPI5) { spi_num = 5; }
+ #endif
+ #if defined(SPI6)
+ else if (spi->Instance == SPI6) { spi_num = 6; }
+ #endif
+
+ mp_printf(print, "SPI(%u", spi_num);
+ if (spi->State != HAL_SPI_STATE_RESET) {
+ if (spi->Init.Mode == SPI_MODE_MASTER) {
+ // compute baudrate
+ uint spi_clock;
+ if (spi->Instance == SPI2 || spi->Instance == SPI3) {
+ // SPI2 and SPI3 are on APB1
+ spi_clock = HAL_RCC_GetPCLK1Freq();
+ } else {
+ // SPI1, SPI4, SPI5 and SPI6 are on APB2
+ spi_clock = HAL_RCC_GetPCLK2Freq();
+ }
+ uint log_prescaler = (spi->Init.BaudRatePrescaler >> 3) + 1;
+ uint baudrate = spi_clock >> log_prescaler;
+ if (legacy) {
+ mp_printf(print, ", SPI.MASTER");
+ }
+ mp_printf(print, ", baudrate=%u", baudrate);
+ if (legacy) {
+ mp_printf(print, ", prescaler=%u", 1 << log_prescaler);
+ }
+ } else {
+ 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) {
+ mp_printf(print, ", crc=0x%x", spi->Init.CRCPolynomial);
+ }
+ }
+ mp_print_str(print, ")");
+}
+
+/******************************************************************************/
+/* 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;
+}
+
+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;
+ spi_print(print, self->spi, true);
+}
+
+/// \method init(mode, baudrate=328125, *, polarity=1, phase=0, bits=8, firstbit=SPI.MSB, ti=False, crc=None)
+///
+/// Initialise the SPI bus with the given parameters:
+///
+/// - `mode` must be either `SPI.MASTER` or `SPI.SLAVE`.
+/// - `baudrate` is the SCK clock rate (only sensible for a master).
+STATIC mp_obj_t pyb_spi_init_helper(const pyb_spi_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_REQUIRED | MP_ARG_INT, {.u_int = 0} },
+ { MP_QSTR_baudrate, MP_ARG_INT, {.u_int = 328125} },
+ { MP_QSTR_prescaler, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0xffffffff} },
+ { 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 = 0} },
+ { MP_QSTR_dir, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = SPI_DIRECTION_2LINES} },
+ { MP_QSTR_bits, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 8} },
+ { MP_QSTR_nss, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = SPI_NSS_SOFT} },
+ { MP_QSTR_firstbit, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = SPI_FIRSTBIT_MSB} },
+ { MP_QSTR_ti, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
+ { MP_QSTR_crc, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
+ };
+
+ // 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 SPI configuration values
+ SPI_InitTypeDef *init = &self->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,
+ args[6].u_int, args[8].u_int);
+
+ init->Direction = args[5].u_int;
+ init->NSS = args[7].u_int;
+ init->TIMode = args[9].u_bool ? SPI_TIMODE_ENABLED : SPI_TIMODE_DISABLED;
+ if (args[10].u_obj == mp_const_none) {
+ init->CRCCalculation = SPI_CRCCALCULATION_DISABLED;
+ init->CRCPolynomial = 0;
+ } else {
+ init->CRCCalculation = SPI_CRCCALCULATION_ENABLED;
+ init->CRCPolynomial = mp_obj_get_int(args[10].u_obj);
+ }
+
+ // init the SPI bus
+ spi_init(self->spi, init->NSS != SPI_NSS_SOFT);
+
+ return mp_const_none;
+}
+
+/// \classmethod \constructor(bus, ...)
+///
+/// Construct an SPI object on the given bus. `bus` can be 1 or 2.
+/// With no additional parameters, the SPI 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 SPI busses are:
+///
+/// - `SPI(1)` is on the X position: `(NSS, SCK, MISO, MOSI) = (X5, X6, X7, X8) = (PA4, PA5, PA6, PA7)`
+/// - `SPI(2)` is on the Y position: `(NSS, SCK, MISO, MOSI) = (Y5, Y6, Y7, Y8) = (PB12, PB13, PB14, PB15)`
+///
+/// At the moment, the NSS pin is not used by the SPI driver and is free
+/// for other use.
+STATIC mp_obj_t pyb_spi_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 SPI bus
+ int spi_id = spi_find(args[0]);
+
+ // get SPI object
+ const pyb_spi_obj_t *spi_obj = &pyb_spi_obj[spi_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_spi_init_helper(spi_obj, n_args - 1, args + 1, &kw_args);
+ }
+
+ return (mp_obj_t)spi_obj;
+}
+
+STATIC mp_obj_t pyb_spi_init(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
+ return pyb_spi_init_helper(args[0], n_args - 1, args + 1, kw_args);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_spi_init_obj, 1, pyb_spi_init);
+
+/// \method deinit()
+/// Turn off the SPI bus.
+STATIC mp_obj_t pyb_spi_deinit(mp_obj_t self_in) {
+ pyb_spi_obj_t *self = self_in;
+ spi_deinit(self->spi);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_spi_deinit_obj, pyb_spi_deinit);
+
+/// \method send(send, *, timeout=5000)
+/// Send data on the bus:
+///
+/// - `send` is the data to send (an integer to send, or a buffer object).
+/// - `timeout` is the timeout in milliseconds to wait for the send.
+///
+/// Return value: `None`.
+STATIC mp_obj_t pyb_spi_send(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ // TODO assumes transmission size is 8-bits wide
+
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_send, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+ { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 5000} },
+ };
+
+ // parse args
+ pyb_spi_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);
+
+ // send the data
+ spi_transfer(self, bufinfo.len, bufinfo.buf, NULL, args[1].u_int);
+
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_spi_send_obj, 1, pyb_spi_send);
+
+/// \method recv(recv, *, 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.
+/// - `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_spi_recv(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ // TODO assumes transmission size is 8-bits wide
+
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_recv, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+ { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 5000} },
+ };
+
+ // parse args
+ pyb_spi_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);
+
+ // receive the data
+ spi_transfer(self, vstr.len, NULL, (uint8_t*)vstr.buf, args[1].u_int);
+
+ // 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_spi_recv_obj, 1, pyb_spi_recv);
+
+/// \method send_recv(send, recv=None, *, timeout=5000)
+///
+/// Send and receive data on the bus at the same time:
+///
+/// - `send` is the data to send (an integer to send, or a buffer object).
+/// - `recv` is a mutable buffer which will be filled with received bytes.
+/// It can be the same as `send`, or omitted. If omitted, a new buffer will
+/// be created.
+/// - `timeout` is the timeout in milliseconds to wait for the receive.
+///
+/// Return value: the buffer with the received bytes.
+STATIC mp_obj_t pyb_spi_send_recv(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ // TODO assumes transmission size is 8-bits wide
+
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_send, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+ { MP_QSTR_recv, MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+ { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 5000} },
+ };
+
+ // parse args
+ pyb_spi_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 buffers to send from/receive to
+ mp_buffer_info_t bufinfo_send;
+ uint8_t data_send[1];
+ mp_buffer_info_t bufinfo_recv;
+ vstr_t vstr_recv;
+ mp_obj_t o_ret;
+
+ if (args[0].u_obj == args[1].u_obj) {
+ // same object for send and receive, it must be a r/w buffer
+ mp_get_buffer_raise(args[0].u_obj, &bufinfo_send, MP_BUFFER_RW);
+ bufinfo_recv = bufinfo_send;
+ o_ret = args[0].u_obj;
+ } else {
+ // get the buffer to send from
+ pyb_buf_get_for_send(args[0].u_obj, &bufinfo_send, data_send);
+
+ // get the buffer to receive into
+ if (args[1].u_obj == MP_OBJ_NULL) {
+ // only send argument given, so create a fresh buffer of the send length
+ vstr_init_len(&vstr_recv, bufinfo_send.len);
+ bufinfo_recv.len = vstr_recv.len;
+ bufinfo_recv.buf = vstr_recv.buf;
+ o_ret = MP_OBJ_NULL;
+ } else {
+ // recv argument given
+ mp_get_buffer_raise(args[1].u_obj, &bufinfo_recv, MP_BUFFER_WRITE);
+ if (bufinfo_recv.len != bufinfo_send.len) {
+ mp_raise_ValueError("recv must be same length as send");
+ }
+ o_ret = args[1].u_obj;
+ }
+ }
+
+ // do the transfer
+ spi_transfer(self, bufinfo_send.len, bufinfo_send.buf, bufinfo_recv.buf, args[2].u_int);
+
+ // 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_recv);
+ }
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_spi_send_recv_obj, 1, pyb_spi_send_recv);
+
+STATIC const mp_rom_map_elem_t pyb_spi_locals_dict_table[] = {
+ // instance methods
+ { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&pyb_spi_init_obj) },
+ { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&pyb_spi_deinit_obj) },
+
+ { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_machine_spi_read_obj) },
+ { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_machine_spi_readinto_obj) },
+ { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_machine_spi_write_obj) },
+ { MP_ROM_QSTR(MP_QSTR_write_readinto), MP_ROM_PTR(&mp_machine_spi_write_readinto_obj) },
+
+ // legacy methods
+ { MP_ROM_QSTR(MP_QSTR_send), MP_ROM_PTR(&pyb_spi_send_obj) },
+ { MP_ROM_QSTR(MP_QSTR_recv), MP_ROM_PTR(&pyb_spi_recv_obj) },
+ { MP_ROM_QSTR(MP_QSTR_send_recv), MP_ROM_PTR(&pyb_spi_send_recv_obj) },
+
+ // class constants
+ /// \constant MASTER - for initialising the bus to master mode
+ /// \constant SLAVE - for initialising the bus to slave mode
+ /// \constant MSB - set the first bit to MSB
+ /// \constant LSB - set the first bit to LSB
+ { MP_ROM_QSTR(MP_QSTR_MASTER), MP_ROM_INT(SPI_MODE_MASTER) },
+ { MP_ROM_QSTR(MP_QSTR_SLAVE), MP_ROM_INT(SPI_MODE_SLAVE) },
+ { MP_ROM_QSTR(MP_QSTR_MSB), MP_ROM_INT(SPI_FIRSTBIT_MSB) },
+ { MP_ROM_QSTR(MP_QSTR_LSB), MP_ROM_INT(SPI_FIRSTBIT_LSB) },
+ /* TODO
+ { MP_ROM_QSTR(MP_QSTR_DIRECTION_2LINES ((uint32_t)0x00000000)
+ { MP_ROM_QSTR(MP_QSTR_DIRECTION_2LINES_RXONLY SPI_CR1_RXONLY
+ { MP_ROM_QSTR(MP_QSTR_DIRECTION_1LINE SPI_CR1_BIDIMODE
+ { MP_ROM_QSTR(MP_QSTR_NSS_SOFT SPI_CR1_SSM
+ { MP_ROM_QSTR(MP_QSTR_NSS_HARD_INPUT ((uint32_t)0x00000000)
+ { MP_ROM_QSTR(MP_QSTR_NSS_HARD_OUTPUT ((uint32_t)0x00040000)
+ */
+};
+
+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));
+}
+
+STATIC const mp_machine_spi_p_t pyb_spi_p = {
+ .transfer = spi_transfer_machine,
+};
+
+const mp_obj_type_t pyb_spi_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_SPI,
+ .print = pyb_spi_print,
+ .make_new = pyb_spi_make_new,
+ .protocol = &pyb_spi_p,
+ .locals_dict = (mp_obj_dict_t*)&pyb_spi_locals_dict,
+};
+
+/******************************************************************************/
+// Implementation of hard SPI for machine module
+
+typedef struct _machine_hard_spi_obj_t {
+ mp_obj_base_t base;
+ const pyb_spi_obj_t *pyb;
+} 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]},
+};
+
+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);
+}
+
+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) {
+ 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_OBJ, {.u_obj = MP_OBJ_NEW_SMALL_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 = SPI_FIRSTBIT_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);
+
+ // get static peripheral object
+ int spi_id = spi_find(args[ARG_id].u_obj);
+ const machine_hard_spi_obj_t *self = &machine_hard_spi_obj[spi_id - 1];
+
+ // here we would check the sck/mosi/miso pins and configure them, but it's not implemented
+ if (args[ARG_sck].u_obj != MP_OBJ_NULL
+ || args[ARG_mosi].u_obj != MP_OBJ_NULL
+ || args[ARG_miso].u_obj != MP_OBJ_NULL) {
+ mp_raise_ValueError("explicit choice of sck/mosi/miso is not implemented");
+ }
+
+ // set the SPI configuration values
+ SPI_InitTypeDef *init = &self->pyb->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->CRCPolynomial = 0;
+
+ // set configurable paramaters
+ spi_set_params(self->pyb->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);
+
+ return MP_OBJ_FROM_PTR(self);
+}
+
+STATIC void machine_hard_spi_init(mp_obj_base_t *self_in, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ machine_hard_spi_obj_t *self = (machine_hard_spi_obj_t*)self_in;
+
+ enum { ARG_baudrate, ARG_polarity, ARG_phase, ARG_bits, ARG_firstbit };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_baudrate, MP_ARG_KW_ONLY | 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_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 SPI configuration values
+ spi_set_params(self->pyb->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);
+}
+
+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);
+}
+
+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));
+}
+
+STATIC const mp_machine_spi_p_t machine_hard_spi_p = {
+ .init = machine_hard_spi_init,
+ .deinit = machine_hard_spi_deinit,
+ .transfer = machine_hard_spi_transfer,
+};
+
+const mp_obj_type_t machine_hard_spi_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_SPI,
+ .print = machine_hard_spi_print,
+ .make_new = mp_machine_spi_make_new, // delegate to master constructor
+ .protocol = &machine_hard_spi_p,
+ .locals_dict = (mp_obj_t)&mp_machine_spi_locals_dict,
+};
diff --git a/ports/stm32/spi.h b/ports/stm32/spi.h
new file mode 100644
index 000000000..eda109a7e
--- /dev/null
+++ b/ports/stm32/spi.h
@@ -0,0 +1,43 @@
+/*
+ * 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.
+ */
+#ifndef MICROPY_INCLUDED_STMHAL_SPI_H
+#define MICROPY_INCLUDED_STMHAL_SPI_H
+
+extern SPI_HandleTypeDef SPIHandle1;
+extern SPI_HandleTypeDef SPIHandle2;
+extern SPI_HandleTypeDef SPIHandle3;
+extern SPI_HandleTypeDef SPIHandle4;
+extern SPI_HandleTypeDef SPIHandle5;
+extern SPI_HandleTypeDef SPIHandle6;
+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);
+
+#endif // MICROPY_INCLUDED_STMHAL_SPI_H
diff --git a/ports/stm32/startup_stm32.S b/ports/stm32/startup_stm32.S
new file mode 100644
index 000000000..a688cd067
--- /dev/null
+++ b/ports/stm32/startup_stm32.S
@@ -0,0 +1,822 @@
+/**
+ ******************************************************************************
+ * @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
+#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
+
+.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 */
+#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 */
+ .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 */
+#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 */
+ .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 */
+#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 */
+ .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 */
+#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 */
+ .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 */
+#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 */
+ .word SPI5_IRQHandler /* SPI5 */
+ .word SPI6_IRQHandler /* SPI6 */
+ .word SAI1_IRQHandler /* SAI1 */
+ .word 0 /* Reserved */
+ .word 0 /* Reserved */
+ .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 DSIHOST_IRQHandler /* DSI host */
+ .word DFSDM1_FLT0_IRQHandler /* DFSDM1 filter 0 */
+ .word DFSDM1_FLT1_IRQHandler /* DFSDM1 filter 1 */
+ .word DFSDM1_FLT2_IRQHandler /* DFSDM1 filter 2 */
+ .word DFSDM1_FLT3_IRQHandler /* DFSDM1 filter 3 */
+ .word SDMMC2_IRQHandler /* SDMMC2 */
+#endif
+
+/*******************************************************************************
+*
+* 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
+
+#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
+
+ .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
+
+#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
+
+ .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
+#endif
+
+ .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
+
+#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
+
+ .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
+#endif
+
+ .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
+
+#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
+
+ .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
+#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
+
+ .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
+
+#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
+
+ .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
+#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
+
+ .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
+#endif
+
+ .weak I2C3_EV_IRQHandler
+ .thumb_set I2C3_EV_IRQHandler,Default_Handler
+
+ .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
+
+ .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
+#endif
+
+ .weak FPU_IRQHandler
+ .thumb_set FPU_IRQHandler,Default_Handler
+#if defined(MCU_SERIES_F7)
+ .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 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 DSIHOST_IRQHandler
+ .thumb_set DSIHOST_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 SDMMC2_IRQHandler
+ .thumb_set SDMMC2_IRQHandler,Default_Handler
+#endif
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/ports/stm32/stm32_it.c b/ports/stm32/stm32_it.c
new file mode 100644
index 000000000..2111da1ae
--- /dev/null
+++ b/ports/stm32/stm32_it.c
@@ -0,0 +1,799 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * Original template from ST Cube library. See below for header.
+ *
+ * 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.
+ */
+
+/**
+ ******************************************************************************
+ * @file Templates/Src/stm32f4xx_it.c
+ * @author MCD Application Team
+ * @version V1.0.1
+ * @date 26-February-2014
+ * @brief Main Interrupt Service Routines.
+ * This file provides template for all exceptions handler and
+ * peripherals interrupt service routine.
+ ******************************************************************************
+ * @attention
+ *
+ * <h2><center>&copy; COPYRIGHT(c) 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.
+ *
+ ******************************************************************************
+ */
+
+#include <stdio.h>
+
+#include "py/mpstate.h"
+#include "py/obj.h"
+#include "py/mphal.h"
+#include "stm32_it.h"
+#include "pendsv.h"
+#include "irq.h"
+#include "pybthread.h"
+#include "gccollect.h"
+#include "extint.h"
+#include "timer.h"
+#include "uart.h"
+#include "storage.h"
+#include "can.h"
+#include "dma.h"
+#include "i2c.h"
+#include "usb.h"
+
+extern void __fatal_error(const char*);
+extern PCD_HandleTypeDef pcd_fs_handle;
+extern PCD_HandleTypeDef pcd_hs_handle;
+
+/******************************************************************************/
+/* Cortex-M4 Processor Exceptions Handlers */
+/******************************************************************************/
+
+// Set the following to 1 to get some more information on the Hard Fault
+// More information about decoding the fault registers can be found here:
+// http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0646a/Cihdjcfc.html
+
+STATIC char *fmt_hex(uint32_t val, char *buf) {
+ const char *hexDig = "0123456789abcdef";
+
+ buf[0] = hexDig[(val >> 28) & 0x0f];
+ buf[1] = hexDig[(val >> 24) & 0x0f];
+ buf[2] = hexDig[(val >> 20) & 0x0f];
+ buf[3] = hexDig[(val >> 16) & 0x0f];
+ buf[4] = hexDig[(val >> 12) & 0x0f];
+ buf[5] = hexDig[(val >> 8) & 0x0f];
+ buf[6] = hexDig[(val >> 4) & 0x0f];
+ buf[7] = hexDig[(val >> 0) & 0x0f];
+ buf[8] = '\0';
+
+ return buf;
+}
+
+STATIC void print_reg(const char *label, uint32_t val) {
+ char hexStr[9];
+
+ mp_hal_stdout_tx_str(label);
+ mp_hal_stdout_tx_str(fmt_hex(val, hexStr));
+ mp_hal_stdout_tx_str("\r\n");
+}
+
+STATIC void print_hex_hex(const char *label, uint32_t val1, uint32_t val2) {
+ char hex_str[9];
+ mp_hal_stdout_tx_str(label);
+ mp_hal_stdout_tx_str(fmt_hex(val1, hex_str));
+ mp_hal_stdout_tx_str(" ");
+ mp_hal_stdout_tx_str(fmt_hex(val2, hex_str));
+ mp_hal_stdout_tx_str("\r\n");
+}
+
+// The ARMv7M Architecture manual (section B.1.5.6) says that upon entry
+// to an exception, that the registers will be in the following order on the
+// // stack: R0, R1, R2, R3, R12, LR, PC, XPSR
+
+typedef struct {
+ uint32_t r0, r1, r2, r3, r12, lr, pc, xpsr;
+} ExceptionRegisters_t;
+
+int pyb_hard_fault_debug = 0;
+
+void HardFault_C_Handler(ExceptionRegisters_t *regs) {
+ if (!pyb_hard_fault_debug) {
+ NVIC_SystemReset();
+ }
+
+ // 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;
+
+ mp_hal_stdout_tx_str("HardFault\r\n");
+
+ print_reg("R0 ", regs->r0);
+ print_reg("R1 ", regs->r1);
+ print_reg("R2 ", regs->r2);
+ print_reg("R3 ", regs->r3);
+ print_reg("R12 ", regs->r12);
+ print_reg("SP ", (uint32_t)regs);
+ print_reg("LR ", regs->lr);
+ print_reg("PC ", regs->pc);
+ print_reg("XPSR ", regs->xpsr);
+
+ uint32_t cfsr = SCB->CFSR;
+
+ print_reg("HFSR ", SCB->HFSR);
+ print_reg("CFSR ", cfsr);
+ if (cfsr & 0x80) {
+ print_reg("MMFAR ", SCB->MMFAR);
+ }
+ if (cfsr & 0x8000) {
+ print_reg("BFAR ", SCB->BFAR);
+ }
+
+ if ((void*)&_ram_start <= (void*)regs && (void*)regs < (void*)&_ram_end) {
+ mp_hal_stdout_tx_str("Stack:\r\n");
+ uint32_t *stack_top = &_estack;
+ if ((void*)regs < (void*)&_heap_end) {
+ // stack not in static stack area so limit the amount we print
+ stack_top = (uint32_t*)regs + 32;
+ }
+ for (uint32_t *sp = (uint32_t*)regs; sp < stack_top; ++sp) {
+ print_hex_hex(" ", (uint32_t)sp, *sp);
+ }
+ }
+
+ /* Go to infinite loop when Hard Fault exception occurs */
+ while (1) {
+ __fatal_error("HardFault");
+ }
+}
+
+// Naked functions have no compiler generated gunk, so are the best thing to
+// use for asm functions.
+__attribute__((naked))
+void HardFault_Handler(void) {
+
+ // From the ARMv7M Architecture Reference Manual, section B.1.5.6
+ // on entry to the Exception, the LR register contains, amongst other
+ // things, the value of CONTROL.SPSEL. This can be found in bit 3.
+ //
+ // If CONTROL.SPSEL is 0, then the exception was stacked up using the
+ // main stack pointer (aka MSP). If CONTROL.SPSEL is 1, then the exception
+ // was stacked up using the process stack pointer (aka PSP).
+
+ __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
+ " mrseq r0, msp \n" // Make R0 point to main stack pointer
+ " mrsne r0, psp \n" // Make R0 point to process stack pointer
+ " b HardFault_C_Handler \n" // Off to C land
+ );
+}
+
+/**
+ * @brief This function handles NMI exception.
+ * @param None
+ * @retval None
+ */
+void NMI_Handler(void) {
+}
+
+/**
+ * @brief This function handles Memory Manage exception.
+ * @param None
+ * @retval None
+ */
+void MemManage_Handler(void) {
+ /* Go to infinite loop when Memory Manage exception occurs */
+ while (1) {
+ __fatal_error("MemManage");
+ }
+}
+
+/**
+ * @brief This function handles Bus Fault exception.
+ * @param None
+ * @retval None
+ */
+void BusFault_Handler(void) {
+ /* Go to infinite loop when Bus Fault exception occurs */
+ while (1) {
+ __fatal_error("BusFault");
+ }
+}
+
+/**
+ * @brief This function handles Usage Fault exception.
+ * @param None
+ * @retval None
+ */
+void UsageFault_Handler(void) {
+ /* Go to infinite loop when Usage Fault exception occurs */
+ while (1) {
+ __fatal_error("UsageFault");
+ }
+}
+
+/**
+ * @brief This function handles SVCall exception.
+ * @param None
+ * @retval None
+ */
+void SVC_Handler(void) {
+}
+
+/**
+ * @brief This function handles Debug Monitor exception.
+ * @param None
+ * @retval None
+ */
+void DebugMon_Handler(void) {
+}
+
+/**
+ * @brief This function handles PendSVC exception.
+ * @param None
+ * @retval None
+ */
+void PendSV_Handler(void) {
+ pendsv_isr_handler();
+}
+
+/**
+ * @brief This function handles SysTick Handler.
+ * @param None
+ * @retval None
+ */
+void SysTick_Handler(void) {
+ // Instead of calling HAL_IncTick we do the increment here of the counter.
+ // This is purely for efficiency, since SysTick is called 1000 times per
+ // second at the highest interrupt priority.
+ // Note: we don't need uwTick to be declared volatile here because this is
+ // the only place where it can be modified, and the code is more efficient
+ // without the volatile specifier.
+ extern uint32_t uwTick;
+ uwTick += 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;
+
+ // Right now we have the storage and DMA controllers to process during
+ // this interrupt and we use custom dispatch handlers. If this needs to
+ // be generalised in the future then a dispatch table can be used as
+ // follows: ((void(*)(void))(systick_dispatch[uwTick & 0xf]))();
+
+ if (STORAGE_IDLE_TICK(uwTick)) {
+ NVIC->STIR = FLASH_IRQn;
+ }
+
+ if (DMA_IDLE_ENABLED() && DMA_IDLE_TICK(uwTick)) {
+ dma_idle_handler(uwTick);
+ }
+
+ #if MICROPY_PY_THREAD
+ if (pyb_thread_enabled) {
+ if (pyb_thread_cur->timeslice == 0) {
+ if (pyb_thread_cur->run_next != pyb_thread_cur) {
+ SCB->ICSR = SCB_ICSR_PENDSVSET_Msk;
+ }
+ } else {
+ --pyb_thread_cur->timeslice;
+ }
+ }
+ #endif
+}
+
+/******************************************************************************/
+/* STM32F4xx Peripherals Interrupt Handlers */
+/* Add here the Interrupt Handler for the used peripheral(s) (PPP), for the */
+/* available peripheral interrupt handler's name please refer to the startup */
+/* file (startup_stm32f4xx.s). */
+/******************************************************************************/
+
+/**
+ * @brief This function handles USB-On-The-Go FS global interrupt request.
+ * @param None
+ * @retval None
+ */
+#if defined(USE_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)
+void OTG_HS_IRQHandler(void) {
+ IRQ_ENTER(OTG_HS_IRQn);
+ HAL_PCD_IRQHandler(&pcd_hs_handle);
+ IRQ_EXIT(OTG_HS_IRQn);
+}
+#endif
+
+#if defined(USE_USB_FS) || defined(USE_USB_HS)
+/**
+ * @brief This function handles USB OTG Common FS/HS Wakeup functions.
+ * @param *pcd_handle for FS or HS
+ * @retval None
+ */
+STATIC void OTG_CMD_WKUP_Handler(PCD_HandleTypeDef *pcd_handle) {
+
+ if (pcd_handle->Init.low_power_enable) {
+ /* Reset SLEEPDEEP bit of Cortex System Control Register */
+ SCB->SCR &= (uint32_t)~((uint32_t)(SCB_SCR_SLEEPDEEP_Msk | SCB_SCR_SLEEPONEXIT_Msk));
+
+ /* 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);
+
+ /* Wait till HSE is ready */
+ while(__HAL_RCC_GET_FLAG(RCC_FLAG_HSERDY) == RESET)
+ {}
+
+ /* Enable the main PLL. */
+ __HAL_RCC_PLL_ENABLE();
+
+ /* Wait till PLL is ready */
+ while(__HAL_RCC_GET_FLAG(RCC_FLAG_PLLRDY) == RESET)
+ {}
+
+ /* Select PLL as SYSCLK */
+ MODIFY_REG(RCC->CFGR, RCC_CFGR_SW, RCC_SYSCLKSOURCE_PLLCLK);
+
+ while (__HAL_RCC_GET_SYSCLK_SOURCE() != RCC_CFGR_SWS_PLL)
+ {}
+
+ /* ungate PHY clock */
+ __HAL_PCD_UNGATE_PHYCLOCK(pcd_handle);
+ }
+
+}
+#endif
+
+#if defined(USE_USB_FS)
+/**
+ * @brief This function handles USB OTG FS Wakeup IRQ Handler.
+ * @param None
+ * @retval None
+ */
+void OTG_FS_WKUP_IRQHandler(void) {
+ IRQ_ENTER(OTG_FS_WKUP_IRQn);
+
+ OTG_CMD_WKUP_Handler(&pcd_fs_handle);
+
+ /* Clear EXTI pending Bit*/
+ __HAL_USB_FS_EXTI_CLEAR_FLAG();
+
+ IRQ_EXIT(OTG_FS_WKUP_IRQn);
+}
+#endif
+
+#if defined(USE_USB_HS)
+/**
+ * @brief This function handles USB OTG HS Wakeup IRQ Handler.
+ * @param None
+ * @retval None
+ */
+void OTG_HS_WKUP_IRQHandler(void) {
+ IRQ_ENTER(OTG_HS_WKUP_IRQn);
+
+ OTG_CMD_WKUP_Handler(&pcd_hs_handle);
+
+ /* Clear EXTI pending Bit*/
+ __HAL_USB_HS_EXTI_CLEAR_FLAG();
+
+ IRQ_EXIT(OTG_HS_WKUP_IRQn);
+}
+#endif
+
+/**
+ * @brief This function handles PPP interrupt request.
+ * @param None
+ * @retval None
+ */
+/*void PPP_IRQHandler(void)
+{
+}*/
+
+// Handle a flash (erase/program) interrupt.
+void FLASH_IRQHandler(void) {
+ IRQ_ENTER(FLASH_IRQn);
+ // This calls the real flash IRQ handler, if needed
+ /*
+ uint32_t flash_cr = FLASH->CR;
+ if ((flash_cr & FLASH_IT_EOP) || (flash_cr & FLASH_IT_ERR)) {
+ HAL_FLASH_IRQHandler();
+ }
+ */
+ // This call the storage IRQ handler, to check if the flash cache needs flushing
+ storage_irq_handler();
+ IRQ_EXIT(FLASH_IRQn);
+}
+
+/**
+ * @brief These functions handle the EXTI interrupt requests.
+ * @param None
+ * @retval None
+ */
+void EXTI0_IRQHandler(void) {
+ IRQ_ENTER(EXTI0_IRQn);
+ Handle_EXTI_Irq(0);
+ IRQ_EXIT(EXTI0_IRQn);
+}
+
+void EXTI1_IRQHandler(void) {
+ IRQ_ENTER(EXTI1_IRQn);
+ Handle_EXTI_Irq(1);
+ IRQ_EXIT(EXTI1_IRQn);
+}
+
+void EXTI2_IRQHandler(void) {
+ IRQ_ENTER(EXTI2_IRQn);
+ Handle_EXTI_Irq(2);
+ IRQ_EXIT(EXTI2_IRQn);
+}
+
+void EXTI3_IRQHandler(void) {
+ IRQ_ENTER(EXTI3_IRQn);
+ Handle_EXTI_Irq(3);
+ IRQ_EXIT(EXTI3_IRQn);
+}
+
+void EXTI4_IRQHandler(void) {
+ IRQ_ENTER(EXTI4_IRQn);
+ Handle_EXTI_Irq(4);
+ IRQ_EXIT(EXTI4_IRQn);
+}
+
+void EXTI9_5_IRQHandler(void) {
+ IRQ_ENTER(EXTI9_5_IRQn);
+ Handle_EXTI_Irq(5);
+ Handle_EXTI_Irq(6);
+ Handle_EXTI_Irq(7);
+ Handle_EXTI_Irq(8);
+ Handle_EXTI_Irq(9);
+ IRQ_EXIT(EXTI9_5_IRQn);
+}
+
+void EXTI15_10_IRQHandler(void) {
+ IRQ_ENTER(EXTI15_10_IRQn);
+ Handle_EXTI_Irq(10);
+ Handle_EXTI_Irq(11);
+ Handle_EXTI_Irq(12);
+ Handle_EXTI_Irq(13);
+ Handle_EXTI_Irq(14);
+ Handle_EXTI_Irq(15);
+ IRQ_EXIT(EXTI15_10_IRQn);
+}
+
+void PVD_IRQHandler(void) {
+ IRQ_ENTER(PVD_IRQn);
+ Handle_EXTI_Irq(EXTI_PVD_OUTPUT);
+ IRQ_EXIT(PVD_IRQn);
+}
+
+#if defined(MCU_SERIES_L4)
+void PVD_PVM_IRQHandler(void) {
+ IRQ_ENTER(PVD_PVM_IRQn);
+ Handle_EXTI_Irq(EXTI_PVD_OUTPUT);
+ IRQ_EXIT(PVD_PVM_IRQn);
+}
+#endif
+
+void RTC_Alarm_IRQHandler(void) {
+ IRQ_ENTER(RTC_Alarm_IRQn);
+ Handle_EXTI_Irq(EXTI_RTC_ALARM);
+ IRQ_EXIT(RTC_Alarm_IRQn);
+}
+
+#if defined(ETH) // The 407 has ETH, the 405 doesn't
+void ETH_WKUP_IRQHandler(void) {
+ IRQ_ENTER(ETH_WKUP_IRQn);
+ Handle_EXTI_Irq(EXTI_ETH_WAKEUP);
+ IRQ_EXIT(ETH_WKUP_IRQn);
+}
+#endif
+
+void TAMP_STAMP_IRQHandler(void) {
+ IRQ_ENTER(TAMP_STAMP_IRQn);
+ Handle_EXTI_Irq(EXTI_RTC_TIMESTAMP);
+ IRQ_EXIT(TAMP_STAMP_IRQn);
+}
+
+void RTC_WKUP_IRQHandler(void) {
+ IRQ_ENTER(RTC_WKUP_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_WKUP_IRQn);
+}
+
+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)
+void TIM1_BRK_TIM15_IRQHandler(void) {
+ IRQ_ENTER(TIM1_BRK_TIM15_IRQn);
+ timer_irq_handler(15);
+ IRQ_EXIT(TIM1_BRK_TIM15_IRQn);
+}
+#endif
+
+void TIM1_UP_TIM10_IRQHandler(void) {
+ IRQ_ENTER(TIM1_UP_TIM10_IRQn);
+ timer_irq_handler(1);
+ timer_irq_handler(10);
+ IRQ_EXIT(TIM1_UP_TIM10_IRQn);
+}
+
+#if defined(MCU_SERIES_L4)
+void TIM1_UP_TIM16_IRQHandler(void) {
+ IRQ_ENTER(TIM1_UP_TIM16_IRQn);
+ timer_irq_handler(1);
+ timer_irq_handler(16);
+ IRQ_EXIT(TIM1_UP_TIM16_IRQn);
+}
+#endif
+
+void TIM1_TRG_COM_TIM11_IRQHandler(void) {
+ IRQ_ENTER(TIM1_TRG_COM_TIM11_IRQn);
+ timer_irq_handler(11);
+ IRQ_EXIT(TIM1_TRG_COM_TIM11_IRQn);
+}
+
+#if defined(MCU_SERIES_L4)
+void TIM1_TRG_COM_TIM17_IRQHandler(void) {
+ IRQ_ENTER(TIM1_TRG_COM_TIM17_IRQn);
+ timer_irq_handler(17);
+ IRQ_EXIT(TIM1_TRG_COM_TIM17_IRQn);
+}
+#endif
+
+void TIM1_CC_IRQHandler(void) {
+ IRQ_ENTER(TIM1_CC_IRQn);
+ timer_irq_handler(1);
+ IRQ_EXIT(TIM1_CC_IRQn);
+}
+
+void TIM2_IRQHandler(void) {
+ IRQ_ENTER(TIM2_IRQn);
+ timer_irq_handler(2);
+ IRQ_EXIT(TIM2_IRQn);
+}
+
+void TIM3_IRQHandler(void) {
+ IRQ_ENTER(TIM3_IRQn);
+ timer_irq_handler(3);
+ IRQ_EXIT(TIM3_IRQn);
+}
+
+void TIM4_IRQHandler(void) {
+ IRQ_ENTER(TIM4_IRQn);
+ timer_irq_handler(4);
+ IRQ_EXIT(TIM4_IRQn);
+}
+
+void TIM5_IRQHandler(void) {
+ IRQ_ENTER(TIM5_IRQn);
+ timer_irq_handler(5);
+ HAL_TIM_IRQHandler(&TIM5_Handle);
+ IRQ_EXIT(TIM5_IRQn);
+}
+
+#if defined(TIM6) // STM32F401 doesn't have TIM6
+void TIM6_DAC_IRQHandler(void) {
+ IRQ_ENTER(TIM6_DAC_IRQn);
+ timer_irq_handler(6);
+ IRQ_EXIT(TIM6_DAC_IRQn);
+}
+#endif
+
+#if defined(TIM7) // STM32F401 doesn't have TIM7
+void TIM7_IRQHandler(void) {
+ IRQ_ENTER(TIM7_IRQn);
+ timer_irq_handler(7);
+ IRQ_EXIT(TIM7_IRQn);
+}
+#endif
+
+#if defined(TIM8) // STM32F401 doesn't have TIM8
+void TIM8_BRK_TIM12_IRQHandler(void) {
+ IRQ_ENTER(TIM8_BRK_TIM12_IRQn);
+ timer_irq_handler(12);
+ IRQ_EXIT(TIM8_BRK_TIM12_IRQn);
+}
+
+void TIM8_UP_TIM13_IRQHandler(void) {
+ IRQ_ENTER(TIM8_UP_TIM13_IRQn);
+ timer_irq_handler(8);
+ timer_irq_handler(13);
+ IRQ_EXIT(TIM8_UP_TIM13_IRQn);
+}
+
+#if defined(MCU_SERIES_L4)
+void TIM8_UP_IRQHandler(void) {
+ IRQ_ENTER(TIM8_UP_IRQn);
+ timer_irq_handler(8);
+ IRQ_EXIT(TIM8_UP_IRQn);
+}
+#endif
+
+void TIM8_CC_IRQHandler(void) {
+ IRQ_ENTER(TIM8_CC_IRQn);
+ timer_irq_handler(8);
+ IRQ_EXIT(TIM8_CC_IRQn);
+}
+
+void TIM8_TRG_COM_TIM14_IRQHandler(void) {
+ IRQ_ENTER(TIM8_TRG_COM_TIM14_IRQn);
+ timer_irq_handler(14);
+ IRQ_EXIT(TIM8_TRG_COM_TIM14_IRQn);
+}
+#endif
+
+// UART/USART IRQ handlers
+void USART1_IRQHandler(void) {
+ IRQ_ENTER(USART1_IRQn);
+ uart_irq_handler(1);
+ IRQ_EXIT(USART1_IRQn);
+}
+
+void USART2_IRQHandler(void) {
+ IRQ_ENTER(USART2_IRQn);
+ uart_irq_handler(2);
+ IRQ_EXIT(USART2_IRQn);
+}
+
+void USART3_IRQHandler(void) {
+ IRQ_ENTER(USART3_IRQn);
+ uart_irq_handler(3);
+ IRQ_EXIT(USART3_IRQn);
+}
+
+void UART4_IRQHandler(void) {
+ IRQ_ENTER(UART4_IRQn);
+ uart_irq_handler(4);
+ IRQ_EXIT(UART4_IRQn);
+}
+
+void UART5_IRQHandler(void) {
+ IRQ_ENTER(UART5_IRQn);
+ uart_irq_handler(5);
+ IRQ_EXIT(UART5_IRQn);
+}
+
+void USART6_IRQHandler(void) {
+ IRQ_ENTER(USART6_IRQn);
+ uart_irq_handler(6);
+ IRQ_EXIT(USART6_IRQn);
+}
+
+#if defined(MICROPY_HW_UART7_TX)
+void UART7_IRQHandler(void) {
+ IRQ_ENTER(UART7_IRQn);
+ uart_irq_handler(7);
+ IRQ_EXIT(UART7_IRQn);
+}
+#endif
+
+#if defined(MICROPY_HW_UART8_TX)
+void UART8_IRQHandler(void) {
+ IRQ_ENTER(UART8_IRQn);
+ uart_irq_handler(8);
+ IRQ_EXIT(UART8_IRQn);
+}
+#endif
+
+#if MICROPY_HW_ENABLE_CAN
+void CAN1_RX0_IRQHandler(void) {
+ IRQ_ENTER(CAN1_RX0_IRQn);
+ can_rx_irq_handler(PYB_CAN_1, CAN_FIFO0);
+ IRQ_EXIT(CAN1_RX0_IRQn);
+}
+
+void CAN1_RX1_IRQHandler(void) {
+ IRQ_ENTER(CAN1_RX1_IRQn);
+ can_rx_irq_handler(PYB_CAN_1, CAN_FIFO1);
+ IRQ_EXIT(CAN1_RX1_IRQn);
+}
+
+void CAN2_RX0_IRQHandler(void) {
+ IRQ_ENTER(CAN2_RX0_IRQn);
+ can_rx_irq_handler(PYB_CAN_2, CAN_FIFO0);
+ IRQ_EXIT(CAN2_RX0_IRQn);
+}
+
+void CAN2_RX1_IRQHandler(void) {
+ IRQ_ENTER(CAN2_RX1_IRQn);
+ can_rx_irq_handler(PYB_CAN_2, CAN_FIFO1);
+ IRQ_EXIT(CAN2_RX1_IRQn);
+}
+#endif // MICROPY_HW_ENABLE_CAN
+
+#if defined(MICROPY_HW_I2C1_SCL)
+void I2C1_EV_IRQHandler(void) {
+ IRQ_ENTER(I2C1_EV_IRQn);
+ i2c_ev_irq_handler(1);
+ IRQ_EXIT(I2C1_EV_IRQn);
+}
+
+void I2C1_ER_IRQHandler(void) {
+ IRQ_ENTER(I2C1_ER_IRQn);
+ i2c_er_irq_handler(1);
+ IRQ_EXIT(I2C1_ER_IRQn);
+}
+#endif // defined(MICROPY_HW_I2C1_SCL)
+
+#if defined(MICROPY_HW_I2C2_SCL)
+void I2C2_EV_IRQHandler(void) {
+ IRQ_ENTER(I2C2_EV_IRQn);
+ i2c_ev_irq_handler(2);
+ IRQ_EXIT(I2C2_EV_IRQn);
+}
+
+void I2C2_ER_IRQHandler(void) {
+ IRQ_ENTER(I2C2_ER_IRQn);
+ i2c_er_irq_handler(2);
+ IRQ_EXIT(I2C2_ER_IRQn);
+}
+#endif // defined(MICROPY_HW_I2C2_SCL)
+
+#if defined(MICROPY_HW_I2C3_SCL)
+void I2C3_EV_IRQHandler(void) {
+ IRQ_ENTER(I2C3_EV_IRQn);
+ i2c_ev_irq_handler(3);
+ IRQ_EXIT(I2C3_EV_IRQn);
+}
+
+void I2C3_ER_IRQHandler(void) {
+ IRQ_ENTER(I2C3_ER_IRQn);
+ i2c_er_irq_handler(3);
+ IRQ_EXIT(I2C3_ER_IRQn);
+}
+#endif // defined(MICROPY_HW_I2C3_SCL)
diff --git a/ports/stm32/stm32_it.h b/ports/stm32/stm32_it.h
new file mode 100644
index 000000000..b498dee8d
--- /dev/null
+++ b/ports/stm32/stm32_it.h
@@ -0,0 +1,86 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * Original template from ST Cube library. See below for header.
+ *
+ * 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.
+ */
+#ifndef MICROPY_INCLUDED_STMHAL_STM32_IT_H
+#define MICROPY_INCLUDED_STMHAL_STM32_IT_H
+
+/**
+ ******************************************************************************
+ * @file Templates/Inc/stm32f4xx_it.h
+ * @author MCD Application Team
+ * @version V1.0.1
+ * @date 26-February-2014
+ * @brief This file contains the headers of the interrupt handlers.
+ ******************************************************************************
+ * @attention
+ *
+ * <h2><center>&copy; COPYRIGHT(c) 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.
+ *
+ ******************************************************************************
+ */
+
+extern int pyb_hard_fault_debug;
+
+void NMI_Handler(void);
+void HardFault_Handler(void);
+void MemManage_Handler(void);
+void BusFault_Handler(void);
+void UsageFault_Handler(void);
+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
diff --git a/ports/stm32/storage.c b/ports/stm32/storage.c
new file mode 100644
index 000000000..af75ccda4
--- /dev/null
+++ b/ports/stm32/storage.c
@@ -0,0 +1,521 @@
+/*
+ * 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 <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(STM32L476xx)
+
+extern uint8_t _flash_fs_start;
+extern uint8_t _flash_fs_end;
+
+// The STM32L476 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
+
+#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"
+
+#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 const mp_spiflash_t spiflash = {
+ .cs = &MICROPY_HW_SPIFLASH_CS,
+ .spi = (mp_obj_base_t*)&spiflash_spi_bus.base,
+};
+
+#endif
+
+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);
+ #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
+}
+
+uint32_t storage_get_block_size(void) {
+ return FLASH_BLOCK_SIZE;
+}
+
+uint32_t storage_get_block_count(void) {
+ return FLASH_PART1_START_BLOCK + FLASH_PART1_NUM_BLOCKS;
+}
+
+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);
+ }
+
+ #endif
+}
+
+void storage_flush(void) {
+ #if USE_INTERNAL
+ flash_cache_flush();
+ #endif
+}
+
+static void build_partition(uint8_t *buf, int boot, int type, uint32_t start_block, uint32_t num_blocks) {
+ buf[0] = boot;
+
+ if (num_blocks == 0) {
+ buf[1] = 0;
+ buf[2] = 0;
+ buf[3] = 0;
+ } else {
+ buf[1] = 0xff;
+ buf[2] = 0xff;
+ buf[3] = 0xff;
+ }
+
+ buf[4] = type;
+
+ if (num_blocks == 0) {
+ buf[5] = 0;
+ buf[6] = 0;
+ buf[7] = 0;
+ } else {
+ buf[5] = 0xff;
+ buf[6] = 0xff;
+ buf[7] = 0xff;
+ }
+
+ buf[8] = start_block;
+ buf[9] = start_block >> 8;
+ buf[10] = start_block >> 16;
+ buf[11] = start_block >> 24;
+
+ buf[12] = num_blocks;
+ buf[13] = num_blocks >> 8;
+ buf[14] = num_blocks >> 16;
+ 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) {
+ // fake the MBR so we can decide on our own partition table
+
+ for (int i = 0; i < 446; i++) {
+ dest[i] = 0;
+ }
+
+ build_partition(dest + 446, 0, 0x01 /* FAT12 */, FLASH_PART1_START_BLOCK, FLASH_PART1_NUM_BLOCKS);
+ build_partition(dest + 462, 0, 0, 0, 0);
+ build_partition(dest + 478, 0, 0, 0, 0);
+ build_partition(dest + 494, 0, 0, 0, 0);
+
+ dest[510] = 0x55;
+ dest[511] = 0xaa;
+
+ return true;
+
+ } 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
+ }
+}
+
+bool storage_write_block(const uint8_t *src, uint32_t block) {
+ //printf("WR %u\n", block);
+ if (block == 0) {
+ // can't write MBR, but pretend we did
+ return true;
+
+ } 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
+ }
+}
+
+mp_uint_t storage_read_blocks(uint8_t *dest, uint32_t block_num, uint32_t num_blocks) {
+ for (size_t i = 0; i < num_blocks; i++) {
+ if (!storage_read_block(dest + i * FLASH_BLOCK_SIZE, block_num + i)) {
+ return 1; // error
+ }
+ }
+ return 0; // success
+}
+
+mp_uint_t storage_write_blocks(const uint8_t *src, uint32_t block_num, uint32_t num_blocks) {
+ for (size_t i = 0; i < num_blocks; i++) {
+ if (!storage_write_block(src + i * FLASH_BLOCK_SIZE, block_num + i)) {
+ return 1; // error
+ }
+ }
+ return 0; // success
+}
+
+/******************************************************************************/
+// MicroPython bindings
+//
+// Expose the flash as an object with the block protocol.
+
+// there is a singleton Flash object
+STATIC const mp_obj_base_t pyb_flash_obj = {&pyb_flash_type};
+
+STATIC mp_obj_t pyb_flash_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 singleton object
+ return (mp_obj_t)&pyb_flash_obj;
+}
+
+STATIC mp_obj_t pyb_flash_readblocks(mp_obj_t self, mp_obj_t block_num, mp_obj_t buf) {
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(buf, &bufinfo, MP_BUFFER_WRITE);
+ mp_uint_t ret = storage_read_blocks(bufinfo.buf, mp_obj_get_int(block_num), bufinfo.len / FLASH_BLOCK_SIZE);
+ return MP_OBJ_NEW_SMALL_INT(ret);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_3(pyb_flash_readblocks_obj, pyb_flash_readblocks);
+
+STATIC mp_obj_t pyb_flash_writeblocks(mp_obj_t self, mp_obj_t block_num, mp_obj_t buf) {
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(buf, &bufinfo, MP_BUFFER_READ);
+ mp_uint_t ret = storage_write_blocks(bufinfo.buf, mp_obj_get_int(block_num), bufinfo.len / FLASH_BLOCK_SIZE);
+ return MP_OBJ_NEW_SMALL_INT(ret);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_3(pyb_flash_writeblocks_obj, pyb_flash_writeblocks);
+
+STATIC mp_obj_t pyb_flash_ioctl(mp_obj_t self, mp_obj_t cmd_in, mp_obj_t arg_in) {
+ mp_int_t cmd = mp_obj_get_int(cmd_in);
+ switch (cmd) {
+ case BP_IOCTL_INIT: storage_init(); return MP_OBJ_NEW_SMALL_INT(0);
+ case BP_IOCTL_DEINIT: storage_flush(); return MP_OBJ_NEW_SMALL_INT(0); // TODO properly
+ case BP_IOCTL_SYNC: storage_flush(); return MP_OBJ_NEW_SMALL_INT(0);
+ case BP_IOCTL_SEC_COUNT: return MP_OBJ_NEW_SMALL_INT(storage_get_block_count());
+ case BP_IOCTL_SEC_SIZE: return MP_OBJ_NEW_SMALL_INT(storage_get_block_size());
+ default: return mp_const_none;
+ }
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_3(pyb_flash_ioctl_obj, pyb_flash_ioctl);
+
+STATIC const mp_rom_map_elem_t pyb_flash_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_readblocks), MP_ROM_PTR(&pyb_flash_readblocks_obj) },
+ { MP_ROM_QSTR(MP_QSTR_writeblocks), MP_ROM_PTR(&pyb_flash_writeblocks_obj) },
+ { MP_ROM_QSTR(MP_QSTR_ioctl), MP_ROM_PTR(&pyb_flash_ioctl_obj) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(pyb_flash_locals_dict, pyb_flash_locals_dict_table);
+
+const mp_obj_type_t pyb_flash_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_Flash,
+ .make_new = pyb_flash_make_new,
+ .locals_dict = (mp_obj_dict_t*)&pyb_flash_locals_dict,
+};
+
+void pyb_flash_init_vfs(fs_user_mount_t *vfs) {
+ vfs->base.type = &mp_fat_vfs_type;
+ vfs->flags |= FSUSER_NATIVE | FSUSER_HAVE_IOCTL;
+ vfs->fatfs.drv = vfs;
+ vfs->fatfs.part = 1; // flash filesystem lives on first partition
+ vfs->readblocks[0] = (mp_obj_t)&pyb_flash_readblocks_obj;
+ vfs->readblocks[1] = (mp_obj_t)&pyb_flash_obj;
+ vfs->readblocks[2] = (mp_obj_t)storage_read_blocks; // native version
+ vfs->writeblocks[0] = (mp_obj_t)&pyb_flash_writeblocks_obj;
+ vfs->writeblocks[1] = (mp_obj_t)&pyb_flash_obj;
+ vfs->writeblocks[2] = (mp_obj_t)storage_write_blocks; // native version
+ vfs->u.ioctl[0] = (mp_obj_t)&pyb_flash_ioctl_obj;
+ vfs->u.ioctl[1] = (mp_obj_t)&pyb_flash_obj;
+}
diff --git a/ports/stm32/storage.h b/ports/stm32/storage.h
new file mode 100644
index 000000000..291e09a9a
--- /dev/null
+++ b/ports/stm32/storage.h
@@ -0,0 +1,51 @@
+/*
+ * 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.
+ */
+#ifndef MICROPY_INCLUDED_STMHAL_STORAGE_H
+#define MICROPY_INCLUDED_STMHAL_STORAGE_H
+
+#define FLASH_BLOCK_SIZE (512)
+
+#define STORAGE_SYSTICK_MASK (0x1ff) // 512ms
+#define STORAGE_IDLE_TICK(tick) (((tick) & STORAGE_SYSTICK_MASK) == 2)
+
+void storage_init(void);
+uint32_t storage_get_block_size(void);
+uint32_t storage_get_block_count(void);
+void storage_irq_handler(void);
+void storage_flush(void);
+bool storage_read_block(uint8_t *dest, uint32_t block);
+bool storage_write_block(const uint8_t *src, uint32_t block);
+
+// these return 0 on success, non-zero on error
+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);
+
+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
diff --git a/ports/stm32/system_stm32.c b/ports/stm32/system_stm32.c
new file mode 100644
index 000000000..b71a03181
--- /dev/null
+++ b/ports/stm32/system_stm32.c
@@ -0,0 +1,496 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * Taken from ST Cube library and modified. See below for original header.
+ *
+ * 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.
+ */
+
+/**
+ ******************************************************************************
+ * @file system_stm32.c
+ * @author MCD Application Team
+ * @version V1.0.1
+ * @date 26-February-2014
+ * @brief CMSIS Cortex-M4/M7 Device Peripheral Access Layer System Source File.
+ *
+ * This file provides two functions and one global variable to be called from
+ * user application:
+ * - SystemInit(): This function is called at startup just after reset and
+ * before branch to main program. This call is made inside
+ * the "startup_stm32.s" file.
+ *
+ * - SystemCoreClock variable: Contains the core clock (HCLK), it can be used
+ * by the user application to setup the SysTick
+ * timer or configure other parameters.
+ *
+ *
+ ******************************************************************************
+ * @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.
+ *
+ ******************************************************************************
+ */
+
+/** @addtogroup CMSIS
+ * @{
+ */
+
+/** @addtogroup stm32fxxx_system
+ * @{
+ */
+
+/** @addtogroup STM32Fxxx_System_Private_Includes
+ * @{
+ */
+
+#include "py/mphal.h"
+
+void __fatal_error(const char *msg);
+
+/**
+ * @}
+ */
+
+/** @addtogroup STM32Fxxx_System_Private_TypesDefinitions
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+/** @addtogroup STM32Fxxx_System_Private_Defines
+ * @{
+ */
+
+#if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7)
+
+#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)
+
+#if defined(MCU_SERIES_F4)
+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)
+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)
+
+#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_PLLCFGR (0x00001000)
+/*
+ * FIXME Do not know why I have to define these arrays here! they should be defined in the
+ * hal_rcc-file!!
+ *
+ */
+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};
+const uint32_t MSIRangeTable[12] = {100000, 200000, 400000, 800000, 1000000, 2000000, \
+ 4000000, 8000000, 16000000, 24000000, 32000000, 48000000};
+#else
+#error Unknown processor
+#endif
+
+/************************* Miscellaneous Configuration ************************/
+
+/*!< Uncomment the following line if you need to relocate your vector Table in
+ Internal SRAM. */
+/* #define VECT_TAB_SRAM */
+#define VECT_TAB_OFFSET 0x00 /*!< Vector Table base offset field.
+ This value must be a multiple of 0x200. */
+/******************************************************************************/
+
+/**
+ * @}
+ */
+
+/** @addtogroup STM32Fxxx_System_Private_Macros
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+/** @addtogroup STM32Fxxx_System_Private_Variables
+ * @{
+ */
+ /* 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; then there
+ is no need to call the 2 first functions listed above, since SystemCoreClock
+ variable is updated automatically.
+ */
+ uint32_t SystemCoreClock = 16000000;
+
+/**
+ * @}
+ */
+
+/** @addtogroup STM32Fxxx_System_Private_FunctionPrototypes
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+/** @addtogroup STM32Fxxx_System_Private_Functions
+ * @{
+ */
+
+/**
+ * @brief Setup the microcontroller system
+ * Initialize the FPU setting, vector table location and External memory
+ * configuration.
+ * @param None
+ * @retval None
+ */
+void SystemInit(void)
+{
+ /* FPU settings ------------------------------------------------------------*/
+ #if (__FPU_PRESENT == 1) && (__FPU_USED == 1)
+ SCB->CPACR |= ((3UL << 10*2)|(3UL << 11*2)); /* set CP10 and CP11 Full Access */
+ #endif
+ /* Reset the RCC clock configuration to the default reset state ------------*/
+
+ /* 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 */
+ #if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7)
+ RCC->CIR = 0x00000000;
+ #elif defined(MCU_SERIES_L4)
+ RCC->CIER = 0x00000000;
+ #endif
+
+ /* Configure the Vector Table location add offset address ------------------*/
+#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
+
+ /* dpgeorge: enable 8-byte stack alignment for IRQ handlers, in accord with EABI */
+ SCB->CCR |= SCB_CCR_STKALIGN_Msk;
+}
+
+
+/**
+ * @brief System Clock Configuration
+ *
+ * The system Clock is configured for F4/F7 as follows:
+ * System Clock source = PLL (HSE)
+ * SYSCLK(Hz) = 168000000
+ * HCLK(Hz) = 168000000
+ * AHB Prescaler = 1
+ * APB1 Prescaler = 4
+ * APB2 Prescaler = 2
+ * HSE Frequency(Hz) = HSE_VALUE
+ * PLL_M = HSE_VALUE/1000000
+ * PLL_N = 336
+ * PLL_P = 2
+ * PLL_Q = 7
+ * VDD(V) = 3.3
+ * Main regulator output voltage = Scale1 mode
+ * Flash Latency(WS) = 5
+ *
+ * The system Clock is configured for L4 as follows:
+ * System Clock source = PLL (MSI)
+ * SYSCLK(Hz) = 80000000
+ * HCLK(Hz) = 80000000
+ * AHB Prescaler = 1
+ * APB1 Prescaler = 1
+ * APB2 Prescaler = 1
+ * MSI Frequency(Hz) = MSI_VALUE (4000000)
+ * LSE Frequency(Hz) = 32768
+ * PLL_M = 1
+ * PLL_N = 40
+ * PLL_P = 7
+ * PLL_Q = 2
+ * PLL_R = 2 <= This is the source for SysClk, not as on F4/7 PLL_P
+ * Flash Latency(WS) = 4
+ * @param None
+ * @retval None
+ *
+ * PLL is configured as follows:
+ *
+ * VCO_IN
+ * F4/F7 = HSE / M
+ * L4 = MSI / M
+ * VCO_OUT
+ * F4/F7 = HSE / M * N
+ * L4 = MSI / M * N
+ * PLLCLK
+ * F4/F7 = HSE / M * N / P
+ * L4 = MSI / M * N / R
+ * PLL48CK
+ * F4/F7 = HSE / M * N / Q
+ * L4 = MSI / M * N / Q USB Clock is obtained over PLLSAI1
+ *
+ * SYSCLK = PLLCLK
+ * HCLK = SYSCLK / AHB_PRESC
+ * PCLKx = HCLK / APBx_PRESC
+ *
+ * Constraints on parameters:
+ *
+ * VCO_IN between 1MHz and 2MHz (2MHz recommended)
+ * VCO_OUT between 192MHz and 432MHz
+ * HSE = 8MHz
+ * M = 2 .. 63 (inclusive)
+ * N = 192 ... 432 (inclusive)
+ * P = 2, 4, 6, 8
+ * Q = 2 .. 15 (inclusive)
+ *
+ * AHB_PRESC=1,2,4,8,16,64,128,256,512
+ * APBx_PRESC=1,2,4,8,16
+ *
+ * Output clocks:
+ *
+ * CPU SYSCLK max 168MHz
+ * USB,RNG,SDIO PLL48CK must be 48MHz for USB
+ * AHB HCLK max 168MHz
+ * APB1 PCLK1 max 42MHz
+ * APB2 PCLK2 max 84MHz
+ *
+ * Timers run from APBx if APBx_PRESC=1, else 2x APBx
+ */
+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)
+ // Configure LSE Drive Capability
+ __HAL_RCC_LSEDRIVE_CONFIG(RCC_LSEDRIVE_LOW);
+ #endif
+
+ /* Enable HSE Oscillator and activate PLL with HSE as source */
+ #if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7)
+ RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
+ RCC_OscInitStruct.HSEState = RCC_HSE_ON;
+ RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
+ #elif defined(MCU_SERIES_L4)
+ 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;
+ RCC_OscInitStruct.MSIClockRange = RCC_MSIRANGE_6;
+ RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_MSI;
+ #endif
+ RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
+ /* 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);
+ RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
+
+#if defined(MICROPY_HW_CLK_LAST_FREQ) && MICROPY_HW_CLK_LAST_FREQ
+ #if defined(MCU_SERIES_F7)
+ #define FREQ_BKP BKP31R
+ #elif defined(MCU_SERIES_L4)
+ #error Unsupported Processor
+ #else
+ #define FREQ_BKP BKP19R
+ #endif
+ uint32_t m = RTC->FREQ_BKP;
+ uint32_t n;
+ uint32_t p;
+ uint32_t q;
+
+ // 222111HH HHQQQQPP nNNNNNNN NNMMMMMM
+ uint32_t h = (m >> 22) & 0xf;
+ uint32_t b1 = (m >> 26) & 0x7;
+ uint32_t b2 = (m >> 29) & 0x7;
+ q = (m >> 18) & 0xf;
+ p = (((m >> 16) & 0x03)+1)*2;
+ n = (m >> 6) & 0x3ff;
+ m &= 0x3f;
+ if ((q < 2) || (q > 15) || (p > 8) || (p < 2) || (n < 192) || (n >= 433) || (m < 2)) {
+ m = MICROPY_HW_CLK_PLLM;
+ n = MICROPY_HW_CLK_PLLN;
+ p = MICROPY_HW_CLK_PLLP;
+ q = MICROPY_HW_CLK_PLLQ;
+ h = RCC_SYSCLK_DIV1;
+ b1 = RCC_HCLK_DIV4;
+ b2 = RCC_HCLK_DIV2;
+ } else {
+ h <<= 4;
+ b1 <<= 10;
+ b2 <<= 10;
+ }
+ RCC_OscInitStruct.PLL.PLLM = m; //MICROPY_HW_CLK_PLLM;
+ RCC_OscInitStruct.PLL.PLLN = n; //MICROPY_HW_CLK_PLLN;
+ RCC_OscInitStruct.PLL.PLLP = p; //MICROPY_HW_CLK_PLLP;
+ RCC_OscInitStruct.PLL.PLLQ = q; //MICROPY_HW_CLK_PLLQ;
+
+ RCC_ClkInitStruct.AHBCLKDivider = h; //RCC_SYSCLK_DIV1;
+ RCC_ClkInitStruct.APB1CLKDivider = b1; //RCC_HCLK_DIV4;
+ RCC_ClkInitStruct.APB2CLKDivider = b2; //RCC_HCLK_DIV2;
+#else // defined(MICROPY_HW_CLK_LAST_FREQ) && MICROPY_HW_CLK_LAST_FREQ
+ RCC_OscInitStruct.PLL.PLLM = MICROPY_HW_CLK_PLLM;
+ 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)
+ RCC_OscInitStruct.PLL.PLLR = MICROPY_HW_CLK_PLLR;
+ #endif
+
+ RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
+ #if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7)
+ RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
+ RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
+ #elif defined(MCU_SERIES_L4)
+ RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
+ RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
+ #endif
+#endif
+ if(HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
+ {
+ __fatal_error("HAL_RCC_OscConfig");
+ }
+
+#if defined(MCU_SERIES_F7)
+ /* Activate the OverDrive to reach the 200 MHz Frequency */
+ if (HAL_PWREx_EnableOverDrive() != HAL_OK)
+ {
+ __fatal_error("HAL_PWREx_EnableOverDrive");
+ }
+#endif
+
+#if !defined(MICROPY_HW_FLASH_LATENCY)
+#define MICROPY_HW_FLASH_LATENCY FLASH_LATENCY_5
+#endif
+
+ if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, MICROPY_HW_FLASH_LATENCY) != HAL_OK)
+ {
+ __fatal_error("HAL_RCC_ClockConfig");
+ }
+
+#if defined(MCU_SERIES_F7)
+ // 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)
+ // Enable MSI-Hardware auto calibration mode with LSE
+ HAL_RCCEx_EnableMSIPLLMode();
+
+ RCC_PeriphCLKInitTypeDef PeriphClkInitStruct;
+ PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_SAI1|RCC_PERIPHCLK_I2C1
+ |RCC_PERIPHCLK_USB |RCC_PERIPHCLK_ADC
+ |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
+ application or the reference manual. */
+ PeriphClkInitStruct.Sai1ClockSelection = RCC_SAI1CLKSOURCE_PLLSAI1;
+ PeriphClkInitStruct.AdcClockSelection = RCC_ADCCLKSOURCE_PLLSAI1;
+ PeriphClkInitStruct.UsbClockSelection = RCC_USBCLKSOURCE_PLLSAI1;
+ PeriphClkInitStruct.RTCClockSelection = RCC_RTCCLKSOURCE_LSE;
+ PeriphClkInitStruct.RngClockSelection = RCC_RNGCLKSOURCE_PLLSAI1;
+ PeriphClkInitStruct.PLLSAI1.PLLSAI1Source = RCC_PLLSOURCE_MSI;
+ PeriphClkInitStruct.PLLSAI1.PLLSAI1M = 1;
+ PeriphClkInitStruct.PLLSAI1.PLLSAI1N = 24;
+ PeriphClkInitStruct.PLLSAI1.PLLSAI1P = RCC_PLLP_DIV7;
+ PeriphClkInitStruct.PLLSAI1.PLLSAI1Q = RCC_PLLQ_DIV2;
+ PeriphClkInitStruct.PLLSAI1.PLLSAI1R = RCC_PLLR_DIV2;
+ PeriphClkInitStruct.PLLSAI1.PLLSAI1ClockOut = RCC_PLLSAI1_SAI1CLK
+ |RCC_PLLSAI1_48M2CLK
+ |RCC_PLLSAI1_ADC1CLK;
+
+ if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK)
+ {
+ __fatal_error("HAL_RCCEx_PeriphCLKConfig");
+ }
+
+ __PWR_CLK_ENABLE();
+
+ 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();
+#endif
+}
diff --git a/ports/stm32/systick.c b/ports/stm32/systick.c
new file mode 100644
index 000000000..c07d0fabc
--- /dev/null
+++ b/ports/stm32/systick.c
@@ -0,0 +1,140 @@
+/*
+ * 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 "py/runtime.h"
+#include "py/mphal.h"
+#include "irq.h"
+#include "systick.h"
+#include "pybthread.h"
+
+extern __IO uint32_t uwTick;
+
+// We provide our own version of HAL_Delay that calls __WFI while waiting,
+// and works when interrupts are disabled. This function is intended to be
+// used only by the ST HAL functions.
+void HAL_Delay(uint32_t Delay) {
+ if (query_irq() == IRQ_STATE_ENABLED) {
+ // IRQs enabled, so can use systick counter to do the delay
+ uint32_t start = uwTick;
+ // Wraparound of tick is taken care of by 2's complement arithmetic.
+ while (uwTick - start < Delay) {
+ // Enter sleep mode, waiting for (at least) the SysTick interrupt.
+ __WFI();
+ }
+ } else {
+ // IRQs disabled, use mp_hal_delay_ms routine.
+ mp_hal_delay_ms(Delay);
+ }
+}
+
+// Core delay function that does an efficient sleep and may switch thread context.
+// If IRQs are enabled then we must have the GIL.
+void mp_hal_delay_ms(mp_uint_t Delay) {
+ if (query_irq() == IRQ_STATE_ENABLED) {
+ // IRQs enabled, so can use systick counter to do the delay
+ uint32_t start = uwTick;
+ // Wraparound of tick is taken care of by 2's complement arithmetic.
+ while (uwTick - start < Delay) {
+ // This macro will execute the necessary idle behaviour. It may
+ // raise an exception, switch threads or enter sleep mode (waiting for
+ // (at least) the SysTick interrupt).
+ MICROPY_EVENT_POLL_HOOK
+ }
+ } 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 = HAL_RCC_GetSysClockFreq() / 4000;
+ for (int i = 0; i < Delay; i++) {
+ for (uint32_t count = 0; ++count <= count_1ms;) {
+ }
+ }
+ }
+}
+
+// delay for given number of microseconds
+void mp_hal_delay_us(mp_uint_t usec) {
+ if (query_irq() == IRQ_STATE_ENABLED) {
+ // IRQs enabled, so can use systick counter to do the delay
+ uint32_t start = mp_hal_ticks_us();
+ while (mp_hal_ticks_us() - start < usec) {
+ }
+ } else {
+ // IRQs disabled, so need to 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 = HAL_RCC_GetSysClockFreq() / 2000000 * usec / 2;
+ for (uint32_t count = 0; ++count <= ucount;) {
+ }
+ }
+}
+
+bool sys_tick_has_passed(uint32_t start_tick, uint32_t delay_ms) {
+ return HAL_GetTick() - start_tick >= delay_ms;
+}
+
+// waits until at least delay_ms milliseconds have passed from the sampling of
+// startTick. Handles overflow properly. Assumes stc was taken from
+// HAL_GetTick() some time before calling this function.
+void sys_tick_wait_at_least(uint32_t start_tick, uint32_t delay_ms) {
+ while (!sys_tick_has_passed(start_tick, delay_ms)) {
+ __WFI(); // enter sleep mode, waiting for interrupt
+ }
+}
+
+mp_uint_t mp_hal_ticks_ms(void) {
+ return uwTick;
+}
+
+// The SysTick timer counts down at 168 MHz, so we can use that knowledge
+// to grab a microsecond counter.
+//
+// We assume that HAL_GetTickis returns milliseconds.
+mp_uint_t mp_hal_ticks_us(void) {
+ mp_uint_t irq_state = disable_irq();
+ uint32_t counter = SysTick->VAL;
+ uint32_t milliseconds = HAL_GetTick();
+ uint32_t status = SysTick->CTRL;
+ enable_irq(irq_state);
+
+ // It's still possible for the countflag bit to get set if the counter was
+ // reloaded between reading VAL and reading CTRL. With interrupts disabled
+ // it definitely takes less than 50 HCLK cycles between reading VAL and
+ // reading CTRL, so the test (counter > 50) is to cover the case where VAL
+ // is +ve and very close to zero, and the COUNTFLAG bit is also set.
+ if ((status & SysTick_CTRL_COUNTFLAG_Msk) && counter > 50) {
+ // This means that the HW reloaded VAL between the time we read VAL and the
+ // time we read CTRL, which implies that there is an interrupt pending
+ // to increment the tick counter.
+ milliseconds++;
+ }
+ uint32_t load = SysTick->LOAD;
+ counter = load - counter; // Convert from decrementing to incrementing
+
+ // ((load + 1) / 1000) is the number of counts per microsecond.
+ //
+ // counter / ((load + 1) / 1000) scales from the systick clock to microseconds
+ // and is the same thing as (counter * 1000) / (load + 1)
+ return milliseconds * 1000 + (counter * 1000) / (load + 1);
+}
diff --git a/ports/stm32/systick.h b/ports/stm32/systick.h
new file mode 100644
index 000000000..c1def50c2
--- /dev/null
+++ b/ports/stm32/systick.h
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ */
+#ifndef MICROPY_INCLUDED_STMHAL_SYSTICK_H
+#define MICROPY_INCLUDED_STMHAL_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
diff --git a/ports/stm32/timer.c b/ports/stm32/timer.c
new file mode 100644
index 000000000..00e9c2a83
--- /dev/null
+++ b/ports/stm32/timer.c
@@ -0,0 +1,1423 @@
+/*
+ * 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 <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "py/runtime.h"
+#include "py/gc.h"
+#include "timer.h"
+#include "servo.h"
+#include "pin.h"
+#include "irq.h"
+
+/// \moduleref pyb
+/// \class Timer - periodically call a function
+///
+/// Timers can be used for a great variety of tasks. At the moment, only
+/// the simplest case is implemented: that of calling a function periodically.
+///
+/// Each timer consists of a counter that counts up at a certain rate. The rate
+/// at which it counts is the peripheral clock frequency (in Hz) divided by the
+/// timer prescaler. When the counter reaches the timer period it triggers an
+/// event, and the counter resets back to zero. By using the callback method,
+/// the timer event can call a Python function.
+///
+/// Example usage to toggle an LED at a fixed frequency:
+///
+/// tim = pyb.Timer(4) # create a timer object using timer 4
+/// tim.init(freq=2) # trigger at 2Hz
+/// tim.callback(lambda t:pyb.LED(1).toggle())
+///
+/// Further examples:
+///
+/// tim = pyb.Timer(4, freq=100) # freq in Hz
+/// tim = pyb.Timer(4, prescaler=0, period=99)
+/// tim.counter() # get counter (can also set)
+/// tim.prescaler(2) # set prescaler (can also get)
+/// tim.period(199) # set period (can also get)
+/// tim.callback(lambda t: ...) # set callback for update interrupt (t=tim instance)
+/// tim.callback(None) # clear callback
+///
+/// *Note:* Timer 3 is used for fading the blue LED. Timer 5 controls
+/// the servo driver, and Timer 6 is used for timed ADC/DAC reading/writing.
+/// It is recommended to use the other timers in your programs.
+
+// The timers can be used by multiple drivers, and need a common point for
+// the interrupts to be dispatched, so they are all collected here.
+//
+// TIM3:
+// - LED 4, PWM to set the LED intensity
+//
+// TIM5:
+// - servo controller, PWM
+//
+// TIM6:
+// - ADC, DAC for read_timed and write_timed
+
+typedef enum {
+ CHANNEL_MODE_PWM_NORMAL,
+ CHANNEL_MODE_PWM_INVERTED,
+ CHANNEL_MODE_OC_TIMING,
+ CHANNEL_MODE_OC_ACTIVE,
+ CHANNEL_MODE_OC_INACTIVE,
+ CHANNEL_MODE_OC_TOGGLE,
+ CHANNEL_MODE_OC_FORCED_ACTIVE,
+ CHANNEL_MODE_OC_FORCED_INACTIVE,
+ CHANNEL_MODE_IC,
+ CHANNEL_MODE_ENC_A,
+ CHANNEL_MODE_ENC_B,
+ CHANNEL_MODE_ENC_AB,
+} pyb_channel_mode;
+
+STATIC const struct {
+ qstr name;
+ uint32_t oc_mode;
+} channel_mode_info[] = {
+ { MP_QSTR_PWM, TIM_OCMODE_PWM1 },
+ { MP_QSTR_PWM_INVERTED, TIM_OCMODE_PWM2 },
+ { MP_QSTR_OC_TIMING, TIM_OCMODE_TIMING },
+ { MP_QSTR_OC_ACTIVE, TIM_OCMODE_ACTIVE },
+ { MP_QSTR_OC_INACTIVE, TIM_OCMODE_INACTIVE },
+ { MP_QSTR_OC_TOGGLE, TIM_OCMODE_TOGGLE },
+ { MP_QSTR_OC_FORCED_ACTIVE, TIM_OCMODE_FORCED_ACTIVE },
+ { MP_QSTR_OC_FORCED_INACTIVE, TIM_OCMODE_FORCED_INACTIVE },
+ { MP_QSTR_IC, 0 },
+ { MP_QSTR_ENC_A, TIM_ENCODERMODE_TI1 },
+ { MP_QSTR_ENC_B, TIM_ENCODERMODE_TI2 },
+ { MP_QSTR_ENC_AB, TIM_ENCODERMODE_TI12 },
+};
+
+typedef struct _pyb_timer_channel_obj_t {
+ mp_obj_base_t base;
+ struct _pyb_timer_obj_t *timer;
+ uint8_t channel;
+ uint8_t mode;
+ mp_obj_t callback;
+ struct _pyb_timer_channel_obj_t *next;
+} pyb_timer_channel_obj_t;
+
+typedef struct _pyb_timer_obj_t {
+ mp_obj_base_t base;
+ uint8_t tim_id;
+ uint8_t is_32bit;
+ mp_obj_t callback;
+ TIM_HandleTypeDef tim;
+ IRQn_Type irqn;
+ pyb_timer_channel_obj_t *channel;
+} pyb_timer_obj_t;
+
+// The following yields TIM_IT_UPDATE when channel is zero and
+// TIM_IT_CC1..TIM_IT_CC4 when channel is 1..4
+#define TIMER_IRQ_MASK(channel) (1 << (channel))
+#define TIMER_CNT_MASK(self) ((self)->is_32bit ? 0xffffffff : 0xffff)
+#define TIMER_CHANNEL(self) ((((self)->channel) - 1) << 2)
+
+TIM_HandleTypeDef TIM5_Handle;
+TIM_HandleTypeDef TIM6_Handle;
+
+#define PYB_TIMER_OBJ_ALL_NUM MP_ARRAY_SIZE(MP_STATE_PORT(pyb_timer_obj_all))
+
+STATIC mp_obj_t pyb_timer_deinit(mp_obj_t self_in);
+STATIC mp_obj_t pyb_timer_callback(mp_obj_t self_in, mp_obj_t callback);
+STATIC mp_obj_t pyb_timer_channel_callback(mp_obj_t self_in, mp_obj_t callback);
+
+void timer_init0(void) {
+ for (uint i = 0; i < PYB_TIMER_OBJ_ALL_NUM; i++) {
+ MP_STATE_PORT(pyb_timer_obj_all)[i] = NULL;
+ }
+}
+
+// unregister all interrupt sources
+void timer_deinit(void) {
+ for (uint i = 0; i < PYB_TIMER_OBJ_ALL_NUM; i++) {
+ pyb_timer_obj_t *tim = MP_STATE_PORT(pyb_timer_obj_all)[i];
+ if (tim != NULL) {
+ pyb_timer_deinit(tim);
+ }
+ }
+}
+
+// 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();
+
+ // set up and enable interrupt
+ HAL_NVIC_SetPriority(TIM5_IRQn, IRQ_PRI_TIM5, IRQ_SUBPRI_TIM5);
+ HAL_NVIC_EnableIRQ(TIM5_IRQn);
+
+ // PWM clock configuration
+ TIM5_Handle.Instance = TIM5;
+ TIM5_Handle.Init.Period = 2000 - 1; // timer cycles at 50Hz
+ TIM5_Handle.Init.Prescaler = (timer_get_source_freq(5) / 100000) - 1; // timer runs at 100kHz
+ TIM5_Handle.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
+ TIM5_Handle.Init.CounterMode = TIM_COUNTERMODE_UP;
+
+ HAL_TIM_PWM_Init(&TIM5_Handle);
+}
+
+#if defined(TIM6)
+// Init TIM6 with a counter-overflow at the given frequency (given in Hz)
+// TIM6 is used by the DAC and ADC for auto sampling at a given frequency
+// This function inits but does not start the timer
+TIM_HandleTypeDef *timer_tim6_init(uint freq) {
+ // TIM6 clock enable
+ __TIM6_CLK_ENABLE();
+
+ // Timer runs at SystemCoreClock / 2
+ // Compute the prescaler value so TIM6 triggers at freq-Hz
+ uint32_t period = MAX(1, timer_get_source_freq(6) / freq);
+ uint32_t prescaler = 1;
+ while (period > 0xffff) {
+ period >>= 1;
+ prescaler <<= 1;
+ }
+
+ // Time base clock configuration
+ TIM6_Handle.Instance = TIM6;
+ TIM6_Handle.Init.Period = period - 1;
+ TIM6_Handle.Init.Prescaler = prescaler - 1;
+ TIM6_Handle.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; // unused for TIM6
+ TIM6_Handle.Init.CounterMode = TIM_COUNTERMODE_UP; // unused for TIM6
+ HAL_TIM_Base_Init(&TIM6_Handle);
+
+ return &TIM6_Handle;
+}
+#endif
+
+// Interrupt dispatch
+void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {
+ #if MICROPY_HW_ENABLE_SERVO
+ if (htim == &TIM5_Handle) {
+ servo_timer_irq_callback();
+ }
+ #endif
+}
+
+// Get the frequency (in Hz) of the source clock for the given timer.
+// On STM32F405/407/415/417 there are 2 cases for how the clock freq is set.
+// If the APB prescaler is 1, then the timer clock is equal to its respective
+// 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;
+ if (tim_id == 1 || (8 <= tim_id && tim_id <= 11)) {
+ // TIM{1,8,9,10,11} are on APB2
+ source = HAL_RCC_GetPCLK2Freq();
+ if ((uint32_t)((RCC->CFGR & RCC_CFGR_PPRE2) >> 3) != RCC_HCLK_DIV1) {
+ source *= 2;
+ }
+ } 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;
+ }
+ }
+ return source;
+}
+
+/******************************************************************************/
+/* MicroPython bindings */
+
+STATIC const mp_obj_type_t pyb_timer_channel_type;
+
+// This is the largest value that we can multiply by 100 and have the result
+// fit in a uint32_t.
+#define MAX_PERIOD_DIV_100 42949672
+
+// computes prescaler and period so TIM triggers at freq-Hz
+STATIC uint32_t compute_prescaler_period_from_freq(pyb_timer_obj_t *self, mp_obj_t freq_in, uint32_t *period_out) {
+ uint32_t source_freq = timer_get_source_freq(self->tim_id);
+ uint32_t prescaler = 1;
+ uint32_t period;
+ if (0) {
+ #if MICROPY_PY_BUILTINS_FLOAT
+ } else if (MP_OBJ_IS_TYPE(freq_in, &mp_type_float)) {
+ float freq = mp_obj_get_float(freq_in);
+ if (freq <= 0) {
+ goto bad_freq;
+ }
+ while (freq < 1 && prescaler < 6553) {
+ prescaler *= 10;
+ freq *= 10;
+ }
+ period = (float)source_freq / freq;
+ #endif
+ } else {
+ mp_int_t freq = mp_obj_get_int(freq_in);
+ if (freq <= 0) {
+ goto bad_freq;
+ bad_freq:
+ mp_raise_ValueError("must have positive freq");
+ }
+ period = source_freq / freq;
+ }
+ period = MAX(1, period);
+ while (period > TIMER_CNT_MASK(self)) {
+ // if we can divide exactly, do that first
+ if (period % 5 == 0) {
+ prescaler *= 5;
+ period /= 5;
+ } else if (period % 3 == 0) {
+ prescaler *= 3;
+ period /= 3;
+ } else {
+ // may not divide exactly, but loses minimal precision
+ prescaler <<= 1;
+ period >>= 1;
+ }
+ }
+ *period_out = (period - 1) & TIMER_CNT_MASK(self);
+ return (prescaler - 1) & 0xffff;
+}
+
+// Helper function for determining the period used for calculating percent
+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));
+ if (period != 0xffffffff) {
+ if (self->tim.Init.CounterMode == TIM_COUNTERMODE_UP ||
+ self->tim.Init.CounterMode == TIM_COUNTERMODE_DOWN) {
+ // Edge mode
+ period++;
+ }
+ }
+ return period;
+}
+
+// Helper function to compute PWM value from timer period and percent value.
+// 'percent_in' can be an int or a float between 0 and 100 (out of range
+// values are clamped).
+STATIC uint32_t compute_pwm_value_from_percent(uint32_t period, mp_obj_t percent_in) {
+ uint32_t cmp;
+ if (0) {
+ #if MICROPY_PY_BUILTINS_FLOAT
+ } else if (MP_OBJ_IS_TYPE(percent_in, &mp_type_float)) {
+ mp_float_t percent = mp_obj_get_float(percent_in);
+ if (percent <= 0.0) {
+ cmp = 0;
+ } else if (percent >= 100.0) {
+ cmp = period;
+ } else {
+ cmp = percent / 100.0 * ((mp_float_t)period);
+ }
+ #endif
+ } else {
+ // For integer arithmetic, if period is large and 100*period will
+ // overflow, then divide period before multiplying by cmp. Otherwise
+ // do it the other way round to retain precision.
+ mp_int_t percent = mp_obj_get_int(percent_in);
+ if (percent <= 0) {
+ cmp = 0;
+ } else if (percent >= 100) {
+ cmp = period;
+ } else if (period > MAX_PERIOD_DIV_100) {
+ cmp = (uint32_t)percent * (period / 100);
+ } else {
+ cmp = ((uint32_t)percent * period) / 100;
+ }
+ }
+ return cmp;
+}
+
+// Helper function to compute percentage from timer perion and PWM value.
+STATIC mp_obj_t compute_percent_from_pwm_value(uint32_t period, uint32_t cmp) {
+ #if MICROPY_PY_BUILTINS_FLOAT
+ mp_float_t percent;
+ if (cmp >= period) {
+ percent = 100.0;
+ } else {
+ percent = (mp_float_t)cmp * 100.0 / ((mp_float_t)period);
+ }
+ return mp_obj_new_float(percent);
+ #else
+ mp_int_t percent;
+ if (cmp >= period) {
+ percent = 100;
+ } else if (cmp > MAX_PERIOD_DIV_100) {
+ percent = cmp / (period / 100);
+ } else {
+ percent = cmp * 100 / period;
+ }
+ return mp_obj_new_int(percent);
+ #endif
+}
+
+// Computes the 8-bit value for the DTG field in the BDTR register.
+//
+// 1 tick = 1 count of the timer's clock (source_freq) divided by div.
+// 0-128 ticks in inrements of 1
+// 128-256 ticks in increments of 2
+// 256-512 ticks in increments of 8
+// 512-1008 ticks in increments of 16
+STATIC uint32_t compute_dtg_from_ticks(mp_int_t ticks) {
+ if (ticks <= 0) {
+ return 0;
+ }
+ if (ticks < 128) {
+ return ticks;
+ }
+ if (ticks < 256) {
+ return 0x80 | ((ticks - 128) / 2);
+ }
+ if (ticks < 512) {
+ return 0xC0 | ((ticks - 256) / 8);
+ }
+ if (ticks < 1008) {
+ return 0xE0 | ((ticks - 512) / 16);
+ }
+ return 0xFF;
+}
+
+// Given the 8-bit value stored in the DTG field of the BDTR register, compute
+// the number of ticks.
+STATIC mp_int_t compute_ticks_from_dtg(uint32_t dtg) {
+ if ((dtg & 0x80) == 0) {
+ return dtg & 0x7F;
+ }
+ if ((dtg & 0xC0) == 0x80) {
+ return 128 + ((dtg & 0x3F) * 2);
+ }
+ if ((dtg & 0xE0) == 0xC0) {
+ return 256 + ((dtg & 0x1F) * 8);
+ }
+ return 512 + ((dtg & 0x1F) * 16);
+}
+
+STATIC void config_deadtime(pyb_timer_obj_t *self, mp_int_t ticks) {
+ TIM_BreakDeadTimeConfigTypeDef deadTimeConfig;
+ deadTimeConfig.OffStateRunMode = TIM_OSSR_DISABLE;
+ deadTimeConfig.OffStateIDLEMode = TIM_OSSI_DISABLE;
+ deadTimeConfig.LockLevel = TIM_LOCKLEVEL_OFF;
+ deadTimeConfig.DeadTime = compute_dtg_from_ticks(ticks);
+ deadTimeConfig.BreakState = TIM_BREAK_DISABLE;
+ deadTimeConfig.BreakPolarity = TIM_BREAKPOLARITY_LOW;
+ deadTimeConfig.AutomaticOutput = TIM_AUTOMATICOUTPUT_DISABLE;
+ HAL_TIMEx_ConfigBreakDeadTime(&self->tim, &deadTimeConfig);
+}
+
+TIM_HandleTypeDef *pyb_timer_get_handle(mp_obj_t timer) {
+ if (mp_obj_get_type(timer) != &pyb_timer_type) {
+ mp_raise_ValueError("need a Timer object");
+ }
+ pyb_timer_obj_t *self = timer;
+ return &self->tim;
+}
+
+STATIC void pyb_timer_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
+ pyb_timer_obj_t *self = self_in;
+
+ if (self->tim.State == HAL_TIM_STATE_RESET) {
+ 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);
+ // 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",
+ self->tim_id,
+ freq,
+ prescaler,
+ period,
+ self->tim.Init.CounterMode == TIM_COUNTERMODE_UP ? "UP" :
+ self->tim.Init.CounterMode == TIM_COUNTERMODE_DOWN ? "DOWN" : "CENTER",
+ self->tim.Init.ClockDivision == TIM_CLOCKDIVISION_DIV4 ? 4 :
+ self->tim.Init.ClockDivision == TIM_CLOCKDIVISION_DIV2 ? 2 : 1);
+
+ #if defined(IS_TIM_ADVANCED_INSTANCE)
+ if (IS_TIM_ADVANCED_INSTANCE(self->tim.Instance))
+ #elif defined(IS_TIM_BREAK_INSTANCE)
+ if (IS_TIM_BREAK_INSTANCE(self->tim.Instance))
+ #else
+ if (0)
+ #endif
+ {
+ mp_printf(print, ", deadtime=%u",
+ compute_ticks_from_dtg(self->tim.Instance->BDTR & TIM_BDTR_DTG));
+ }
+ mp_print_str(print, ")");
+ }
+}
+
+/// \method init(*, freq, prescaler, period)
+/// Initialise the timer. Initialisation must be either by frequency (in Hz)
+/// or by prescaler and period:
+///
+/// tim.init(freq=100) # set the timer to trigger at 100Hz
+/// tim.init(prescaler=83, period=999) # set the prescaler and period directly
+///
+/// Keyword arguments:
+///
+/// - `freq` - specifies the periodic frequency of the timer. You migh also
+/// view this as the frequency with which the timer goes through
+/// one complete cycle.
+///
+/// - `prescaler` [0-0xffff] - specifies the value to be loaded into the
+/// timer's Prescaler Register (PSC). The timer clock source is divided by
+/// (`prescaler + 1`) to arrive at the timer clock. Timers 2-7 and 12-14
+/// have a clock source of 84 MHz (pyb.freq()[2] * 2), and Timers 1, and 8-11
+/// have a clock source of 168 MHz (pyb.freq()[3] * 2).
+///
+/// - `period` [0-0xffff] for timers 1, 3, 4, and 6-15. [0-0x3fffffff] for timers 2 & 5.
+/// Specifies the value to be loaded into the timer's AutoReload
+/// Register (ARR). This determines the period of the timer (i.e. when the
+/// counter cycles). The timer counter will roll-over after `period + 1`
+/// timer clock cycles.
+///
+/// - `mode` can be one of:
+/// - `Timer.UP` - configures the timer to count from 0 to ARR (default)
+/// - `Timer.DOWN` - configures the timer to count from ARR down to 0.
+/// - `Timer.CENTER` - confgures the timer to count from 0 to ARR and
+/// then back down to 0.
+///
+/// - `div` can be one of 1, 2, or 4. Divides the timer clock to determine
+/// the sampling clock used by the digital filters.
+///
+/// - `callback` - as per Timer.callback()
+///
+/// - `deadtime` - specifies the amount of "dead" or inactive time between
+/// transitions on complimentary channels (both channels will be inactive)
+/// for this time). `deadtime` may be an integer between 0 and 1008, with
+/// the following restrictions: 0-128 in steps of 1. 128-256 in steps of
+/// 2, 256-512 in steps of 8, and 512-1008 in steps of 16. `deadime`
+/// measures ticks of `source_freq` divided by `div` clock ticks.
+/// `deadtime` is only available on timers 1 and 8.
+///
+/// You must either specify freq or both of period and prescaler.
+STATIC mp_obj_t pyb_timer_init_helper(pyb_timer_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_freq, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
+ { MP_QSTR_prescaler, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0xffffffff} },
+ { 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 = TIM_COUNTERMODE_UP} },
+ { MP_QSTR_div, 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} },
+ { MP_QSTR_deadtime, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
+ };
+
+ // 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 TIM configuration values
+ TIM_Base_InitTypeDef *init = &self->tim.Init;
+
+ if (args[0].u_obj != mp_const_none) {
+ // set prescaler and period from desired frequency
+ init->Prescaler = compute_prescaler_period_from_freq(self, args[0].u_obj, &init->Period);
+ } else if (args[1].u_int != 0xffffffff && args[2].u_int != 0xffffffff) {
+ // set prescaler and period directly
+ init->Prescaler = args[1].u_int;
+ init->Period = args[2].u_int;
+ } else {
+ mp_raise_TypeError("must specify either freq, or prescaler and period");
+ }
+
+ init->CounterMode = args[3].u_int;
+ if (!IS_TIM_COUNTER_MODE(init->CounterMode)) {
+ nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "invalid mode (%d)", init->CounterMode));
+ }
+
+ init->ClockDivision = args[4].u_int == 2 ? TIM_CLOCKDIVISION_DIV2 :
+ args[4].u_int == 4 ? TIM_CLOCKDIVISION_DIV4 :
+ TIM_CLOCKDIVISION_DIV1;
+
+ init->RepetitionCounter = 0;
+
+ // 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;
+ #if defined(TIM6)
+ case 6: __TIM6_CLK_ENABLE(); break;
+ #endif
+ #if defined(TIM7)
+ case 7: __TIM7_CLK_ENABLE(); break;
+ #endif
+ #if defined(TIM8)
+ case 8: __TIM8_CLK_ENABLE(); break;
+ #endif
+ #if defined(TIM9)
+ case 9: __TIM9_CLK_ENABLE(); break;
+ #endif
+ #if defined(TIM10)
+ case 10: __TIM10_CLK_ENABLE(); break;
+ #endif
+ #if defined(TIM11)
+ case 11: __TIM11_CLK_ENABLE(); break;
+ #endif
+ #if defined(TIM12)
+ case 12: __TIM12_CLK_ENABLE(); break;
+ #endif
+ #if defined(TIM13)
+ case 13: __TIM13_CLK_ENABLE(); break;
+ #endif
+ #if defined(TIM14)
+ case 14: __TIM14_CLK_ENABLE(); break;
+ #endif
+ #if defined(TIM15)
+ case 15: __TIM15_CLK_ENABLE(); break;
+ #endif
+ #if defined(TIM16)
+ case 16: __TIM16_CLK_ENABLE(); break;
+ #endif
+ #if defined(TIM17)
+ case 17: __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);
+ if (self->tim_id == 1) {
+ HAL_NVIC_SetPriority(TIM1_CC_IRQn, IRQ_PRI_TIMX, IRQ_SUBPRI_TIMX);
+ #if defined(TIM8)
+ } else if (self->tim_id == 8) {
+ HAL_NVIC_SetPriority(TIM8_CC_IRQn, IRQ_PRI_TIMX, IRQ_SUBPRI_TIMX);
+ #endif
+ }
+ }
+
+ // init TIM
+ HAL_TIM_Base_Init(&self->tim);
+ #if defined(IS_TIM_ADVANCED_INSTANCE)
+ if (IS_TIM_ADVANCED_INSTANCE(self->tim.Instance)) {
+ #elif defined(IS_TIM_BREAK_INSTANCE)
+ if (IS_TIM_BREAK_INSTANCE(self->tim.Instance)) {
+ #else
+ if (0) {
+ #endif
+ config_deadtime(self, args[6].u_int);
+ }
+ if (args[5].u_obj == mp_const_none) {
+ HAL_TIM_Base_Start(&self->tim);
+ } else {
+ pyb_timer_callback(self, args[5].u_obj);
+ }
+
+ return mp_const_none;
+}
+
+/// \classmethod \constructor(id, ...)
+/// Construct a new timer object of the given id. If additional
+/// arguments are given, then the timer is initialised by `init(...)`.
+/// `id` can be 1 to 14, excluding 3.
+STATIC mp_obj_t pyb_timer_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);
+
+ // create new Timer object
+ pyb_timer_obj_t *tim = m_new_obj(pyb_timer_obj_t);
+ memset(tim, 0, sizeof(*tim));
+
+ tim->base.type = &pyb_timer_type;
+ tim->callback = mp_const_none;
+ tim->channel = NULL;
+
+ // get TIM number
+ tim->tim_id = mp_obj_get_int(args[0]);
+ tim->is_32bit = false;
+
+ switch (tim->tim_id) {
+ #if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7)
+ case 1: tim->tim.Instance = TIM1; tim->irqn = TIM1_UP_TIM10_IRQn; break;
+ #elif defined(MCU_SERIES_L4)
+ case 1: tim->tim.Instance = TIM1; tim->irqn = TIM1_UP_TIM16_IRQn; break;
+ #endif
+ case 2: tim->tim.Instance = TIM2; tim->irqn = TIM2_IRQn; tim->is_32bit = true; break;
+ case 3: tim->tim.Instance = TIM3; tim->irqn = TIM3_IRQn; break;
+ case 4: tim->tim.Instance = TIM4; tim->irqn = TIM4_IRQn; break;
+ case 5: tim->tim.Instance = TIM5; tim->irqn = TIM5_IRQn; tim->is_32bit = true; break;
+ #if defined(TIM6)
+ case 6: tim->tim.Instance = TIM6; tim->irqn = TIM6_DAC_IRQn; break;
+ #endif
+ #if defined(TIM7)
+ case 7: tim->tim.Instance = TIM7; tim->irqn = TIM7_IRQn; break;
+ #endif
+ #if defined(TIM8)
+ #if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7)
+ case 8: tim->tim.Instance = TIM8; tim->irqn = TIM8_UP_TIM13_IRQn; break;
+ #elif defined(MCU_SERIES_L4)
+ case 8: tim->tim.Instance = TIM8; tim->irqn = TIM8_UP_IRQn; break;
+ #endif
+ #endif
+ #if defined(TIM9)
+ case 9: tim->tim.Instance = TIM9; tim->irqn = TIM1_BRK_TIM9_IRQn; break;
+ #endif
+ #if defined(TIM10)
+ case 10: tim->tim.Instance = TIM10; tim->irqn = TIM1_UP_TIM10_IRQn; break;
+ #endif
+ #if defined(TIM11)
+ case 11: tim->tim.Instance = TIM11; tim->irqn = TIM1_TRG_COM_TIM11_IRQn; break;
+ #endif
+ #if defined(TIM12)
+ case 12: tim->tim.Instance = TIM12; tim->irqn = TIM8_BRK_TIM12_IRQn; break;
+ #endif
+ #if defined(TIM13)
+ case 13: tim->tim.Instance = TIM13; tim->irqn = TIM8_UP_TIM13_IRQn; break;
+ #endif
+ #if defined(TIM14)
+ case 14: tim->tim.Instance = TIM14; tim->irqn = TIM8_TRG_COM_TIM14_IRQn; break;
+ #endif
+ #if defined(TIM15)
+ case 15: tim->tim.Instance = TIM15; tim->irqn = TIM1_BRK_TIM15_IRQn; break;
+ #endif
+ #if defined(TIM16)
+ case 16: tim->tim.Instance = TIM16; tim->irqn = TIM1_UP_TIM16_IRQn; break;
+ #endif
+ #if defined(TIM17)
+ case 17: tim->tim.Instance = TIM17; tim->irqn = TIM1_TRG_COM_TIM17_IRQn; break;
+ #endif
+ default: nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "Timer(%d) doesn't exist", tim->tim_id));
+ }
+
+ // set the global variable for interrupt callbacks
+ if (tim->tim_id - 1 < PYB_TIMER_OBJ_ALL_NUM) {
+ MP_STATE_PORT(pyb_timer_obj_all)[tim->tim_id - 1] = tim;
+ }
+
+ 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_timer_init_helper(tim, n_args - 1, args + 1, &kw_args);
+ }
+
+ return (mp_obj_t)tim;
+}
+
+STATIC mp_obj_t pyb_timer_init(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
+ return pyb_timer_init_helper(args[0], n_args - 1, args + 1, kw_args);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_timer_init_obj, 1, pyb_timer_init);
+
+// timer.deinit()
+STATIC mp_obj_t pyb_timer_deinit(mp_obj_t self_in) {
+ pyb_timer_obj_t *self = self_in;
+
+ // Disable the base interrupt
+ pyb_timer_callback(self_in, mp_const_none);
+
+ pyb_timer_channel_obj_t *chan = self->channel;
+ self->channel = NULL;
+
+ // Disable the channel interrupts
+ while (chan != NULL) {
+ pyb_timer_channel_callback(chan, mp_const_none);
+ pyb_timer_channel_obj_t *prev_chan = chan;
+ chan = chan->next;
+ prev_chan->next = NULL;
+ }
+
+ self->tim.State = HAL_TIM_STATE_RESET;
+ self->tim.Instance->CCER = 0x0000; // disable all capture/compare outputs
+ self->tim.Instance->CR1 = 0x0000; // disable the timer and reset its state
+
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_timer_deinit_obj, pyb_timer_deinit);
+
+/// \method channel(channel, mode, ...)
+///
+/// If only a channel number is passed, then a previously initialized channel
+/// object is returned (or `None` if there is no previous channel).
+///
+/// Othwerwise, a TimerChannel object is initialized and returned.
+///
+/// Each channel can be configured to perform pwm, output compare, or
+/// input capture. All channels share the same underlying timer, which means
+/// that they share the same timer clock.
+///
+/// Keyword arguments:
+///
+/// - `mode` can be one of:
+/// - `Timer.PWM` - configure the timer in PWM mode (active high).
+/// - `Timer.PWM_INVERTED` - configure the timer in PWM mode (active low).
+/// - `Timer.OC_TIMING` - indicates that no pin is driven.
+/// - `Timer.OC_ACTIVE` - the pin will be made active when a compare
+/// match occurs (active is determined by polarity)
+/// - `Timer.OC_INACTIVE` - the pin will be made inactive when a compare
+/// match occurs.
+/// - `Timer.OC_TOGGLE` - the pin will be toggled when an compare match occurs.
+/// - `Timer.OC_FORCED_ACTIVE` - the pin is forced active (compare match is ignored).
+/// - `Timer.OC_FORCED_INACTIVE` - the pin is forced inactive (compare match is ignored).
+/// - `Timer.IC` - configure the timer in Input Capture mode.
+/// - `Timer.ENC_A` --- configure the timer in Encoder mode. The counter only changes when CH1 changes.
+/// - `Timer.ENC_B` --- configure the timer in Encoder mode. The counter only changes when CH2 changes.
+/// - `Timer.ENC_AB` --- configure the timer in Encoder mode. The counter changes when CH1 or CH2 changes.
+///
+/// - `callback` - as per TimerChannel.callback()
+///
+/// - `pin` None (the default) or a Pin object. If specified (and not None)
+/// this will cause the alternate function of the the indicated pin
+/// to be configured for this timer channel. An error will be raised if
+/// the pin doesn't support any alternate functions for this timer channel.
+///
+/// Keyword arguments for Timer.PWM modes:
+///
+/// - `pulse_width` - determines the initial pulse width value to use.
+/// - `pulse_width_percent` - determines the initial pulse width percentage to use.
+///
+/// Keyword arguments for Timer.OC modes:
+///
+/// - `compare` - determines the initial value of the compare register.
+///
+/// - `polarity` can be one of:
+/// - `Timer.HIGH` - output is active high
+/// - `Timer.LOW` - output is acive low
+///
+/// Optional keyword arguments for Timer.IC modes:
+///
+/// - `polarity` can be one of:
+/// - `Timer.RISING` - captures on rising edge.
+/// - `Timer.FALLING` - captures on falling edge.
+/// - `Timer.BOTH` - captures on both edges.
+///
+/// Note that capture only works on the primary channel, and not on the
+/// complimentary channels.
+///
+/// Notes for Timer.ENC modes:
+///
+/// - Requires 2 pins, so one or both pins will need to be configured to use
+/// the appropriate timer AF using the Pin API.
+/// - Read the encoder value using the timer.counter() method.
+/// - Only works on CH1 and CH2 (and not on CH1N or CH2N)
+/// - The channel number is ignored when setting the encoder mode.
+///
+/// PWM Example:
+///
+/// timer = pyb.Timer(2, freq=1000)
+/// ch2 = timer.channel(2, pyb.Timer.PWM, pin=pyb.Pin.board.X2, pulse_width=210000)
+/// ch3 = timer.channel(3, pyb.Timer.PWM, pin=pyb.Pin.board.X3, pulse_width=420000)
+STATIC mp_obj_t pyb_timer_channel(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_REQUIRED | MP_ARG_INT, {.u_int = 0} },
+ { MP_QSTR_callback, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
+ { MP_QSTR_pin, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
+ { MP_QSTR_pulse_width, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
+ { MP_QSTR_pulse_width_percent, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
+ { MP_QSTR_compare, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
+ { MP_QSTR_polarity, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0xffffffff} },
+ };
+
+ pyb_timer_obj_t *self = pos_args[0];
+ mp_int_t channel = mp_obj_get_int(pos_args[1]);
+
+ if (channel < 1 || channel > 4) {
+ nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "invalid channel (%d)", channel));
+ }
+
+ pyb_timer_channel_obj_t *chan = self->channel;
+ pyb_timer_channel_obj_t *prev_chan = NULL;
+
+ while (chan != NULL) {
+ if (chan->channel == channel) {
+ break;
+ }
+ prev_chan = chan;
+ chan = chan->next;
+ }
+
+ // If only the channel number is given return the previously allocated
+ // channel (or None if no previous channel).
+ if (n_args == 2 && kw_args->used == 0) {
+ if (chan) {
+ return chan;
+ }
+ return mp_const_none;
+ }
+
+ // If there was already a channel, then remove it from the list. Note that
+ // the order we do things here is important so as to appear atomic to
+ // the IRQ handler.
+ if (chan) {
+ // Turn off any IRQ associated with the channel.
+ pyb_timer_channel_callback(chan, mp_const_none);
+
+ // Unlink the channel from the list.
+ if (prev_chan) {
+ prev_chan->next = chan->next;
+ }
+ self->channel = chan->next;
+ chan->next = NULL;
+ }
+
+ // Allocate and initialize a new channel
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args - 2, pos_args + 2, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ chan = m_new_obj(pyb_timer_channel_obj_t);
+ memset(chan, 0, sizeof(*chan));
+ chan->base.type = &pyb_timer_channel_type;
+ chan->timer = self;
+ chan->channel = channel;
+ chan->mode = args[0].u_int;
+ chan->callback = args[1].u_obj;
+
+ mp_obj_t pin_obj = args[2].u_obj;
+ if (pin_obj != mp_const_none) {
+ if (!MP_OBJ_IS_TYPE(pin_obj, &pin_type)) {
+ mp_raise_ValueError("pin argument needs to be be a Pin type");
+ }
+ const pin_obj_t *pin = pin_obj;
+ const pin_af_obj_t *af = pin_find_af(pin, AF_FN_TIM, self->tim_id);
+ if (af == NULL) {
+ nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "Pin(%q) doesn't have an af for Timer(%d)", pin->name, self->tim_id));
+ }
+ // pin.init(mode=AF_PP, af=idx)
+ const mp_obj_t args2[6] = {
+ (mp_obj_t)&pin_init_obj,
+ pin_obj,
+ MP_OBJ_NEW_QSTR(MP_QSTR_mode), MP_OBJ_NEW_SMALL_INT(GPIO_MODE_AF_PP),
+ MP_OBJ_NEW_QSTR(MP_QSTR_af), MP_OBJ_NEW_SMALL_INT(af->idx)
+ };
+ mp_call_method_n_kw(0, 2, args2);
+ }
+
+ // Link the channel to the timer before we turn the channel on.
+ // Note that this needs to appear atomic to the IRQ handler (the write
+ // to self->channel is atomic, so we're good, but I thought I'd mention
+ // in case this was ever changed in the future).
+ chan->next = self->channel;
+ self->channel = chan;
+
+ switch (chan->mode) {
+
+ case CHANNEL_MODE_PWM_NORMAL:
+ case CHANNEL_MODE_PWM_INVERTED: {
+ TIM_OC_InitTypeDef oc_config;
+ oc_config.OCMode = channel_mode_info[chan->mode].oc_mode;
+ if (args[4].u_obj != mp_const_none) {
+ // pulse width percent given
+ uint32_t period = compute_period(self);
+ oc_config.Pulse = compute_pwm_value_from_percent(period, args[4].u_obj);
+ } else {
+ // use absolute pulse width value (defaults to 0 if nothing given)
+ oc_config.Pulse = args[3].u_int;
+ }
+ oc_config.OCPolarity = TIM_OCPOLARITY_HIGH;
+ oc_config.OCNPolarity = TIM_OCNPOLARITY_HIGH;
+ oc_config.OCFastMode = TIM_OCFAST_DISABLE;
+ oc_config.OCIdleState = TIM_OCIDLESTATE_SET;
+ oc_config.OCNIdleState = TIM_OCNIDLESTATE_SET;
+
+ HAL_TIM_PWM_ConfigChannel(&self->tim, &oc_config, TIMER_CHANNEL(chan));
+ if (chan->callback == mp_const_none) {
+ HAL_TIM_PWM_Start(&self->tim, TIMER_CHANNEL(chan));
+ } else {
+ pyb_timer_channel_callback(chan, chan->callback);
+ }
+ // Start the complimentary channel too (if its supported)
+ if (IS_TIM_CCXN_INSTANCE(self->tim.Instance, TIMER_CHANNEL(chan))) {
+ HAL_TIMEx_PWMN_Start(&self->tim, TIMER_CHANNEL(chan));
+ }
+ break;
+ }
+
+ case CHANNEL_MODE_OC_TIMING:
+ case CHANNEL_MODE_OC_ACTIVE:
+ case CHANNEL_MODE_OC_INACTIVE:
+ case CHANNEL_MODE_OC_TOGGLE:
+ case CHANNEL_MODE_OC_FORCED_ACTIVE:
+ case CHANNEL_MODE_OC_FORCED_INACTIVE: {
+ TIM_OC_InitTypeDef oc_config;
+ oc_config.OCMode = channel_mode_info[chan->mode].oc_mode;
+ oc_config.Pulse = args[5].u_int;
+ oc_config.OCPolarity = args[6].u_int;
+ if (oc_config.OCPolarity == 0xffffffff) {
+ oc_config.OCPolarity = TIM_OCPOLARITY_HIGH;
+ }
+ if (oc_config.OCPolarity == TIM_OCPOLARITY_HIGH) {
+ oc_config.OCNPolarity = TIM_OCNPOLARITY_HIGH;
+ } else {
+ oc_config.OCNPolarity = TIM_OCNPOLARITY_LOW;
+ }
+ oc_config.OCFastMode = TIM_OCFAST_DISABLE;
+ oc_config.OCIdleState = TIM_OCIDLESTATE_SET;
+ oc_config.OCNIdleState = TIM_OCNIDLESTATE_SET;
+
+ if (!IS_TIM_OC_POLARITY(oc_config.OCPolarity)) {
+ nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "invalid polarity (%d)", oc_config.OCPolarity));
+ }
+ HAL_TIM_OC_ConfigChannel(&self->tim, &oc_config, TIMER_CHANNEL(chan));
+ if (chan->callback == mp_const_none) {
+ HAL_TIM_OC_Start(&self->tim, TIMER_CHANNEL(chan));
+ } else {
+ pyb_timer_channel_callback(chan, chan->callback);
+ }
+ // Start the complimentary channel too (if its supported)
+ if (IS_TIM_CCXN_INSTANCE(self->tim.Instance, TIMER_CHANNEL(chan))) {
+ HAL_TIMEx_OCN_Start(&self->tim, TIMER_CHANNEL(chan));
+ }
+ break;
+ }
+
+ case CHANNEL_MODE_IC: {
+ TIM_IC_InitTypeDef ic_config;
+
+ ic_config.ICPolarity = args[6].u_int;
+ if (ic_config.ICPolarity == 0xffffffff) {
+ ic_config.ICPolarity = TIM_ICPOLARITY_RISING;
+ }
+ ic_config.ICSelection = TIM_ICSELECTION_DIRECTTI;
+ ic_config.ICPrescaler = TIM_ICPSC_DIV1;
+ ic_config.ICFilter = 0;
+
+ if (!IS_TIM_IC_POLARITY(ic_config.ICPolarity)) {
+ nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "invalid polarity (%d)", ic_config.ICPolarity));
+ }
+ HAL_TIM_IC_ConfigChannel(&self->tim, &ic_config, TIMER_CHANNEL(chan));
+ if (chan->callback == mp_const_none) {
+ HAL_TIM_IC_Start(&self->tim, TIMER_CHANNEL(chan));
+ } else {
+ pyb_timer_channel_callback(chan, chan->callback);
+ }
+ break;
+ }
+
+ case CHANNEL_MODE_ENC_A:
+ case CHANNEL_MODE_ENC_B:
+ case CHANNEL_MODE_ENC_AB: {
+ TIM_Encoder_InitTypeDef enc_config;
+
+ enc_config.EncoderMode = channel_mode_info[chan->mode].oc_mode;
+ enc_config.IC1Polarity = args[6].u_int;
+ if (enc_config.IC1Polarity == 0xffffffff) {
+ enc_config.IC1Polarity = TIM_ICPOLARITY_RISING;
+ }
+ enc_config.IC2Polarity = enc_config.IC1Polarity;
+ enc_config.IC1Selection = TIM_ICSELECTION_DIRECTTI;
+ enc_config.IC2Selection = TIM_ICSELECTION_DIRECTTI;
+ enc_config.IC1Prescaler = TIM_ICPSC_DIV1;
+ enc_config.IC2Prescaler = TIM_ICPSC_DIV1;
+ enc_config.IC1Filter = 0;
+ enc_config.IC2Filter = 0;
+
+ if (!IS_TIM_IC_POLARITY(enc_config.IC1Polarity)) {
+ nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "invalid polarity (%d)", enc_config.IC1Polarity));
+ }
+ // Only Timers 1, 2, 3, 4, 5, and 8 support encoder mode
+ if (self->tim.Instance != TIM1
+ && self->tim.Instance != TIM2
+ && self->tim.Instance != TIM3
+ && self->tim.Instance != TIM4
+ && self->tim.Instance != TIM5
+ #if defined(TIM8)
+ && self->tim.Instance != TIM8
+ #endif
+ ) {
+ nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "encoder not supported on timer %d", self->tim_id));
+ }
+
+ // Disable & clear the timer interrupt so that we don't trigger
+ // 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);
+ if (self->callback != mp_const_none) {
+ __HAL_TIM_CLEAR_FLAG(&self->tim, TIM_IT_UPDATE);
+ __HAL_TIM_ENABLE_IT(&self->tim, TIM_IT_UPDATE);
+ }
+ HAL_TIM_Encoder_Start(&self->tim, TIM_CHANNEL_ALL);
+ break;
+ }
+
+ default:
+ nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "invalid mode (%d)", chan->mode));
+ }
+
+ return chan;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_timer_channel_obj, 2, pyb_timer_channel);
+
+/// \method counter([value])
+/// Get or set the timer counter.
+STATIC mp_obj_t pyb_timer_counter(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(self->tim.Instance->CNT);
+ } else {
+ // set
+ __HAL_TIM_SetCounter(&self->tim, mp_obj_get_int(args[1]));
+ return mp_const_none;
+ }
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_timer_counter_obj, 1, 2, pyb_timer_counter);
+
+/// \method source_freq()
+/// Get the frequency of the source of the timer.
+STATIC mp_obj_t pyb_timer_source_freq(mp_obj_t self_in) {
+ pyb_timer_obj_t *self = self_in;
+ uint32_t source_freq = timer_get_source_freq(self->tim_id);
+ return mp_obj_new_int(source_freq);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_timer_source_freq_obj, pyb_timer_source_freq);
+
+/// \method freq([value])
+/// Get or set the frequency for the timer (changes prescaler and period if set).
+STATIC mp_obj_t pyb_timer_freq(size_t n_args, const mp_obj_t *args) {
+ pyb_timer_obj_t *self = args[0];
+ 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 source_freq = timer_get_source_freq(self->tim_id);
+ uint32_t divide = ((prescaler + 1) * (period + 1));
+ #if MICROPY_PY_BUILTINS_FLOAT
+ if (source_freq % divide != 0) {
+ return mp_obj_new_float((float)source_freq / (float)divide);
+ } else
+ #endif
+ {
+ return mp_obj_new_int(source_freq / divide);
+ }
+ } else {
+ // set
+ 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);
+ // Reset the counter to zero. Otherwise, if counter >= period it will
+ // continue counting until it wraps (at either 16 or 32 bits depending
+ // on the timer).
+ __HAL_TIM_SetCounter(&self->tim, 0);
+ return mp_const_none;
+ }
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_timer_freq_obj, 1, 2, pyb_timer_freq);
+
+/// \method prescaler([value])
+/// Get or set the prescaler for the timer.
+STATIC mp_obj_t pyb_timer_prescaler(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(self->tim.Instance->PSC & 0xffff);
+ } else {
+ // set
+ self->tim.Instance->PSC = mp_obj_get_int(args[1]) & 0xffff;
+ return mp_const_none;
+ }
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_timer_prescaler_obj, 1, 2, pyb_timer_prescaler);
+
+/// \method period([value])
+/// Get or set the period of the timer.
+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));
+ } else {
+ // set
+ __HAL_TIM_SetAutoreload(&self->tim, mp_obj_get_int(args[1]) & TIMER_CNT_MASK(self));
+ // Reset the counter to zero. Otherwise, if counter >= period it will
+ // continue counting until it wraps (at either 16 or 32 bits depending
+ // on the timer).
+ __HAL_TIM_SetCounter(&self->tim, 0);
+ return mp_const_none;
+ }
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_timer_period_obj, 1, 2, pyb_timer_period);
+
+/// \method callback(fun)
+/// Set the function to be called when the timer triggers.
+/// `fun` is passed 1 argument, the timer object.
+/// If `fun` is `None` then the callback will be disabled.
+STATIC mp_obj_t pyb_timer_callback(mp_obj_t self_in, mp_obj_t callback) {
+ pyb_timer_obj_t *self = self_in;
+ if (callback == mp_const_none) {
+ // stop interrupt (but not timer)
+ __HAL_TIM_DISABLE_IT(&self->tim, TIM_IT_UPDATE);
+ self->callback = mp_const_none;
+ } else if (mp_obj_is_callable(callback)) {
+ __HAL_TIM_DISABLE_IT(&self->tim, TIM_IT_UPDATE);
+ self->callback = callback;
+ // start timer, so that it interrupts on overflow, but clear any
+ // pending interrupts which may have been set by initializing it.
+ __HAL_TIM_CLEAR_FLAG(&self->tim, TIM_IT_UPDATE);
+ HAL_TIM_Base_Start_IT(&self->tim); // This will re-enable the IRQ
+ HAL_NVIC_EnableIRQ(self->irqn);
+ } else {
+ mp_raise_ValueError("callback must be None or a callable object");
+ }
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(pyb_timer_callback_obj, pyb_timer_callback);
+
+STATIC const mp_rom_map_elem_t pyb_timer_locals_dict_table[] = {
+ // instance methods
+ { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&pyb_timer_init_obj) },
+ { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&pyb_timer_deinit_obj) },
+ { MP_ROM_QSTR(MP_QSTR_channel), MP_ROM_PTR(&pyb_timer_channel_obj) },
+ { MP_ROM_QSTR(MP_QSTR_counter), MP_ROM_PTR(&pyb_timer_counter_obj) },
+ { MP_ROM_QSTR(MP_QSTR_source_freq), MP_ROM_PTR(&pyb_timer_source_freq_obj) },
+ { MP_ROM_QSTR(MP_QSTR_freq), MP_ROM_PTR(&pyb_timer_freq_obj) },
+ { MP_ROM_QSTR(MP_QSTR_prescaler), MP_ROM_PTR(&pyb_timer_prescaler_obj) },
+ { MP_ROM_QSTR(MP_QSTR_period), MP_ROM_PTR(&pyb_timer_period_obj) },
+ { MP_ROM_QSTR(MP_QSTR_callback), MP_ROM_PTR(&pyb_timer_callback_obj) },
+ { MP_ROM_QSTR(MP_QSTR_UP), MP_ROM_INT(TIM_COUNTERMODE_UP) },
+ { MP_ROM_QSTR(MP_QSTR_DOWN), MP_ROM_INT(TIM_COUNTERMODE_DOWN) },
+ { MP_ROM_QSTR(MP_QSTR_CENTER), MP_ROM_INT(TIM_COUNTERMODE_CENTERALIGNED1) },
+ { MP_ROM_QSTR(MP_QSTR_PWM), MP_ROM_INT(CHANNEL_MODE_PWM_NORMAL) },
+ { MP_ROM_QSTR(MP_QSTR_PWM_INVERTED), MP_ROM_INT(CHANNEL_MODE_PWM_INVERTED) },
+ { MP_ROM_QSTR(MP_QSTR_OC_TIMING), MP_ROM_INT(CHANNEL_MODE_OC_TIMING) },
+ { MP_ROM_QSTR(MP_QSTR_OC_ACTIVE), MP_ROM_INT(CHANNEL_MODE_OC_ACTIVE) },
+ { MP_ROM_QSTR(MP_QSTR_OC_INACTIVE), MP_ROM_INT(CHANNEL_MODE_OC_INACTIVE) },
+ { MP_ROM_QSTR(MP_QSTR_OC_TOGGLE), MP_ROM_INT(CHANNEL_MODE_OC_TOGGLE) },
+ { MP_ROM_QSTR(MP_QSTR_OC_FORCED_ACTIVE), MP_ROM_INT(CHANNEL_MODE_OC_FORCED_ACTIVE) },
+ { MP_ROM_QSTR(MP_QSTR_OC_FORCED_INACTIVE), MP_ROM_INT(CHANNEL_MODE_OC_FORCED_INACTIVE) },
+ { MP_ROM_QSTR(MP_QSTR_IC), MP_ROM_INT(CHANNEL_MODE_IC) },
+ { MP_ROM_QSTR(MP_QSTR_ENC_A), MP_ROM_INT(CHANNEL_MODE_ENC_A) },
+ { MP_ROM_QSTR(MP_QSTR_ENC_B), MP_ROM_INT(CHANNEL_MODE_ENC_B) },
+ { MP_ROM_QSTR(MP_QSTR_ENC_AB), MP_ROM_INT(CHANNEL_MODE_ENC_AB) },
+ { MP_ROM_QSTR(MP_QSTR_HIGH), MP_ROM_INT(TIM_OCPOLARITY_HIGH) },
+ { MP_ROM_QSTR(MP_QSTR_LOW), MP_ROM_INT(TIM_OCPOLARITY_LOW) },
+ { MP_ROM_QSTR(MP_QSTR_RISING), MP_ROM_INT(TIM_ICPOLARITY_RISING) },
+ { MP_ROM_QSTR(MP_QSTR_FALLING), MP_ROM_INT(TIM_ICPOLARITY_FALLING) },
+ { MP_ROM_QSTR(MP_QSTR_BOTH), MP_ROM_INT(TIM_ICPOLARITY_BOTHEDGE) },
+};
+STATIC MP_DEFINE_CONST_DICT(pyb_timer_locals_dict, pyb_timer_locals_dict_table);
+
+const mp_obj_type_t pyb_timer_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_Timer,
+ .print = pyb_timer_print,
+ .make_new = pyb_timer_make_new,
+ .locals_dict = (mp_obj_dict_t*)&pyb_timer_locals_dict,
+};
+
+/// \moduleref pyb
+/// \class TimerChannel - setup a channel for a timer.
+///
+/// Timer channels are used to generate/capture a signal using a timer.
+///
+/// TimerChannel objects are created using the Timer.channel() method.
+STATIC void pyb_timer_channel_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
+ pyb_timer_channel_obj_t *self = self_in;
+
+ mp_printf(print, "TimerChannel(timer=%u, channel=%u, mode=%s)",
+ self->timer->tim_id,
+ self->channel,
+ qstr_str(channel_mode_info[self->mode].name));
+}
+
+/// \method capture([value])
+/// Get or set the capture value associated with a channel.
+/// capture, compare, and pulse_width are all aliases for the same function.
+/// capture is the logical name to use when the channel is in input capture mode.
+
+/// \method compare([value])
+/// Get or set the compare value associated with a channel.
+/// capture, compare, and pulse_width are all aliases for the same function.
+/// compare is the logical name to use when the channel is in output compare mode.
+
+/// \method pulse_width([value])
+/// Get or set the pulse width value associated with a channel.
+/// capture, compare, and pulse_width are all aliases for the same function.
+/// pulse_width is the logical name to use when the channel is in PWM mode.
+///
+/// In edge aligned mode, a pulse_width of `period + 1` corresponds to a duty cycle of 100%
+/// In center aligned mode, a pulse width of `period` corresponds to a duty cycle of 100%
+STATIC mp_obj_t pyb_timer_channel_capture_compare(size_t n_args, const mp_obj_t *args) {
+ 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));
+ } else {
+ // set
+ __HAL_TIM_SetCompare(&self->timer->tim, TIMER_CHANNEL(self), mp_obj_get_int(args[1]) & TIMER_CNT_MASK(self->timer));
+ return mp_const_none;
+ }
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_timer_channel_capture_compare_obj, 1, 2, pyb_timer_channel_capture_compare);
+
+/// \method pulse_width_percent([value])
+/// Get or set the pulse width percentage associated with a channel. The value
+/// is a number between 0 and 100 and sets the percentage of the timer period
+/// for which the pulse is active. The value can be an integer or
+/// floating-point number for more accuracy. For example, a value of 25 gives
+/// a duty cycle of 25%.
+STATIC mp_obj_t pyb_timer_channel_pulse_width_percent(size_t n_args, const mp_obj_t *args) {
+ pyb_timer_channel_obj_t *self = args[0];
+ 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);
+ 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));
+ return mp_const_none;
+ }
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_timer_channel_pulse_width_percent_obj, 1, 2, pyb_timer_channel_pulse_width_percent);
+
+/// \method callback(fun)
+/// Set the function to be called when the timer channel triggers.
+/// `fun` is passed 1 argument, the timer object.
+/// If `fun` is `None` then the callback will be disabled.
+STATIC mp_obj_t pyb_timer_channel_callback(mp_obj_t self_in, mp_obj_t callback) {
+ pyb_timer_channel_obj_t *self = self_in;
+ if (callback == mp_const_none) {
+ // stop interrupt (but not timer)
+ __HAL_TIM_DISABLE_IT(&self->timer->tim, TIMER_IRQ_MASK(self->channel));
+ self->callback = mp_const_none;
+ } else if (mp_obj_is_callable(callback)) {
+ self->callback = callback;
+ uint8_t tim_id = self->timer->tim_id;
+ __HAL_TIM_CLEAR_IT(&self->timer->tim, TIMER_IRQ_MASK(self->channel));
+ if (tim_id == 1) {
+ HAL_NVIC_EnableIRQ(TIM1_CC_IRQn);
+ #if defined(TIM8) // STM32F401 doesn't have a TIM8
+ } else if (tim_id == 8) {
+ HAL_NVIC_EnableIRQ(TIM8_CC_IRQn);
+ #endif
+ } else {
+ HAL_NVIC_EnableIRQ(self->timer->irqn);
+ }
+ // start timer, so that it interrupts on overflow
+ switch (self->mode) {
+ case CHANNEL_MODE_PWM_NORMAL:
+ case CHANNEL_MODE_PWM_INVERTED:
+ HAL_TIM_PWM_Start_IT(&self->timer->tim, TIMER_CHANNEL(self));
+ break;
+ case CHANNEL_MODE_OC_TIMING:
+ case CHANNEL_MODE_OC_ACTIVE:
+ case CHANNEL_MODE_OC_INACTIVE:
+ case CHANNEL_MODE_OC_TOGGLE:
+ case CHANNEL_MODE_OC_FORCED_ACTIVE:
+ case CHANNEL_MODE_OC_FORCED_INACTIVE:
+ HAL_TIM_OC_Start_IT(&self->timer->tim, TIMER_CHANNEL(self));
+ break;
+ case CHANNEL_MODE_IC:
+ HAL_TIM_IC_Start_IT(&self->timer->tim, TIMER_CHANNEL(self));
+ break;
+ }
+ } else {
+ mp_raise_ValueError("callback must be None or a callable object");
+ }
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(pyb_timer_channel_callback_obj, pyb_timer_channel_callback);
+
+STATIC const mp_rom_map_elem_t pyb_timer_channel_locals_dict_table[] = {
+ // instance methods
+ { MP_ROM_QSTR(MP_QSTR_callback), MP_ROM_PTR(&pyb_timer_channel_callback_obj) },
+ { MP_ROM_QSTR(MP_QSTR_pulse_width), MP_ROM_PTR(&pyb_timer_channel_capture_compare_obj) },
+ { MP_ROM_QSTR(MP_QSTR_pulse_width_percent), MP_ROM_PTR(&pyb_timer_channel_pulse_width_percent_obj) },
+ { MP_ROM_QSTR(MP_QSTR_capture), MP_ROM_PTR(&pyb_timer_channel_capture_compare_obj) },
+ { MP_ROM_QSTR(MP_QSTR_compare), MP_ROM_PTR(&pyb_timer_channel_capture_compare_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(pyb_timer_channel_locals_dict, pyb_timer_channel_locals_dict_table);
+
+STATIC const mp_obj_type_t pyb_timer_channel_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_TimerChannel,
+ .print = pyb_timer_channel_print,
+ .locals_dict = (mp_obj_dict_t*)&pyb_timer_channel_locals_dict,
+};
+
+STATIC void timer_handle_irq_channel(pyb_timer_obj_t *tim, uint8_t channel, mp_obj_t callback) {
+ 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) {
+ // clear the interrupt
+ __HAL_TIM_CLEAR_IT(&tim->tim, irq_mask);
+
+ // execute callback if it's set
+ if (callback != mp_const_none) {
+ mp_sched_lock();
+ // When executing code within a handler we must lock the GC to prevent
+ // any memory allocations. We must also catch any exceptions.
+ gc_lock();
+ nlr_buf_t nlr;
+ if (nlr_push(&nlr) == 0) {
+ mp_call_function_1(callback, tim);
+ nlr_pop();
+ } else {
+ // Uncaught exception; disable the callback so it doesn't run again.
+ tim->callback = mp_const_none;
+ __HAL_TIM_DISABLE_IT(&tim->tim, irq_mask);
+ if (channel == 0) {
+ printf("uncaught exception in Timer(%u) interrupt handler\n", tim->tim_id);
+ } else {
+ printf("uncaught exception in Timer(%u) channel %u interrupt handler\n", tim->tim_id, channel);
+ }
+ mp_obj_print_exception(&mp_plat_print, (mp_obj_t)nlr.ret_val);
+ }
+ gc_unlock();
+ mp_sched_unlock();
+ }
+ }
+ }
+}
+
+void timer_irq_handler(uint tim_id) {
+ if (tim_id - 1 < PYB_TIMER_OBJ_ALL_NUM) {
+ // get the timer object
+ pyb_timer_obj_t *tim = MP_STATE_PORT(pyb_timer_obj_all)[tim_id - 1];
+
+ if (tim == NULL) {
+ // Timer object has not been set, so we can't do anything.
+ // This can happen under normal circumstances for timers like
+ // 1 & 10 which use the same IRQ.
+ return;
+ }
+
+ // Check for timer (versus timer channel) interrupt.
+ timer_handle_irq_channel(tim, 0, tim->callback);
+ uint32_t handled = TIMER_IRQ_MASK(0);
+
+ // Check to see if a timer channel interrupt was pending
+ pyb_timer_channel_obj_t *chan = tim->channel;
+ while (chan != NULL) {
+ timer_handle_irq_channel(tim, chan->channel, chan->callback);
+ handled |= TIMER_IRQ_MASK(chan->channel);
+ chan = chan->next;
+ }
+
+ // Finally, clear any remaining interrupt sources. Otherwise we'll
+ // just get called continuously.
+ uint32_t unhandled = tim->tim.Instance->DIER & 0xff & ~handled;
+ 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);
+ }
+ }
+}
diff --git a/ports/stm32/timer.h b/ports/stm32/timer.h
new file mode 100644
index 000000000..775accc3d
--- /dev/null
+++ b/ports/stm32/timer.h
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+#ifndef MICROPY_INCLUDED_STMHAL_TIMER_H
+#define MICROPY_INCLUDED_STMHAL_TIMER_H
+
+extern TIM_HandleTypeDef TIM5_Handle;
+
+extern const mp_obj_type_t pyb_timer_type;
+
+void timer_init0(void);
+void timer_tim5_init(void);
+TIM_HandleTypeDef *timer_tim6_init(uint freq);
+void timer_deinit(void);
+uint32_t timer_get_source_freq(uint32_t tim_id);
+void timer_irq_handler(uint tim_id);
+
+TIM_HandleTypeDef *pyb_timer_get_handle(mp_obj_t timer);
+
+#endif // MICROPY_INCLUDED_STMHAL_TIMER_H
diff --git a/ports/stm32/uart.c b/ports/stm32/uart.c
new file mode 100644
index 000000000..1238b4e31
--- /dev/null
+++ b/ports/stm32/uart.c
@@ -0,0 +1,1044 @@
+/*
+ * 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 <stdarg.h>
+
+#include "py/nlr.h"
+#include "py/runtime.h"
+#include "py/stream.h"
+#include "py/mperrno.h"
+#include "py/mphal.h"
+#include "uart.h"
+#include "irq.h"
+#include "genhdr/pins.h"
+
+/// \moduleref pyb
+/// \class UART - duplex serial communication bus
+///
+/// UART implements the standard UART/USART duplex serial communications protocol. At
+/// the physical level it consists of 2 lines: RX and TX. The unit of communication
+/// is a character (not to be confused with a string character) which can be 8 or 9
+/// bits wide.
+///
+/// UART objects can be created and initialised using:
+///
+/// from pyb import UART
+///
+/// uart = UART(1, 9600) # init with given baudrate
+/// uart.init(9600, bits=8, parity=None, stop=1) # init with given parameters
+///
+/// Bits can be 8 or 9. Parity can be None, 0 (even) or 1 (odd). Stop can be 1 or 2.
+///
+/// A UART object acts like a stream object and reading and writing is done
+/// using the standard stream methods:
+///
+/// uart.read(10) # read 10 characters, returns a bytes object
+/// uart.read() # read all available characters
+/// uart.readline() # read a line
+/// uart.readinto(buf) # read and store into the given buffer
+/// uart.write('abc') # write the 3 characters
+///
+/// Individual characters can be read/written using:
+///
+/// uart.readchar() # read 1 character and returns it as an integer
+/// uart.writechar(42) # write 1 character
+///
+/// To check if there is anything to be read, use:
+///
+/// uart.any() # returns True if any characters waiting
+
+#define CHAR_WIDTH_8BIT (0)
+#define CHAR_WIDTH_9BIT (1)
+
+struct _pyb_uart_obj_t {
+ mp_obj_base_t base;
+ UART_HandleTypeDef uart; // this is 17 words big
+ IRQn_Type irqn;
+ pyb_uart_t uart_id : 8;
+ bool is_enabled : 1;
+ 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
+ uint16_t timeout_char; // timeout waiting between chars
+ uint16_t read_buf_len; // len in chars; buf can hold len-1 chars
+ volatile uint16_t read_buf_head; // indexes first empty slot
+ uint16_t read_buf_tail; // indexes first full slot (not full if equals head)
+ byte *read_buf; // byte or uint16_t, depending on char size
+};
+
+STATIC mp_obj_t pyb_uart_deinit(mp_obj_t self_in);
+
+void uart_init0(void) {
+ 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;
+ }
+}
+
+// unregister all interrupt sources
+void uart_deinit(void) {
+ for (int i = 0; i < MP_ARRAY_SIZE(MP_STATE_PORT(pyb_uart_obj_all)); i++) {
+ pyb_uart_obj_t *uart_obj = MP_STATE_PORT(pyb_uart_obj_all)[i];
+ if (uart_obj != NULL) {
+ pyb_uart_deinit(uart_obj);
+ }
+ }
+}
+
+STATIC bool uart_exists(int uart_id) {
+ if (uart_id > MP_ARRAY_SIZE(MP_STATE_PORT(pyb_uart_obj_all))) {
+ // safeguard against pyb_uart_obj_all array being configured too small
+ return false;
+ }
+ switch (uart_id) {
+ #if defined(MICROPY_HW_UART1_TX) && defined(MICROPY_HW_UART1_RX)
+ case PYB_UART_1: return true;
+ #endif
+
+ #if defined(MICROPY_HW_UART2_TX) && defined(MICROPY_HW_UART2_RX)
+ case PYB_UART_2: return true;
+ #endif
+
+ #if defined(MICROPY_HW_UART3_TX) && defined(MICROPY_HW_UART3_RX)
+ case PYB_UART_3: return true;
+ #endif
+
+ #if defined(MICROPY_HW_UART4_TX) && defined(MICROPY_HW_UART4_RX)
+ case PYB_UART_4: return true;
+ #endif
+
+ #if defined(MICROPY_HW_UART5_TX) && defined(MICROPY_HW_UART5_RX)
+ case PYB_UART_5: return true;
+ #endif
+
+ #if defined(MICROPY_HW_UART6_TX) && defined(MICROPY_HW_UART6_RX)
+ case PYB_UART_6: return true;
+ #endif
+
+ #if defined(MICROPY_HW_UART7_TX) && defined(MICROPY_HW_UART7_RX)
+ case PYB_UART_7: return true;
+ #endif
+
+ #if defined(MICROPY_HW_UART8_TX) && defined(MICROPY_HW_UART8_RX)
+ case PYB_UART_8: return true;
+ #endif
+
+ default: return false;
+ }
+}
+
+// assumes Init parameters have been set up correctly
+STATIC bool uart_init2(pyb_uart_obj_t *uart_obj) {
+ USART_TypeDef *UARTx;
+ IRQn_Type irqn;
+ int uart_unit;
+
+ const pin_obj_t *pins[4] = {0};
+
+ switch (uart_obj->uart_id) {
+ #if defined(MICROPY_HW_UART1_TX) && defined(MICROPY_HW_UART1_RX)
+ case PYB_UART_1:
+ uart_unit = 1;
+ UARTx = USART1;
+ irqn = USART1_IRQn;
+ pins[0] = &MICROPY_HW_UART1_TX;
+ pins[1] = &MICROPY_HW_UART1_RX;
+ __USART1_CLK_ENABLE();
+ break;
+ #endif
+
+ #if defined(MICROPY_HW_UART2_TX) && defined(MICROPY_HW_UART2_RX)
+ case PYB_UART_2:
+ uart_unit = 2;
+ UARTx = USART2;
+ irqn = USART2_IRQn;
+ 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;
+ }
+ #endif
+ #if defined(MICROPY_HW_UART2_CTS)
+ if (uart_obj->uart.Init.HwFlowCtl & UART_HWCONTROL_CTS) {
+ pins[3] = &MICROPY_HW_UART2_CTS;
+ }
+ #endif
+ __USART2_CLK_ENABLE();
+ break;
+ #endif
+
+ #if defined(MICROPY_HW_UART3_TX) && defined(MICROPY_HW_UART3_RX)
+ case PYB_UART_3:
+ uart_unit = 3;
+ UARTx = USART3;
+ irqn = USART3_IRQn;
+ 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;
+ }
+ #endif
+ #if defined(MICROPY_HW_UART3_CTS)
+ if (uart_obj->uart.Init.HwFlowCtl & UART_HWCONTROL_CTS) {
+ pins[3] = &MICROPY_HW_UART3_CTS;
+ }
+ #endif
+ __USART3_CLK_ENABLE();
+ break;
+ #endif
+
+ #if defined(MICROPY_HW_UART4_TX) && defined(MICROPY_HW_UART4_RX)
+ case PYB_UART_4:
+ uart_unit = 4;
+ UARTx = UART4;
+ irqn = UART4_IRQn;
+ pins[0] = &MICROPY_HW_UART4_TX;
+ pins[1] = &MICROPY_HW_UART4_RX;
+ __UART4_CLK_ENABLE();
+ break;
+ #endif
+
+ #if defined(MICROPY_HW_UART5_TX) && defined(MICROPY_HW_UART5_RX)
+ case PYB_UART_5:
+ uart_unit = 5;
+ UARTx = UART5;
+ irqn = UART5_IRQn;
+ pins[0] = &MICROPY_HW_UART5_TX;
+ pins[1] = &MICROPY_HW_UART5_RX;
+ __UART5_CLK_ENABLE();
+ break;
+ #endif
+
+ #if defined(MICROPY_HW_UART6_TX) && defined(MICROPY_HW_UART6_RX)
+ case PYB_UART_6:
+ uart_unit = 6;
+ UARTx = USART6;
+ irqn = USART6_IRQn;
+ pins[0] = &MICROPY_HW_UART6_TX;
+ pins[1] = &MICROPY_HW_UART6_RX;
+ __USART6_CLK_ENABLE();
+ break;
+ #endif
+
+ #if defined(MICROPY_HW_UART7_TX) && defined(MICROPY_HW_UART7_RX)
+ case PYB_UART_7:
+ uart_unit = 7;
+ UARTx = UART7;
+ irqn = UART7_IRQn;
+ pins[0] = &MICROPY_HW_UART7_TX;
+ pins[1] = &MICROPY_HW_UART7_RX;
+ __UART7_CLK_ENABLE();
+ break;
+ #endif
+
+ #if defined(MICROPY_HW_UART8_TX) && defined(MICROPY_HW_UART8_RX)
+ case PYB_UART_8:
+ uart_unit = 8;
+ UARTx = UART8;
+ irqn = UART8_IRQn;
+ pins[0] = &MICROPY_HW_UART8_TX;
+ pins[1] = &MICROPY_HW_UART8_RX;
+ __UART8_CLK_ENABLE();
+ break;
+ #endif
+
+ default:
+ // UART does not exist or is not configured for this board
+ return false;
+ }
+
+ uint32_t mode = MP_HAL_PIN_MODE_ALT;
+ uint32_t pull = MP_HAL_PIN_PULL_UP;
+
+ for (uint i = 0; i < 4; i++) {
+ if (pins[i] != NULL) {
+ bool ret = mp_hal_pin_config_alt(pins[i], mode, pull, AF_FN_UART, uart_unit);
+ if (!ret) {
+ return false;
+ }
+ }
+ }
+
+ uart_obj->irqn = irqn;
+ uart_obj->uart.Instance = UARTx;
+
+ // init UARTx
+ HAL_UART_Init(&uart_obj->uart);
+
+ uart_obj->is_enabled = true;
+
+ return true;
+}
+
+/* obsolete and unused
+bool uart_init(pyb_uart_obj_t *uart_obj, uint32_t baudrate) {
+ UART_HandleTypeDef *uh = &uart_obj->uart;
+ memset(uh, 0, sizeof(*uh));
+ uh->Init.BaudRate = baudrate;
+ uh->Init.WordLength = UART_WORDLENGTH_8B;
+ uh->Init.StopBits = UART_STOPBITS_1;
+ uh->Init.Parity = UART_PARITY_NONE;
+ uh->Init.Mode = UART_MODE_TX_RX;
+ uh->Init.HwFlowCtl = UART_HWCONTROL_NONE;
+ uh->Init.OverSampling = UART_OVERSAMPLING_16;
+ return uart_init2(uart_obj);
+}
+*/
+
+mp_uint_t uart_rx_any(pyb_uart_obj_t *self) {
+ int buffer_bytes = self->read_buf_head - self->read_buf_tail;
+ if (buffer_bytes < 0) {
+ return buffer_bytes + self->read_buf_len;
+ } else if (buffer_bytes > 0) {
+ return buffer_bytes;
+ } else {
+ return __HAL_UART_GET_FLAG(&self->uart, UART_FLAG_RXNE) != RESET;
+ }
+}
+
+// Waits at most timeout milliseconds for at least 1 char to become ready for
+// reading (from buf or for direct reading).
+// Returns true if something available, false if not.
+STATIC bool uart_rx_wait(pyb_uart_obj_t *self, uint32_t timeout) {
+ uint32_t start = HAL_GetTick();
+ for (;;) {
+ if (self->read_buf_tail != self->read_buf_head || __HAL_UART_GET_FLAG(&self->uart, UART_FLAG_RXNE) != RESET) {
+ return true; // have at least 1 char ready for reading
+ }
+ if (HAL_GetTick() - start >= timeout) {
+ return false; // timeout
+ }
+ MICROPY_EVENT_POLL_HOOK
+ }
+}
+
+// assumes there is a character available
+int uart_rx_char(pyb_uart_obj_t *self) {
+ if (self->read_buf_tail != self->read_buf_head) {
+ // buffering via IRQ
+ int data;
+ if (self->char_width == CHAR_WIDTH_9BIT) {
+ data = ((uint16_t*)self->read_buf)[self->read_buf_tail];
+ } else {
+ data = self->read_buf[self->read_buf_tail];
+ }
+ self->read_buf_tail = (self->read_buf_tail + 1) % self->read_buf_len;
+ if (__HAL_UART_GET_FLAG(&self->uart, UART_FLAG_RXNE) != RESET) {
+ // UART was stalled by flow ctrl: re-enable IRQ now we have room in buffer
+ __HAL_UART_ENABLE_IT(&self->uart, UART_IT_RXNE);
+ }
+ return data;
+ } else {
+ // no buffering
+ #if defined(MCU_SERIES_F7) || defined(MCU_SERIES_L4)
+ return self->uart.Instance->RDR & self->char_mask;
+ #else
+ return self->uart.Instance->DR & self->char_mask;
+ #endif
+ }
+}
+
+// Waits at most timeout milliseconds for TX register to become empty.
+// Returns true if can write, false if can't.
+STATIC bool uart_tx_wait(pyb_uart_obj_t *self, uint32_t timeout) {
+ uint32_t start = HAL_GetTick();
+ for (;;) {
+ if (__HAL_UART_GET_FLAG(&self->uart, UART_FLAG_TXE)) {
+ return true; // tx register is empty
+ }
+ if (HAL_GetTick() - start >= timeout) {
+ return false; // timeout
+ }
+ MICROPY_EVENT_POLL_HOOK
+ }
+}
+
+// Waits at most timeout milliseconds for UART flag to be set.
+// Returns true if flag is/was set, false on timeout.
+STATIC bool uart_wait_flag_set(pyb_uart_obj_t *self, uint32_t flag, uint32_t timeout) {
+ // Note: we don't use WFI to idle in this loop because UART tx doesn't generate
+ // an interrupt and the flag can be set quickly if the baudrate is large.
+ uint32_t start = HAL_GetTick();
+ for (;;) {
+ if (__HAL_UART_GET_FLAG(&self->uart, flag)) {
+ return true;
+ }
+ if (timeout == 0 || HAL_GetTick() - start >= timeout) {
+ return false; // timeout
+ }
+ }
+}
+
+// src - a pointer to the data to send (16-bit aligned for 9-bit chars)
+// num_chars - number of characters to send (9-bit chars count for 2 bytes from src)
+// *errcode - returns 0 for success, MP_Exxx on error
+// returns the number of characters sent (valid even if there was an error)
+STATIC size_t uart_tx_data(pyb_uart_obj_t *self, const void *src_in, size_t num_chars, int *errcode) {
+ if (num_chars == 0) {
+ *errcode = 0;
+ return 0;
+ }
+
+ uint32_t timeout;
+ if (self->uart.Init.HwFlowCtl & UART_HWCONTROL_CTS) {
+ // CTS can hold off transmission for an arbitrarily long time. Apply
+ // the overall timeout rather than the character timeout.
+ timeout = self->timeout;
+ } else {
+ // The timeout specified here is for waiting for the TX data register to
+ // become empty (ie between chars), as well as for the final char to be
+ // completely transferred. The default value for timeout_char is long
+ // enough for 1 char, but we need to double it to wait for the last char
+ // to be transferred to the data register, and then to be transmitted.
+ timeout = 2 * self->timeout_char;
+ }
+
+ const uint8_t *src = (const uint8_t*)src_in;
+ size_t num_tx = 0;
+ USART_TypeDef *uart = self->uart.Instance;
+
+ while (num_tx < num_chars) {
+ if (!uart_wait_flag_set(self, UART_FLAG_TXE, timeout)) {
+ *errcode = MP_ETIMEDOUT;
+ return num_tx;
+ }
+ uint32_t data;
+ if (self->char_width == CHAR_WIDTH_9BIT) {
+ data = *((uint16_t*)src) & 0x1ff;
+ src += 2;
+ } else {
+ data = *src++;
+ }
+ #if defined(MCU_SERIES_F4)
+ uart->DR = data;
+ #else
+ uart->TDR = data;
+ #endif
+ ++num_tx;
+ }
+
+ // wait for the UART frame to complete
+ if (!uart_wait_flag_set(self, UART_FLAG_TC, timeout)) {
+ *errcode = MP_ETIMEDOUT;
+ return num_tx;
+ }
+
+ *errcode = 0;
+ return num_tx;
+}
+
+STATIC void uart_tx_char(pyb_uart_obj_t *uart_obj, int c) {
+ uint16_t ch = c;
+ int errcode;
+ uart_tx_data(uart_obj, &ch, 1, &errcode);
+}
+
+void uart_tx_strn(pyb_uart_obj_t *uart_obj, const char *str, uint len) {
+ int errcode;
+ uart_tx_data(uart_obj, str, len, &errcode);
+}
+
+void uart_tx_strn_cooked(pyb_uart_obj_t *uart_obj, const char *str, uint len) {
+ for (const char *top = str + len; str < top; str++) {
+ if (*str == '\n') {
+ uart_tx_char(uart_obj, '\r');
+ }
+ uart_tx_char(uart_obj, *str);
+ }
+}
+
+// this IRQ handler is set up to handle RXNE interrupts only
+void uart_irq_handler(mp_uint_t uart_id) {
+ // get the uart object
+ pyb_uart_obj_t *self = MP_STATE_PORT(pyb_uart_obj_all)[uart_id - 1];
+
+ if (self == NULL) {
+ // UART object has not been set, so we can't do anything, not
+ // even disable the IRQ. This should never happen.
+ return;
+ }
+
+ if (__HAL_UART_GET_FLAG(&self->uart, UART_FLAG_RXNE) != RESET) {
+ if (self->read_buf_len != 0) {
+ 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)
+ 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;
+ if (self->char_width == CHAR_WIDTH_9BIT) {
+ ((uint16_t*)self->read_buf)[self->read_buf_head] = data;
+ } else {
+ self->read_buf[self->read_buf_head] = data;
+ }
+ self->read_buf_head = next_head;
+ } else { // No room: leave char in buf, disable interrupt
+ __HAL_UART_DISABLE_IT(&self->uart, UART_IT_RXNE);
+ }
+ }
+ }
+}
+
+/******************************************************************************/
+/* MicroPython bindings */
+
+STATIC void pyb_uart_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
+ pyb_uart_obj_t *self = self_in;
+ 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);
+ if (self->uart.Init.Parity != UART_PARITY_NONE) {
+ bits -= 1;
+ }
+ mp_printf(print, "UART(%u, baudrate=%u, bits=%u, parity=",
+ self->uart_id, self->uart.Init.BaudRate, bits);
+ if (self->uart.Init.Parity == UART_PARITY_NONE) {
+ mp_print_str(print, "None");
+ } else {
+ mp_printf(print, "%u", self->uart.Init.Parity == UART_PARITY_EVEN ? 0 : 1);
+ }
+ if (self->uart.Init.HwFlowCtl) {
+ mp_printf(print, ", flow=");
+ if (self->uart.Init.HwFlowCtl & UART_HWCONTROL_RTS) {
+ mp_printf(print, "RTS%s", self->uart.Init.HwFlowCtl & UART_HWCONTROL_CTS ? "|" : "");
+ }
+ if (self->uart.Init.HwFlowCtl & UART_HWCONTROL_CTS) {
+ mp_printf(print, "CTS");
+ }
+ }
+ mp_printf(print, ", stop=%u, timeout=%u, timeout_char=%u, read_buf_len=%u)",
+ self->uart.Init.StopBits == UART_STOPBITS_1 ? 1 : 2,
+ self->timeout, self->timeout_char,
+ self->read_buf_len == 0 ? 0 : self->read_buf_len - 1); // -1 to adjust for usable length of buffer
+ }
+}
+
+/// \method init(baudrate, bits=8, parity=None, stop=1, *, timeout=1000, timeout_char=0, flow=0, read_buf_len=64)
+///
+/// Initialise the UART bus with the given parameters:
+///
+/// - `baudrate` is the clock rate.
+/// - `bits` is the number of bits per byte, 7, 8 or 9.
+/// - `parity` is the parity, `None`, 0 (even) or 1 (odd).
+/// - `stop` is the number of stop bits, 1 or 2.
+/// - `timeout` is the timeout in milliseconds to wait for the first character.
+/// - `timeout_char` is the timeout in milliseconds to wait between characters.
+/// - `flow` is RTS | CTS where RTS == 256, CTS == 512
+/// - `read_buf_len` is the character length of the read buffer (0 to disable).
+STATIC mp_obj_t pyb_uart_init_helper(pyb_uart_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_baudrate, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 9600} },
+ { MP_QSTR_bits, MP_ARG_INT, {.u_int = 8} },
+ { MP_QSTR_parity, MP_ARG_OBJ, {.u_obj = mp_const_none} },
+ { MP_QSTR_stop, MP_ARG_INT, {.u_int = 1} },
+ { MP_QSTR_flow, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = UART_HWCONTROL_NONE} },
+ { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1000} },
+ { MP_QSTR_timeout_char, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
+ { MP_QSTR_read_buf_len, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 64} },
+ };
+
+ // parse args
+ struct {
+ mp_arg_val_t baudrate, bits, parity, stop, flow, timeout, timeout_char, read_buf_len;
+ } args;
+ mp_arg_parse_all(n_args, pos_args, kw_args,
+ MP_ARRAY_SIZE(allowed_args), allowed_args, (mp_arg_val_t*)&args);
+
+ // set the UART configuration values
+ memset(&self->uart, 0, sizeof(self->uart));
+ UART_InitTypeDef *init = &self->uart.Init;
+
+ // baudrate
+ init->BaudRate = args.baudrate.u_int;
+
+ // parity
+ mp_int_t bits = args.bits.u_int;
+ if (args.parity.u_obj == mp_const_none) {
+ init->Parity = UART_PARITY_NONE;
+ } else {
+ mp_int_t parity = mp_obj_get_int(args.parity.u_obj);
+ init->Parity = (parity & 1) ? UART_PARITY_ODD : UART_PARITY_EVEN;
+ bits += 1; // STs convention has bits including parity
+ }
+
+ // number of bits
+ if (bits == 8) {
+ init->WordLength = UART_WORDLENGTH_8B;
+ } else if (bits == 9) {
+ init->WordLength = UART_WORDLENGTH_9B;
+ } else {
+ mp_raise_ValueError("unsupported combination of bits and parity");
+ }
+
+ // stop bits
+ switch (args.stop.u_int) {
+ case 1: init->StopBits = UART_STOPBITS_1; break;
+ default: init->StopBits = UART_STOPBITS_2; break;
+ }
+
+ // flow control
+ init->HwFlowCtl = args.flow.u_int;
+
+ // extra config (not yet configurable)
+ init->Mode = UART_MODE_TX_RX;
+ init->OverSampling = UART_OVERSAMPLING_16;
+
+ // init UART (if it fails, it's because the port doesn't exist)
+ if (!uart_init2(self)) {
+ nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "UART(%d) doesn't exist", self->uart_id));
+ }
+
+ // set timeout
+ self->timeout = args.timeout.u_int;
+
+ // set timeout_char
+ // make sure it is at least as long as a whole character (13 bits to be safe)
+ // minimum value is 2ms because sys-tick has a resolution of only 1ms
+ self->timeout_char = args.timeout_char.u_int;
+ uint32_t min_timeout_char = 13000 / init->BaudRate + 2;
+ if (self->timeout_char < min_timeout_char) {
+ self->timeout_char = min_timeout_char;
+ }
+
+ // setup the read buffer
+ m_del(byte, self->read_buf, self->read_buf_len << self->char_width);
+ if (init->WordLength == UART_WORDLENGTH_9B && init->Parity == UART_PARITY_NONE) {
+ self->char_mask = 0x1ff;
+ self->char_width = CHAR_WIDTH_9BIT;
+ } else {
+ if (init->WordLength == UART_WORDLENGTH_9B || init->Parity == UART_PARITY_NONE) {
+ self->char_mask = 0xff;
+ } else {
+ self->char_mask = 0x7f;
+ }
+ self->char_width = CHAR_WIDTH_8BIT;
+ }
+ self->read_buf_head = 0;
+ self->read_buf_tail = 0;
+ if (args.read_buf_len.u_int <= 0) {
+ // no read buffer
+ self->read_buf_len = 0;
+ self->read_buf = NULL;
+ HAL_NVIC_DisableIRQ(self->irqn);
+ __HAL_UART_DISABLE_IT(&self->uart, UART_IT_RXNE);
+ } else {
+ // read buffer using interrupts
+ 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);
+ 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)
+ UART_ClockSourceTypeDef clocksource = UART_CLOCKSOURCE_UNDEFINED;
+ UART_GETCLOCKSOURCE(&self->uart, clocksource);
+ switch (clocksource) {
+ 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;
+ case UART_CLOCKSOURCE_LSE: actual_baudrate = LSE_VALUE; break;
+ case UART_CLOCKSOURCE_UNDEFINED: break;
+ }
+ #else
+ if (self->uart.Instance == USART1
+ #if defined(USART6)
+ || self->uart.Instance == USART6
+ #endif
+ ) {
+ actual_baudrate = HAL_RCC_GetPCLK2Freq();
+ } else {
+ actual_baudrate = HAL_RCC_GetPCLK1Freq();
+ }
+ #endif
+ actual_baudrate /= self->uart.Instance->BRR;
+
+ // check we could set the baudrate within 5%
+ uint32_t baudrate_diff;
+ if (actual_baudrate > init->BaudRate) {
+ baudrate_diff = actual_baudrate - init->BaudRate;
+ } else {
+ baudrate_diff = init->BaudRate - actual_baudrate;
+ }
+ init->BaudRate = actual_baudrate; // remember actual baudrate for printing
+ if (20 * baudrate_diff > init->BaudRate) {
+ nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "set baudrate %d is not within 5%% of desired value", actual_baudrate));
+ }
+
+ return mp_const_none;
+}
+
+/// \classmethod \constructor(bus, ...)
+///
+/// Construct a UART object on the given bus. `bus` can be 1-6, or 'XA', 'XB', 'YA', or 'YB'.
+/// With no additional parameters, the UART 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 UART busses are:
+///
+/// - `UART(4)` is on `XA`: `(TX, RX) = (X1, X2) = (PA0, PA1)`
+/// - `UART(1)` is on `XB`: `(TX, RX) = (X9, X10) = (PB6, PB7)`
+/// - `UART(6)` is on `YA`: `(TX, RX) = (Y1, Y2) = (PC6, PC7)`
+/// - `UART(3)` is on `YB`: `(TX, RX) = (Y9, Y10) = (PB10, PB11)`
+/// - `UART(2)` is on: `(TX, RX) = (X3, X4) = (PA2, PA3)`
+STATIC mp_obj_t pyb_uart_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 port
+ int uart_id = 0;
+ if (MP_OBJ_IS_STR(args[0])) {
+ const char *port = mp_obj_str_get_str(args[0]);
+ if (0) {
+ #ifdef MICROPY_HW_UART1_NAME
+ } else if (strcmp(port, MICROPY_HW_UART1_NAME) == 0) {
+ uart_id = PYB_UART_1;
+ #endif
+ #ifdef MICROPY_HW_UART2_NAME
+ } else if (strcmp(port, MICROPY_HW_UART2_NAME) == 0) {
+ uart_id = PYB_UART_2;
+ #endif
+ #ifdef MICROPY_HW_UART3_NAME
+ } else if (strcmp(port, MICROPY_HW_UART3_NAME) == 0) {
+ uart_id = PYB_UART_3;
+ #endif
+ #ifdef MICROPY_HW_UART4_NAME
+ } else if (strcmp(port, MICROPY_HW_UART4_NAME) == 0) {
+ uart_id = PYB_UART_4;
+ #endif
+ #ifdef MICROPY_HW_UART5_NAME
+ } else if (strcmp(port, MICROPY_HW_UART5_NAME) == 0) {
+ uart_id = PYB_UART_5;
+ #endif
+ #ifdef MICROPY_HW_UART6_NAME
+ } else if (strcmp(port, MICROPY_HW_UART6_NAME) == 0) {
+ uart_id = PYB_UART_6;
+ #endif
+ } else {
+ nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "UART(%s) doesn't exist", port));
+ }
+ } else {
+ uart_id = mp_obj_get_int(args[0]);
+ if (!uart_exists(uart_id)) {
+ nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "UART(%d) doesn't exist", uart_id));
+ }
+ }
+
+ pyb_uart_obj_t *self;
+ if (MP_STATE_PORT(pyb_uart_obj_all)[uart_id - 1] == NULL) {
+ // create new UART object
+ self = m_new0(pyb_uart_obj_t, 1);
+ self->base.type = &pyb_uart_type;
+ self->uart_id = uart_id;
+ MP_STATE_PORT(pyb_uart_obj_all)[uart_id - 1] = self;
+ } else {
+ // reference existing UART object
+ self = MP_STATE_PORT(pyb_uart_obj_all)[uart_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_uart_init_helper(self, n_args - 1, args + 1, &kw_args);
+ }
+
+ return self;
+}
+
+STATIC mp_obj_t pyb_uart_init(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
+ return pyb_uart_init_helper(args[0], n_args - 1, args + 1, kw_args);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_uart_init_obj, 1, pyb_uart_init);
+
+/// \method deinit()
+/// Turn off the UART bus.
+STATIC mp_obj_t pyb_uart_deinit(mp_obj_t self_in) {
+ pyb_uart_obj_t *self = self_in;
+ self->is_enabled = false;
+ UART_HandleTypeDef *uart = &self->uart;
+ HAL_UART_DeInit(uart);
+ if (uart->Instance == USART1) {
+ HAL_NVIC_DisableIRQ(USART1_IRQn);
+ __USART1_FORCE_RESET();
+ __USART1_RELEASE_RESET();
+ __USART1_CLK_DISABLE();
+ } else if (uart->Instance == USART2) {
+ HAL_NVIC_DisableIRQ(USART2_IRQn);
+ __USART2_FORCE_RESET();
+ __USART2_RELEASE_RESET();
+ __USART2_CLK_DISABLE();
+ #if defined(USART3)
+ } else if (uart->Instance == USART3) {
+ HAL_NVIC_DisableIRQ(USART3_IRQn);
+ __USART3_FORCE_RESET();
+ __USART3_RELEASE_RESET();
+ __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();
+ #endif
+ #if defined(UART5)
+ } else if (uart->Instance == UART5) {
+ HAL_NVIC_DisableIRQ(UART5_IRQn);
+ __UART5_FORCE_RESET();
+ __UART5_RELEASE_RESET();
+ __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();
+ #endif
+ #if defined(UART7)
+ } else if (uart->Instance == UART7) {
+ HAL_NVIC_DisableIRQ(UART7_IRQn);
+ __UART7_FORCE_RESET();
+ __UART7_RELEASE_RESET();
+ __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();
+ #endif
+ }
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_uart_deinit_obj, pyb_uart_deinit);
+
+/// \method any()
+/// Return `True` if any characters waiting, else `False`.
+STATIC mp_obj_t pyb_uart_any(mp_obj_t self_in) {
+ pyb_uart_obj_t *self = self_in;
+ return MP_OBJ_NEW_SMALL_INT(uart_rx_any(self));
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_uart_any_obj, pyb_uart_any);
+
+/// \method writechar(char)
+/// Write a single character on the bus. `char` is an integer to write.
+/// Return value: `None`.
+STATIC mp_obj_t pyb_uart_writechar(mp_obj_t self_in, mp_obj_t char_in) {
+ pyb_uart_obj_t *self = self_in;
+
+ // get the character to write (might be 9 bits)
+ uint16_t data = mp_obj_get_int(char_in);
+
+ // write the character
+ int errcode;
+ if (uart_tx_wait(self, self->timeout)) {
+ uart_tx_data(self, &data, 1, &errcode);
+ } else {
+ errcode = MP_ETIMEDOUT;
+ }
+
+ if (errcode != 0) {
+ mp_raise_OSError(errcode);
+ }
+
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(pyb_uart_writechar_obj, pyb_uart_writechar);
+
+/// \method readchar()
+/// Receive a single character on the bus.
+/// Return value: The character read, as an integer. Returns -1 on timeout.
+STATIC mp_obj_t pyb_uart_readchar(mp_obj_t self_in) {
+ pyb_uart_obj_t *self = self_in;
+ if (uart_rx_wait(self, self->timeout)) {
+ return MP_OBJ_NEW_SMALL_INT(uart_rx_char(self));
+ } else {
+ // return -1 on timeout
+ return MP_OBJ_NEW_SMALL_INT(-1);
+ }
+}
+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)
+ self->uart.Instance->RQR = USART_RQR_SBKRQ; // write-only register
+ #else
+ self->uart.Instance->CR1 |= USART_CR1_SBK;
+ #endif
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_uart_sendbreak_obj, pyb_uart_sendbreak);
+
+STATIC const mp_rom_map_elem_t pyb_uart_locals_dict_table[] = {
+ // instance methods
+
+ { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&pyb_uart_init_obj) },
+ { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&pyb_uart_deinit_obj) },
+ { MP_ROM_QSTR(MP_QSTR_any), MP_ROM_PTR(&pyb_uart_any_obj) },
+
+ /// \method read([nbytes])
+ { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) },
+ /// \method readline()
+ { MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj)},
+ /// \method readinto(buf[, nbytes])
+ { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) },
+ /// \method write(buf)
+ { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) },
+
+ { MP_ROM_QSTR(MP_QSTR_writechar), MP_ROM_PTR(&pyb_uart_writechar_obj) },
+ { MP_ROM_QSTR(MP_QSTR_readchar), MP_ROM_PTR(&pyb_uart_readchar_obj) },
+ { MP_ROM_QSTR(MP_QSTR_sendbreak), MP_ROM_PTR(&pyb_uart_sendbreak_obj) },
+
+ // class constants
+ { MP_ROM_QSTR(MP_QSTR_RTS), MP_ROM_INT(UART_HWCONTROL_RTS) },
+ { MP_ROM_QSTR(MP_QSTR_CTS), MP_ROM_INT(UART_HWCONTROL_CTS) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(pyb_uart_locals_dict, pyb_uart_locals_dict_table);
+
+STATIC mp_uint_t pyb_uart_read(mp_obj_t self_in, void *buf_in, mp_uint_t size, int *errcode) {
+ pyb_uart_obj_t *self = self_in;
+ byte *buf = buf_in;
+
+ // check that size is a multiple of character width
+ if (size & self->char_width) {
+ *errcode = MP_EIO;
+ return MP_STREAM_ERROR;
+ }
+
+ // convert byte size to char size
+ size >>= self->char_width;
+
+ // make sure we want at least 1 char
+ if (size == 0) {
+ return 0;
+ }
+
+ // wait for first char to become available
+ if (!uart_rx_wait(self, self->timeout)) {
+ // return EAGAIN error to indicate non-blocking (then read() method returns None)
+ *errcode = MP_EAGAIN;
+ return MP_STREAM_ERROR;
+ }
+
+ // read the data
+ byte *orig_buf = buf;
+ for (;;) {
+ int data = uart_rx_char(self);
+ if (self->char_width == CHAR_WIDTH_9BIT) {
+ *(uint16_t*)buf = data;
+ buf += 2;
+ } else {
+ *buf++ = data;
+ }
+ if (--size == 0 || !uart_rx_wait(self, self->timeout_char)) {
+ // return number of bytes read
+ return buf - orig_buf;
+ }
+ }
+}
+
+STATIC mp_uint_t pyb_uart_write(mp_obj_t self_in, const void *buf_in, mp_uint_t size, int *errcode) {
+ pyb_uart_obj_t *self = self_in;
+ const byte *buf = buf_in;
+
+ // check that size is a multiple of character width
+ if (size & self->char_width) {
+ *errcode = MP_EIO;
+ return MP_STREAM_ERROR;
+ }
+
+ // wait to be able to write the first character. EAGAIN causes write to return None
+ if (!uart_tx_wait(self, self->timeout)) {
+ *errcode = MP_EAGAIN;
+ return MP_STREAM_ERROR;
+ }
+
+ // write the data
+ size_t num_tx = uart_tx_data(self, buf, size >> self->char_width, errcode);
+
+ if (*errcode == 0 || *errcode == MP_ETIMEDOUT) {
+ // return number of bytes written, even if there was a timeout
+ return num_tx << self->char_width;
+ } else {
+ return MP_STREAM_ERROR;
+ }
+}
+
+STATIC mp_uint_t pyb_uart_ioctl(mp_obj_t self_in, mp_uint_t request, mp_uint_t arg, int *errcode) {
+ pyb_uart_obj_t *self = self_in;
+ mp_uint_t ret;
+ if (request == MP_STREAM_POLL) {
+ mp_uint_t flags = arg;
+ ret = 0;
+ if ((flags & MP_STREAM_POLL_RD) && uart_rx_any(self)) {
+ ret |= MP_STREAM_POLL_RD;
+ }
+ if ((flags & MP_STREAM_POLL_WR) && __HAL_UART_GET_FLAG(&self->uart, UART_FLAG_TXE)) {
+ 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 = pyb_uart_read,
+ .write = pyb_uart_write,
+ .ioctl = pyb_uart_ioctl,
+ .is_text = false,
+};
+
+const mp_obj_type_t pyb_uart_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_UART,
+ .print = pyb_uart_print,
+ .make_new = pyb_uart_make_new,
+ .getiter = mp_identity_getiter,
+ .iternext = mp_stream_unbuffered_iter,
+ .protocol = &uart_stream_p,
+ .locals_dict = (mp_obj_dict_t*)&pyb_uart_locals_dict,
+};
diff --git a/ports/stm32/uart.h b/ports/stm32/uart.h
new file mode 100644
index 000000000..e96b25b5f
--- /dev/null
+++ b/ports/stm32/uart.h
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ */
+#ifndef MICROPY_INCLUDED_STMHAL_UART_H
+#define MICROPY_INCLUDED_STMHAL_UART_H
+
+typedef enum {
+ PYB_UART_NONE = 0,
+ PYB_UART_1 = 1,
+ PYB_UART_2 = 2,
+ PYB_UART_3 = 3,
+ PYB_UART_4 = 4,
+ PYB_UART_5 = 5,
+ PYB_UART_6 = 6,
+ PYB_UART_7 = 7,
+ PYB_UART_8 = 8,
+} pyb_uart_t;
+
+typedef struct _pyb_uart_obj_t pyb_uart_obj_t;
+extern const mp_obj_type_t pyb_uart_type;
+
+void uart_init0(void);
+void uart_deinit(void);
+void uart_irq_handler(mp_uint_t uart_id);
+
+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);
+void uart_tx_strn_cooked(pyb_uart_obj_t *uart_obj, const char *str, uint len);
+
+#endif // MICROPY_INCLUDED_STMHAL_UART_H
diff --git a/ports/stm32/usb.c b/ports/stm32/usb.c
new file mode 100644
index 000000000..6e06e70ba
--- /dev/null
+++ b/ports/stm32/usb.c
@@ -0,0 +1,719 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2013, 2014, 2015 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 <stdarg.h>
+#include <string.h>
+
+#include "usbd_core.h"
+#include "usbd_desc.h"
+#include "usbd_cdc_msc_hid.h"
+#include "usbd_cdc_interface.h"
+#include "usbd_msc_storage.h"
+#include "usbd_hid_interface.h"
+
+#include "py/objstr.h"
+#include "py/runtime.h"
+#include "py/stream.h"
+#include "py/mperrno.h"
+#include "py/mphal.h"
+#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
+#else
+#error Unable to determine proper USB_PHY_ID to use
+#endif
+
+// this will be persistent across a soft-reset
+mp_uint_t pyb_usb_flags = 0;
+
+#ifdef USE_DEVICE_MODE
+STATIC USBD_HandleTypeDef hUSBDDevice;
+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 = {
+ {&mp_type_bytes},
+ 0, // hash not valid
+ USBD_HID_MOUSE_REPORT_DESC_SIZE,
+ USBD_HID_MOUSE_ReportDesc,
+};
+const mp_obj_tuple_t pyb_usb_hid_mouse_obj = {
+ {&mp_type_tuple},
+ 5,
+ {
+ MP_OBJ_NEW_SMALL_INT(1), // subclass: boot
+ MP_OBJ_NEW_SMALL_INT(2), // protocol: mouse
+ MP_OBJ_NEW_SMALL_INT(USBD_HID_MOUSE_MAX_PACKET),
+ MP_OBJ_NEW_SMALL_INT(8), // polling interval: 8ms
+ (mp_obj_t)&pyb_usb_hid_mouse_desc_obj,
+ },
+};
+
+// predefined hid keyboard data
+STATIC const mp_obj_str_t pyb_usb_hid_keyboard_desc_obj = {
+ {&mp_type_bytes},
+ 0, // hash not valid
+ USBD_HID_KEYBOARD_REPORT_DESC_SIZE,
+ USBD_HID_KEYBOARD_ReportDesc,
+};
+const mp_obj_tuple_t pyb_usb_hid_keyboard_obj = {
+ {&mp_type_tuple},
+ 5,
+ {
+ MP_OBJ_NEW_SMALL_INT(1), // subclass: boot
+ MP_OBJ_NEW_SMALL_INT(1), // protocol: keyboard
+ MP_OBJ_NEW_SMALL_INT(USBD_HID_KEYBOARD_MAX_PACKET),
+ MP_OBJ_NEW_SMALL_INT(8), // polling interval: 8ms
+ (mp_obj_t)&pyb_usb_hid_keyboard_desc_obj,
+ },
+};
+
+void pyb_usb_init0(void) {
+ mp_hal_set_interrupt_char(-1);
+ MP_STATE_PORT(pyb_hid_report_desc) = MP_OBJ_NULL;
+}
+
+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
+ if (!(pyb_usb_flags & PYB_USB_FLAG_DEV_ENABLED)) {
+ // only init USB once in the device's power-lifetime
+ USBD_SetVIDPIDRelease(vid, pid, 0x0200, mode == USBD_MODE_CDC);
+ if (USBD_SelectMode(mode, hid_info) != 0) {
+ return false;
+ }
+ USBD_Init(&hUSBDDevice, (USBD_DescriptorsTypeDef*)&USBD_Descriptors, USB_PHY_ID);
+ USBD_RegisterClass(&hUSBDDevice, &USBD_CDC_MSC_HID);
+ USBD_CDC_RegisterInterface(&hUSBDDevice, (USBD_CDC_ItfTypeDef*)&USBD_CDC_fops);
+ switch (pyb_usb_storage_medium) {
+#if MICROPY_HW_HAS_SDCARD
+ case PYB_USB_STORAGE_MEDIUM_SDCARD:
+ USBD_MSC_RegisterStorage(&hUSBDDevice, (USBD_StorageTypeDef*)&USBD_SDCARD_STORAGE_fops);
+ break;
+#endif
+ default:
+ USBD_MSC_RegisterStorage(&hUSBDDevice, (USBD_StorageTypeDef*)&USBD_FLASH_STORAGE_fops);
+ break;
+ }
+ USBD_HID_RegisterInterface(&hUSBDDevice, (USBD_HID_ItfTypeDef*)&USBD_HID_fops);
+ USBD_Start(&hUSBDDevice);
+ }
+ pyb_usb_flags |= PYB_USB_FLAG_DEV_ENABLED;
+#endif
+
+ return true;
+}
+
+void pyb_usb_dev_deinit(void) {
+ if (pyb_usb_flags & PYB_USB_FLAG_DEV_ENABLED) {
+ USBD_Stop(&hUSBDDevice);
+ pyb_usb_flags &= ~PYB_USB_FLAG_DEV_ENABLED;
+ }
+}
+
+bool usb_vcp_is_enabled(void) {
+ return (pyb_usb_flags & PYB_USB_FLAG_DEV_ENABLED) != 0;
+}
+
+int usb_vcp_recv_byte(uint8_t *c) {
+ return USBD_CDC_Rx(c, 1, 0);
+}
+
+void usb_vcp_send_strn(const char *str, int len) {
+#ifdef USE_DEVICE_MODE
+ if (pyb_usb_flags & PYB_USB_FLAG_DEV_ENABLED) {
+ USBD_CDC_TxAlways((const uint8_t*)str, len);
+ }
+#endif
+}
+
+void usb_vcp_send_strn_cooked(const char *str, int len) {
+#ifdef USE_DEVICE_MODE
+ if (pyb_usb_flags & PYB_USB_FLAG_DEV_ENABLED) {
+ for (const char *top = str + len; str < top; str++) {
+ if (*str == '\n') {
+ USBD_CDC_TxAlways((const uint8_t*)"\r\n", 2);
+ } else {
+ USBD_CDC_TxAlways((const uint8_t*)str, 1);
+ }
+ }
+ }
+#endif
+}
+
+/******************************************************************************/
+// MicroPython bindings for USB
+
+/*
+ Philosophy of USB driver and Python API: pyb.usb_mode(...) configures the USB
+ on the board. The USB itself is not an entity, rather the interfaces are, and
+ can be accessed by creating objects, such as pyb.USB_VCP() and pyb.USB_HID().
+
+ We have:
+
+ pyb.usb_mode() # return the current usb mode
+ pyb.usb_mode(None) # disable USB
+ pyb.usb_mode('VCP') # enable with VCP interface
+ pyb.usb_mode('VCP+MSC') # enable with VCP and MSC interfaces
+ pyb.usb_mode('VCP+HID') # enable with VCP and HID, defaulting to mouse protocol
+ pyb.usb_mode('VCP+HID', vid=0xf055, pid=0x9800) # specify VID and PID
+ pyb.usb_mode('VCP+HID', hid=pyb.hid_mouse)
+ pyb.usb_mode('VCP+HID', hid=pyb.hid_keyboard)
+ pyb.usb_mode('VCP+HID', pid=0x1234, hid=(subclass, protocol, max_packet_len, polling_interval, report_desc))
+
+ vcp = pyb.USB_VCP() # get the VCP device for read/write
+ hid = pyb.USB_HID() # get the HID device for write/poll
+
+ Possible extensions:
+ pyb.usb_mode('host', ...)
+ pyb.usb_mode('OTG', ...)
+ pyb.usb_mode(..., port=2) # for second USB port
+*/
+
+STATIC mp_obj_t pyb_usb_mode(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_REQUIRED | MP_ARG_OBJ, {.u_obj = mp_const_none} },
+ { 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} },
+ };
+
+ // 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)
+ uint8_t mode = USBD_GetMode();
+ switch (mode) {
+ case USBD_MODE_CDC:
+ return MP_OBJ_NEW_QSTR(MP_QSTR_VCP);
+ case USBD_MODE_MSC:
+ return MP_OBJ_NEW_QSTR(MP_QSTR_MSC);
+ case USBD_MODE_HID:
+ return MP_OBJ_NEW_QSTR(MP_QSTR_HID);
+ case USBD_MODE_CDC_MSC:
+ return MP_OBJ_NEW_QSTR(MP_QSTR_VCP_plus_MSC);
+ case USBD_MODE_CDC_HID:
+ return MP_OBJ_NEW_QSTR(MP_QSTR_VCP_plus_HID);
+ case USBD_MODE_MSC_HID:
+ return MP_OBJ_NEW_QSTR(MP_QSTR_MSC_plus_HID);
+ default:
+ return mp_const_none;
+ }
+ #endif
+ }
+
+ // 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);
+
+ // record the fact that the usb has been explicitly configured
+ pyb_usb_flags |= PYB_USB_FLAG_USB_MODE_CALLED;
+
+ // 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;
+ }
+
+ // get mode string
+ const char *mode_str = mp_obj_str_get_str(args[0].u_obj);
+
+#if defined(USE_HOST_MODE)
+
+ // hardware configured for USB host mode
+
+ if (strcmp(mode_str, "host") == 0) {
+ pyb_usb_host_init();
+ } else {
+ goto bad_mode;
+ }
+
+#elif defined(USE_DEVICE_MODE)
+
+ // hardware configured for USB device mode
+
+ // get the VID, PID and USB mode
+ // note: PID=-1 means select PID based on mode
+ // note: we support CDC as a synonym for VCP for backward compatibility
+ uint16_t vid = args[1].u_int;
+ uint16_t pid = args[2].u_int;
+ usb_device_mode_t mode;
+ if (strcmp(mode_str, "CDC+MSC") == 0 || strcmp(mode_str, "VCP+MSC") == 0) {
+ if (args[2].u_int == -1) {
+ pid = USBD_PID_CDC_MSC;
+ }
+ mode = USBD_MODE_CDC_MSC;
+ } 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;
+ }
+ mode = USBD_MODE_CDC_HID;
+ } else if (strcmp(mode_str, "CDC") == 0 || strcmp(mode_str, "VCP") == 0) {
+ if (args[2].u_int == -1) {
+ pid = USBD_PID_CDC;
+ }
+ mode = USBD_MODE_CDC;
+ } else {
+ goto bad_mode;
+ }
+
+ // get hid info if user selected such a mode
+ USBD_HID_ModeInfoTypeDef hid_info;
+ if (mode & USBD_MODE_HID) {
+ mp_obj_t *items;
+ mp_obj_get_array_fixed_n(args[3].u_obj, 5, &items);
+ hid_info.subclass = mp_obj_get_int(items[0]);
+ hid_info.protocol = mp_obj_get_int(items[1]);
+ hid_info.max_packet_len = mp_obj_get_int(items[2]);
+ hid_info.polling_interval = mp_obj_get_int(items[3]);
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(items[4], &bufinfo, MP_BUFFER_READ);
+ hid_info.report_desc = bufinfo.buf;
+ hid_info.report_desc_len = bufinfo.len;
+
+ // need to keep a copy of this so report_desc does not get GC'd
+ MP_STATE_PORT(pyb_hid_report_desc) = items[4];
+ }
+
+ // 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;
+
+bad_mode:
+ mp_raise_ValueError("bad USB mode");
+}
+MP_DEFINE_CONST_FUN_OBJ_KW(pyb_usb_mode_obj, 0, pyb_usb_mode);
+
+/******************************************************************************/
+// MicroPython bindings for USB VCP
+
+/// \moduleref pyb
+/// \class USB_VCP - USB virtual comm port
+///
+/// The USB_VCP class allows creation of an object representing the USB
+/// virtual comm port. It can be used to read and write data over USB to
+/// the connected host.
+
+typedef struct _pyb_usb_vcp_obj_t {
+ mp_obj_base_t base;
+} pyb_usb_vcp_obj_t;
+
+STATIC const pyb_usb_vcp_obj_t pyb_usb_vcp_obj = {{&pyb_usb_vcp_type}};
+
+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()");
+}
+
+/// \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);
+
+ // TODO raise exception if USB is not configured for VCP
+
+ // return the USB VCP object
+ return (mp_obj_t)&pyb_usb_vcp_obj;
+}
+
+STATIC mp_obj_t pyb_usb_vcp_setinterrupt(mp_obj_t self_in, mp_obj_t int_chr_in) {
+ mp_hal_set_interrupt_char(mp_obj_get_int(int_chr_in));
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(pyb_usb_vcp_setinterrupt_obj, pyb_usb_vcp_setinterrupt);
+
+STATIC mp_obj_t pyb_usb_vcp_isconnected(mp_obj_t self_in) {
+ return mp_obj_new_bool(USBD_CDC_IsConnected());
+}
+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);
+}
+MP_DEFINE_CONST_FUN_OBJ_0(pyb_have_cdc_obj, pyb_have_cdc);
+
+/// \method any()
+/// Return `True` if any characters waiting, else `False`.
+STATIC mp_obj_t pyb_usb_vcp_any(mp_obj_t self_in) {
+ if (USBD_CDC_RxNum() > 0) {
+ return mp_const_true;
+ } else {
+ return mp_const_false;
+ }
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_usb_vcp_any_obj, pyb_usb_vcp_any);
+
+/// \method send(data, *, timeout=5000)
+/// Send data over the USB VCP:
+///
+/// - `data` is the data to send (an integer to send, or a buffer object).
+/// - `timeout` is the timeout in milliseconds to wait for the send.
+///
+/// Return value: number of bytes sent.
+STATIC const mp_arg_t pyb_usb_vcp_send_args[] = {
+ { MP_QSTR_data, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+ { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 5000} },
+};
+#define PYB_USB_VCP_SEND_NUM_ARGS MP_ARRAY_SIZE(pyb_usb_vcp_send_args)
+
+STATIC mp_obj_t pyb_usb_vcp_send(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
+ // parse args
+ mp_arg_val_t vals[PYB_USB_VCP_SEND_NUM_ARGS];
+ mp_arg_parse_all(n_args - 1, args + 1, kw_args, PYB_USB_VCP_SEND_NUM_ARGS, pyb_usb_vcp_send_args, vals);
+
+ // get the buffer to send from
+ mp_buffer_info_t bufinfo;
+ uint8_t data[1];
+ pyb_buf_get_for_send(vals[0].u_obj, &bufinfo, data);
+
+ // send the data
+ int ret = USBD_CDC_Tx(bufinfo.buf, bufinfo.len, vals[1].u_int);
+
+ return mp_obj_new_int(ret);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_usb_vcp_send_obj, 1, pyb_usb_vcp_send);
+
+/// \method recv(data, *, timeout=5000)
+///
+/// Receive data on the bus:
+///
+/// - `data` can be an integer, which is the number of bytes to receive,
+/// or a mutable buffer, which will be filled with received bytes.
+/// - `timeout` is the timeout in milliseconds to wait for the receive.
+///
+/// Return value: if `data` is an integer then a new buffer of the bytes received,
+/// otherwise the number of bytes read into `data` is returned.
+STATIC mp_obj_t pyb_usb_vcp_recv(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
+ // parse args
+ mp_arg_val_t vals[PYB_USB_VCP_SEND_NUM_ARGS];
+ mp_arg_parse_all(n_args - 1, args + 1, kw_args, PYB_USB_VCP_SEND_NUM_ARGS, pyb_usb_vcp_send_args, vals);
+
+ // get the buffer to receive into
+ vstr_t vstr;
+ mp_obj_t o_ret = pyb_buf_get_for_recv(vals[0].u_obj, &vstr);
+
+ // receive the data
+ int ret = USBD_CDC_Rx((uint8_t*)vstr.buf, vstr.len, vals[1].u_int);
+
+ // return the received data
+ if (o_ret != MP_OBJ_NULL) {
+ return mp_obj_new_int(ret); // number of bytes read into given buffer
+ } else {
+ vstr.len = ret; // set actual number of bytes read
+ return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); // create a new buffer
+ }
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_usb_vcp_recv_obj, 1, pyb_usb_vcp_recv);
+
+mp_obj_t pyb_usb_vcp___exit__(size_t n_args, const mp_obj_t *args) {
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_usb_vcp___exit___obj, 4, 4, pyb_usb_vcp___exit__);
+
+STATIC const mp_rom_map_elem_t pyb_usb_vcp_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_setinterrupt), MP_ROM_PTR(&pyb_usb_vcp_setinterrupt_obj) },
+ { MP_ROM_QSTR(MP_QSTR_isconnected), MP_ROM_PTR(&pyb_usb_vcp_isconnected_obj) },
+ { MP_ROM_QSTR(MP_QSTR_any), MP_ROM_PTR(&pyb_usb_vcp_any_obj) },
+ { MP_ROM_QSTR(MP_QSTR_send), MP_ROM_PTR(&pyb_usb_vcp_send_obj) },
+ { MP_ROM_QSTR(MP_QSTR_recv), MP_ROM_PTR(&pyb_usb_vcp_recv_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_readlines), MP_ROM_PTR(&mp_stream_unbuffered_readlines_obj)},
+ { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) },
+ { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_identity_obj) },
+ { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mp_identity_obj) },
+ { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&mp_identity_obj) },
+ { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&pyb_usb_vcp___exit___obj) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(pyb_usb_vcp_locals_dict, pyb_usb_vcp_locals_dict_table);
+
+STATIC mp_uint_t pyb_usb_vcp_read(mp_obj_t self_in, void *buf, mp_uint_t size, int *errcode) {
+ int ret = USBD_CDC_Rx((byte*)buf, size, 0);
+ if (ret == 0) {
+ // return EAGAIN error to indicate non-blocking
+ *errcode = MP_EAGAIN;
+ return MP_STREAM_ERROR;
+ }
+ return ret;
+}
+
+STATIC mp_uint_t pyb_usb_vcp_write(mp_obj_t self_in, const void *buf, mp_uint_t size, int *errcode) {
+ int ret = USBD_CDC_Tx((const byte*)buf, size, 0);
+ if (ret == 0) {
+ // return EAGAIN error to indicate non-blocking
+ *errcode = MP_EAGAIN;
+ return MP_STREAM_ERROR;
+ }
+ return ret;
+}
+
+STATIC mp_uint_t pyb_usb_vcp_ioctl(mp_obj_t self_in, mp_uint_t request, mp_uint_t arg, int *errcode) {
+ mp_uint_t ret;
+ if (request == MP_STREAM_POLL) {
+ mp_uint_t flags = arg;
+ ret = 0;
+ if ((flags & MP_STREAM_POLL_RD) && USBD_CDC_RxNum() > 0) {
+ ret |= MP_STREAM_POLL_RD;
+ }
+ if ((flags & MP_STREAM_POLL_WR) && USBD_CDC_TxHalfEmpty()) {
+ ret |= MP_STREAM_POLL_WR;
+ }
+ } else {
+ *errcode = MP_EINVAL;
+ ret = MP_STREAM_ERROR;
+ }
+ return ret;
+}
+
+STATIC const mp_stream_p_t pyb_usb_vcp_stream_p = {
+ .read = pyb_usb_vcp_read,
+ .write = pyb_usb_vcp_write,
+ .ioctl = pyb_usb_vcp_ioctl,
+};
+
+const mp_obj_type_t pyb_usb_vcp_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_USB_VCP,
+ .print = pyb_usb_vcp_print,
+ .make_new = pyb_usb_vcp_make_new,
+ .getiter = mp_identity_getiter,
+ .iternext = mp_stream_unbuffered_iter,
+ .protocol = &pyb_usb_vcp_stream_p,
+ .locals_dict = (mp_obj_dict_t*)&pyb_usb_vcp_locals_dict,
+};
+
+/******************************************************************************/
+// MicroPython bindings for USB HID
+
+typedef struct _pyb_usb_hid_obj_t {
+ mp_obj_base_t base;
+} pyb_usb_hid_obj_t;
+
+STATIC const pyb_usb_hid_obj_t pyb_usb_hid_obj = {{&pyb_usb_hid_type}};
+
+STATIC mp_obj_t pyb_usb_hid_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);
+
+ // TODO raise exception if USB is not configured for HID
+
+ // return the USB HID object
+ return (mp_obj_t)&pyb_usb_hid_obj;
+}
+
+/// \method recv(data, *, timeout=5000)
+///
+/// Receive data on the bus:
+///
+/// - `data` can be an integer, which is the number of bytes to receive,
+/// or a mutable buffer, which will be filled with received bytes.
+/// - `timeout` is the timeout in milliseconds to wait for the receive.
+///
+/// Return value: if `data` is an integer then a new buffer of the bytes received,
+/// otherwise the number of bytes read into `data` is returned.
+STATIC mp_obj_t pyb_usb_hid_recv(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_data, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+ { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 5000} },
+ };
+
+ // parse args
+ 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);
+
+ // get the buffer to receive into
+ vstr_t vstr;
+ mp_obj_t o_ret = pyb_buf_get_for_recv(vals[0].u_obj, &vstr);
+
+ // receive the data
+ int ret = USBD_HID_Rx(&hUSBDDevice, (uint8_t*)vstr.buf, vstr.len, vals[1].u_int);
+
+ // return the received data
+ if (o_ret != MP_OBJ_NULL) {
+ return mp_obj_new_int(ret); // number of bytes read into given buffer
+ } else {
+ vstr.len = ret; // set actual number of bytes read
+ return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); // create a new buffer
+ }
+}
+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
+ mp_buffer_info_t bufinfo;
+ byte temp_buf[8];
+ // get the buffer to send from
+ // we accept either a byte array, or a tuple/list of integers
+ if (!mp_get_buffer(report_in, &bufinfo, MP_BUFFER_READ)) {
+ mp_obj_t *items;
+ mp_obj_get_array(report_in, &bufinfo.len, &items);
+ if (bufinfo.len > sizeof(temp_buf)) {
+ mp_raise_ValueError("tuple/list too large for HID report; use bytearray instead");
+ }
+ for (int i = 0; i < bufinfo.len; i++) {
+ temp_buf[i] = mp_obj_get_int(items[i]);
+ }
+ bufinfo.buf = temp_buf;
+ }
+
+ // send the data
+ if (USBD_OK == USBD_HID_SendReport(&hUSBDDevice, bufinfo.buf, bufinfo.len)) {
+ return mp_obj_new_int(bufinfo.len);
+ } else {
+ return mp_obj_new_int(0);
+ }
+#endif
+
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(pyb_usb_hid_send_obj, pyb_usb_hid_send);
+
+// deprecated in favour of USB_HID.send
+STATIC mp_obj_t pyb_hid_send_report(mp_obj_t arg) {
+ return pyb_usb_hid_send(MP_OBJ_NULL, arg);
+}
+MP_DEFINE_CONST_FUN_OBJ_1(pyb_hid_send_report_obj, pyb_hid_send_report);
+
+STATIC const mp_rom_map_elem_t pyb_usb_hid_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_send), MP_ROM_PTR(&pyb_usb_hid_send_obj) },
+ { MP_ROM_QSTR(MP_QSTR_recv), MP_ROM_PTR(&pyb_usb_hid_recv_obj) },
+};
+
+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) {
+ mp_uint_t ret;
+ if (request == MP_STREAM_POLL) {
+ mp_uint_t flags = arg;
+ ret = 0;
+ if ((flags & MP_STREAM_POLL_RD) && USBD_HID_RxNum() > 0) {
+ ret |= MP_STREAM_POLL_RD;
+ }
+ if ((flags & MP_STREAM_POLL_WR) && USBD_HID_CanSendReport(&hUSBDDevice)) {
+ ret |= MP_STREAM_POLL_WR;
+ }
+ } else {
+ *errcode = MP_EINVAL;
+ ret = MP_STREAM_ERROR;
+ }
+ return ret;
+}
+
+STATIC const mp_stream_p_t pyb_usb_hid_stream_p = {
+ .ioctl = pyb_usb_hid_ioctl,
+};
+
+const mp_obj_type_t pyb_usb_hid_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_USB_HID,
+ .make_new = pyb_usb_hid_make_new,
+ .protocol = &pyb_usb_hid_stream_p,
+ .locals_dict = (mp_obj_dict_t*)&pyb_usb_hid_locals_dict,
+};
+
+/******************************************************************************/
+// code for experimental USB OTG support
+
+#ifdef USE_HOST_MODE
+
+#include "led.h"
+#include "usbh_core.h"
+#include "usbh_usr.h"
+#include "usbh_hid_core.h"
+#include "usbh_hid_keybd.h"
+#include "usbh_hid_mouse.h"
+
+__ALIGN_BEGIN USBH_HOST USB_Host __ALIGN_END ;
+
+static int host_is_enabled = 0;
+
+void pyb_usb_host_init(void) {
+ if (!host_is_enabled) {
+ // only init USBH once in the device's power-lifetime
+ /* Init Host Library */
+ USBH_Init(&USB_OTG_Core, USB_OTG_FS_CORE_ID, &USB_Host, &HID_cb, &USR_Callbacks);
+ }
+ host_is_enabled = 1;
+}
+
+void pyb_usb_host_process(void) {
+ USBH_Process(&USB_OTG_Core, &USB_Host);
+}
+
+uint8_t usb_keyboard_key = 0;
+
+// TODO this is an ugly hack to get key presses
+uint pyb_usb_host_get_keyboard(void) {
+ uint key = usb_keyboard_key;
+ usb_keyboard_key = 0;
+ return key;
+}
+
+void USR_MOUSE_Init(void) {
+ led_state(4, 1);
+ USB_OTG_BSP_mDelay(100);
+ led_state(4, 0);
+}
+
+void USR_MOUSE_ProcessData(HID_MOUSE_Data_TypeDef *data) {
+ led_state(4, 1);
+ USB_OTG_BSP_mDelay(50);
+ led_state(4, 0);
+}
+
+void USR_KEYBRD_Init(void) {
+ led_state(4, 1);
+ USB_OTG_BSP_mDelay(100);
+ led_state(4, 0);
+}
+
+void USR_KEYBRD_ProcessData(uint8_t pbuf) {
+ led_state(4, 1);
+ USB_OTG_BSP_mDelay(50);
+ led_state(4, 0);
+ usb_keyboard_key = pbuf;
+}
+
+#endif // USE_HOST_MODE
diff --git a/ports/stm32/usb.h b/ports/stm32/usb.h
new file mode 100644
index 000000000..d39f49a6c
--- /dev/null
+++ b/ports/stm32/usb.h
@@ -0,0 +1,73 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2013, 2014, 2015 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_STMHAL_USB_H
+#define MICROPY_INCLUDED_STMHAL_USB_H
+
+#include "usbd_cdc_msc_hid0.h"
+
+#define PYB_USB_FLAG_DEV_ENABLED (0x0001)
+#define PYB_USB_FLAG_USB_MODE_CALLED (0x0002)
+
+// Windows needs a different PID to distinguish different device configurations
+#define USBD_VID (0xf055)
+#define USBD_PID_CDC_MSC (0x9800)
+#define USBD_PID_CDC_HID (0x9801)
+#define USBD_PID_CDC (0x9802)
+
+typedef enum {
+ PYB_USB_STORAGE_MEDIUM_NONE = 0,
+ PYB_USB_STORAGE_MEDIUM_FLASH,
+ PYB_USB_STORAGE_MEDIUM_SDCARD,
+} pyb_usb_storage_medium_t;
+
+typedef enum {
+ USB_PHY_FS_ID = 0,
+ USB_PHY_HS_ID = 1,
+} USB_PHY_ID;
+
+extern mp_uint_t pyb_usb_flags;
+extern pyb_usb_storage_medium_t pyb_usb_storage_medium;
+extern const struct _mp_obj_tuple_t pyb_usb_hid_mouse_obj;
+extern const struct _mp_obj_tuple_t pyb_usb_hid_keyboard_obj;
+extern const mp_obj_type_t pyb_usb_vcp_type;
+extern const mp_obj_type_t pyb_usb_hid_type;
+MP_DECLARE_CONST_FUN_OBJ_KW(pyb_usb_mode_obj);
+MP_DECLARE_CONST_FUN_OBJ_0(pyb_have_cdc_obj); // deprecated
+MP_DECLARE_CONST_FUN_OBJ_1(pyb_hid_send_report_obj); // deprecated
+
+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);
+void pyb_usb_dev_deinit(void);
+bool usb_vcp_is_enabled(void);
+int usb_vcp_recv_byte(uint8_t *c); // if a byte is available, return 1 and put the byte in *c, else return 0
+void usb_vcp_send_strn(const char* str, int len);
+void usb_vcp_send_strn_cooked(const char *str, int len);
+
+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
diff --git a/ports/stm32/usbd_cdc_interface.c b/ports/stm32/usbd_cdc_interface.c
new file mode 100644
index 000000000..3e107d418
--- /dev/null
+++ b/ports/stm32/usbd_cdc_interface.c
@@ -0,0 +1,409 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * Taken from ST Cube library and heavily modified. See below for original
+ * copyright header.
+ */
+
+/**
+ ******************************************************************************
+ * @file USB_Device/CDC_Standalone/Src/usbd_cdc_interface.c
+ * @author MCD Application Team
+ * @version V1.0.1
+ * @date 26-February-2014
+ * @brief Source file for USBD CDC interface
+ ******************************************************************************
+ * @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 <stdbool.h>
+#include <stdint.h>
+
+#include "usbd_cdc_msc_hid.h"
+#include "usbd_cdc_interface.h"
+#include "pendsv.h"
+
+#include "py/mpstate.h"
+#include "py/obj.h"
+#include "lib/utils/interrupt_char.h"
+#include "irq.h"
+#include "timer.h"
+#include "usb.h"
+
+// CDC control commands
+#define CDC_SEND_ENCAPSULATED_COMMAND 0x00
+#define CDC_GET_ENCAPSULATED_RESPONSE 0x01
+#define CDC_SET_COMM_FEATURE 0x02
+#define CDC_GET_COMM_FEATURE 0x03
+#define CDC_CLEAR_COMM_FEATURE 0x04
+#define CDC_SET_LINE_CODING 0x20
+#define CDC_GET_LINE_CODING 0x21
+#define CDC_SET_CONTROL_LINE_STATE 0x22
+#define CDC_SEND_BREAK 0x23
+
+/* Private typedef -----------------------------------------------------------*/
+/* Private define ------------------------------------------------------------*/
+#define APP_RX_DATA_SIZE 1024 // this must be 2 or greater, and a power of 2
+#define APP_TX_DATA_SIZE 1024 // I think this can be any value (was 2048)
+
+/* Private macro -------------------------------------------------------------*/
+/* Private variables ---------------------------------------------------------*/
+
+static __IO uint8_t dev_is_connected = 0; // indicates if we are connected
+
+static uint8_t cdc_rx_packet_buf[CDC_DATA_FS_MAX_PACKET_SIZE]; // received data from USB OUT endpoint is stored in this buffer
+static uint8_t cdc_rx_user_buf[APP_RX_DATA_SIZE]; // received data is buffered here until the user reads it
+static volatile uint16_t cdc_rx_buf_put = 0; // circular buffer index
+static uint16_t cdc_rx_buf_get = 0; // circular buffer index
+
+static uint8_t UserTxBuffer[APP_TX_DATA_SIZE]; // data for USB IN endpoind is stored in this buffer
+static uint16_t UserTxBufPtrIn = 0; // increment this pointer modulo APP_TX_DATA_SIZE when new data is available
+static __IO uint16_t UserTxBufPtrOut = 0; // increment this pointer modulo APP_TX_DATA_SIZE when data is drained
+static uint16_t UserTxBufPtrOutShadow = 0; // shadow of above
+static uint8_t UserTxBufPtrWaitCount = 0; // used to implement a timeout waiting for low-level USB driver
+static uint8_t UserTxNeedEmptyPacket = 0; // used to flush the USB IN endpoint if the last packet was exactly the endpoint packet size
+
+/* Private function prototypes -----------------------------------------------*/
+static int8_t CDC_Itf_Init (USBD_HandleTypeDef *pdev);
+static int8_t CDC_Itf_DeInit (void);
+static int8_t CDC_Itf_Control (uint8_t cmd, uint8_t* pbuf, uint16_t length);
+static int8_t CDC_Itf_Receive (USBD_HandleTypeDef *pdev, uint8_t* pbuf, uint32_t *Len);
+
+const USBD_CDC_ItfTypeDef USBD_CDC_fops = {
+ CDC_Itf_Init,
+ CDC_Itf_DeInit,
+ CDC_Itf_Control,
+ CDC_Itf_Receive
+};
+
+/* Private functions ---------------------------------------------------------*/
+
+/**
+ * @brief CDC_Itf_Init
+ * Initializes the CDC media low layer
+ * @param None
+ * @retval Result of the opeartion: USBD_OK if all operations are OK else USBD_FAIL
+ */
+static int8_t CDC_Itf_Init(USBD_HandleTypeDef *pdev) {
+ USBD_CDC_SetTxBuffer(pdev, UserTxBuffer, 0);
+ USBD_CDC_SetRxBuffer(pdev, cdc_rx_packet_buf);
+
+ cdc_rx_buf_put = 0;
+ cdc_rx_buf_get = 0;
+
+ return USBD_OK;
+}
+
+/**
+ * @brief CDC_Itf_DeInit
+ * DeInitializes the CDC media low layer
+ * @param None
+ * @retval Result of the opeartion: USBD_OK if all operations are OK else USBD_FAIL
+ */
+static int8_t CDC_Itf_DeInit(void) {
+ return USBD_OK;
+}
+
+/**
+ * @brief CDC_Itf_Control
+ * Manage the CDC class requests
+ * @param Cmd: Command code
+ * @param Buf: Buffer containing command data (request parameters)
+ * @param Len: Number of data to be sent (in bytes)
+ * @retval Result of the opeartion: USBD_OK if all operations are OK else USBD_FAIL
+ */
+static int8_t CDC_Itf_Control(uint8_t cmd, uint8_t* pbuf, uint16_t length) {
+ switch (cmd) {
+ case CDC_SEND_ENCAPSULATED_COMMAND:
+ /* Add your code here */
+ break;
+
+ case CDC_GET_ENCAPSULATED_RESPONSE:
+ /* Add your code here */
+ break;
+
+ case CDC_SET_COMM_FEATURE:
+ /* Add your code here */
+ break;
+
+ case CDC_GET_COMM_FEATURE:
+ /* Add your code here */
+ break;
+
+ case CDC_CLEAR_COMM_FEATURE:
+ /* Add your code here */
+ break;
+
+ case CDC_SET_LINE_CODING:
+ #if 0
+ LineCoding.bitrate = (uint32_t)(pbuf[0] | (pbuf[1] << 8) |\
+ (pbuf[2] << 16) | (pbuf[3] << 24));
+ LineCoding.format = pbuf[4];
+ LineCoding.paritytype = pbuf[5];
+ LineCoding.datatype = pbuf[6];
+ /* Set the new configuration */
+ #endif
+ break;
+
+ case CDC_GET_LINE_CODING:
+ /* Add your code here */
+ pbuf[0] = (uint8_t)(115200);
+ pbuf[1] = (uint8_t)(115200 >> 8);
+ pbuf[2] = (uint8_t)(115200 >> 16);
+ pbuf[3] = (uint8_t)(115200 >> 24);
+ pbuf[4] = 0; // stop bits (1)
+ pbuf[5] = 0; // parity (none)
+ pbuf[6] = 8; // number of bits (8)
+ break;
+
+ case CDC_SET_CONTROL_LINE_STATE:
+ dev_is_connected = length & 1; // wValue is passed in Len (bit of a hack)
+ break;
+
+ case CDC_SEND_BREAK:
+ /* Add your code here */
+ break;
+
+ default:
+ break;
+ }
+
+ return USBD_OK;
+}
+
+// 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) {
+ if (!dev_is_connected) {
+ // CDC device is not connected to a host, so we are unable to send any data
+ return;
+ }
+
+ if (UserTxBufPtrOut == UserTxBufPtrIn && !UserTxNeedEmptyPacket) {
+ // No outstanding data to send
+ return;
+ }
+
+ if (UserTxBufPtrOut != UserTxBufPtrOutShadow) {
+ // We have sent data and are waiting for the low-level USB driver to
+ // finish sending it over the USB in-endpoint.
+ // SOF occurs every 1ms, so we have a 500 * 1ms = 500ms timeout
+ // We have a relatively large timeout because the USB host may be busy
+ // doing other things and we must give it a chance to read our data.
+ if (UserTxBufPtrWaitCount < 500) {
+ USB_OTG_GlobalTypeDef *USBx = hpcd->Instance;
+ if (USBx_INEP(CDC_IN_EP & 0x7f)->DIEPTSIZ & USB_OTG_DIEPTSIZ_XFRSIZ) {
+ // USB in-endpoint is still reading the data
+ UserTxBufPtrWaitCount++;
+ return;
+ }
+ }
+ UserTxBufPtrOut = UserTxBufPtrOutShadow;
+ }
+
+ if (UserTxBufPtrOutShadow != UserTxBufPtrIn || UserTxNeedEmptyPacket) {
+ uint32_t buffptr;
+ uint32_t buffsize;
+
+ if (UserTxBufPtrOutShadow > UserTxBufPtrIn) { // rollback
+ buffsize = APP_TX_DATA_SIZE - UserTxBufPtrOutShadow;
+ } else {
+ buffsize = UserTxBufPtrIn - UserTxBufPtrOutShadow;
+ }
+
+ buffptr = UserTxBufPtrOutShadow;
+
+ USBD_CDC_SetTxBuffer(hpcd->pData, (uint8_t*)&UserTxBuffer[buffptr], buffsize);
+
+ if (USBD_CDC_TransmitPacket(hpcd->pData) == USBD_OK) {
+ UserTxBufPtrOutShadow += buffsize;
+ if (UserTxBufPtrOutShadow == APP_TX_DATA_SIZE) {
+ UserTxBufPtrOutShadow = 0;
+ }
+ UserTxBufPtrWaitCount = 0;
+
+ // According to the USB specification, a packet size of 64 bytes (CDC_DATA_FS_MAX_PACKET_SIZE)
+ // gets held at the USB host until the next packet is sent. This is because a
+ // packet of maximum size is considered to be part of a longer chunk of data, and
+ // 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
+ UserTxNeedEmptyPacket = (buffsize > 0 && buffsize % CDC_DATA_FS_MAX_PACKET_SIZE == 0 && UserTxBufPtrOutShadow == UserTxBufPtrIn);
+ }
+ }
+}
+
+/**
+ * @brief CDC_Itf_DataRx
+ * Data received over USB OUT endpoint is processed here.
+ * @param Buf: Buffer of data received
+ * @param Len: Number of data received (in bytes)
+ * @retval Result of the opeartion: USBD_OK if all operations are OK else USBD_FAIL
+ * @note The buffer we are passed here is just cdc_rx_packet_buf, so we are
+ * free to modify it.
+ */
+static int8_t CDC_Itf_Receive(USBD_HandleTypeDef *pdev, uint8_t* Buf, uint32_t *Len) {
+ // copy the incoming data into the circular buffer
+ for (uint8_t *src = Buf, *top = Buf + *Len; src < top; ++src) {
+ if (mp_interrupt_char != -1 && *src == mp_interrupt_char) {
+ pendsv_kbd_intr();
+ } else {
+ uint16_t next_put = (cdc_rx_buf_put + 1) & (APP_RX_DATA_SIZE - 1);
+ if (next_put == cdc_rx_buf_get) {
+ // overflow, we just discard the rest of the chars
+ break;
+ }
+ cdc_rx_user_buf[cdc_rx_buf_put] = *src;
+ cdc_rx_buf_put = next_put;
+ }
+ }
+
+ // initiate next USB packet transfer
+ USBD_CDC_SetRxBuffer(pdev, cdc_rx_packet_buf);
+ USBD_CDC_ReceivePacket(pdev);
+
+ return USBD_OK;
+}
+
+int USBD_CDC_IsConnected(void) {
+ return dev_is_connected;
+}
+
+int USBD_CDC_TxHalfEmpty(void) {
+ int32_t tx_waiting = (int32_t)UserTxBufPtrIn - (int32_t)UserTxBufPtrOut;
+ if (tx_waiting < 0) {
+ tx_waiting += APP_TX_DATA_SIZE;
+ }
+ return tx_waiting <= APP_TX_DATA_SIZE / 2;
+}
+
+// timout in milliseconds.
+// Returns number of bytes written to the device.
+int USBD_CDC_Tx(const uint8_t *buf, uint32_t len, uint32_t timeout) {
+ for (uint32_t i = 0; i < len; i++) {
+ // Wait until the device is connected and the buffer has space, with a given timeout
+ uint32_t start = HAL_GetTick();
+ while (!dev_is_connected || ((UserTxBufPtrIn + 1) & (APP_TX_DATA_SIZE - 1)) == UserTxBufPtrOut) {
+ // Wraparound of tick is taken care of by 2's complement arithmetic.
+ if (HAL_GetTick() - start >= timeout) {
+ // timeout
+ return i;
+ }
+ if (query_irq() == IRQ_STATE_DISABLED) {
+ // IRQs disabled so buffer will never be drained; return immediately
+ return i;
+ }
+ __WFI(); // enter sleep mode, waiting for interrupt
+ }
+
+ // Write data to device buffer
+ UserTxBuffer[UserTxBufPtrIn] = buf[i];
+ UserTxBufPtrIn = (UserTxBufPtrIn + 1) & (APP_TX_DATA_SIZE - 1);
+ }
+
+ // Success, return number of bytes read
+ return len;
+}
+
+// Always write all of the data to the device tx buffer, even if the
+// device is not connected, or if the buffer is full. Has a small timeout
+// to wait for the buffer to be drained, in the case the device is connected.
+void USBD_CDC_TxAlways(const uint8_t *buf, uint32_t len) {
+ for (int i = 0; i < len; i++) {
+ // If the CDC device is not connected to the host then we don't have anyone to receive our data.
+ // The device may become connected in the future, so we should at least try to fill the buffer
+ // and hope that it doesn't overflow by the time the device connects.
+ // If the device is not connected then we should go ahead and fill the buffer straight away,
+ // ignoring overflow. Otherwise, we should make sure that we have enough room in the buffer.
+ if (dev_is_connected) {
+ // If the buffer is full, wait until it gets drained, with a timeout of 500ms
+ // (wraparound of tick is taken care of by 2's complement arithmetic).
+ uint32_t start = HAL_GetTick();
+ while (((UserTxBufPtrIn + 1) & (APP_TX_DATA_SIZE - 1)) == UserTxBufPtrOut && HAL_GetTick() - start <= 500) {
+ if (query_irq() == IRQ_STATE_DISABLED) {
+ // IRQs disabled so buffer will never be drained; exit loop
+ break;
+ }
+ __WFI(); // enter sleep mode, waiting for interrupt
+ }
+
+ // Some unused code that makes sure the low-level USB buffer is drained.
+ // Waiting for low-level is handled in HAL_PCD_SOFCallback.
+ /*
+ start = HAL_GetTick();
+ PCD_HandleTypeDef *hpcd = hUSBDDevice.pData;
+ if (hpcd->IN_ep[0x83 & 0x7f].is_in) {
+ //volatile uint32_t *xfer_count = &hpcd->IN_ep[0x83 & 0x7f].xfer_count;
+ //volatile uint32_t *xfer_len = &hpcd->IN_ep[0x83 & 0x7f].xfer_len;
+ USB_OTG_GlobalTypeDef *USBx = hpcd->Instance;
+ while (
+ // *xfer_count < *xfer_len // using this works
+ // (USBx_INEP(3)->DIEPTSIZ & USB_OTG_DIEPTSIZ_XFRSIZ) // using this works
+ && HAL_GetTick() - start <= 2000) {
+ __WFI(); // enter sleep mode, waiting for interrupt
+ }
+ }
+ */
+ }
+
+ UserTxBuffer[UserTxBufPtrIn] = buf[i];
+ UserTxBufPtrIn = (UserTxBufPtrIn + 1) & (APP_TX_DATA_SIZE - 1);
+ }
+}
+
+// Returns number of bytes in the rx buffer.
+int USBD_CDC_RxNum(void) {
+ int32_t rx_waiting = (int32_t)cdc_rx_buf_put - (int32_t)cdc_rx_buf_get;
+ if (rx_waiting < 0) {
+ rx_waiting += APP_RX_DATA_SIZE;
+ }
+ return rx_waiting;
+}
+
+// timout in milliseconds.
+// Returns number of bytes read from the device.
+int USBD_CDC_Rx(uint8_t *buf, uint32_t len, uint32_t timeout) {
+ // loop to read bytes
+ for (uint32_t i = 0; i < len; i++) {
+ // Wait until we have at least 1 byte to read
+ uint32_t start = HAL_GetTick();
+ while (cdc_rx_buf_put == cdc_rx_buf_get) {
+ // Wraparound of tick is taken care of by 2's complement arithmetic.
+ if (HAL_GetTick() - start >= timeout) {
+ // timeout
+ return i;
+ }
+ if (query_irq() == IRQ_STATE_DISABLED) {
+ // IRQs disabled so buffer will never be filled; return immediately
+ return i;
+ }
+ __WFI(); // enter sleep mode, waiting for interrupt
+ }
+
+ // Copy byte from device to user buffer
+ buf[i] = cdc_rx_user_buf[cdc_rx_buf_get];
+ cdc_rx_buf_get = (cdc_rx_buf_get + 1) & (APP_RX_DATA_SIZE - 1);
+ }
+
+ // Success, return number of bytes read
+ return len;
+}
diff --git a/ports/stm32/usbd_cdc_interface.h b/ports/stm32/usbd_cdc_interface.h
new file mode 100644
index 000000000..811a28928
--- /dev/null
+++ b/ports/stm32/usbd_cdc_interface.h
@@ -0,0 +1,45 @@
+/*
+ * 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
+
+/**
+ ******************************************************************************
+ * @file USB_Device/CDC_Standalone/Inc/usbd_cdc_interface.h
+ * @author MCD Application Team
+ * @version V1.0.1
+ * @date 26-February-2014
+ * @brief Header for usbd_cdc_interface.c file.
+ ******************************************************************************
+ * @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.
+ *
+ ******************************************************************************
+ */
+
+extern const USBD_CDC_ItfTypeDef USBD_CDC_fops;
+
+int USBD_CDC_IsConnected(void);
+
+int USBD_CDC_TxHalfEmpty(void);
+int USBD_CDC_Tx(const uint8_t *buf, uint32_t len, uint32_t timeout);
+void USBD_CDC_TxAlways(const uint8_t *buf, uint32_t len);
+
+int USBD_CDC_RxNum(void);
+int USBD_CDC_Rx(uint8_t *buf, uint32_t len, uint32_t timeout);
+
+#endif // MICROPY_INCLUDED_STMHAL_USBD_CDC_INTERFACE_H
diff --git a/ports/stm32/usbd_conf.c b/ports/stm32/usbd_conf.c
new file mode 100644
index 000000000..d39144851
--- /dev/null
+++ b/ports/stm32/usbd_conf.c
@@ -0,0 +1,689 @@
+/*
+ * 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****/
diff --git a/ports/stm32/usbd_conf.h b/ports/stm32/usbd_conf.h
new file mode 100644
index 000000000..34ebe27b9
--- /dev/null
+++ b/ports/stm32/usbd_conf.h
@@ -0,0 +1,93 @@
+/*
+ * 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****/
diff --git a/ports/stm32/usbd_desc.c b/ports/stm32/usbd_desc.c
new file mode 100644
index 000000000..09e1608c8
--- /dev/null
+++ b/ports/stm32/usbd_desc.c
@@ -0,0 +1,226 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ */
+
+/**
+ ******************************************************************************
+ * @file USB_Device/CDC_Standalone/Src/usbd_desc.c
+ * @author MCD Application Team
+ * @version V1.0.1
+ * @date 26-February-2014
+ * @brief This file provides the USBD descriptors and string formating method.
+ ******************************************************************************
+ * @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 "usbd_desc.h"
+#include "usbd_conf.h"
+
+// need these headers just for MP_HAL_UNIQUE_ID_ADDRESS
+#include "py/misc.h"
+#include "py/mphal.h"
+
+// So we don't clash with existing ST boards, we use the unofficial FOSS VID.
+// This needs a proper solution.
+#define USBD_VID 0xf055
+#define USBD_PID 0x9800
+#define USBD_LANGID_STRING 0x409
+#define USBD_MANUFACTURER_STRING "MicroPython"
+#define USBD_PRODUCT_HS_STRING "Pyboard Virtual Comm Port in HS Mode"
+#define USBD_PRODUCT_FS_STRING "Pyboard Virtual Comm Port in FS Mode"
+#define USBD_CONFIGURATION_HS_STRING "Pyboard Config"
+#define USBD_INTERFACE_HS_STRING "Pyboard Interface"
+#define USBD_CONFIGURATION_FS_STRING "Pyboard Config"
+#define USBD_INTERFACE_FS_STRING "Pyboard Interface"
+
+// USB Standard Device Descriptor
+// needs to be in RAM because we modify the VID and PID
+__ALIGN_BEGIN static uint8_t hUSBDDeviceDesc[USB_LEN_DEV_DESC] __ALIGN_END = {
+ 0x12, // bLength
+ USB_DESC_TYPE_DEVICE, // bDescriptorType
+ 0x00, // bcdUSB
+ 0x02,
+ 0xef, // bDeviceClass: Miscellaneous Device Class
+ 0x02, // bDeviceSubClass: Common Class
+ 0x01, // bDeviceProtocol: Interface Association Descriptor
+ USB_MAX_EP0_SIZE, // bMaxPacketSize
+ LOBYTE(USBD_VID), // idVendor
+ HIBYTE(USBD_VID), // idVendor
+ LOBYTE(USBD_PID), // idVendor
+ HIBYTE(USBD_PID), // idVendor
+ 0x00, // bcdDevice rel. 2.00
+ 0x02,
+ USBD_IDX_MFC_STR, // Index of manufacturer string
+ USBD_IDX_PRODUCT_STR, // Index of product string
+ USBD_IDX_SERIAL_STR, // Index of serial number string
+ USBD_MAX_NUM_CONFIGURATION // bNumConfigurations
+};
+
+__ALIGN_BEGIN static 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),
+};
+
+__ALIGN_BEGIN static uint8_t USBD_StrDesc[USBD_MAX_STR_DESC_SIZ] __ALIGN_END;
+
+// set the VID, PID and device release number
+void USBD_SetVIDPIDRelease(uint16_t vid, uint16_t pid, uint16_t device_release_num, int cdc_only) {
+ if (cdc_only) {
+ // Make it look like a Communications device if we're only
+ // using CDC. Otherwise, windows gets confused when we tell it that
+ // its a composite device with only a cdc serial interface.
+ hUSBDDeviceDesc[4] = 0x02;
+ hUSBDDeviceDesc[5] = 0x00;
+ hUSBDDeviceDesc[6] = 0x00;
+ } else {
+ // For the other modes, we make this look like a composite device.
+ hUSBDDeviceDesc[4] = 0xef;
+ hUSBDDeviceDesc[5] = 0x02;
+ hUSBDDeviceDesc[6] = 0x01;
+ }
+ hUSBDDeviceDesc[8] = LOBYTE(vid);
+ hUSBDDeviceDesc[9] = HIBYTE(vid);
+ hUSBDDeviceDesc[10] = LOBYTE(pid);
+ hUSBDDeviceDesc[11] = HIBYTE(pid);
+ hUSBDDeviceDesc[12] = LOBYTE(device_release_num);
+ hUSBDDeviceDesc[13] = HIBYTE(device_release_num);
+}
+
+/**
+ * @brief Returns the device descriptor.
+ * @param speed: Current device speed
+ * @param length: Pointer to data length variable
+ * @retval Pointer to descriptor buffer
+ */
+STATIC uint8_t *USBD_DeviceDescriptor(USBD_SpeedTypeDef speed, uint16_t *length) {
+ *length = sizeof(hUSBDDeviceDesc);
+ return hUSBDDeviceDesc;
+}
+
+/**
+ * @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_SpeedTypeDef speed, uint16_t *length) {
+ *length = sizeof(USBD_LangIDDesc);
+ return USBD_LangIDDesc;
+}
+
+/**
+ * @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_SpeedTypeDef speed, uint16_t *length) {
+ if(speed == 0) {
+ USBD_GetString((uint8_t *)USBD_PRODUCT_HS_STRING, USBD_StrDesc, length);
+ } else {
+ USBD_GetString((uint8_t *)USBD_PRODUCT_FS_STRING, USBD_StrDesc, length);
+ }
+ return USBD_StrDesc;
+}
+
+/**
+ * @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_SpeedTypeDef speed, uint16_t *length) {
+ USBD_GetString((uint8_t *)USBD_MANUFACTURER_STRING, USBD_StrDesc, length);
+ return USBD_StrDesc;
+}
+
+/**
+ * @brief Returns the serial number string descriptor.
+ * @param speed: Current device speed
+ * @param length: Pointer to data length variable
+ * @retval Pointer to descriptor buffer
+ */
+STATIC uint8_t *USBD_SerialStrDescriptor(USBD_SpeedTypeDef speed, 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]);
+
+ USBD_GetString((uint8_t *)serial_buf, USBD_StrDesc, length);
+ return USBD_StrDesc;
+}
+
+/**
+ * @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_SpeedTypeDef speed, uint16_t *length) {
+ if(speed == USBD_SPEED_HIGH) {
+ USBD_GetString((uint8_t *)USBD_CONFIGURATION_HS_STRING, USBD_StrDesc, length);
+ } else {
+ USBD_GetString((uint8_t *)USBD_CONFIGURATION_FS_STRING, USBD_StrDesc, length);
+ }
+ return USBD_StrDesc;
+}
+
+/**
+ * @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_SpeedTypeDef speed, uint16_t *length) {
+ if(speed == 0) {
+ USBD_GetString((uint8_t *)USBD_INTERFACE_HS_STRING, USBD_StrDesc, length);
+ } else {
+ USBD_GetString((uint8_t *)USBD_INTERFACE_FS_STRING, USBD_StrDesc, length);
+ }
+ return USBD_StrDesc;
+}
+
+const USBD_DescriptorsTypeDef USBD_Descriptors = {
+ USBD_DeviceDescriptor,
+ USBD_LangIDStrDescriptor,
+ USBD_ManufacturerStrDescriptor,
+ USBD_ProductStrDescriptor,
+ USBD_SerialStrDescriptor,
+ USBD_ConfigStrDescriptor,
+ USBD_InterfaceStrDescriptor,
+};
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/ports/stm32/usbd_desc.h b/ports/stm32/usbd_desc.h
new file mode 100644
index 000000000..05cbbe5b1
--- /dev/null
+++ b/ports/stm32/usbd_desc.h
@@ -0,0 +1,33 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2013, 2014, 2015 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_STMHAL_USBD_DESC_H
+#define MICROPY_INCLUDED_STMHAL_USBD_DESC_H
+
+extern const USBD_DescriptorsTypeDef USBD_Descriptors;
+
+void USBD_SetVIDPIDRelease(uint16_t vid, uint16_t pid, uint16_t device_release_num, int cdc_only);
+
+#endif // MICROPY_INCLUDED_STMHAL_USBD_DESC_H
diff --git a/ports/stm32/usbd_hid_interface.c b/ports/stm32/usbd_hid_interface.c
new file mode 100644
index 000000000..11b3a3acd
--- /dev/null
+++ b/ports/stm32/usbd_hid_interface.c
@@ -0,0 +1,134 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * Taken from ST Cube library and heavily modified. See below for original
+ * copyright header.
+ */
+
+/**
+ ******************************************************************************
+ * @file USB_Device/CDC_Standalone/Src/usbd_cdc_interface.c
+ * @author MCD Application Team
+ * @version V1.0.1
+ * @date 26-February-2014
+ * @brief Source file for USBD CDC interface
+ ******************************************************************************
+ * @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 <stdint.h>
+
+#include "usbd_cdc_msc_hid.h"
+#include "usbd_hid_interface.h"
+
+#include "py/obj.h"
+#include "irq.h"
+#include "usb.h"
+
+/* Private variables ---------------------------------------------------------*/
+
+static uint8_t buffer[2][HID_DATA_FS_MAX_PACKET_SIZE]; // pair of buffers to read individual packets into
+static int8_t current_read_buffer = 0; // which buffer to read from
+static uint32_t last_read_len = 0; // length of last read
+static int8_t current_write_buffer = 0; // which buffer to write to
+
+/* Private function prototypes -----------------------------------------------*/
+static int8_t HID_Itf_Init (USBD_HandleTypeDef *pdev);
+static int8_t HID_Itf_Receive (USBD_HandleTypeDef *pdev, uint8_t* pbuf, uint32_t Len);
+
+const USBD_HID_ItfTypeDef USBD_HID_fops = {
+ HID_Itf_Init,
+ HID_Itf_Receive
+};
+
+/**
+ * @brief HID_Itf_Init
+ * Initializes the HID media low layer
+ * @param None
+ * @retval Result of the opeartion: USBD_OK if all operations are OK else USBD_FAIL
+ */
+static int8_t HID_Itf_Init(USBD_HandleTypeDef *pdev)
+{
+ current_read_buffer = 0;
+ last_read_len = 0;
+ current_write_buffer = 0;
+ USBD_HID_SetRxBuffer(pdev, buffer[current_write_buffer]);
+ return USBD_OK;
+}
+
+/**
+ * @brief HID_Itf_Receive
+ * Data received over USB OUT endpoint is processed here.
+ * @param Buf: Buffer of data received
+ * @param Len: Number of data received (in bytes)
+ * @retval Result of the opeartion: USBD_OK if all operations are OK else USBD_FAIL
+ * @note The buffer we are passed here is just UserRxBuffer, so we are
+ * free to modify it.
+ */
+static int8_t HID_Itf_Receive(USBD_HandleTypeDef *pdev, uint8_t* Buf, uint32_t Len) {
+ current_write_buffer = !current_write_buffer;
+ last_read_len = Len;
+ // initiate next USB packet transfer, to append to existing data in buffer
+ USBD_HID_SetRxBuffer(pdev, buffer[current_write_buffer]);
+ USBD_HID_ReceivePacket(pdev);
+ // Set NAK to indicate we need to process read buffer
+ USBD_HID_SetNAK(pdev);
+ return USBD_OK;
+}
+
+// Returns number of ready rx buffers.
+int USBD_HID_RxNum(void) {
+ return (current_read_buffer != current_write_buffer);
+}
+
+// timout in milliseconds.
+// Returns number of bytes read from the device.
+int USBD_HID_Rx(USBD_HandleTypeDef *pdev, uint8_t *buf, uint32_t len, uint32_t timeout) {
+ // Wait until we have buffer to read
+ uint32_t start = HAL_GetTick();
+ while (current_read_buffer == current_write_buffer) {
+ // Wraparound of tick is taken care of by 2's complement arithmetic.
+ if (HAL_GetTick() - start >= timeout) {
+ // timeout
+ return 0;
+ }
+ if (query_irq() == IRQ_STATE_DISABLED) {
+ // IRQs disabled so buffer will never be filled; return immediately
+ return 0;
+ }
+ __WFI(); // enter sleep mode, waiting for interrupt
+ }
+
+ // There is not enough space in buffer
+ if (len < last_read_len) {
+ return 0;
+ }
+
+ // Copy bytes from device to user buffer
+ memcpy(buf, buffer[current_read_buffer], last_read_len);
+ current_read_buffer = !current_read_buffer;
+
+ // Clear NAK to indicate we are ready to read more data
+ USBD_HID_ClearNAK(pdev);
+
+ // Success, return number of bytes read
+ return last_read_len;
+}
diff --git a/ports/stm32/usbd_hid_interface.h b/ports/stm32/usbd_hid_interface.h
new file mode 100644
index 000000000..b2ff75fa1
--- /dev/null
+++ b/ports/stm32/usbd_hid_interface.h
@@ -0,0 +1,14 @@
+/*
+ * 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
+
+#include "usbd_cdc_msc_hid.h"
+
+extern const USBD_HID_ItfTypeDef USBD_HID_fops;
+
+int USBD_HID_RxNum(void);
+int USBD_HID_Rx(USBD_HandleTypeDef *pdev, uint8_t *buf, uint32_t len, uint32_t timeout);
+
+#endif // MICROPY_INCLUDED_STMHAL_USBD_HID_INTERFACE_H
diff --git a/ports/stm32/usbd_msc_storage.c b/ports/stm32/usbd_msc_storage.c
new file mode 100644
index 000000000..f825c3d70
--- /dev/null
+++ b/ports/stm32/usbd_msc_storage.c
@@ -0,0 +1,306 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ */
+
+/**
+ ******************************************************************************
+ * @file usbd_storage_msd.c
+ * @author MCD application Team
+ * @version V1.1.0
+ * @date 19-March-2012
+ * @brief This file provides the disk operations functions.
+ ******************************************************************************
+ * @attention
+ *
+ * <h2><center>&copy; COPYRIGHT 2012 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.
+ *
+ * Heavily modified by dpgeorge for MicroPython.
+ *
+ ******************************************************************************
+ */
+
+#include <stdint.h>
+
+#include "usbd_cdc_msc_hid.h"
+#include "usbd_msc_storage.h"
+
+#include "py/misc.h"
+#include "storage.h"
+#include "sdcard.h"
+
+// These are needed to support removal of the medium, so that the USB drive
+// can be unmounted, and won't be remounted automatically.
+static uint8_t flash_started = 0;
+
+#if MICROPY_HW_HAS_SDCARD
+static uint8_t sdcard_started = 0;
+#endif
+
+/******************************************************************************/
+// Callback functions for when the internal flash is the mass storage device
+
+static const int8_t FLASH_STORAGE_Inquirydata[] = { // 36 bytes
+ // LUN 0
+ 0x00,
+ 0x80, // 0x00 for a fixed drive, 0x80 for a removable drive
+ 0x02,
+ 0x02,
+ (STANDARD_INQUIRY_DATA_LEN - 5),
+ 0x00,
+ 0x00,
+ 0x00,
+ 'u', 'P', 'y', ' ', ' ', ' ', ' ', ' ', // Manufacturer : 8 bytes
+ 'm', 'i', 'c', 'r', 'o', 'S', 'D', ' ', // Product : 16 Bytes
+ 'F', 'l', 'a', 's', 'h', ' ', ' ', ' ',
+ '1', '.', '0' ,'0', // Version : 4 Bytes
+};
+
+/**
+ * @brief Initialize the storage medium
+ * @param lun : logical unit number
+ * @retval Status
+ */
+int8_t FLASH_STORAGE_Init(uint8_t lun) {
+ storage_init();
+ flash_started = 1;
+ return 0;
+}
+
+/**
+ * @brief return medium capacity and block size
+ * @param lun : logical unit number
+ * @param block_num : number of physical block
+ * @param block_size : size of a physical block
+ * @retval Status
+ */
+int8_t FLASH_STORAGE_GetCapacity(uint8_t lun, uint32_t *block_num, uint16_t *block_size) {
+ *block_size = storage_get_block_size();
+ *block_num = storage_get_block_count();
+ return 0;
+}
+
+/**
+ * @brief check whether the medium is ready
+ * @param lun : logical unit number
+ * @retval Status
+ */
+int8_t FLASH_STORAGE_IsReady(uint8_t lun) {
+ if (flash_started) {
+ return 0;
+ }
+ return -1;
+}
+
+/**
+ * @brief check whether the medium is write-protected
+ * @param lun : logical unit number
+ * @retval Status
+ */
+int8_t FLASH_STORAGE_IsWriteProtected(uint8_t lun) {
+ return 0;
+}
+
+// Remove the lun
+int8_t FLASH_STORAGE_StartStopUnit(uint8_t lun, uint8_t started) {
+ flash_started = started;
+ return 0;
+}
+
+int8_t FLASH_STORAGE_PreventAllowMediumRemoval(uint8_t lun, uint8_t param) {
+ // sync the flash so that the cache is cleared and the device can be unplugged/turned off
+ storage_flush();
+ return 0;
+}
+
+/**
+ * @brief Read data from the medium
+ * @param lun : logical unit number
+ * @param buf : Pointer to the buffer to save data
+ * @param blk_addr : address of 1st block to be read
+ * @param blk_len : nmber of blocks to be read
+ * @retval Status
+ */
+int8_t FLASH_STORAGE_Read(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len) {
+ storage_read_blocks(buf, blk_addr, blk_len);
+ return 0;
+}
+
+/**
+ * @brief Write data to the medium
+ * @param lun : logical unit number
+ * @param buf : Pointer to the buffer to write from
+ * @param blk_addr : address of 1st block to be written
+ * @param blk_len : nmber of blocks to be read
+ * @retval Status
+ */
+int8_t FLASH_STORAGE_Write (uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len) {
+ storage_write_blocks(buf, blk_addr, blk_len);
+ return 0;
+}
+
+/**
+ * @brief Return number of supported logical unit
+ * @param None
+ * @retval number of logical unit
+ */
+int8_t FLASH_STORAGE_GetMaxLun(void) {
+ return 0;
+}
+
+const USBD_StorageTypeDef USBD_FLASH_STORAGE_fops = {
+ FLASH_STORAGE_Init,
+ FLASH_STORAGE_GetCapacity,
+ FLASH_STORAGE_IsReady,
+ FLASH_STORAGE_IsWriteProtected,
+ FLASH_STORAGE_StartStopUnit,
+ FLASH_STORAGE_PreventAllowMediumRemoval,
+ FLASH_STORAGE_Read,
+ FLASH_STORAGE_Write,
+ FLASH_STORAGE_GetMaxLun,
+ (int8_t *)FLASH_STORAGE_Inquirydata,
+};
+
+/******************************************************************************/
+// Callback functions for when the SD card is the mass storage device
+
+#if MICROPY_HW_HAS_SDCARD
+
+static const int8_t SDCARD_STORAGE_Inquirydata[] = { // 36 bytes
+ // LUN 0
+ 0x00,
+ 0x80, // 0x00 for a fixed drive, 0x80 for a removable drive
+ 0x02,
+ 0x02,
+ (STANDARD_INQUIRY_DATA_LEN - 5),
+ 0x00,
+ 0x00,
+ 0x00,
+ 'u', 'P', 'y', ' ', ' ', ' ', ' ', ' ', // Manufacturer : 8 bytes
+ 'm', 'i', 'c', 'r', 'o', 'S', 'D', ' ', // Product : 16 Bytes
+ 'S', 'D', ' ', 'c', 'a', 'r', 'd', ' ',
+ '1', '.', '0' ,'0', // Version : 4 Bytes
+};
+
+/**
+ * @brief Initialize the storage medium
+ * @param lun : logical unit number
+ * @retval Status
+ */
+int8_t SDCARD_STORAGE_Init(uint8_t lun) {
+ if (!sdcard_power_on()) {
+ return -1;
+ }
+ sdcard_started = 1;
+ return 0;
+
+}
+
+/**
+ * @brief return medium capacity and block size
+ * @param lun : logical unit number
+ * @param block_num : number of physical block
+ * @param block_size : size of a physical block
+ * @retval Status
+ */
+int8_t SDCARD_STORAGE_GetCapacity(uint8_t lun, uint32_t *block_num, uint16_t *block_size) {
+ *block_size = SDCARD_BLOCK_SIZE;
+ *block_num = sdcard_get_capacity_in_bytes() / SDCARD_BLOCK_SIZE;
+ return 0;
+}
+
+/**
+ * @brief check whether the medium is ready
+ * @param lun : logical unit number
+ * @retval Status
+ */
+int8_t SDCARD_STORAGE_IsReady(uint8_t lun) {
+ if (sdcard_started) {
+ return 0;
+ }
+ return -1;
+}
+
+/**
+ * @brief check whether the medium is write-protected
+ * @param lun : logical unit number
+ * @retval Status
+ */
+int8_t SDCARD_STORAGE_IsWriteProtected(uint8_t lun) {
+ return 0;
+}
+
+// Remove the lun
+int8_t SDCARD_STORAGE_StartStopUnit(uint8_t lun, uint8_t started) {
+ sdcard_started = started;
+ return 0;
+}
+
+int8_t SDCARD_STORAGE_PreventAllowMediumRemoval(uint8_t lun, uint8_t param) {
+ return 0;
+}
+
+/**
+ * @brief Read data from the medium
+ * @param lun : logical unit number
+ * @param buf : Pointer to the buffer to save data
+ * @param blk_addr : address of 1st block to be read
+ * @param blk_len : nmber of blocks to be read
+ * @retval Status
+ */
+int8_t SDCARD_STORAGE_Read(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len) {
+ if (sdcard_read_blocks(buf, blk_addr, blk_len) != 0) {
+ return -1;
+ }
+ return 0;
+}
+
+/**
+ * @brief Write data to the medium
+ * @param lun : logical unit number
+ * @param buf : Pointer to the buffer to write from
+ * @param blk_addr : address of 1st block to be written
+ * @param blk_len : nmber of blocks to be read
+ * @retval Status
+ */
+int8_t SDCARD_STORAGE_Write(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len) {
+ if (sdcard_write_blocks(buf, blk_addr, blk_len) != 0) {
+ return -1;
+ }
+ return 0;
+}
+
+/**
+ * @brief Return number of supported logical unit
+ * @param None
+ * @retval number of logical unit
+ */
+int8_t SDCARD_STORAGE_GetMaxLun(void) {
+ return 0;
+}
+
+const USBD_StorageTypeDef USBD_SDCARD_STORAGE_fops = {
+ SDCARD_STORAGE_Init,
+ SDCARD_STORAGE_GetCapacity,
+ SDCARD_STORAGE_IsReady,
+ SDCARD_STORAGE_IsWriteProtected,
+ SDCARD_STORAGE_StartStopUnit,
+ SDCARD_STORAGE_PreventAllowMediumRemoval,
+ SDCARD_STORAGE_Read,
+ SDCARD_STORAGE_Write,
+ SDCARD_STORAGE_GetMaxLun,
+ (int8_t *)SDCARD_STORAGE_Inquirydata,
+};
+
+#endif // MICROPY_HW_HAS_SDCARD
diff --git a/ports/stm32/usbd_msc_storage.h b/ports/stm32/usbd_msc_storage.h
new file mode 100644
index 000000000..6cc40d2d6
--- /dev/null
+++ b/ports/stm32/usbd_msc_storage.h
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ */
+#ifndef MICROPY_INCLUDED_STMHAL_USBD_MSC_STORAGE_H
+#define MICROPY_INCLUDED_STMHAL_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
diff --git a/ports/stm32/usbdev/Release_Notes.html b/ports/stm32/usbdev/Release_Notes.html
new file mode 100644
index 000000000..487b45526
--- /dev/null
+++ b/ports/stm32/usbdev/Release_Notes.html
@@ -0,0 +1,974 @@
+<!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
new file mode 100644
index 000000000..96617b107
--- /dev/null
+++ b/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid.h
@@ -0,0 +1,122 @@
+#ifndef _USB_CDC_MSC_CORE_H_
+#define _USB_CDC_MSC_CORE_H_
+
+#include "usbd_cdc_msc_hid0.h"
+#include "usbd_msc_bot.h"
+#include "usbd_msc_scsi.h"
+#include "usbd_ioreq.h"
+
+// CDC, MSC and HID packet sizes
+#define CDC_DATA_FS_MAX_PACKET_SIZE (64) // endpoint IN & OUT packet size
+#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
+
+// Need to define here for BOT and SCSI layers
+#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;
+
+typedef struct _USBD_CDC_Itf {
+ int8_t (* Init) (USBD_HandleTypeDef *pdev);
+ int8_t (* DeInit) (void);
+ int8_t (* Control) (uint8_t, uint8_t * , uint16_t);
+ int8_t (* Receive) (USBD_HandleTypeDef *pdev, uint8_t *, uint32_t *);
+} USBD_CDC_ItfTypeDef;
+
+typedef struct {
+ uint32_t data[CDC_DATA_FS_MAX_PACKET_SIZE/4]; /* Force 32bits alignment */
+ uint8_t CmdOpCode;
+ uint8_t CmdLength;
+ uint8_t *RxBuffer;
+ uint8_t *TxBuffer;
+ uint32_t RxLength;
+ uint32_t TxLength;
+
+ __IO uint32_t TxState;
+ __IO uint32_t RxState;
+} USBD_CDC_HandleTypeDef;
+
+typedef struct _USBD_HID_Itf {
+ int8_t (* Init) (USBD_HandleTypeDef *pdev);
+ int8_t (* Receive)(USBD_HandleTypeDef *pdev, uint8_t *, uint32_t);
+} USBD_HID_ItfTypeDef;
+
+typedef struct _USBD_STORAGE {
+ int8_t (* Init) (uint8_t lun);
+ int8_t (* GetCapacity) (uint8_t lun, uint32_t *block_num, uint16_t *block_size);
+ int8_t (* IsReady) (uint8_t lun);
+ int8_t (* IsWriteProtected) (uint8_t lun);
+ int8_t (* StartStopUnit)(uint8_t lun, uint8_t started);
+ int8_t (* PreventAllowMediumRemoval)(uint8_t lun, uint8_t param0);
+ int8_t (* Read) (uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len);
+ int8_t (* Write)(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len);
+ int8_t (* GetMaxLun)(void);
+ int8_t *pInquiry;
+} USBD_StorageTypeDef;
+
+typedef struct {
+ uint32_t max_lun;
+ uint32_t interface;
+ uint8_t bot_state;
+ uint8_t bot_status;
+ uint16_t bot_data_length;
+ uint8_t bot_data[MSC_MEDIA_PACKET];
+ USBD_MSC_BOT_CBWTypeDef cbw;
+ USBD_MSC_BOT_CSWTypeDef csw;
+
+ USBD_SCSI_SenseTypeDef scsi_sense [SENSE_LIST_DEEPTH];
+ uint8_t scsi_sense_head;
+ uint8_t scsi_sense_tail;
+
+ uint16_t scsi_blk_size;
+ uint32_t scsi_blk_nbr;
+
+ uint32_t scsi_blk_addr_in_blks;
+ uint32_t scsi_blk_len;
+} USBD_MSC_BOT_HandleTypeDef;
+
+#define USBD_HID_MOUSE_MAX_PACKET (4)
+#define USBD_HID_MOUSE_REPORT_DESC_SIZE (74)
+
+extern const uint8_t USBD_HID_MOUSE_ReportDesc[USBD_HID_MOUSE_REPORT_DESC_SIZE];
+
+#define USBD_HID_KEYBOARD_MAX_PACKET (8)
+#define USBD_HID_KEYBOARD_REPORT_DESC_SIZE (63)
+
+extern const uint8_t USBD_HID_KEYBOARD_ReportDesc[USBD_HID_KEYBOARD_REPORT_DESC_SIZE];
+
+extern USBD_ClassTypeDef USBD_CDC_MSC_HID;
+
+// returns 0 on success, -1 on failure
+int USBD_SelectMode(uint32_t mode, USBD_HID_ModeInfoTypeDef *hid_info);
+// returns the current usb mode
+uint8_t USBD_GetMode();
+
+uint8_t USBD_CDC_RegisterInterface (USBD_HandleTypeDef *pdev, USBD_CDC_ItfTypeDef *fops);
+uint8_t USBD_CDC_SetTxBuffer (USBD_HandleTypeDef *pdev, uint8_t *pbuff, uint16_t length);
+uint8_t USBD_CDC_SetRxBuffer (USBD_HandleTypeDef *pdev, uint8_t *pbuff);
+uint8_t USBD_CDC_ReceivePacket (USBD_HandleTypeDef *pdev);
+uint8_t USBD_CDC_TransmitPacket (USBD_HandleTypeDef *pdev);
+
+uint8_t USBD_MSC_RegisterStorage(USBD_HandleTypeDef *pdev, USBD_StorageTypeDef *fops);
+
+uint8_t USBD_HID_RegisterInterface(USBD_HandleTypeDef *pdev, USBD_HID_ItfTypeDef *fops);
+uint8_t USBD_HID_SetRxBuffer(USBD_HandleTypeDef *pdev, uint8_t *pbuff);
+uint8_t USBD_HID_ReceivePacket(USBD_HandleTypeDef *pdev);
+int USBD_HID_CanSendReport(USBD_HandleTypeDef *pdev);
+uint8_t USBD_HID_SendReport(USBD_HandleTypeDef *pdev, uint8_t *report, uint16_t len);
+uint8_t USBD_HID_SetNAK(USBD_HandleTypeDef *pdev);
+uint8_t USBD_HID_ClearNAK(USBD_HandleTypeDef *pdev);
+
+#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
new file mode 100644
index 000000000..08882bb1a
--- /dev/null
+++ b/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid0.h
@@ -0,0 +1,51 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2015 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_STMHAL_USBDEV_CLASS_INC_USBD_CDC_MSC_HID0_H
+#define MICROPY_INCLUDED_STMHAL_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
+
+// only CDC_MSC and CDC_HID are available
+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,
+} usb_device_mode_t;
+
+typedef struct _USBD_HID_ModeInfoTypeDef {
+ uint8_t subclass; // 0=no sub class, 1=boot
+ uint8_t protocol; // 0=none, 1=keyboard, 2=mouse
+ uint8_t max_packet_len; // only support up to 255
+ uint8_t polling_interval; // in units of 1ms
+ uint8_t report_desc_len;
+ const uint8_t *report_desc;
+} USBD_HID_ModeInfoTypeDef;
+
+#endif // MICROPY_INCLUDED_STMHAL_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
new file mode 100644
index 000000000..41f8ab5a5
--- /dev/null
+++ b/ports/stm32/usbdev/class/inc/usbd_msc_bot.h
@@ -0,0 +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****/
+
diff --git a/ports/stm32/usbdev/class/inc/usbd_msc_data.h b/ports/stm32/usbdev/class/inc/usbd_msc_data.h
new file mode 100644
index 000000000..f468267f4
--- /dev/null
+++ b/ports/stm32/usbdev/class/inc/usbd_msc_data.h
@@ -0,0 +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****/
diff --git a/ports/stm32/usbdev/class/inc/usbd_msc_scsi.h b/ports/stm32/usbdev/class/inc/usbd_msc_scsi.h
new file mode 100644
index 000000000..34f059ee5
--- /dev/null
+++ b/ports/stm32/usbdev/class/inc/usbd_msc_scsi.h
@@ -0,0 +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****/
+
diff --git a/ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c b/ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c
new file mode 100644
index 000000000..d61073f4d
--- /dev/null
+++ b/ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c
@@ -0,0 +1,1130 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2015 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 "usbd_ioreq.h"
+#include "usbd_cdc_msc_hid.h"
+
+#define MAX_TEMPLATE_CONFIG_DESC_SIZE (107) // should be maximum of all template config desc's
+#define CDC_TEMPLATE_CONFIG_DESC_SIZE (67)
+#define CDC_MSC_TEMPLATE_CONFIG_DESC_SIZE (98)
+#define CDC_HID_TEMPLATE_CONFIG_DESC_SIZE (107)
+#define CDC_HID_TEMPLATE_HID_DESC_OFFSET (9)
+#define HID_DESC_OFFSET_SUBCLASS (6)
+#define HID_DESC_OFFSET_PROTOCOL (7)
+#define HID_DESC_OFFSET_SUBDESC (9)
+#define HID_DESC_OFFSET_REPORT_DESC_LEN (16)
+#define HID_DESC_OFFSET_MAX_PACKET_LO (22)
+#define HID_DESC_OFFSET_MAX_PACKET_HI (23)
+#define HID_DESC_OFFSET_POLLING_INTERVAL (24)
+#define HID_DESC_OFFSET_MAX_PACKET_OUT_LO (29)
+#define HID_DESC_OFFSET_MAX_PACKET_OUT_HI (30)
+#define HID_DESC_OFFSET_POLLING_INTERVAL_OUT (31)
+#define HID_SUBDESC_LEN (9)
+
+#define CDC_IFACE_NUM_ALONE (0)
+#define CDC_IFACE_NUM_WITH_MSC (1)
+#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 HID_IN_EP_WITH_CDC (0x81)
+#define HID_OUT_EP_WITH_CDC (0x01)
+#define HID_IN_EP_WITH_MSC (0x83)
+#define HID_OUT_EP_WITH_MSC (0x03)
+
+#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)
+
+#define HID_DESCRIPTOR_TYPE (0x21)
+#define HID_REPORT_DESC (0x22)
+#define HID_REQ_SET_PROTOCOL (0x0b)
+#define HID_REQ_GET_PROTOCOL (0x03)
+#define HID_REQ_SET_IDLE (0x0a)
+#define HID_REQ_GET_IDLE (0x02)
+
+typedef enum {
+ HID_IDLE = 0,
+ HID_BUSY,
+} HID_StateTypeDef;
+
+typedef struct {
+ uint32_t Protocol;
+ uint32_t IdleState;
+ uint32_t AltSetting;
+ HID_StateTypeDef state;
+ uint8_t *RxBuffer;
+ uint32_t RxLength;
+} USBD_HID_HandleTypeDef;
+
+static uint8_t usbd_mode;
+static uint8_t cdc_iface_num;
+static uint8_t hid_in_ep;
+static uint8_t hid_out_ep;
+static uint8_t hid_iface_num;
+static uint8_t usbd_config_desc_size;
+static uint8_t *hid_desc;
+static const uint8_t *hid_report_desc;
+
+static USBD_CDC_ItfTypeDef *CDC_fops;
+static USBD_StorageTypeDef *MSC_fops;
+static USBD_HID_ItfTypeDef *HID_fops;
+
+static USBD_CDC_HandleTypeDef CDC_ClassData;
+static USBD_MSC_BOT_HandleTypeDef MSC_BOT_ClassData;
+static USBD_HID_HandleTypeDef HID_ClassData;
+
+// RAM to hold the current configuration descriptor, which we configure on the fly
+__ALIGN_BEGIN static uint8_t usbd_config_desc[MAX_TEMPLATE_CONFIG_DESC_SIZE] __ALIGN_END;
+
+/*
+// this is used only in high-speed mode, which we don't support
+// 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,
+ USB_DESC_TYPE_DEVICE_QUALIFIER,
+ 0x00,
+ 0x02,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x40, // same for CDC and MSC (latter being MSC_MAX_PACKET), HID is 0x04
+ 0x01,
+ 0x00,
+};
+*/
+
+// USB CDC MSC device Configuration Descriptor
+static const uint8_t cdc_msc_template_config_desc[CDC_MSC_TEMPLATE_CONFIG_DESC_SIZE] = {
+ //--------------------------------------------------------------------------
+ // Configuration Descriptor
+ 0x09, // bLength: Configuration Descriptor size
+ USB_DESC_TYPE_CONFIGURATION, // bDescriptorType: Configuration
+ LOBYTE(CDC_MSC_TEMPLATE_CONFIG_DESC_SIZE), // wTotalLength: no of returned bytes
+ HIBYTE(CDC_MSC_TEMPLATE_CONFIG_DESC_SIZE),
+ 0x03, // bNumInterfaces: 3 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_MAX_PACKET), // wMaxPacketSize
+ HIBYTE(MSC_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_MAX_PACKET), // wMaxPacketSize
+ HIBYTE(MSC_MAX_PACKET),
+ 0x00, // bInterval: ignore for Bulk transfer
+
+ //==========================================================================
+ // Interface Association for CDC VCP
+ 0x08, // bLength: 8 bytes
+ USB_DESC_TYPE_ASSOCIATION, // bDescriptorType: IAD
+ CDC_IFACE_NUM_WITH_MSC, // bFirstInterface: first interface for this association
+ 0x02, // bInterfaceCount: nummber of interfaces for this association
+ 0x02, // bFunctionClass: Communication Interface Class
+ 0x02, // bFunctionSubClass: Abstract Control Model
+ 0x01, // bFunctionProtocol: Common AT commands
+ 0x00, // iFunction: index of string for this function
+
+ //--------------------------------------------------------------------------
+ // Interface Descriptor
+ 0x09, // bLength: Interface Descriptor size
+ USB_DESC_TYPE_INTERFACE, // bDescriptorType: Interface
+ CDC_IFACE_NUM_WITH_MSC, // bInterfaceNumber: Number of Interface
+ 0x00, // bAlternateSetting: Alternate setting
+ 0x01, // bNumEndpoints: One endpoints used
+ 0x02, // bInterfaceClass: Communication Interface Class
+ 0x02, // bInterfaceSubClass: Abstract Control Model
+ 0x01, // bInterfaceProtocol: Common AT commands
+ 0x00, // iInterface:
+
+ // Header Functional Descriptor
+ 0x05, // bLength: Endpoint Descriptor size
+ 0x24, // bDescriptorType: CS_INTERFACE
+ 0x00, // bDescriptorSubtype: Header Func Desc
+ 0x10, // bcdCDC: spec release number
+ 0x01, // ?
+
+ // Call Management Functional Descriptor
+ 0x05, // bFunctionLength
+ 0x24, // bDescriptorType: CS_INTERFACE
+ 0x01, // bDescriptorSubtype: Call Management Func Desc
+ 0x00, // bmCapabilities: D0+D1
+ CDC_IFACE_NUM_WITH_MSC + 1, // bDataInterface: 1
+
+ // ACM Functional Descriptor
+ 0x04, // bFunctionLength
+ 0x24, // bDescriptorType: CS_INTERFACE
+ 0x02, // bDescriptorSubtype: Abstract Control Management desc
+ 0x02, // bmCapabilities
+
+ // Union Functional Descriptor
+ 0x05, // bFunctionLength
+ 0x24, // bDescriptorType: CS_INTERFACE
+ 0x06, // bDescriptorSubtype: Union func desc
+ CDC_IFACE_NUM_WITH_MSC + 0, // bMasterInterface: Communication class interface
+ CDC_IFACE_NUM_WITH_MSC + 1, // bSlaveInterface0: Data Class Interface
+
+ // Endpoint 2 Descriptor
+ 0x07, // bLength: Endpoint Descriptor size
+ USB_DESC_TYPE_ENDPOINT, // bDescriptorType: Endpoint
+ CDC_CMD_EP, // bEndpointAddress
+ 0x03, // bmAttributes: Interrupt
+ LOBYTE(CDC_CMD_PACKET_SIZE), // wMaxPacketSize:
+ HIBYTE(CDC_CMD_PACKET_SIZE),
+ 0x20, // bInterval: polling interval in frames of 1ms
+
+ //--------------------------------------------------------------------------
+ // Data class interface descriptor
+ 0x09, // bLength: Endpoint Descriptor size
+ USB_DESC_TYPE_INTERFACE, // bDescriptorType: interface
+ CDC_IFACE_NUM_WITH_MSC + 1, // bInterfaceNumber: Number of Interface
+ 0x00, // bAlternateSetting: Alternate setting
+ 0x02, // bNumEndpoints: Two endpoints used
+ 0x0A, // bInterfaceClass: CDC
+ 0x00, // bInterfaceSubClass: ?
+ 0x00, // bInterfaceProtocol: ?
+ 0x00, // iInterface:
+
+ // Endpoint OUT Descriptor
+ 0x07, // bLength: Endpoint Descriptor size
+ USB_DESC_TYPE_ENDPOINT, // bDescriptorType: Endpoint
+ CDC_OUT_EP, // bEndpointAddress
+ 0x02, // bmAttributes: Bulk
+ LOBYTE(CDC_DATA_FS_MAX_PACKET_SIZE),// wMaxPacketSize:
+ HIBYTE(CDC_DATA_FS_MAX_PACKET_SIZE),
+ 0x00, // bInterval: ignore for Bulk transfer
+
+ // Endpoint IN Descriptor
+ 0x07, // bLength: Endpoint Descriptor size
+ USB_DESC_TYPE_ENDPOINT, // bDescriptorType: Endpoint
+ CDC_IN_EP, // bEndpointAddress
+ 0x02, // bmAttributes: Bulk
+ LOBYTE(CDC_DATA_FS_MAX_PACKET_SIZE),// wMaxPacketSize:
+ HIBYTE(CDC_DATA_FS_MAX_PACKET_SIZE),
+ 0x00, // bInterval: ignore for Bulk transfer
+};
+
+// USB CDC HID device Configuration Descriptor
+static const uint8_t cdc_hid_template_config_desc[CDC_HID_TEMPLATE_CONFIG_DESC_SIZE] = {
+ //--------------------------------------------------------------------------
+ // Configuration Descriptor
+ 0x09, // bLength: Configuration Descriptor size
+ USB_DESC_TYPE_CONFIGURATION, // bDescriptorType: Configuration
+ LOBYTE(CDC_HID_TEMPLATE_CONFIG_DESC_SIZE), // wTotalLength: no of returned bytes
+ HIBYTE(CDC_HID_TEMPLATE_CONFIG_DESC_SIZE),
+ 0x03, // bNumInterfaces: 3 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
+
+ //==========================================================================
+ // HID only has 1 interface so doesn't need an IAD
+
+ //--------------------------------------------------------------------------
+ // Interface Descriptor
+ 0x09, // bLength: Interface Descriptor size
+ USB_DESC_TYPE_INTERFACE, // bDescriptorType: interface descriptor
+ HID_IFACE_NUM_WITH_CDC, // bInterfaceNumber: Number of Interface
+ 0x00, // bAlternateSetting: Alternate setting
+ 0x02, // bNumEndpoints
+ 0x03, // bInterfaceClass: HID Class
+ 0x01, // bInterfaceSubClass: 0=no sub class, 1=boot
+ 0x02, // nInterfaceProtocol: 0=none, 1=keyboard, 2=mouse
+ 0x00, // iInterface:
+
+ // HID descriptor
+ 0x09, // bLength: HID Descriptor size
+ HID_DESCRIPTOR_TYPE, // bDescriptorType: HID
+ 0x11, // bcdHID: HID Class Spec release number
+ 0x01,
+ 0x00, // bCountryCode: Hardware target country
+ 0x01, // bNumDescriptors: Number of HID class descriptors to follow
+ 0x22, // bDescriptorType
+ USBD_HID_MOUSE_REPORT_DESC_SIZE, // wItemLength: Total length of Report descriptor
+ 0x00,
+
+ // Endpoint IN descriptor
+ 0x07, // bLength: Endpoint descriptor length
+ USB_DESC_TYPE_ENDPOINT, // bDescriptorType: Endpoint descriptor type
+ HID_IN_EP_WITH_CDC, // bEndpointAddress: IN
+ 0x03, // bmAttributes: Interrupt endpoint type
+ LOBYTE(USBD_HID_MOUSE_MAX_PACKET), // wMaxPacketSize
+ HIBYTE(USBD_HID_MOUSE_MAX_PACKET),
+ 0x08, // bInterval: Polling interval
+
+ // Endpoint OUT descriptor
+ 0x07, // bLength: Endpoint descriptor length
+ USB_DESC_TYPE_ENDPOINT, // bDescriptorType: Endpoint descriptor type
+ HID_OUT_EP_WITH_CDC, // bEndpointAddress: OUT
+ 0x03, // bmAttributes: Interrupt endpoint type
+ LOBYTE(USBD_HID_MOUSE_MAX_PACKET), // wMaxPacketSize
+ HIBYTE(USBD_HID_MOUSE_MAX_PACKET),
+ 0x08, // bInterval: Polling interval
+
+ //==========================================================================
+ // Interface Association for CDC VCP
+ 0x08, // bLength: 8 bytes
+ USB_DESC_TYPE_ASSOCIATION, // bDescriptorType: IAD
+ CDC_IFACE_NUM_WITH_HID, // bFirstInterface: first interface for this association
+ 0x02, // bInterfaceCount: nummber of interfaces for this association
+ 0x02, // bFunctionClass: Communication Interface Class
+ 0x02, // bFunctionSubClass: Abstract Control Model
+ 0x01, // bFunctionProtocol: Common AT commands
+ 0x00, // iFunction: index of string for this function
+
+ //--------------------------------------------------------------------------
+ // Interface Descriptor
+ 0x09, // bLength: Interface Descriptor size
+ USB_DESC_TYPE_INTERFACE, // bDescriptorType: Interface
+ CDC_IFACE_NUM_WITH_HID, // bInterfaceNumber: Number of Interface
+ 0x00, // bAlternateSetting: Alternate setting
+ 0x01, // bNumEndpoints: One endpoints used
+ 0x02, // bInterfaceClass: Communication Interface Class
+ 0x02, // bInterfaceSubClass: Abstract Control Model
+ 0x01, // bInterfaceProtocol: Common AT commands
+ 0x00, // iInterface:
+
+ // Header Functional Descriptor
+ 0x05, // bLength: Endpoint Descriptor size
+ 0x24, // bDescriptorType: CS_INTERFACE
+ 0x00, // bDescriptorSubtype: Header Func Desc
+ 0x10, // bcdCDC: spec release number
+ 0x01, // ?
+
+ // Call Management Functional Descriptor
+ 0x05, // bFunctionLength
+ 0x24, // bDescriptorType: CS_INTERFACE
+ 0x01, // bDescriptorSubtype: Call Management Func Desc
+ 0x00, // bmCapabilities: D0+D1
+ CDC_IFACE_NUM_WITH_HID + 1, // bDataInterface: 1
+
+ // ACM Functional Descriptor
+ 0x04, // bFunctionLength
+ 0x24, // bDescriptorType: CS_INTERFACE
+ 0x02, // bDescriptorSubtype: Abstract Control Management desc
+ 0x02, // bmCapabilities
+
+ // Union Functional Descriptor
+ 0x05, // bFunctionLength
+ 0x24, // bDescriptorType: CS_INTERFACE
+ 0x06, // bDescriptorSubtype: Union func desc
+ CDC_IFACE_NUM_WITH_HID + 0, // bMasterInterface: Communication class interface
+ CDC_IFACE_NUM_WITH_HID + 1, // bSlaveInterface0: Data Class Interface
+
+ // Endpoint 2 Descriptor
+ 0x07, // bLength: Endpoint Descriptor size
+ USB_DESC_TYPE_ENDPOINT, // bDescriptorType: Endpoint
+ CDC_CMD_EP, // bEndpointAddress
+ 0x03, // bmAttributes: Interrupt
+ LOBYTE(CDC_CMD_PACKET_SIZE), // wMaxPacketSize:
+ HIBYTE(CDC_CMD_PACKET_SIZE),
+ 0x20, // bInterval: polling interval in frames of 1ms
+
+ //--------------------------------------------------------------------------
+ // Data class interface descriptor
+ 0x09, // bLength: Endpoint Descriptor size
+ USB_DESC_TYPE_INTERFACE, // bDescriptorType: interface
+ CDC_IFACE_NUM_WITH_HID + 1, // bInterfaceNumber: Number of Interface
+ 0x00, // bAlternateSetting: Alternate setting
+ 0x02, // bNumEndpoints: Two endpoints used
+ 0x0A, // bInterfaceClass: CDC
+ 0x00, // bInterfaceSubClass: ?
+ 0x00, // bInterfaceProtocol: ?
+ 0x00, // iInterface:
+
+ // Endpoint OUT Descriptor
+ 0x07, // bLength: Endpoint Descriptor size
+ USB_DESC_TYPE_ENDPOINT, // bDescriptorType: Endpoint
+ CDC_OUT_EP, // bEndpointAddress
+ 0x02, // bmAttributes: Bulk
+ LOBYTE(CDC_DATA_FS_MAX_PACKET_SIZE),// wMaxPacketSize:
+ HIBYTE(CDC_DATA_FS_MAX_PACKET_SIZE),
+ 0x00, // bInterval: ignore for Bulk transfer
+
+ // Endpoint IN Descriptor
+ 0x07, // bLength: Endpoint Descriptor size
+ USB_DESC_TYPE_ENDPOINT, // bDescriptorType: Endpoint
+ CDC_IN_EP, // bEndpointAddress
+ 0x02, // bmAttributes: Bulk
+ LOBYTE(CDC_DATA_FS_MAX_PACKET_SIZE),// wMaxPacketSize:
+ HIBYTE(CDC_DATA_FS_MAX_PACKET_SIZE),
+ 0x00, // bInterval: ignore for Bulk transfer
+};
+
+static const uint8_t cdc_template_config_desc[CDC_TEMPLATE_CONFIG_DESC_SIZE] = {
+ //--------------------------------------------------------------------------
+ // Configuration Descriptor
+ 0x09, // bLength: Configuration Descriptor size
+ USB_DESC_TYPE_CONFIGURATION, // bDescriptorType: Configuration
+ LOBYTE(CDC_TEMPLATE_CONFIG_DESC_SIZE), // wTotalLength:no of returned bytes
+ HIBYTE(CDC_TEMPLATE_CONFIG_DESC_SIZE),
+ 0x02, // bNumInterfaces: 2 interface
+ 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
+
+ //--------------------------------------------------------------------------
+ // Interface Descriptor
+ 0x09, // bLength: Interface Descriptor size
+ USB_DESC_TYPE_INTERFACE, // bDescriptorType: Interface
+ CDC_IFACE_NUM_ALONE, // bInterfaceNumber: Number of Interface
+ 0x00, // bAlternateSetting: Alternate setting
+ 0x01, // bNumEndpoints: One endpoints used
+ 0x02, // bInterfaceClass: Communication Interface Class
+ 0x02, // bInterfaceSubClass: Abstract Control Model
+ 0x01, // bInterfaceProtocol: Common AT commands
+ 0x00, // iInterface:
+
+ // Header Functional Descriptor
+ 0x05, // bLength: Endpoint Descriptor size
+ 0x24, // bDescriptorType: CS_INTERFACE
+ 0x00, // bDescriptorSubtype: Header Func Desc
+ 0x10, // bcdCDC: spec release number
+ 0x01, // ?
+
+ // Call Management Functional Descriptor
+ 0x05, // bFunctionLength
+ 0x24, // bDescriptorType: CS_INTERFACE
+ 0x01, // bDescriptorSubtype: Call Management Func Desc
+ 0x00, // bmCapabilities: D0+D1
+ CDC_IFACE_NUM_ALONE + 1, // bDataInterface: 1
+
+ // ACM Functional Descriptor
+ 0x04, // bFunctionLength
+ 0x24, // bDescriptorType: CS_INTERFACE
+ 0x02, // bDescriptorSubtype: Abstract Control Management desc
+ 0x02, // bmCapabilities
+
+ // Union Functional Descriptor
+ 0x05, // bFunctionLength
+ 0x24, // bDescriptorType: CS_INTERFACE
+ 0x06, // bDescriptorSubtype: Union func desc
+ CDC_IFACE_NUM_ALONE + 0, // bMasterInterface: Communication class interface
+ CDC_IFACE_NUM_ALONE + 1, // bSlaveInterface0: Data Class Interface
+
+ // Endpoint 2 Descriptor
+ 0x07, // bLength: Endpoint Descriptor size
+ USB_DESC_TYPE_ENDPOINT, // bDescriptorType: Endpoint
+ CDC_CMD_EP, // bEndpointAddress
+ 0x03, // bmAttributes: Interrupt
+ LOBYTE(CDC_CMD_PACKET_SIZE), // wMaxPacketSize:
+ HIBYTE(CDC_CMD_PACKET_SIZE),
+ 0x20, // bInterval: polling interval in frames of 1ms
+
+ //--------------------------------------------------------------------------
+ // Data class interface descriptor
+ 0x09, // bLength: Endpoint Descriptor size
+ USB_DESC_TYPE_INTERFACE, // bDescriptorType:
+ CDC_IFACE_NUM_ALONE + 1, // bInterfaceNumber: Number of Interface
+ 0x00, // bAlternateSetting: Alternate setting
+ 0x02, // bNumEndpoints: Two endpoints used
+ 0x0a, // bInterfaceClass: CDC
+ 0x00, // bInterfaceSubClass: ?
+ 0x00, // bInterfaceProtocol: ?
+ 0x00, // iInterface:
+
+ // Endpoint OUT Descriptor
+ 0x07, // bLength: Endpoint Descriptor size
+ USB_DESC_TYPE_ENDPOINT, // bDescriptorType: Endpoint
+ CDC_OUT_EP, // bEndpointAddress
+ 0x02, // bmAttributes: Bulk
+ LOBYTE(CDC_DATA_FS_MAX_PACKET_SIZE),// wMaxPacketSize:
+ HIBYTE(CDC_DATA_FS_MAX_PACKET_SIZE),
+ 0x00, // bInterval: ignore for Bulk transfer
+
+ // Endpoint IN Descriptor
+ 0x07, // bLength: Endpoint Descriptor size
+ USB_DESC_TYPE_ENDPOINT, // bDescriptorType: Endpoint
+ CDC_IN_EP, // bEndpointAddress
+ 0x02, // bmAttributes: Bulk
+ LOBYTE(CDC_DATA_FS_MAX_PACKET_SIZE),// wMaxPacketSize:
+ HIBYTE(CDC_DATA_FS_MAX_PACKET_SIZE),
+ 0x00 // bInterval: ignore for Bulk transfer
+};
+
+__ALIGN_BEGIN const uint8_t USBD_HID_MOUSE_ReportDesc[USBD_HID_MOUSE_REPORT_DESC_SIZE] __ALIGN_END = {
+ 0x05, 0x01, // Usage Page (Generic Desktop),
+ 0x09, 0x02, // Usage (Mouse),
+ 0xA1, 0x01, // Collection (Application),
+ 0x09, 0x01, // Usage (Pointer),
+ 0xA1, 0x00, // Collection (Physical),
+ 0x05, 0x09, // Usage Page (Buttons),
+ 0x19, 0x01, // Usage Minimum (01),
+ 0x29, 0x03, // Usage Maximum (03),
+ 0x15, 0x00, // Logical Minimum (0),
+ 0x25, 0x01, // Logical Maximum (1),
+ 0x95, 0x03, // Report Count (3),
+ 0x75, 0x01, // Report Size (1),
+ 0x81, 0x02, // Input(Data, Variable, Absolute), -- 3 button bits
+ 0x95, 0x01, // Report Count(1),
+ 0x75, 0x05, // Report Size(5),
+ 0x81, 0x01, // Input(Constant), -- 5 bit padding
+ 0x05, 0x01, // Usage Page (Generic Desktop),
+ 0x09, 0x30, // Usage (X),
+ 0x09, 0x31, // Usage (Y),
+ 0x09, 0x38, // Usage (Wheel),
+ 0x15, 0x81, // Logical Minimum (-127),
+ 0x25, 0x7F, // Logical Maximum (127),
+ 0x75, 0x08, // Report Size (8),
+ 0x95, 0x03, // Report Count (3),
+ 0x81, 0x06, // Input(Data, Variable, Relative), -- 3 position bytes (X,Y,Wheel)
+ 0xC0, // End Collection,
+ 0x09, 0x3c, // Usage (Motion Wakeup),
+ 0x05, 0xff, // Usage Page (?),
+ 0x09, 0x01, // Usage (?),
+ 0x15, 0x00, // Logical Minimum (0),
+ 0x25, 0x01, // Logical Maximum (1),
+ 0x75, 0x01, // Report Size(1),
+ 0x95, 0x02, // Report Count(2),
+ 0xb1, 0x22, // ?
+ 0x75, 0x06, // Report Size(6),
+ 0x95, 0x01, // Report Count(1),
+ 0xb1, 0x01, // ?
+ 0xc0 // End Collection
+};
+
+__ALIGN_BEGIN const uint8_t USBD_HID_KEYBOARD_ReportDesc[USBD_HID_KEYBOARD_REPORT_DESC_SIZE] __ALIGN_END = {
+ // From p69 of http://www.usb.org/developers/devclass_docs/HID1_11.pdf
+ 0x05, 0x01, // Usage Page (Generic Desktop),
+ 0x09, 0x06, // Usage (Keyboard),
+ 0xA1, 0x01, // Collection (Application),
+ 0x05, 0x07, // Usage Page (Key Codes);
+ 0x19, 0xE0, // Usage Minimum (224),
+ 0x29, 0xE7, // Usage Maximum (231),
+ 0x15, 0x00, // Logical Minimum (0),
+ 0x25, 0x01, // Logical Maximum (1),
+ 0x75, 0x01, // Report Size (1),
+ 0x95, 0x08, // Report Count (8),
+ 0x81, 0x02, // Input (Data, Variable, Absolute), ;Modifier byte
+ 0x95, 0x01, // Report Count (1),
+ 0x75, 0x08, // Report Size (8),
+ 0x81, 0x01, // Input (Constant), ;Reserved byte
+ 0x95, 0x05, // Report Count (5),
+ 0x75, 0x01, // Report Size (1),
+ 0x05, 0x08, // Usage Page (Page# for LEDs),
+ 0x19, 0x01, // Usage Minimum (1),
+ 0x29, 0x05, // Usage Maximum (5),
+ 0x91, 0x02, // Output (Data, Variable, Absolute), ;LED report
+ 0x95, 0x01, // Report Count (1),
+ 0x75, 0x03, // Report Size (3),
+ 0x91, 0x01, // Output (Constant), ;LED report padding
+ 0x95, 0x06, // Report Count (6),
+ 0x75, 0x08, // Report Size (8),
+ 0x15, 0x00, // Logical Minimum (0),
+ 0x25, 0x65, // Logical Maximum(101),
+ 0x05, 0x07, // Usage Page (Key Codes),
+ 0x19, 0x00, // Usage Minimum (0),
+ 0x29, 0x65, // Usage Maximum (101),
+ 0x81, 0x00, // Input (Data, Array), ;Key arrays (6 bytes)
+ 0xC0 // End Collection
+};
+
+// return the saved usb mode
+uint8_t USBD_GetMode() {
+ return usbd_mode;
+}
+
+int USBD_SelectMode(uint32_t mode, USBD_HID_ModeInfoTypeDef *hid_info) {
+ // save mode
+ usbd_mode = mode;
+
+ // construct config desc
+ switch (usbd_mode) {
+ case USBD_MODE_CDC_MSC:
+ usbd_config_desc_size = sizeof(cdc_msc_template_config_desc);
+ memcpy(usbd_config_desc, cdc_msc_template_config_desc, sizeof(cdc_msc_template_config_desc));
+ cdc_iface_num = CDC_IFACE_NUM_WITH_MSC;
+ break;
+
+ case USBD_MODE_CDC_HID:
+ usbd_config_desc_size = sizeof(cdc_hid_template_config_desc);
+ memcpy(usbd_config_desc, cdc_hid_template_config_desc, sizeof(cdc_hid_template_config_desc));
+ cdc_iface_num = CDC_IFACE_NUM_WITH_HID;
+ hid_in_ep = HID_IN_EP_WITH_CDC;
+ hid_out_ep = HID_OUT_EP_WITH_CDC;
+ hid_iface_num = HID_IFACE_NUM_WITH_CDC;
+ hid_desc = usbd_config_desc + CDC_HID_TEMPLATE_HID_DESC_OFFSET;
+ break;
+
+ case USBD_MODE_CDC:
+ usbd_config_desc_size = sizeof(cdc_template_config_desc);
+ memcpy(usbd_config_desc, cdc_template_config_desc, sizeof(cdc_template_config_desc));
+ cdc_iface_num = CDC_IFACE_NUM_ALONE;
+ break;
+
+ /*
+ // not implemented
+ case USBD_MODE_MSC_HID:
+ hid_in_ep = HID_IN_EP_WITH_MSC;
+ hid_out_ep = HID_OUT_EP_WITH_MSC;
+ hid_iface_num = HID_IFACE_NUM_WITH_MSC;
+ break;
+ */
+
+ default:
+ // mode not supported
+ return -1;
+ }
+
+ // configure the HID descriptor, if needed
+ if (usbd_mode & USBD_MODE_HID) {
+ 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;
+ hid_desc[HID_DESC_OFFSET_MAX_PACKET_LO] = hid_info->max_packet_len;
+ hid_desc[HID_DESC_OFFSET_MAX_PACKET_HI] = 0;
+ hid_desc[HID_DESC_OFFSET_POLLING_INTERVAL] = hid_info->polling_interval;
+ 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;
+ hid_report_desc = hid_info->report_desc;
+ }
+
+ return 0;
+}
+
+static uint8_t USBD_CDC_MSC_HID_Init(USBD_HandleTypeDef *pdev, uint8_t cfgidx) {
+ if (pdev->dev_speed == USBD_SPEED_HIGH) {
+ // can't handle high speed
+ return 1;
+ }
+
+ if (usbd_mode & USBD_MODE_CDC) {
+ // CDC VCP component
+
+ // 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
+ CDC_fops->Init(pdev);
+
+ // Init Xfer states
+ CDC_ClassData.TxState =0;
+ CDC_ClassData.RxState =0;
+
+ // Prepare Out endpoint to receive next packet
+ USBD_LL_PrepareReceive(pdev, CDC_OUT_EP, CDC_ClassData.RxBuffer, CDC_DATA_OUT_PACKET_SIZE);
+ }
+
+ if (usbd_mode & USBD_MODE_MSC) {
+ // MSC component
+
+ // Open EP OUT
+ USBD_LL_OpenEP(pdev,
+ MSC_OUT_EP,
+ USBD_EP_TYPE_BULK,
+ MSC_MAX_PACKET);
+
+ // Open EP IN
+ USBD_LL_OpenEP(pdev,
+ MSC_IN_EP,
+ USBD_EP_TYPE_BULK,
+ MSC_MAX_PACKET);
+
+ // MSC uses the pClassData pointer because SCSI and BOT reference it
+ pdev->pClassData = &MSC_BOT_ClassData;
+
+ // Init the BOT layer
+ MSC_BOT_Init(pdev);
+ }
+
+ if (usbd_mode & USBD_MODE_HID) {
+ // HID component
+
+ // get max packet lengths from descriptor
+ uint16_t mps_in =
+ hid_desc[HID_DESC_OFFSET_MAX_PACKET_LO]
+ | (hid_desc[HID_DESC_OFFSET_MAX_PACKET_HI] << 8);
+ uint16_t mps_out =
+ hid_desc[HID_DESC_OFFSET_MAX_PACKET_OUT_LO]
+ | (hid_desc[HID_DESC_OFFSET_MAX_PACKET_OUT_HI] << 8);
+
+ // Open EP IN
+ USBD_LL_OpenEP(pdev,
+ hid_in_ep,
+ USBD_EP_TYPE_INTR,
+ mps_in);
+
+ // Open EP OUT
+ USBD_LL_OpenEP(pdev,
+ hid_out_ep,
+ USBD_EP_TYPE_INTR,
+ mps_out);
+
+ HID_fops->Init(pdev);
+
+ // Prepare Out endpoint to receive next packet
+ USBD_LL_PrepareReceive(pdev, hid_out_ep, HID_ClassData.RxBuffer, mps_out);
+
+ HID_ClassData.state = HID_IDLE;
+ }
+
+ return 0;
+}
+
+static uint8_t USBD_CDC_MSC_HID_DeInit(USBD_HandleTypeDef *pdev, uint8_t cfgidx) {
+ if (usbd_mode & USBD_MODE_CDC) {
+ // CDC VCP component
+
+ // close endpoints
+ USBD_LL_CloseEP(pdev, CDC_IN_EP);
+ USBD_LL_CloseEP(pdev, CDC_OUT_EP);
+ USBD_LL_CloseEP(pdev, CDC_CMD_EP);
+
+ // DeInit physical Interface components
+ CDC_fops->DeInit();
+ }
+
+ if (usbd_mode & USBD_MODE_MSC) {
+ // MSC component
+
+ // close endpoints
+ USBD_LL_CloseEP(pdev, MSC_OUT_EP);
+ USBD_LL_CloseEP(pdev, MSC_IN_EP);
+
+ // DeInit the BOT layer
+ MSC_BOT_DeInit(pdev);
+
+ // clear the pointer
+ pdev->pClassData = NULL;
+ }
+
+ if (usbd_mode & USBD_MODE_HID) {
+ // HID component
+
+ // close endpoints
+ USBD_LL_CloseEP(pdev, hid_in_ep);
+ USBD_LL_CloseEP(pdev, hid_out_ep);
+ }
+
+ return 0;
+}
+
+static uint8_t USBD_CDC_MSC_HID_Setup(USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req) {
+
+ /*
+ printf("SU: %x %x %x %x\n", req->bmRequest, req->bRequest, req->wValue, req->wIndex);
+
+ This is what we get when MSC is IFACE=0 and CDC is IFACE=1,2:
+ SU: 21 22 0 1 -- USB_REQ_TYPE_CLASS | USB_REQ_RECIPIENT_INTERFACE; CDC_SET_CONTROL_LINE_STATE
+ SU: 21 20 0 1 -- USB_REQ_TYPE_CLASS | USB_REQ_RECIPIENT_INTERFACE; CDC_SET_LINE_CODING
+ SU: a1 fe 0 0 -- 0x80 | USB_REQ_TYPE_CLASS | USB_REQ_RECIPIENT_INTERFACE; BOT_GET_MAX_LUN; 0; 0
+ SU: 21 22 3 1 -- USB_REQ_TYPE_CLASS | USB_REQ_RECIPIENT_INTERFACE; CDC_SET_CONTROL_LINE_STATE
+
+ On a Mac OS X, with MSC then CDC:
+ SU: a1 fe 0 0
+ SU: 21 22 2 1
+ SU: 21 22 3 1
+ SU: 21 20 0 1
+ */
+
+ switch (req->bmRequest & USB_REQ_TYPE_MASK) {
+
+ // Class request
+ case USB_REQ_TYPE_CLASS:
+ // req->wIndex is the recipient interface number
+ if ((usbd_mode & USBD_MODE_CDC) && req->wIndex == cdc_iface_num) {
+ // CDC component
+ if (req->wLength) {
+ if (req->bmRequest & 0x80) {
+ // device-to-host request
+ CDC_fops->Control(req->bRequest, (uint8_t*)CDC_ClassData.data, req->wLength);
+ USBD_CtlSendData(pdev, (uint8_t*)CDC_ClassData.data, req->wLength);
+ } else {
+ // host-to-device request
+ CDC_ClassData.CmdOpCode = req->bRequest;
+ CDC_ClassData.CmdLength = req->wLength;
+ USBD_CtlPrepareRx(pdev, (uint8_t*)CDC_ClassData.data, req->wLength);
+ }
+ } else {
+ // Not a Data request
+ // Transfer the command to the interface layer
+ return CDC_fops->Control(req->bRequest, NULL, req->wValue);
+ }
+ } else if ((usbd_mode & USBD_MODE_MSC) && req->wIndex == MSC_IFACE_NUM_WITH_CDC) {
+ // MSC component
+ switch (req->bRequest) {
+ case BOT_GET_MAX_LUN:
+ if ((req->wValue == 0) && (req->wLength == 1) && ((req->bmRequest & 0x80) == 0x80)) {
+ MSC_BOT_ClassData.max_lun = MSC_fops->GetMaxLun();
+ USBD_CtlSendData(pdev, (uint8_t *)&MSC_BOT_ClassData.max_lun, 1);
+ } else {
+ USBD_CtlError(pdev, req);
+ return USBD_FAIL;
+ }
+ break;
+
+ case BOT_RESET:
+ if ((req->wValue == 0) && (req->wLength == 0) && ((req->bmRequest & 0x80) != 0x80)) {
+ MSC_BOT_Reset(pdev);
+ } else {
+ USBD_CtlError(pdev, req);
+ return USBD_FAIL;
+ }
+ break;
+
+ default:
+ USBD_CtlError(pdev, req);
+ return USBD_FAIL;
+ }
+ } else if ((usbd_mode & USBD_MODE_HID) && req->wIndex == hid_iface_num) {
+ switch (req->bRequest) {
+ case HID_REQ_SET_PROTOCOL:
+ HID_ClassData.Protocol = (uint8_t)(req->wValue);
+ break;
+
+ case HID_REQ_GET_PROTOCOL:
+ USBD_CtlSendData (pdev, (uint8_t *)&HID_ClassData.Protocol, 1);
+ break;
+
+ case HID_REQ_SET_IDLE:
+ HID_ClassData.IdleState = (uint8_t)(req->wValue >> 8);
+ break;
+
+ case HID_REQ_GET_IDLE:
+ USBD_CtlSendData (pdev, (uint8_t *)&HID_ClassData.IdleState, 1);
+ break;
+
+ default:
+ USBD_CtlError(pdev, req);
+ return USBD_FAIL;
+ }
+ }
+ break;
+
+ // Interface & Endpoint request
+ case USB_REQ_TYPE_STANDARD:
+ if ((usbd_mode & USBD_MODE_MSC) && req->wIndex == MSC_IFACE_NUM_WITH_CDC) {
+ switch (req->bRequest) {
+ case USB_REQ_GET_INTERFACE :
+ USBD_CtlSendData(pdev, (uint8_t *)&MSC_BOT_ClassData.interface, 1);
+ break;
+
+ case USB_REQ_SET_INTERFACE :
+ MSC_BOT_ClassData.interface = (uint8_t)(req->wValue);
+ break;
+
+ case USB_REQ_CLEAR_FEATURE:
+ // Flush the FIFO and Clear the stall status
+ USBD_LL_FlushEP(pdev, (uint8_t)req->wIndex);
+
+ // Re-activate the EP
+ 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);
+ } else {
+ // Open EP OUT
+ USBD_LL_OpenEP(pdev, MSC_OUT_EP, USBD_EP_TYPE_BULK, MSC_MAX_PACKET);
+ }
+ // Handle BOT error
+ MSC_BOT_CplClrFeature(pdev, (uint8_t)req->wIndex);
+ break;
+ }
+ } else if ((usbd_mode & USBD_MODE_HID) && req->wIndex == hid_iface_num) {
+ 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 = hid_desc[HID_DESC_OFFSET_REPORT_DESC_LEN];
+ len = MIN(len, req->wLength);
+ pbuf = hid_report_desc;
+ } else if (req->wValue >> 8 == HID_DESCRIPTOR_TYPE) {
+ len = MIN(HID_SUBDESC_LEN, req->wLength);
+ pbuf = hid_desc + HID_DESC_OFFSET_SUBDESC;
+ }
+ USBD_CtlSendData(pdev, (uint8_t*)pbuf, len);
+ break;
+ }
+
+ case USB_REQ_GET_INTERFACE:
+ USBD_CtlSendData (pdev, (uint8_t *)&HID_ClassData.AltSetting, 1);
+ break;
+
+ case USB_REQ_SET_INTERFACE:
+ HID_ClassData.AltSetting = (uint8_t)(req->wValue);
+ break;
+ }
+ }
+ break;
+ }
+ return USBD_OK;
+}
+
+/* unused
+static uint8_t EP0_TxSent(USBD_HandleTypeDef *pdev) {
+}
+*/
+
+static uint8_t USBD_CDC_MSC_HID_EP0_RxReady(USBD_HandleTypeDef *pdev) {
+ if ((CDC_fops != NULL) && (CDC_ClassData.CmdOpCode != 0xff)) {
+ CDC_fops->Control(CDC_ClassData.CmdOpCode, (uint8_t*)CDC_ClassData.data, CDC_ClassData.CmdLength);
+ CDC_ClassData.CmdOpCode = 0xff;
+ }
+
+ return USBD_OK;
+}
+
+static uint8_t USBD_CDC_MSC_HID_DataIn(USBD_HandleTypeDef *pdev, uint8_t epnum) {
+ if ((usbd_mode & USBD_MODE_CDC) && (epnum == (CDC_IN_EP & 0x7f) || epnum == (CDC_CMD_EP & 0x7f))) {
+ CDC_ClassData.TxState = 0;
+ return USBD_OK;
+ } else if ((usbd_mode & USBD_MODE_MSC) && epnum == (MSC_IN_EP & 0x7f)) {
+ MSC_BOT_DataIn(pdev, epnum);
+ return USBD_OK;
+ } else if ((usbd_mode & USBD_MODE_HID) && epnum == (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 */
+ HID_ClassData.state = HID_IDLE;
+ return USBD_OK;
+ }
+
+ return USBD_OK;
+}
+
+static uint8_t USBD_CDC_MSC_HID_DataOut(USBD_HandleTypeDef *pdev, uint8_t epnum) {
+ if ((usbd_mode & USBD_MODE_CDC) && epnum == (CDC_OUT_EP & 0x7f)) {
+ /* Get the received data length */
+ CDC_ClassData.RxLength = USBD_LL_GetRxDataSize (pdev, epnum);
+
+ /* USB data will be immediately processed, this allow next USB traffic being
+ NAKed till the end of the application Xfer */
+ CDC_fops->Receive(pdev, CDC_ClassData.RxBuffer, &CDC_ClassData.RxLength);
+
+ return USBD_OK;
+ } else if ((usbd_mode & USBD_MODE_MSC) && epnum == (MSC_OUT_EP & 0x7f)) {
+ MSC_BOT_DataOut(pdev, epnum);
+ return USBD_OK;
+ } else if ((usbd_mode & USBD_MODE_HID) && epnum == (hid_out_ep & 0x7f)) {
+ HID_ClassData.RxLength = USBD_LL_GetRxDataSize(pdev, epnum);
+ HID_fops->Receive(pdev, HID_ClassData.RxBuffer, HID_ClassData.RxLength);
+ }
+
+ return USBD_OK;
+}
+
+static uint8_t *USBD_CDC_MSC_HID_GetCfgDesc(uint16_t *length) {
+ *length = usbd_config_desc_size;
+ return usbd_config_desc;
+}
+
+// this is used only in high-speed mode, which we don't support
+uint8_t *USBD_CDC_MSC_HID_GetDeviceQualifierDescriptor (uint16_t *length) {
+ /*
+ *length = sizeof(USBD_CDC_MSC_HID_DeviceQualifierDesc);
+ return USBD_CDC_MSC_HID_DeviceQualifierDesc;
+ */
+ *length = 0;
+ return NULL;
+}
+
+uint8_t USBD_CDC_RegisterInterface(USBD_HandleTypeDef *pdev, USBD_CDC_ItfTypeDef *fops) {
+ if (fops == NULL) {
+ return USBD_FAIL;
+ } else {
+ CDC_fops = fops;
+ return USBD_OK;
+ }
+}
+
+uint8_t USBD_CDC_SetTxBuffer(USBD_HandleTypeDef *pdev, uint8_t *pbuff, uint16_t length) {
+ CDC_ClassData.TxBuffer = pbuff;
+ CDC_ClassData.TxLength = length;
+ return USBD_OK;
+}
+
+uint8_t USBD_CDC_SetRxBuffer(USBD_HandleTypeDef *pdev, uint8_t *pbuff) {
+ CDC_ClassData.RxBuffer = pbuff;
+ return USBD_OK;
+}
+
+// data received on non-control OUT endpoint
+uint8_t USBD_CDC_TransmitPacket(USBD_HandleTypeDef *pdev) {
+ if (CDC_ClassData.TxState == 0) {
+ // transmit next packet
+ USBD_LL_Transmit(pdev, CDC_IN_EP, CDC_ClassData.TxBuffer, CDC_ClassData.TxLength);
+
+ // Tx transfer in progress
+ CDC_ClassData.TxState = 1;
+ return USBD_OK;
+ } else {
+ return USBD_BUSY;
+ }
+}
+
+// prepare OUT endpoint for reception
+uint8_t USBD_CDC_ReceivePacket(USBD_HandleTypeDef *pdev) {
+ // Suspend or Resume USB Out process
+ if (pdev->dev_speed == USBD_SPEED_HIGH) {
+ return USBD_FAIL;
+ }
+
+ // Prepare Out endpoint to receive next packet
+ USBD_LL_PrepareReceive(pdev, CDC_OUT_EP, CDC_ClassData.RxBuffer, CDC_DATA_OUT_PACKET_SIZE);
+
+ return USBD_OK;
+}
+
+uint8_t USBD_MSC_RegisterStorage(USBD_HandleTypeDef *pdev, USBD_StorageTypeDef *fops) {
+ if (fops == NULL) {
+ return USBD_FAIL;
+ } else {
+ MSC_fops = fops;
+ pdev->pUserData = fops; // MSC uses pUserData because SCSI and BOT reference it
+ return USBD_OK;
+ }
+}
+
+uint8_t USBD_HID_RegisterInterface(USBD_HandleTypeDef *pdev, USBD_HID_ItfTypeDef *fops) {
+ if (fops == NULL) {
+ return USBD_FAIL;
+ } else {
+ HID_fops = fops;
+ return USBD_OK;
+ }
+}
+
+uint8_t USBD_HID_SetRxBuffer(USBD_HandleTypeDef *pdev, uint8_t *pbuff) {
+ HID_ClassData.RxBuffer = pbuff;
+ return USBD_OK;
+}
+
+// prepare OUT endpoint for reception
+uint8_t USBD_HID_ReceivePacket(USBD_HandleTypeDef *pdev) {
+ // Suspend or Resume USB Out process
+ if (pdev->dev_speed == USBD_SPEED_HIGH) {
+ return USBD_FAIL;
+ }
+
+ // Prepare Out endpoint to receive next packet
+ uint16_t mps_out =
+ hid_desc[HID_DESC_OFFSET_MAX_PACKET_OUT_LO]
+ | (hid_desc[HID_DESC_OFFSET_MAX_PACKET_OUT_HI] << 8);
+ USBD_LL_PrepareReceive(pdev, hid_out_ep, HID_ClassData.RxBuffer, mps_out);
+
+ return USBD_OK;
+}
+
+int USBD_HID_CanSendReport(USBD_HandleTypeDef *pdev) {
+ return pdev->dev_state == USBD_STATE_CONFIGURED && HID_ClassData.state == HID_IDLE;
+}
+
+uint8_t USBD_HID_SendReport(USBD_HandleTypeDef *pdev, uint8_t *report, uint16_t len) {
+ if (pdev->dev_state == USBD_STATE_CONFIGURED) {
+ if (HID_ClassData.state == HID_IDLE) {
+ HID_ClassData.state = HID_BUSY;
+ USBD_LL_Transmit(pdev, hid_in_ep, report, len);
+ }
+ }
+ return USBD_OK;
+}
+
+uint8_t USBD_HID_SetNAK(USBD_HandleTypeDef *pdev) {
+ // get USBx object from pdev (needed for USBx_OUTEP macro below)
+ PCD_HandleTypeDef *hpcd = 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_HandleTypeDef *pdev) {
+ // get USBx object from pdev (needed for USBx_OUTEP macro below)
+ PCD_HandleTypeDef *hpcd = 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;
+ return USBD_OK;
+}
+
+// CDC/MSC/HID interface class callback structure
+USBD_ClassTypeDef USBD_CDC_MSC_HID = {
+ USBD_CDC_MSC_HID_Init,
+ USBD_CDC_MSC_HID_DeInit,
+ USBD_CDC_MSC_HID_Setup,
+ NULL, // EP0_TxSent
+ USBD_CDC_MSC_HID_EP0_RxReady,
+ USBD_CDC_MSC_HID_DataIn,
+ USBD_CDC_MSC_HID_DataOut,
+ NULL, // SOF
+ NULL, // IsoINIncomplete
+ NULL, // IsoOUTIncomplete
+ USBD_CDC_MSC_HID_GetCfgDesc,
+ USBD_CDC_MSC_HID_GetCfgDesc,
+ USBD_CDC_MSC_HID_GetCfgDesc,
+ USBD_CDC_MSC_HID_GetDeviceQualifierDescriptor,
+};
diff --git a/ports/stm32/usbdev/class/src/usbd_msc.c b/ports/stm32/usbdev/class/src/usbd_msc.c
new file mode 100644
index 000000000..7817c98b1
--- /dev/null
+++ b/ports/stm32/usbdev/class/src/usbd_msc.c
@@ -0,0 +1,609 @@
+/**
+ ******************************************************************************
+ * @file usbd_msc_core.c
+ * @author MCD Application Team
+ * @version V2.0.0
+ * @date 18-February-2014
+ * @brief This file provides all the MSC core functions.
+ *
+ * @verbatim
+ *
+ * ===================================================================
+ * MSC Class Description
+ * ===================================================================
+ * This module manages the MSC class V1.0 following the "Universal
+ * Serial Bus Mass Storage Class (MSC) Bulk-Only Transport (BOT) Version 1.0
+ * Sep. 31, 1999".
+ * This driver implements the following aspects of the specification:
+ * - Bulk-Only Transport protocol
+ * - Subclass : SCSI transparent command set (ref. SCSI Primary Commands - 3 (SPC-3))
+ *
+ * @endverbatim
+ *
+ ******************************************************************************
+ * @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.h"
+
+
+/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY
+ * @{
+ */
+
+
+/** @defgroup MSC_CORE
+ * @brief Mass storage core module
+ * @{
+ */
+
+/** @defgroup MSC_CORE_Private_TypesDefinitions
+ * @{
+ */
+/**
+ * @}
+ */
+
+
+/** @defgroup MSC_CORE_Private_Defines
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+
+/** @defgroup MSC_CORE_Private_Macros
+ * @{
+ */
+/**
+ * @}
+ */
+
+
+/** @defgroup MSC_CORE_Private_FunctionPrototypes
+ * @{
+ */
+uint8_t USBD_MSC_Init (USBD_HandleTypeDef *pdev,
+ uint8_t cfgidx);
+
+uint8_t USBD_MSC_DeInit (USBD_HandleTypeDef *pdev,
+ uint8_t cfgidx);
+
+uint8_t USBD_MSC_Setup (USBD_HandleTypeDef *pdev,
+ USBD_SetupReqTypedef *req);
+
+uint8_t USBD_MSC_DataIn (USBD_HandleTypeDef *pdev,
+ uint8_t epnum);
+
+
+uint8_t USBD_MSC_DataOut (USBD_HandleTypeDef *pdev,
+ uint8_t epnum);
+
+uint8_t *USBD_MSC_GetHSCfgDesc (uint16_t *length);
+
+uint8_t *USBD_MSC_GetFSCfgDesc (uint16_t *length);
+
+uint8_t *USBD_MSC_GetOtherSpeedCfgDesc (uint16_t *length);
+
+uint8_t *USBD_MSC_GetDeviceQualifierDescriptor (uint16_t *length);
+
+
+/**
+ * @}
+ */
+
+
+/** @defgroup MSC_CORE_Private_Variables
+ * @{
+ */
+
+
+USBD_ClassTypeDef USBD_MSC =
+{
+ USBD_MSC_Init,
+ USBD_MSC_DeInit,
+ USBD_MSC_Setup,
+ NULL, /*EP0_TxSent*/
+ NULL, /*EP0_RxReady*/
+ USBD_MSC_DataIn,
+ USBD_MSC_DataOut,
+ NULL, /*SOF */
+ NULL,
+ NULL,
+ USBD_MSC_GetHSCfgDesc,
+ USBD_MSC_GetFSCfgDesc,
+ USBD_MSC_GetOtherSpeedCfgDesc,
+ USBD_MSC_GetDeviceQualifierDescriptor,
+};
+
+/* USB Mass storage device Configuration Descriptor */
+/* All Descriptors (Configuration, Interface, Endpoint, Class, Vendor */
+__ALIGN_BEGIN uint8_t USBD_MSC_CfgHSDesc[USB_MSC_CONFIG_DESC_SIZ] __ALIGN_END =
+{
+
+ 0x09, /* bLength: Configuation Descriptor size */
+ USB_DESC_TYPE_CONFIGURATION, /* bDescriptorType: Configuration */
+ USB_MSC_CONFIG_DESC_SIZ,
+
+ 0x00,
+ 0x01, /* bNumInterfaces: 1 interface */
+ 0x01, /* bConfigurationValue: */
+ 0x04, /* iConfiguration: */
+ 0xC0, /* bmAttributes: */
+ 0x32, /* MaxPower 100 mA */
+
+ /******************** Mass Storage interface ********************/
+ 0x09, /* bLength: Interface Descriptor size */
+ 0x04, /* bDescriptorType: */
+ 0x00, /* bInterfaceNumber: Number of Interface */
+ 0x00, /* bAlternateSetting: Alternate setting */
+ 0x02, /* bNumEndpoints*/
+ 0x08, /* bInterfaceClass: MSC Class */
+ 0x06, /* bInterfaceSubClass : SCSI transparent*/
+ 0x50, /* nInterfaceProtocol */
+ 0x05, /* iInterface: */
+ /******************** Mass Storage Endpoints ********************/
+ 0x07, /*Endpoint descriptor length = 7*/
+ 0x05, /*Endpoint descriptor type */
+ MSC_EPIN_ADDR, /*Endpoint address (IN, address 1) */
+ 0x02, /*Bulk endpoint type */
+ LOBYTE(MSC_MAX_HS_PACKET),
+ HIBYTE(MSC_MAX_HS_PACKET),
+ 0x00, /*Polling interval in milliseconds */
+
+ 0x07, /*Endpoint descriptor length = 7 */
+ 0x05, /*Endpoint descriptor type */
+ MSC_EPOUT_ADDR, /*Endpoint address (OUT, address 1) */
+ 0x02, /*Bulk endpoint type */
+ LOBYTE(MSC_MAX_HS_PACKET),
+ HIBYTE(MSC_MAX_HS_PACKET),
+ 0x00 /*Polling interval in milliseconds*/
+};
+
+/* USB Mass storage device Configuration Descriptor */
+/* All Descriptors (Configuration, Interface, Endpoint, Class, Vendor */
+uint8_t USBD_MSC_CfgFSDesc[USB_MSC_CONFIG_DESC_SIZ] __ALIGN_END =
+{
+
+ 0x09, /* bLength: Configuation Descriptor size */
+ USB_DESC_TYPE_CONFIGURATION, /* bDescriptorType: Configuration */
+ USB_MSC_CONFIG_DESC_SIZ,
+
+ 0x00,
+ 0x01, /* bNumInterfaces: 1 interface */
+ 0x01, /* bConfigurationValue: */
+ 0x04, /* iConfiguration: */
+ 0xC0, /* bmAttributes: */
+ 0x32, /* MaxPower 100 mA */
+
+ /******************** Mass Storage interface ********************/
+ 0x09, /* bLength: Interface Descriptor size */
+ 0x04, /* bDescriptorType: */
+ 0x00, /* bInterfaceNumber: Number of Interface */
+ 0x00, /* bAlternateSetting: Alternate setting */
+ 0x02, /* bNumEndpoints*/
+ 0x08, /* bInterfaceClass: MSC Class */
+ 0x06, /* bInterfaceSubClass : SCSI transparent*/
+ 0x50, /* nInterfaceProtocol */
+ 0x05, /* iInterface: */
+ /******************** Mass Storage Endpoints ********************/
+ 0x07, /*Endpoint descriptor length = 7*/
+ 0x05, /*Endpoint descriptor type */
+ MSC_EPIN_ADDR, /*Endpoint address (IN, address 1) */
+ 0x02, /*Bulk endpoint type */
+ LOBYTE(MSC_MAX_FS_PACKET),
+ HIBYTE(MSC_MAX_FS_PACKET),
+ 0x00, /*Polling interval in milliseconds */
+
+ 0x07, /*Endpoint descriptor length = 7 */
+ 0x05, /*Endpoint descriptor type */
+ MSC_EPOUT_ADDR, /*Endpoint address (OUT, address 1) */
+ 0x02, /*Bulk endpoint type */
+ LOBYTE(MSC_MAX_FS_PACKET),
+ HIBYTE(MSC_MAX_FS_PACKET),
+ 0x00 /*Polling interval in milliseconds*/
+};
+
+__ALIGN_BEGIN uint8_t USBD_MSC_OtherSpeedCfgDesc[USB_MSC_CONFIG_DESC_SIZ] __ALIGN_END =
+{
+
+ 0x09, /* bLength: Configuation Descriptor size */
+ USB_DESC_TYPE_OTHER_SPEED_CONFIGURATION,
+ USB_MSC_CONFIG_DESC_SIZ,
+
+ 0x00,
+ 0x01, /* bNumInterfaces: 1 interface */
+ 0x01, /* bConfigurationValue: */
+ 0x04, /* iConfiguration: */
+ 0xC0, /* bmAttributes: */
+ 0x32, /* MaxPower 100 mA */
+
+ /******************** Mass Storage interface ********************/
+ 0x09, /* bLength: Interface Descriptor size */
+ 0x04, /* bDescriptorType: */
+ 0x00, /* bInterfaceNumber: Number of Interface */
+ 0x00, /* bAlternateSetting: Alternate setting */
+ 0x02, /* bNumEndpoints*/
+ 0x08, /* bInterfaceClass: MSC Class */
+ 0x06, /* bInterfaceSubClass : SCSI transparent command set*/
+ 0x50, /* nInterfaceProtocol */
+ 0x05, /* iInterface: */
+ /******************** Mass Storage Endpoints ********************/
+ 0x07, /*Endpoint descriptor length = 7*/
+ 0x05, /*Endpoint descriptor type */
+ MSC_EPIN_ADDR, /*Endpoint address (IN, address 1) */
+ 0x02, /*Bulk endpoint type */
+ 0x40,
+ 0x00,
+ 0x00, /*Polling interval in milliseconds */
+
+ 0x07, /*Endpoint descriptor length = 7 */
+ 0x05, /*Endpoint descriptor type */
+ MSC_EPOUT_ADDR, /*Endpoint address (OUT, address 1) */
+ 0x02, /*Bulk endpoint type */
+ 0x40,
+ 0x00,
+ 0x00 /*Polling interval in milliseconds*/
+};
+
+/* USB Standard Device Descriptor */
+__ALIGN_BEGIN uint8_t USBD_MSC_DeviceQualifierDesc[USB_LEN_DEV_QUALIFIER_DESC] __ALIGN_END =
+{
+ USB_LEN_DEV_QUALIFIER_DESC,
+ USB_DESC_TYPE_DEVICE_QUALIFIER,
+ 0x00,
+ 0x02,
+ 0x00,
+ 0x00,
+ 0x00,
+ MSC_MAX_FS_PACKET,
+ 0x01,
+ 0x00,
+};
+/**
+ * @}
+ */
+
+
+/** @defgroup MSC_CORE_Private_Functions
+ * @{
+ */
+
+/**
+ * @brief USBD_MSC_Init
+ * Initialize the mass storage configuration
+ * @param pdev: device instance
+ * @param cfgidx: configuration index
+ * @retval status
+ */
+uint8_t USBD_MSC_Init (USBD_HandleTypeDef *pdev,
+ uint8_t cfgidx)
+{
+ int16_t ret = 0;
+
+ if(pdev->dev_speed == USBD_SPEED_HIGH )
+ {
+ /* Open EP OUT */
+ USBD_LL_OpenEP(pdev,
+ MSC_EPOUT_ADDR,
+ USBD_EP_TYPE_BULK,
+ MSC_MAX_HS_PACKET);
+
+ /* Open EP IN */
+ USBD_LL_OpenEP(pdev,
+ MSC_EPIN_ADDR,
+ USBD_EP_TYPE_BULK,
+ MSC_MAX_HS_PACKET);
+ }
+ else
+ {
+ /* Open EP OUT */
+ USBD_LL_OpenEP(pdev,
+ MSC_EPOUT_ADDR,
+ USBD_EP_TYPE_BULK,
+ MSC_MAX_FS_PACKET);
+
+ /* Open EP IN */
+ USBD_LL_OpenEP(pdev,
+ MSC_EPIN_ADDR,
+ USBD_EP_TYPE_BULK,
+ MSC_MAX_FS_PACKET);
+ }
+ pdev->pClassData = USBD_malloc(sizeof (USBD_MSC_BOT_HandleTypeDef));
+
+ if(pdev->pClassData == NULL)
+ {
+ ret = 1;
+ }
+ else
+ {
+ /* Init the BOT layer */
+ MSC_BOT_Init(pdev);
+ ret = 0;
+ }
+
+ return ret;
+}
+
+/**
+ * @brief USBD_MSC_DeInit
+ * DeInitilaize the mass storage configuration
+ * @param pdev: device instance
+ * @param cfgidx: configuration index
+ * @retval status
+ */
+uint8_t USBD_MSC_DeInit (USBD_HandleTypeDef *pdev,
+ uint8_t cfgidx)
+{
+ /* Close MSC EPs */
+ USBD_LL_CloseEP(pdev,
+ MSC_EPOUT_ADDR);
+
+ /* Open EP IN */
+ USBD_LL_CloseEP(pdev,
+ MSC_EPIN_ADDR);
+
+
+ /* D-Init the BOT layer */
+ MSC_BOT_DeInit(pdev);
+
+ /* Free MSC Class Resources */
+ if(pdev->pClassData != NULL)
+ {
+ USBD_free(pdev->pClassData);
+ pdev->pClassData = NULL;
+ }
+ return 0;
+}
+/**
+* @brief USBD_MSC_Setup
+* Handle the MSC specific requests
+* @param pdev: device instance
+* @param req: USB request
+* @retval status
+*/
+uint8_t USBD_MSC_Setup (USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req)
+{
+ USBD_MSC_BOT_HandleTypeDef *hmsc = pdev->pClassData;
+
+ switch (req->bmRequest & USB_REQ_TYPE_MASK)
+ {
+
+ /* Class request */
+ case USB_REQ_TYPE_CLASS :
+ switch (req->bRequest)
+ {
+ case BOT_GET_MAX_LUN :
+
+ if((req->wValue == 0) &&
+ (req->wLength == 1) &&
+ ((req->bmRequest & 0x80) == 0x80))
+ {
+ hmsc->max_lun = ((USBD_StorageTypeDef *)pdev->pUserData)->GetMaxLun();
+ USBD_CtlSendData (pdev,
+ (uint8_t *)&hmsc->max_lun,
+ 1);
+ }
+ else
+ {
+ USBD_CtlError(pdev , req);
+ return USBD_FAIL;
+ }
+ break;
+
+ case BOT_RESET :
+ if((req->wValue == 0) &&
+ (req->wLength == 0) &&
+ ((req->bmRequest & 0x80) != 0x80))
+ {
+ MSC_BOT_Reset(pdev);
+ }
+ else
+ {
+ USBD_CtlError(pdev , req);
+ return USBD_FAIL;
+ }
+ break;
+
+ default:
+ USBD_CtlError(pdev , req);
+ return USBD_FAIL;
+ }
+ break;
+ /* Interface & Endpoint request */
+ case USB_REQ_TYPE_STANDARD:
+ switch (req->bRequest)
+ {
+ case USB_REQ_GET_INTERFACE :
+ USBD_CtlSendData (pdev,
+ (uint8_t *)&hmsc->interface,
+ 1);
+ break;
+
+ case USB_REQ_SET_INTERFACE :
+ hmsc->interface = (uint8_t)(req->wValue);
+ break;
+
+ case USB_REQ_CLEAR_FEATURE:
+
+ /* Flush the FIFO and Clear the stall status */
+ USBD_LL_FlushEP(pdev, (uint8_t)req->wIndex);
+
+ /* Re-activate the EP */
+ USBD_LL_CloseEP (pdev , (uint8_t)req->wIndex);
+ if((((uint8_t)req->wIndex) & 0x80) == 0x80)
+ {
+ if(pdev->dev_speed == USBD_SPEED_HIGH )
+ {
+ /* Open EP IN */
+ USBD_LL_OpenEP(pdev,
+ MSC_EPIN_ADDR,
+ USBD_EP_TYPE_BULK,
+ MSC_MAX_HS_PACKET);
+ }
+ else
+ {
+ /* Open EP IN */
+ USBD_LL_OpenEP(pdev,
+ MSC_EPIN_ADDR,
+ USBD_EP_TYPE_BULK,
+ MSC_MAX_FS_PACKET);
+ }
+ }
+ else
+ {
+ if(pdev->dev_speed == USBD_SPEED_HIGH )
+ {
+ /* Open EP IN */
+ USBD_LL_OpenEP(pdev,
+ MSC_EPOUT_ADDR,
+ USBD_EP_TYPE_BULK,
+ MSC_MAX_HS_PACKET);
+ }
+ else
+ {
+ /* Open EP IN */
+ USBD_LL_OpenEP(pdev,
+ MSC_EPOUT_ADDR,
+ USBD_EP_TYPE_BULK,
+ MSC_MAX_FS_PACKET);
+ }
+ }
+
+ /* Handle BOT error */
+ MSC_BOT_CplClrFeature(pdev, (uint8_t)req->wIndex);
+ break;
+
+ }
+ break;
+
+ default:
+ break;
+ }
+ return 0;
+}
+
+/**
+* @brief USBD_MSC_DataIn
+* handle data IN Stage
+* @param pdev: device instance
+* @param epnum: endpoint index
+* @retval status
+*/
+uint8_t USBD_MSC_DataIn (USBD_HandleTypeDef *pdev,
+ uint8_t epnum)
+{
+ MSC_BOT_DataIn(pdev , epnum);
+ return 0;
+}
+
+/**
+* @brief USBD_MSC_DataOut
+* handle data OUT Stage
+* @param pdev: device instance
+* @param epnum: endpoint index
+* @retval status
+*/
+uint8_t USBD_MSC_DataOut (USBD_HandleTypeDef *pdev,
+ uint8_t epnum)
+{
+ MSC_BOT_DataOut(pdev , epnum);
+ return 0;
+}
+
+/**
+* @brief USBD_MSC_GetHSCfgDesc
+* return configuration descriptor
+* @param length : pointer data length
+* @retval pointer to descriptor buffer
+*/
+uint8_t *USBD_MSC_GetHSCfgDesc (uint16_t *length)
+{
+ *length = sizeof (USBD_MSC_CfgHSDesc);
+ return USBD_MSC_CfgHSDesc;
+}
+
+/**
+* @brief USBD_MSC_GetFSCfgDesc
+* return configuration descriptor
+* @param length : pointer data length
+* @retval pointer to descriptor buffer
+*/
+uint8_t *USBD_MSC_GetFSCfgDesc (uint16_t *length)
+{
+ *length = sizeof (USBD_MSC_CfgFSDesc);
+ return USBD_MSC_CfgFSDesc;
+}
+
+/**
+* @brief USBD_MSC_GetOtherSpeedCfgDesc
+* return other speed configuration descriptor
+* @param length : pointer data length
+* @retval pointer to descriptor buffer
+*/
+uint8_t *USBD_MSC_GetOtherSpeedCfgDesc (uint16_t *length)
+{
+ *length = sizeof (USBD_MSC_OtherSpeedCfgDesc);
+ return USBD_MSC_OtherSpeedCfgDesc;
+}
+/**
+* @brief DeviceQualifierDescriptor
+* return Device Qualifier descriptor
+* @param length : pointer data length
+* @retval pointer to descriptor buffer
+*/
+uint8_t *USBD_MSC_GetDeviceQualifierDescriptor (uint16_t *length)
+{
+ *length = sizeof (USBD_MSC_DeviceQualifierDesc);
+ return USBD_MSC_DeviceQualifierDesc;
+}
+
+/**
+* @brief USBD_MSC_RegisterStorage
+* @param fops: storage callback
+* @retval status
+*/
+uint8_t USBD_MSC_RegisterStorage (USBD_HandleTypeDef *pdev,
+ USBD_StorageTypeDef *fops)
+{
+ if(fops != NULL)
+ {
+ pdev->pUserData= fops;
+ }
+ return 0;
+}
+
+/**
+ * @}
+ */
+
+
+/**
+ * @}
+ */
+
+
+/**
+ * @}
+ */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/ports/stm32/usbdev/class/src/usbd_msc_bot.c b/ports/stm32/usbdev/class/src/usbd_msc_bot.c
new file mode 100644
index 000000000..3c06f3cf6
--- /dev/null
+++ b/ports/stm32/usbdev/class/src/usbd_msc_bot.c
@@ -0,0 +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 = pdev->pClassData;
+
+ hmsc->bot_state = USBD_BOT_IDLE;
+ hmsc->bot_status = USBD_BOT_STATUS_NORMAL;
+
+ hmsc->scsi_sense_tail = 0;
+ hmsc->scsi_sense_head = 0;
+
+ ((USBD_StorageTypeDef *)pdev->pUserData)->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 = pdev->pClassData;
+
+ 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 = pdev->pClassData;
+ 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 = pdev->pClassData;
+
+ 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 = pdev->pClassData;
+
+ 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 = pdev->pClassData;
+
+ 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 = pdev->pClassData;
+
+ 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 = pdev->pClassData;
+
+ 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 = pdev->pClassData;
+
+ 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 = pdev->pClassData;
+
+ 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
new file mode 100644
index 000000000..4d72bd5fc
--- /dev/null
+++ b/ports/stm32/usbdev/class/src/usbd_msc_data.c
@@ -0,0 +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****/
diff --git a/ports/stm32/usbdev/class/src/usbd_msc_scsi.c b/ports/stm32/usbdev/class/src/usbd_msc_scsi.c
new file mode 100644
index 000000000..b2931b745
--- /dev/null
+++ b/ports/stm32/usbdev/class/src/usbd_msc_scsi.c
@@ -0,0 +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 = pdev->pClassData;
+
+ /* case 9 : Hi > D0 */
+ if (hmsc->cbw.dDataLength != 0)
+ {
+ SCSI_SenseCode(pdev,
+ hmsc->cbw.bLUN,
+ ILLEGAL_REQUEST,
+ INVALID_CDB);
+ return -1;
+ }
+
+ if(((USBD_StorageTypeDef *)pdev->pUserData)->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 = pdev->pClassData;
+
+ if (params[1] & 0x01)/*Evpd is set*/
+ {
+ pPage = (uint8_t *)MSC_Page00_Inquiry_Data;
+ len = LENGTH_INQUIRY_PAGE00;
+ }
+ else
+ {
+
+ pPage = (uint8_t *)&((USBD_StorageTypeDef *)pdev->pUserData)->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 = pdev->pClassData;
+
+ if(((USBD_StorageTypeDef *)pdev->pUserData)->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 = pdev->pClassData;
+
+ uint16_t blk_size;
+ uint32_t blk_nbr;
+ uint16_t i;
+
+ for(i=0 ; i < 12 ; i++)
+ {
+ hmsc->bot_data[i] = 0;
+ }
+
+ if(((USBD_StorageTypeDef *)pdev->pUserData)->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 = pdev->pClassData;
+ 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 = pdev->pClassData;
+
+ 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 = pdev->pClassData;
+ 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 = pdev->pClassData;
+
+ 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 = pdev->pClassData;
+
+ 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 = pdev->pClassData;
+ 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.
+ ((USBD_StorageTypeDef *)pdev->pUserData)->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 = pdev->pClassData;
+ hmsc->bot_data_length = 0;
+ ((USBD_StorageTypeDef *)pdev->pUserData)->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 = pdev->pClassData;
+
+ 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(((USBD_StorageTypeDef *)pdev->pUserData)->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 = pdev->pClassData;
+
+ 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(((USBD_StorageTypeDef *)pdev->pUserData)->IsReady(lun) !=0 )
+ {
+ SCSI_SenseCode(pdev,
+ lun,
+ NOT_READY,
+ MEDIUM_NOT_PRESENT);
+ return -1;
+ }
+
+ /* Check If media is write-protected */
+ if(((USBD_StorageTypeDef *)pdev->pUserData)->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 = pdev->pClassData;
+
+ 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 = pdev->pClassData;
+
+ 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 = pdev->pClassData;
+ uint32_t len;
+
+ len = MIN(hmsc->scsi_blk_len , MSC_MEDIA_PACKET);
+
+ if( ((USBD_StorageTypeDef *)pdev->pUserData)->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 = pdev->pClassData;
+
+ len = MIN(hmsc->scsi_blk_len , MSC_MEDIA_PACKET);
+
+ if(((USBD_StorageTypeDef *)pdev->pUserData)->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
new file mode 100644
index 000000000..5360680b9
--- /dev/null
+++ b/ports/stm32/usbdev/core/inc/usbd_core.h
@@ -0,0 +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, 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****/
+
+
+
diff --git a/ports/stm32/usbdev/core/inc/usbd_ctlreq.h b/ports/stm32/usbdev/core/inc/usbd_ctlreq.h
new file mode 100644
index 000000000..9edf07924
--- /dev/null
+++ b/ports/stm32/usbdev/core/inc/usbd_ctlreq.h
@@ -0,0 +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****/
diff --git a/ports/stm32/usbdev/core/inc/usbd_def.h b/ports/stm32/usbdev/core/inc/usbd_def.h
new file mode 100644
index 000000000..5c0506a14
--- /dev/null
+++ b/ports/stm32/usbdev/core/inc/usbd_def.h
@@ -0,0 +1,319 @@
+/**
+ ******************************************************************************
+ * @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)(uint16_t *length);
+ uint8_t *(*GetFSConfigDescriptor)(uint16_t *length);
+ uint8_t *(*GetOtherSpeedConfigDescriptor)(uint16_t *length);
+ uint8_t *(*GetDeviceQualifierDescriptor)(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;
+
+/* USB Device descriptors structure */
+typedef struct
+{
+ uint8_t *(*GetDeviceDescriptor)( USBD_SpeedTypeDef speed , uint16_t *length);
+ uint8_t *(*GetLangIDStrDescriptor)( USBD_SpeedTypeDef speed , uint16_t *length);
+ uint8_t *(*GetManufacturerStrDescriptor)( USBD_SpeedTypeDef speed , uint16_t *length);
+ uint8_t *(*GetProductStrDescriptor)( USBD_SpeedTypeDef speed , uint16_t *length);
+ uint8_t *(*GetSerialStrDescriptor)( USBD_SpeedTypeDef speed , uint16_t *length);
+ uint8_t *(*GetConfigurationStrDescriptor)( USBD_SpeedTypeDef speed , uint16_t *length);
+ uint8_t *(*GetInterfaceStrDescriptor)( USBD_SpeedTypeDef speed , 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;
+ 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
new file mode 100644
index 000000000..04e01b854
--- /dev/null
+++ b/ports/stm32/usbdev/core/inc/usbd_ioreq.h
@@ -0,0 +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****/
diff --git a/ports/stm32/usbdev/core/src/usbd_core.c b/ports/stm32/usbdev/core/src/usbd_core.c
new file mode 100644
index 000000000..bb44513d7
--- /dev/null
+++ b/ports/stm32/usbdev/core/src/usbd_core.c
@@ -0,0 +1,554 @@
+/**
+ ******************************************************************************
+ * @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, 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****/
+
diff --git a/ports/stm32/usbdev/core/src/usbd_ctlreq.c b/ports/stm32/usbdev/core/src/usbd_ctlreq.c
new file mode 100644
index 000000000..80b1da8ea
--- /dev/null
+++ b/ports/stm32/usbdev/core/src/usbd_ctlreq.c
@@ -0,0 +1,769 @@
+/**
+ ******************************************************************************
+ * @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->dev_speed, &len);
+ break;
+
+ case USB_DESC_TYPE_CONFIGURATION:
+ if(pdev->dev_speed == USBD_SPEED_HIGH )
+ {
+ pbuf = (uint8_t *)pdev->pClass->GetHSConfigDescriptor(&len);
+ pbuf[1] = USB_DESC_TYPE_CONFIGURATION;
+ }
+ else
+ {
+ pbuf = (uint8_t *)pdev->pClass->GetFSConfigDescriptor(&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->dev_speed, &len);
+ break;
+
+ case USBD_IDX_MFC_STR:
+ pbuf = pdev->pDesc->GetManufacturerStrDescriptor(pdev->dev_speed, &len);
+ break;
+
+ case USBD_IDX_PRODUCT_STR:
+ pbuf = pdev->pDesc->GetProductStrDescriptor(pdev->dev_speed, &len);
+ break;
+
+ case USBD_IDX_SERIAL_STR:
+ pbuf = pdev->pDesc->GetSerialStrDescriptor(pdev->dev_speed, &len);
+ break;
+
+ case USBD_IDX_CONFIG_STR:
+ pbuf = pdev->pDesc->GetConfigurationStrDescriptor(pdev->dev_speed, &len);
+ break;
+
+ case USBD_IDX_INTERFACE_STR:
+ pbuf = pdev->pDesc->GetInterfaceStrDescriptor(pdev->dev_speed, &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(&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(&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)
+{
+
+ static 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
new file mode 100644
index 000000000..9e396ba56
--- /dev/null
+++ b/ports/stm32/usbdev/core/src/usbd_ioreq.c
@@ -0,0 +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****/
diff --git a/ports/stm32/usbhost/Class/AUDIO/Inc/usbh_audio.h b/ports/stm32/usbhost/Class/AUDIO/Inc/usbh_audio.h
new file mode 100644
index 000000000..8cee530d0
--- /dev/null
+++ b/ports/stm32/usbhost/Class/AUDIO/Inc/usbh_audio.h
@@ -0,0 +1,581 @@
+/**
+ ******************************************************************************
+ * @file usbh_audio.h
+ * @author MCD Application Team
+ * @version V3.0.0
+ * @date 18-February-2014
+ * @brief This file contains all the prototypes for the usbh_audio.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 ----------------------------------------------*/
+#ifndef __USBH_AUDIO_H
+#define __USBH_AUDIO_H
+
+/* Includes ------------------------------------------------------------------*/
+#include "usbh_core.h"
+
+/** @addtogroup USBH_LIB
+ * @{
+ */
+
+/** @addtogroup USBH_CLASS
+ * @{
+ */
+
+/** @addtogroup USBH_AUDIO_CLASS
+ * @{
+ */
+
+/** @defgroup USBH_AUDIO_CORE
+ * @brief This file is the Header file for usbh_audio.c
+ * @{
+ */
+
+
+/** @defgroup USBH_AUDIO_CORE_Exported_Types
+ * @{
+ */
+
+/* States for AUDIO State Machine */
+typedef enum
+{
+ AUDIO_INIT = 0,
+ AUDIO_IDLE,
+ AUDIO_CS_REQUESTS,
+ AUDIO_SET_DEFAULT_FEATURE_UNIT,
+ AUDIO_SET_INTERFACE,
+ AUDIO_SET_STREAMING_INTERFACE,
+ AUDIO_SET_CUR1,
+ AUDIO_GET_MIN,
+ AUDIO_GET_MAX,
+ AUDIO_GET_RES,
+ AUDIO_GET_CUR1,
+ AUDIO_SET_CUR2,
+ AUDIO_GET_CUR2,
+ AUDIO_SET_CUR3,
+ AUDIO_SET_INTERFACE0,
+ AUDIO_SET_INTERFACE1,
+ AUDIO_SET_INTERFACE2,
+ AUDIO_ISOC_OUT,
+ AUDIO_ISOC_IN,
+ AUDIO_ISOC_POLL,
+ AUDIO_ERROR,
+}
+AUDIO_StateTypeDef;
+
+typedef enum
+{
+ AUDIO_REQ_INIT = 1,
+ AUDIO_REQ_IDLE,
+ AUDIO_REQ_SET_DEFAULT_IN_INTERFACE,
+ AUDIO_REQ_SET_DEFAULT_OUT_INTERFACE,
+ AUDIO_REQ_SET_IN_INTERFACE,
+ AUDIO_REQ_SET_OUT_INTERFACE,
+ AUDIO_REQ_CS_REQUESTS,
+}
+AUDIO_ReqStateTypeDef;
+
+typedef enum
+{
+ AUDIO_REQ_SET_VOLUME = 1,
+ AUDIO_REQ_SET_MUTE,
+ AUDIO_REQ_GET_CURR_VOLUME,
+ AUDIO_REQ_GET_MIN_VOLUME,
+ AUDIO_REQ_GET_MAX_VOLUME,
+ AUDIO_REQ_GET_VOLUME,
+ AUDIO_REQ_GET_RESOLUTION,
+ AUDIO_REQ_CS_IDLE,
+}
+AUDIO_CSReqStateTypeDef;
+
+typedef enum
+{
+ AUDIO_PLAYBACK_INIT = 1,
+ AUDIO_PLAYBACK_SET_EP,
+ AUDIO_PLAYBACK_SET_EP_FREQ,
+ AUDIO_PLAYBACK_PLAY,
+ AUDIO_PLAYBACK_IDLE,
+}
+AUDIO_PlayStateTypeDef;
+
+typedef enum
+{
+ VOLUME_UP = 1,
+ VOLUME_DOWN = 2,
+}
+AUDIO_VolumeCtrlTypeDef;
+
+typedef enum
+{
+ AUDIO_CONTROL_INIT = 1,
+ AUDIO_CONTROL_CHANGE,
+ AUDIO_CONTROL_IDLE,
+ AUDIO_CONTROL_VOLUME_UP,
+ AUDIO_CONTROL_VOLUME_DOWN,
+}
+AUDIO_ControlStateTypeDef;
+
+
+typedef enum
+{
+ AUDIO_DATA_START_OUT = 1,
+ AUDIO_DATA_OUT,
+}
+AUDIO_ProcessingTypeDef;
+
+/* Structure for AUDIO process */
+typedef struct
+{
+ uint8_t Channels;
+ uint8_t Bits;
+ uint32_t SampleRate;
+}
+AUDIO_FormatTypeDef;
+
+typedef struct
+{
+ uint8_t Ep;
+ uint16_t EpSize;
+ uint8_t AltSettings;
+ uint8_t interface;
+ uint8_t valid;
+ uint16_t Poll;
+}
+AUDIO_STREAMING_IN_HandleTypeDef;
+
+typedef struct
+{
+ uint8_t Ep;
+ uint16_t EpSize;
+ uint8_t AltSettings;
+ uint8_t interface;
+ uint8_t valid;
+ uint16_t Poll;
+}
+AUDIO_STREAMING_OUT_HandleTypeDef;
+
+
+typedef struct
+{
+ uint8_t mute;
+ uint32_t volumeMin;
+ uint32_t volumeMax;
+ uint32_t volume;
+ uint32_t resolution;
+}
+AUDIO_ControlAttributeTypeDef;
+
+typedef struct
+{
+
+ uint8_t Ep;
+ uint16_t EpSize;
+ uint8_t interface;
+ uint8_t AltSettings;
+ uint8_t supported;
+
+ uint8_t Pipe;
+ uint8_t Poll;
+ uint32_t timer ;
+
+ uint8_t asociated_as;
+ uint8_t asociated_mixer;
+ uint8_t asociated_selector;
+ uint8_t asociated_feature;
+ uint8_t asociated_terminal;
+ uint8_t asociated_channels;
+
+ uint32_t frequency;
+ uint8_t *buf;
+ uint8_t *cbuf;
+ uint32_t partial_ptr;
+
+ uint32_t global_ptr;
+ uint16_t frame_length;
+ uint32_t total_length;
+
+ AUDIO_ControlAttributeTypeDef attribute;
+}
+AUDIO_InterfaceStreamPropTypeDef;
+
+typedef struct
+{
+
+ uint8_t Ep;
+ uint16_t EpSize;
+ uint8_t interface;
+ uint8_t supported;
+
+ uint8_t Pipe;
+ uint8_t Poll;
+ uint32_t timer ;
+}
+AUDIO_InterfaceControlPropTypeDef;
+
+
+#define AUDIO_MAX_AUDIO_STD_INTERFACE 0x05
+#define AUDIO_MAX_FREQ_SUPPORTED 0x05
+#define AUDIO_MAX_STREAMING_INTERFACE 0x05
+#define AUDIO_MAX_NUM_IN_TERMINAL 0x04
+#define AUDIO_MAX_NUM_OUT_TERMINAL 0x04
+#define AUDIO_MAX_NUM_FEATURE_UNIT 0x04
+#define AUDIO_MAX_NUM_MIXER_UNIT 0x04
+#define AUDIO_MAX_NUM_SELECTOR_UNIT 0x04
+
+#define HEADPHONE_SUPPORTED 0x01
+#define MICROPHONE_SUPPORTED 0x02
+#define HEADSET_SUPPORTED 0x03
+
+
+/*Class-Specific AS(Audio Streaming) Interface Descriptor*/
+typedef struct
+{
+ uint8_t bLength;
+ uint8_t bDescriptorType;
+ uint8_t bDescriptorSubtype;
+ uint8_t bTerminalLink;
+ uint8_t bDelay;
+ uint8_t wFormatTag[2];
+}
+AUDIO_ASGeneralDescTypeDef;
+
+/*Class-Specific AS(Audio Streaming) Format Type Descriptor*/
+typedef struct
+{
+ uint8_t bLength; /*At to be deside*/
+ uint8_t bDescriptorType;
+ uint8_t bDescriptorSubtype;
+ uint8_t bFormatType;
+ uint8_t bNrChannels;
+ uint8_t bSubframeSize;
+ uint8_t bBitResolution;
+ uint8_t bSamFreqType;
+ uint8_t tSamFreq[][3];
+}
+AUDIO_ASFormatTypeDescTypeDef;
+
+/*Class-Specific AS(Audio Streaming) Interface Descriptor*/
+typedef struct
+{
+ AUDIO_ASGeneralDescTypeDef *GeneralDesc;
+ AUDIO_ASFormatTypeDescTypeDef *FormatTypeDesc;
+}
+AUDIO_ASDescTypeDef;
+
+/* 4.3.2 Class-Specific AC Interface Descriptor */
+
+typedef struct
+{
+ uint8_t bLength;
+ uint8_t bDescriptorType;
+ uint8_t bDescriptorSubtype;
+ uint8_t bcdADC[2];
+ uint8_t wTotalLength[2];
+ uint8_t bInCollection;
+ uint8_t baInterfaceNr[];
+}
+AUDIO_HeaderDescTypeDef;
+
+/* 4.3.2.1 Input Terminal Descriptor */
+typedef struct
+{
+ uint8_t bLength;
+ uint8_t bDescriptorType;
+ uint8_t bDescriptorSubtype;
+ uint8_t bTerminalID;
+ uint8_t wTerminalType[2];
+ uint8_t bAssocTerminal;
+ uint8_t bNrChannels;
+ uint8_t wChannelConfig[2];
+ uint8_t iChannelNames;
+ uint8_t iTerminal;
+}
+AUDIO_ITDescTypeDef;
+
+/* 4.3.2.2 Output Terminal Descriptor */
+typedef struct
+{
+ uint8_t bLength;
+ uint8_t bDescriptorType;
+ uint8_t bDescriptorSubtype;
+ uint8_t bTerminalID;
+ uint8_t wTerminalType[2];
+ uint8_t bAssocTerminal;
+ uint8_t bSourceID;
+ uint8_t iTerminal;
+}
+AUDIO_OTDescTypeDef;
+
+/* 4.3.2.3 Feature Descriptor */
+typedef struct
+{
+ uint8_t bLength;
+ uint8_t bDescriptorType;
+ uint8_t bDescriptorSubtype;
+ uint8_t bUnitID;
+ uint8_t bSourceID;
+ uint8_t bControlSize;
+ uint8_t bmaControls[][2];
+}
+AUDIO_FeatureDescTypeDef;
+
+
+/* 4.3.2.3 Feature Descriptor */
+typedef struct
+{
+ uint8_t bLength;
+ uint8_t bDescriptorType;
+ uint8_t bDescriptorSubtype;
+ uint8_t bUnitID;
+ uint8_t bNrInPins;
+ uint8_t bSourceID0;
+ uint8_t bSourceID1;
+ uint8_t bNrChannels;
+ uint8_t bmChannelsConfig[2];
+ uint8_t iChannelsNames;
+ uint8_t bmaControls;
+ uint8_t iMixer;
+}
+AUDIO_MixerDescTypeDef;
+
+
+
+/* 4.3.2.3 Feature Descriptor */
+typedef struct
+{
+ uint8_t bLength;
+ uint8_t bDescriptorType;
+ uint8_t bDescriptorSubtype;
+ uint8_t bUnitID;
+ uint8_t bNrInPins;
+ uint8_t bSourceID0;
+ uint8_t iSelector;
+}
+AUDIO_SelectorDescTypeDef;
+
+/*Class-Specific AC(Audio Control) Interface Descriptor*/
+typedef struct
+{
+ AUDIO_HeaderDescTypeDef *HeaderDesc;
+ AUDIO_ITDescTypeDef *InputTerminalDesc [AUDIO_MAX_NUM_IN_TERMINAL];
+ AUDIO_OTDescTypeDef *OutputTerminalDesc[AUDIO_MAX_NUM_OUT_TERMINAL];
+ AUDIO_FeatureDescTypeDef *FeatureUnitDesc [AUDIO_MAX_NUM_FEATURE_UNIT];
+ AUDIO_MixerDescTypeDef *MixerUnitDesc [AUDIO_MAX_NUM_MIXER_UNIT];
+ AUDIO_SelectorDescTypeDef *SelectorUnitDesc [AUDIO_MAX_NUM_SELECTOR_UNIT];
+}
+AUDIO_ACDescTypeDef;
+
+/*Class-Specific AC : Global descriptor*/
+
+typedef struct
+{
+ AUDIO_ACDescTypeDef cs_desc; /* Only one control descriptor*/
+ AUDIO_ASDescTypeDef as_desc[AUDIO_MAX_STREAMING_INTERFACE];
+
+ uint16_t ASNum;
+ uint16_t InputTerminalNum;
+ uint16_t OutputTerminalNum;
+ uint16_t FeatureUnitNum;
+ uint16_t SelectorUnitNum;
+ uint16_t MixerUnitNum;
+}
+AUDIO_ClassSpecificDescTypedef;
+
+
+typedef struct _AUDIO_Process
+{
+ AUDIO_ReqStateTypeDef req_state;
+ AUDIO_CSReqStateTypeDef cs_req_state;
+ AUDIO_PlayStateTypeDef play_state;
+ AUDIO_ControlStateTypeDef control_state;
+ AUDIO_ProcessingTypeDef processing_state;
+
+ AUDIO_STREAMING_IN_HandleTypeDef stream_in[AUDIO_MAX_AUDIO_STD_INTERFACE];
+ AUDIO_STREAMING_OUT_HandleTypeDef stream_out[AUDIO_MAX_AUDIO_STD_INTERFACE];
+ AUDIO_ClassSpecificDescTypedef class_desc;
+
+ AUDIO_InterfaceStreamPropTypeDef headphone;
+ AUDIO_InterfaceStreamPropTypeDef microphone;
+ AUDIO_InterfaceControlPropTypeDef control;
+ uint16_t mem [8];
+ uint8_t temp_feature;
+ uint8_t temp_channels;
+}
+AUDIO_HandleTypeDef;
+
+/**
+ * @}
+ */
+
+/** @defgroup USBH_AUDIO_CORE_Exported_Defines
+ * @{
+ */
+
+
+/*Audio Interface Subclass Codes*/
+#define AC_CLASS 0x01
+
+/* A.2 Audio Interface Subclass Codes */
+#define USB_SUBCLASS_AUDIOCONTROL 0x01
+#define USB_SUBCLASS_AUDIOSTREAMING 0x02
+#define USB_SUBCLASS_MIDISTREAMING 0x03
+
+#define USB_DESC_TYPE_CS_INTERFACE 0x24
+#define USB_DESC_TYPE_CS_ENDPOINT 0x25
+
+/* A.5 Audio Class-Specific AC Interface Descriptor Subtypes */
+#define UAC_HEADER 0x01
+#define UAC_INPUT_TERMINAL 0x02
+#define UAC_OUTPUT_TERMINAL 0x03
+#define UAC_MIXER_UNIT 0x04
+#define UAC_SELECTOR_UNIT 0x05
+#define UAC_FEATURE_UNIT 0x06
+#define UAC_PROCESSING_UNIT 0x07
+#define UAC_EXTENSION_UNIT 0x08
+
+/*Audio Class-Specific Endpoint Descriptor Subtypes*/
+#define EP_CONTROL_UNDEFINED 0x00
+#define SAMPLING_FREQ_CONTROL 0x01
+#define PITCH_CONTROL 0x02
+
+/*Feature unit control selector*/
+#define FU_CONTROL_UNDEFINED 0x00
+#define MUTE_CONTROL 0x01
+#define VOLUME_CONTROL 0x02
+#define BASS_CONTROL 0x03
+#define MID_CONTROL 0x04
+#define TREBLE_CONTROL 0x05
+#define GRAPHIC_EQUALIZER_CONTROL 0x06
+#define AUTOMATIC_GAIN_CONTROL 0x07
+#define DELAY_CONTROL 0x08
+#define BASS_BOOST_CONTROL 0x09
+#define LOUDNESS_CONTROL 0x0A
+
+/*Terminal control selector*/
+#define TE_CONTROL_UNDEFINED 0x00
+#define COPY_PROTECT_CONTROL 0x01
+
+
+/* A.6 Audio Class-Specific AS Interface Descriptor Subtypes */
+#define UAC_AS_GENERAL 0x01
+#define UAC_FORMAT_TYPE 0x02
+#define UAC_FORMAT_SPECIFIC 0x03
+
+/* A.8 Audio Class-Specific Endpoint Descriptor Subtypes */
+#define UAC_EP_GENERAL 0x01
+
+/* A.9 Audio Class-Specific Request Codes */
+#define UAC_SET_ 0x00
+#define UAC_GET_ 0x80
+
+#define UAC__CUR 0x1
+#define UAC__MIN 0x2
+#define UAC__MAX 0x3
+#define UAC__RES 0x4
+#define UAC__MEM 0x5
+
+#define UAC_SET_CUR (UAC_SET_ | UAC__CUR)
+#define UAC_GET_CUR (UAC_GET_ | UAC__CUR)
+#define UAC_SET_MIN (UAC_SET_ | UAC__MIN)
+#define UAC_GET_MIN (UAC_GET_ | UAC__MIN)
+#define UAC_SET_MAX (UAC_SET_ | UAC__MAX)
+#define UAC_GET_MAX (UAC_GET_ | UAC__MAX)
+#define UAC_SET_RES (UAC_SET_ | UAC__RES)
+#define UAC_GET_RES (UAC_GET_ | UAC__RES)
+#define UAC_SET_MEM (UAC_SET_ | UAC__MEM)
+#define UAC_GET_MEM (UAC_GET_ | UAC__MEM)
+
+#define UAC_GET_STAT 0xff
+
+/* MIDI - A.1 MS Class-Specific Interface Descriptor Subtypes */
+#define UAC_MS_HEADER 0x01
+#define UAC_MIDI_IN_JACK 0x02
+#define UAC_MIDI_OUT_JACK 0x03
+
+/* MIDI - A.1 MS Class-Specific Endpoint Descriptor Subtypes */
+#define UAC_MS_GENERAL 0x01
+
+/* Terminals - 2.1 USB Terminal Types */
+#define UAC_TERMINAL_UNDEFINED 0x100
+#define UAC_TERMINAL_STREAMING 0x101
+#define UAC_TERMINAL_VENDOR_SPEC 0x1FF
+
+/**
+ * @}
+ */
+
+/** @defgroup USBH_AUDIO_CORE_Exported_Macros
+ * @{
+ */
+/**
+ * @}
+ */
+
+/** @defgroup USBH_AUDIO_CORE_Exported_Variables
+ * @{
+ */
+extern USBH_ClassTypeDef AUDIO_Class;
+#define USBH_AUDIO_CLASS &AUDIO_Class
+/**
+ * @}
+ */
+
+/** @defgroup USBH_AUDIO_CORE_Exported_FunctionsPrototype
+ * @{
+ */
+USBH_StatusTypeDef USBH_AUDIO_SetFrequency (USBH_HandleTypeDef *phost,
+ uint16_t sample_rate,
+ uint8_t channel_num,
+ uint8_t data_width);
+
+USBH_StatusTypeDef USBH_AUDIO_Play (USBH_HandleTypeDef *phost, uint8_t *buf, uint32_t length);
+USBH_StatusTypeDef USBH_AUDIO_Stop (USBH_HandleTypeDef *phost);
+USBH_StatusTypeDef USBH_AUDIO_Suspend (USBH_HandleTypeDef *phost);
+USBH_StatusTypeDef USBH_AUDIO_Resume (USBH_HandleTypeDef *phost);
+USBH_StatusTypeDef USBH_AUDIO_SetVolume (USBH_HandleTypeDef *phost, AUDIO_VolumeCtrlTypeDef volume_ctl);
+USBH_StatusTypeDef USBH_AUDIO_ChangeOutBuffer (USBH_HandleTypeDef *phost, uint8_t *buf);
+int32_t USBH_AUDIO_GetOutOffset (USBH_HandleTypeDef *phost);
+
+void USBH_AUDIO_FrequencySet(USBH_HandleTypeDef *phost);
+/**
+ * @}
+ */
+
+
+#endif /* __USBH_AUDIO_H */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
+
diff --git a/ports/stm32/usbhost/Class/AUDIO/Src/usbh_audio.c b/ports/stm32/usbhost/Class/AUDIO/Src/usbh_audio.c
new file mode 100644
index 000000000..b9677b6c2
--- /dev/null
+++ b/ports/stm32/usbhost/Class/AUDIO/Src/usbh_audio.c
@@ -0,0 +1,1994 @@
+/**
+ ******************************************************************************
+ * @file usbh_audio.c
+ * @author MCD Application Team
+ * @version V3.0.0
+ * @date 18-February-2014
+ * @brief This file is the AC Layer Handlers for USB Host AC class.
+ *
+ ******************************************************************************
+ * @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 "usbh_audio.h"
+
+/** @addtogroup USBH_LIB
+ * @{
+ */
+
+/** @addtogroup USBH_CLASS
+ * @{
+ */
+
+/** @addtogroup USBH_AUDIO_CLASS
+ * @{
+ */
+
+/** @defgroup USBH_AUDIO_CORE
+ * @brief This file includes HID Layer Handlers for USB Host HID class.
+ * @{
+ */
+
+/** @defgroup USBH_AUDIO_CORE_Private_TypesDefinitions
+ * @{
+ */
+/**
+ * @}
+ */
+
+
+/** @defgroup USBH_AUDIO_CORE_Private_Defines
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+
+/** @defgroup USBH_AUDIO_CORE_Private_Macros
+ * @{
+ */
+/**
+ * @}
+ */
+
+
+/** @defgroup USBH_AUDIO_CORE_Private_Variables
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+
+/** @defgroup USBH_AUDIO_CORE_Private_FunctionPrototypes
+ * @{
+ */
+
+static USBH_StatusTypeDef USBH_AUDIO_InterfaceInit (USBH_HandleTypeDef *phost);
+static USBH_StatusTypeDef USBH_AUDIO_InterfaceDeInit (USBH_HandleTypeDef *phost);
+static USBH_StatusTypeDef USBH_AUDIO_Process(USBH_HandleTypeDef *phost);
+static USBH_StatusTypeDef USBH_AUDIO_SOFProcess(USBH_HandleTypeDef *phost);
+static USBH_StatusTypeDef USBH_AUDIO_ClassRequest(USBH_HandleTypeDef *phost);
+static USBH_StatusTypeDef USBH_AUDIO_CSRequest(USBH_HandleTypeDef *phost,
+ uint8_t feature,
+ uint8_t channel);
+
+static USBH_StatusTypeDef USBH_AUDIO_HandleCSRequest(USBH_HandleTypeDef *phost);
+
+static USBH_StatusTypeDef USBH_AUDIO_FindAudioStreamingIN(USBH_HandleTypeDef *phost);
+static USBH_StatusTypeDef USBH_AUDIO_FindAudioStreamingOUT(USBH_HandleTypeDef *phost);
+static USBH_StatusTypeDef USBH_AUDIO_FindHIDControl(USBH_HandleTypeDef *phost);
+static USBH_StatusTypeDef USBH_AUDIO_ParseCSDescriptors(USBH_HandleTypeDef *phost);
+
+static USBH_StatusTypeDef USBH_AUDIO_BuildHeadphonePath(USBH_HandleTypeDef *phost);
+static USBH_StatusTypeDef USBH_AUDIO_BuildMicrophonePath(USBH_HandleTypeDef *phost);
+int32_t USBH_AUDIO_FindLinkedUnitIN(USBH_HandleTypeDef *phost, uint8_t UnitID);
+int32_t USBH_AUDIO_FindLinkedUnitOUT(USBH_HandleTypeDef *phost, uint8_t UnitID);
+
+
+
+static USBH_StatusTypeDef ParseCSDescriptors(AUDIO_ClassSpecificDescTypedef *class_desc,
+ uint8_t ac_subclass,
+ uint8_t *pdesc);
+
+
+static USBH_StatusTypeDef USBH_AUDIO_Transmit (USBH_HandleTypeDef *phost);
+
+
+static USBH_StatusTypeDef USBH_AC_SetCur(USBH_HandleTypeDef *phost,
+ uint8_t subtype,
+ uint8_t feature,
+ uint8_t controlSelector,
+ uint8_t channel,
+ uint16_t length);
+
+static USBH_StatusTypeDef USBH_AC_GetCur(USBH_HandleTypeDef *phost,
+ uint8_t subtype,
+ uint8_t feature,
+ uint8_t controlSelector,
+ uint8_t channel,
+ uint16_t length);
+
+static USBH_StatusTypeDef USBH_AC_GetMin(USBH_HandleTypeDef *phost,
+ uint8_t subtype,
+ uint8_t feature,
+ uint8_t controlSelector,
+ uint8_t channel,
+ uint16_t length);
+
+static USBH_StatusTypeDef USBH_AC_GetMax(USBH_HandleTypeDef *phost,
+ uint8_t subtype,
+ uint8_t feature,
+ uint8_t controlSelector,
+ uint8_t channel,
+ uint16_t length);
+
+static USBH_StatusTypeDef USBH_AC_GetRes(USBH_HandleTypeDef *phost,
+ uint8_t subtype,
+ uint8_t feature,
+ uint8_t controlSelector,
+ uint8_t channel,
+ uint16_t length);
+
+static USBH_StatusTypeDef USBH_AUDIO_SetEndpointControls(USBH_HandleTypeDef *phost,
+ uint8_t Ep,
+ uint8_t *buff);
+
+static USBH_StatusTypeDef AUDIO_SetVolume (USBH_HandleTypeDef *phost, uint8_t feature, uint8_t channel, uint16_t volume);
+
+static USBH_StatusTypeDef USBH_AUDIO_InputStream (USBH_HandleTypeDef *phost);
+static USBH_StatusTypeDef USBH_AUDIO_OutputStream (USBH_HandleTypeDef *phost);
+static USBH_StatusTypeDef USBH_AUDIO_Control (USBH_HandleTypeDef *phost);
+static USBH_StatusTypeDef USBH_AUDIO_SetControlAttribute (USBH_HandleTypeDef *phost, uint8_t attrib);
+static int32_t USBH_AUDIO_FindLinkedUnit(USBH_HandleTypeDef *phost, uint8_t UnitID);
+
+USBH_ClassTypeDef AUDIO_Class =
+{
+ "AUDIO",
+ AC_CLASS,
+ USBH_AUDIO_InterfaceInit,
+ USBH_AUDIO_InterfaceDeInit,
+ USBH_AUDIO_ClassRequest,
+ USBH_AUDIO_Process,
+ USBH_AUDIO_SOFProcess,
+ NULL,
+};
+
+/**
+ * @}
+ */
+
+/** @defgroup USBH_AUDIO_CORE_Private_Functions
+ * @{
+ */
+
+/**
+ * @brief USBH_AUDIO_InterfaceInit
+ * The function init the Audio class.
+ * @param phost: Host handle
+ * @retval USBH Status
+ */
+static USBH_StatusTypeDef USBH_AUDIO_InterfaceInit (USBH_HandleTypeDef *phost)
+{
+ USBH_StatusTypeDef status = USBH_FAIL ;
+ USBH_StatusTypeDef out_status, in_status ;
+ AUDIO_HandleTypeDef *AUDIO_Handle;
+ uint8_t interface, index;
+ uint16_t ep_size_out = 0;
+ uint16_t ep_size_in = 0;
+
+ interface = USBH_FindInterface(phost, AC_CLASS, USB_SUBCLASS_AUDIOCONTROL, 0x00);
+
+ if(interface == 0xFF) /* Not Valid Interface */
+ {
+ USBH_DbgLog ("Cannot Find the interface for %s class.", phost->pActiveClass->Name);
+ status = USBH_FAIL;
+ }
+ else
+ {
+
+
+ phost->pActiveClass->pData = (AUDIO_HandleTypeDef *)USBH_malloc (sizeof(AUDIO_HandleTypeDef));
+ AUDIO_Handle = phost->pActiveClass->pData;
+ USBH_memset(AUDIO_Handle, 0, sizeof(AUDIO_HandleTypeDef));
+
+
+ /* 1st Step: Find Audio Interfaces */
+ out_status = USBH_AUDIO_FindAudioStreamingIN (phost);
+
+ in_status = USBH_AUDIO_FindAudioStreamingOUT(phost);
+
+ if((out_status == USBH_FAIL) && (in_status == USBH_FAIL))
+ {
+ USBH_DbgLog ("%s class configuration not supported.", phost->pActiveClass->Name);
+ }
+ else
+ {
+ /* 2nd Step: Select Audio Streaming Interfaces with largest endpoint size : default behavior*/
+ for (index = 0; index < AUDIO_MAX_AUDIO_STD_INTERFACE; index ++)
+ {
+ if( AUDIO_Handle->stream_out[index].valid == 1)
+ {
+ if(ep_size_out < AUDIO_Handle->stream_out[index].EpSize)
+ {
+ ep_size_out = AUDIO_Handle->stream_out[index].EpSize;
+ AUDIO_Handle->headphone.interface = AUDIO_Handle->stream_out[index].interface;
+ AUDIO_Handle->headphone.AltSettings = AUDIO_Handle->stream_out[index].AltSettings;
+ AUDIO_Handle->headphone.Ep = AUDIO_Handle->stream_out[index].Ep;
+ AUDIO_Handle->headphone.EpSize = AUDIO_Handle->stream_out[index].EpSize;
+ AUDIO_Handle->headphone.Poll = AUDIO_Handle->stream_out[index].Poll;
+ AUDIO_Handle->headphone.supported = 1;
+ }
+ }
+
+ if( AUDIO_Handle->stream_in[index].valid == 1)
+ {
+ if(ep_size_in < AUDIO_Handle->stream_in[index].EpSize)
+ {
+ ep_size_in = AUDIO_Handle->stream_in[index].EpSize;
+ AUDIO_Handle->microphone.interface = AUDIO_Handle->stream_in[index].interface;
+ AUDIO_Handle->microphone.AltSettings = AUDIO_Handle->stream_in[index].AltSettings;
+ AUDIO_Handle->microphone.Ep = AUDIO_Handle->stream_in[index].Ep;
+ AUDIO_Handle->microphone.EpSize = AUDIO_Handle->stream_in[index].EpSize;
+ AUDIO_Handle->microphone.Poll = AUDIO_Handle->stream_out[index].Poll;
+ AUDIO_Handle->microphone.supported = 1;
+ }
+ }
+ }
+
+ if(USBH_AUDIO_FindHIDControl(phost) == USBH_OK)
+ {
+ AUDIO_Handle->control.supported = 1;
+ }
+
+ /* 3rd Step: Find and Parse Audio interfaces */
+ USBH_AUDIO_ParseCSDescriptors (phost);
+
+
+ /* 4th Step: Open the Audio streaming pipes*/
+ if(AUDIO_Handle->headphone.supported == 1)
+ {
+ USBH_AUDIO_BuildHeadphonePath (phost);
+
+ AUDIO_Handle->headphone.Pipe = USBH_AllocPipe(phost, AUDIO_Handle->headphone.Ep);
+
+ /* Open pipe for IN endpoint */
+ USBH_OpenPipe (phost,
+ AUDIO_Handle->headphone.Pipe,
+ AUDIO_Handle->headphone.Ep,
+ phost->device.address,
+ phost->device.speed,
+ USB_EP_TYPE_ISOC,
+ AUDIO_Handle->headphone.EpSize);
+
+ USBH_LL_SetToggle (phost, AUDIO_Handle->headphone.Pipe, 0);
+
+ }
+
+ if(AUDIO_Handle->microphone.supported == 1)
+ {
+ USBH_AUDIO_BuildMicrophonePath (phost);
+ AUDIO_Handle->microphone.Pipe = USBH_AllocPipe(phost, AUDIO_Handle->microphone.Ep);
+
+ /* Open pipe for IN endpoint */
+ USBH_OpenPipe (phost,
+ AUDIO_Handle->microphone.Pipe,
+ AUDIO_Handle->microphone.Ep,
+ phost->device.address,
+ phost->device.speed,
+ USB_EP_TYPE_ISOC,
+ AUDIO_Handle->microphone.EpSize);
+
+ USBH_LL_SetToggle (phost, AUDIO_Handle->microphone.Pipe, 0);
+ }
+
+ if(AUDIO_Handle->control.supported == 1)
+ {
+ AUDIO_Handle->control.Pipe = USBH_AllocPipe(phost, AUDIO_Handle->control.Ep);
+
+ /* Open pipe for IN endpoint */
+ USBH_OpenPipe (phost,
+ AUDIO_Handle->control.Pipe,
+ AUDIO_Handle->control.Ep,
+ phost->device.address,
+ phost->device.speed,
+ USB_EP_TYPE_INTR,
+ AUDIO_Handle->control.EpSize);
+
+ USBH_LL_SetToggle (phost, AUDIO_Handle->control.Pipe, 0);
+
+ }
+
+ AUDIO_Handle->req_state = AUDIO_REQ_INIT;
+ AUDIO_Handle->control_state = AUDIO_CONTROL_INIT;
+
+ status = USBH_OK;
+ }
+ }
+ return status;
+}
+
+
+
+/**
+ * @brief USBH_AUDIO_InterfaceDeInit
+ * The function DeInit the Pipes used for the Audio class.
+ * @param phost: Host handle
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_AUDIO_InterfaceDeInit (USBH_HandleTypeDef *phost)
+{
+ AUDIO_HandleTypeDef *AUDIO_Handle = phost->pActiveClass->pData;
+
+ if(AUDIO_Handle->microphone.Pipe != 0x00)
+ {
+ USBH_ClosePipe (phost, AUDIO_Handle->microphone.Pipe);
+ USBH_FreePipe (phost, AUDIO_Handle->microphone.Pipe);
+ AUDIO_Handle->microphone.Pipe = 0; /* Reset the pipe as Free */
+ }
+
+ if( AUDIO_Handle->headphone.Pipe != 0x00)
+ {
+ USBH_ClosePipe(phost, AUDIO_Handle->headphone.Pipe);
+ USBH_FreePipe (phost, AUDIO_Handle->headphone.Pipe);
+ AUDIO_Handle->headphone.Pipe = 0; /* Reset the pipe as Free */
+ }
+
+ if( AUDIO_Handle->control.Pipe != 0x00)
+ {
+ USBH_ClosePipe(phost, AUDIO_Handle->control.Pipe);
+ USBH_FreePipe (phost, AUDIO_Handle->control.Pipe);
+ AUDIO_Handle->control.Pipe = 0; /* Reset the pipe as Free */
+ }
+
+ if(phost->pActiveClass->pData)
+ {
+ USBH_free (phost->pActiveClass->pData);
+ phost->pActiveClass->pData = 0;
+ }
+ return USBH_OK ;
+}
+
+/**
+ * @brief USBH_AUDIO_ClassRequest
+ * The function is responsible for handling Standard requests
+ * for Audio class.
+ * @param phost: Host handle
+ * @retval USBH Status
+ */
+static USBH_StatusTypeDef USBH_AUDIO_ClassRequest(USBH_HandleTypeDef *phost)
+{
+ AUDIO_HandleTypeDef *AUDIO_Handle = phost->pActiveClass->pData;
+ USBH_StatusTypeDef status = USBH_BUSY;
+ USBH_StatusTypeDef req_status = USBH_BUSY;
+
+ /* Switch AUDIO REQ state machine */
+ switch (AUDIO_Handle->req_state)
+ {
+ case AUDIO_REQ_INIT:
+ case AUDIO_REQ_SET_DEFAULT_IN_INTERFACE:
+ if(AUDIO_Handle->microphone.supported == 1)
+ {
+ req_status = USBH_SetInterface(phost,
+ AUDIO_Handle->microphone.interface,
+ 0);
+
+ if(req_status == USBH_OK)
+ {
+ AUDIO_Handle->req_state = AUDIO_REQ_SET_DEFAULT_OUT_INTERFACE;
+ }
+
+ }
+ else
+ {
+ AUDIO_Handle->req_state = AUDIO_REQ_SET_DEFAULT_OUT_INTERFACE;
+#if (USBH_USE_OS == 1)
+ osMessagePut ( phost->os_event, USBH_URB_EVENT, 0);
+#endif
+ }
+ break;
+
+ case AUDIO_REQ_SET_DEFAULT_OUT_INTERFACE:
+ if(AUDIO_Handle->headphone.supported == 1)
+ {
+ req_status = USBH_SetInterface(phost,
+ AUDIO_Handle->headphone.interface,
+ 0);
+
+ if(req_status == USBH_OK)
+ {
+ AUDIO_Handle->req_state = AUDIO_REQ_CS_REQUESTS;
+ AUDIO_Handle->cs_req_state = AUDIO_REQ_GET_VOLUME;
+
+ AUDIO_Handle->temp_feature = AUDIO_Handle->headphone.asociated_feature;
+ AUDIO_Handle->temp_channels = AUDIO_Handle->headphone.asociated_channels;
+ }
+ }
+ else
+ {
+ AUDIO_Handle->req_state = AUDIO_REQ_CS_REQUESTS;
+ AUDIO_Handle->cs_req_state = AUDIO_REQ_GET_VOLUME;
+#if (USBH_USE_OS == 1)
+ osMessagePut ( phost->os_event, USBH_URB_EVENT, 0);
+#endif
+ }
+ break;
+
+ case AUDIO_REQ_CS_REQUESTS:
+ if(USBH_AUDIO_HandleCSRequest (phost) == USBH_OK)
+ {
+ AUDIO_Handle->req_state = AUDIO_REQ_SET_IN_INTERFACE;
+ }
+ break;
+
+ case AUDIO_REQ_SET_IN_INTERFACE:
+ if(AUDIO_Handle->microphone.supported == 1)
+ {
+ req_status = USBH_SetInterface(phost,
+ AUDIO_Handle->microphone.interface,
+ AUDIO_Handle->microphone.AltSettings);
+
+ if(req_status == USBH_OK)
+ {
+ AUDIO_Handle->req_state = AUDIO_REQ_SET_OUT_INTERFACE;
+ }
+ }
+ else
+ {
+ AUDIO_Handle->req_state = AUDIO_REQ_SET_OUT_INTERFACE;
+#if (USBH_USE_OS == 1)
+ osMessagePut ( phost->os_event, USBH_URB_EVENT, 0);
+#endif
+ }
+ break;
+ case AUDIO_REQ_SET_OUT_INTERFACE:
+ if(AUDIO_Handle->headphone.supported == 1)
+ {
+ req_status = USBH_SetInterface(phost,
+ AUDIO_Handle->headphone.interface,
+ AUDIO_Handle->headphone.AltSettings);
+
+ if(req_status == USBH_OK)
+ {
+ AUDIO_Handle->req_state = AUDIO_REQ_IDLE;
+ }
+
+ }
+ else
+ {
+ AUDIO_Handle->req_state = AUDIO_REQ_IDLE;
+#if (USBH_USE_OS == 1)
+ osMessagePut ( phost->os_event, USBH_URB_EVENT, 0);
+#endif
+ }
+ break;
+ case AUDIO_REQ_IDLE:
+ AUDIO_Handle->play_state = AUDIO_PLAYBACK_INIT;
+ phost->pUser(phost, HOST_USER_CLASS_ACTIVE);
+ status = USBH_OK;
+#if (USBH_USE_OS == 1)
+ osMessagePut ( phost->os_event, USBH_CLASS_EVENT, 0);
+#endif
+ default:
+ break;
+ }
+ return status;
+}
+
+/**
+ * @brief USBH_AUDIO_CSRequest
+ * The function is responsible for handling AC Specific requests for a specific feature and channel
+ * for Audio class.
+ * @param phost: Host handle
+ * @retval USBH Status
+ */
+static USBH_StatusTypeDef USBH_AUDIO_CSRequest(USBH_HandleTypeDef *phost, uint8_t feature, uint8_t channel)
+{
+ AUDIO_HandleTypeDef *AUDIO_Handle = phost->pActiveClass->pData;
+ USBH_StatusTypeDef status = USBH_BUSY;
+ USBH_StatusTypeDef req_status = USBH_BUSY;
+
+ /* Switch AUDIO REQ state machine */
+ switch (AUDIO_Handle->cs_req_state)
+ {
+ case AUDIO_REQ_GET_VOLUME:
+ req_status = USBH_AC_GetCur(phost,
+ UAC_FEATURE_UNIT, /* subtype */
+ feature, /* feature */
+ VOLUME_CONTROL, /* Selector */
+ channel, /* channel */
+ 0x02); /* length */
+ if(req_status != USBH_BUSY)
+ {
+ AUDIO_Handle->cs_req_state = AUDIO_REQ_GET_MIN_VOLUME;
+ AUDIO_Handle->headphone.attribute.volume = LE16(&(AUDIO_Handle->mem[0]));
+ }
+ break;
+
+ case AUDIO_REQ_GET_MIN_VOLUME:
+ req_status = USBH_AC_GetMin(phost,
+ UAC_FEATURE_UNIT, /* subtype */
+ feature, /* feature */
+ VOLUME_CONTROL, /* Selector */
+ channel, /* channel */
+ 0x02); /* length */
+ if(req_status != USBH_BUSY)
+ {
+ AUDIO_Handle->cs_req_state = AUDIO_REQ_GET_MAX_VOLUME;
+ AUDIO_Handle->headphone.attribute.volumeMin = LE16(&AUDIO_Handle->mem[0]);
+ }
+ break;
+
+ case AUDIO_REQ_GET_MAX_VOLUME:
+ req_status = USBH_AC_GetMax(phost,
+ UAC_FEATURE_UNIT, /* subtype */
+ feature, /* feature */
+ VOLUME_CONTROL, /* Selector */
+ channel, /* channel */
+ 0x02); /* length */
+ if(req_status != USBH_BUSY)
+ {
+ AUDIO_Handle->cs_req_state = AUDIO_REQ_GET_RESOLUTION;
+ AUDIO_Handle->headphone.attribute.volumeMax = LE16(&AUDIO_Handle->mem[0]);
+
+ if (AUDIO_Handle->headphone.attribute.volumeMax < AUDIO_Handle->headphone.attribute.volumeMin)
+ {
+ AUDIO_Handle->headphone.attribute.volumeMax = 0xFF00;
+ }
+ }
+ break;
+
+ case AUDIO_REQ_GET_RESOLUTION:
+ req_status = USBH_AC_GetRes(phost,
+ UAC_FEATURE_UNIT, /* subtype */
+ feature, /* feature */
+ VOLUME_CONTROL, /* Selector */
+ channel, /* channel */
+ 0x02); /* length */
+ if(req_status != USBH_BUSY)
+ {
+ AUDIO_Handle->cs_req_state = AUDIO_REQ_CS_IDLE;
+ AUDIO_Handle->headphone.attribute.resolution = LE16(&AUDIO_Handle->mem[0]);
+ }
+ break;
+
+
+ case AUDIO_REQ_CS_IDLE:
+ status = USBH_OK;
+ default:
+ break;
+ }
+ return status;
+}
+
+/**
+ * @brief USBH_AUDIO_HandleCSRequest
+ * The function is responsible for handling AC Specific requests for a all features
+ * and associated channels for Audio class.
+ * @param phost: Host handle
+ * @retval USBH Status
+ */
+static USBH_StatusTypeDef USBH_AUDIO_HandleCSRequest(USBH_HandleTypeDef *phost)
+{
+
+ USBH_StatusTypeDef status = USBH_BUSY;
+ USBH_StatusTypeDef cs_status = USBH_BUSY;
+ AUDIO_HandleTypeDef *AUDIO_Handle = phost->pActiveClass->pData;
+
+ cs_status = USBH_AUDIO_CSRequest(phost,
+ AUDIO_Handle->temp_feature,
+ AUDIO_Handle->temp_channels);
+
+ if(cs_status != USBH_BUSY)
+ {
+
+ if(AUDIO_Handle->temp_channels == 1)
+ {
+ AUDIO_Handle->temp_feature = AUDIO_Handle->headphone.asociated_feature;
+ AUDIO_Handle->temp_channels = 0;
+ status = USBH_OK;
+ }
+ else
+ {
+ AUDIO_Handle->temp_channels--;
+ }
+ AUDIO_Handle->cs_req_state = AUDIO_REQ_GET_VOLUME;
+#if (USBH_USE_OS == 1)
+ osMessagePut ( phost->os_event, USBH_URB_EVENT, 0);
+#endif
+ }
+
+ return status;
+}
+
+/**
+ * @brief USBH_AUDIO_Process
+ * The function is for managing state machine for Audio data transfers
+ * @param phost: Host handle
+ * @retval USBH Status
+ */
+static USBH_StatusTypeDef USBH_AUDIO_Process (USBH_HandleTypeDef *phost)
+{
+ USBH_StatusTypeDef status = USBH_BUSY;
+ AUDIO_HandleTypeDef *AUDIO_Handle = phost->pActiveClass->pData;
+
+ if(AUDIO_Handle->headphone.supported == 1)
+ {
+ USBH_AUDIO_OutputStream (phost);
+ }
+
+ if(AUDIO_Handle->microphone.supported == 1)
+ {
+ USBH_AUDIO_InputStream (phost);
+ }
+
+ return status;
+}
+
+/**
+ * @brief USBH_AUDIO_SOFProcess
+ * The function is for managing the SOF callback
+ * @param phost: Host handle
+ * @retval USBH Status
+ */
+static USBH_StatusTypeDef USBH_AUDIO_SOFProcess (USBH_HandleTypeDef *phost)
+{
+ return USBH_OK;
+}
+/**
+ * @brief Find IN Audio Streaming interfaces
+ * @param phost: Host handle
+ * @retval USBH Status
+ */
+static USBH_StatusTypeDef USBH_AUDIO_FindAudioStreamingIN(USBH_HandleTypeDef *phost)
+{
+ uint8_t interface, alt_settings;
+ USBH_StatusTypeDef status = USBH_FAIL ;
+ AUDIO_HandleTypeDef *AUDIO_Handle;
+
+ AUDIO_Handle = phost->pActiveClass->pData;
+
+ /* Look For AUDIOSTREAMING IN interface */
+ alt_settings = 0;
+ for (interface = 0; interface < USBH_MAX_NUM_INTERFACES ; interface ++ )
+ {
+ if((phost->device.CfgDesc.Itf_Desc[interface].bInterfaceClass == AC_CLASS)&&
+ (phost->device.CfgDesc.Itf_Desc[interface].bInterfaceSubClass == USB_SUBCLASS_AUDIOSTREAMING))
+ {
+ if((phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[0].bEndpointAddress & 0x80)&&
+ (phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[0].wMaxPacketSize > 0))
+ {
+ AUDIO_Handle->stream_in[alt_settings].Ep = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[0].bEndpointAddress;
+ AUDIO_Handle->stream_in[alt_settings].EpSize = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[0].wMaxPacketSize;
+ AUDIO_Handle->stream_in[alt_settings].interface = phost->device.CfgDesc.Itf_Desc[interface].bInterfaceNumber;
+ AUDIO_Handle->stream_in[alt_settings].AltSettings = phost->device.CfgDesc.Itf_Desc[interface].bAlternateSetting;
+ AUDIO_Handle->stream_in[alt_settings].Poll = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[0].bInterval;
+ AUDIO_Handle->stream_in[alt_settings].valid = 1;
+ alt_settings++;
+ }
+ }
+ }
+
+ if(alt_settings > 0)
+ {
+ status = USBH_OK;
+ }
+
+ return status;
+}
+
+/**
+ * @brief Find OUT Audio Streaming interfaces
+ * @param phost: Host handle
+ * @retval USBH Status
+ */
+static USBH_StatusTypeDef USBH_AUDIO_FindAudioStreamingOUT(USBH_HandleTypeDef *phost)
+{
+ uint8_t interface, alt_settings;
+ USBH_StatusTypeDef status = USBH_FAIL ;
+ AUDIO_HandleTypeDef *AUDIO_Handle;
+
+ AUDIO_Handle = phost->pActiveClass->pData;
+
+ /* Look For AUDIOSTREAMING IN interface */
+ alt_settings = 0;
+ for (interface = 0; interface < USBH_MAX_NUM_INTERFACES ; interface ++ )
+ {
+ if((phost->device.CfgDesc.Itf_Desc[interface].bInterfaceClass == AC_CLASS)&&
+ (phost->device.CfgDesc.Itf_Desc[interface].bInterfaceSubClass == USB_SUBCLASS_AUDIOSTREAMING))
+ {
+ if(((phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[0].bEndpointAddress & 0x80) == 0x00)&&
+ (phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[0].wMaxPacketSize > 0))
+ {
+ AUDIO_Handle->stream_out[alt_settings].Ep = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[0].bEndpointAddress;
+ AUDIO_Handle->stream_out[alt_settings].EpSize = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[0].wMaxPacketSize;
+ AUDIO_Handle->stream_out[alt_settings].interface = phost->device.CfgDesc.Itf_Desc[interface].bInterfaceNumber;
+ AUDIO_Handle->stream_out[alt_settings].AltSettings = phost->device.CfgDesc.Itf_Desc[interface].bAlternateSetting;
+ AUDIO_Handle->stream_out[alt_settings].Poll = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[0].bInterval;
+ AUDIO_Handle->stream_out[alt_settings].valid = 1;
+ alt_settings++;
+ }
+ }
+ }
+
+ if(alt_settings > 0)
+ {
+ status = USBH_OK;
+ }
+
+ return status;
+}
+
+/**
+ * @brief Find HID Control interfaces
+ * @param phost: Host handle
+ * @retval USBH Status
+ */
+static USBH_StatusTypeDef USBH_AUDIO_FindHIDControl(USBH_HandleTypeDef *phost)
+{
+ uint8_t interface;
+ USBH_StatusTypeDef status = USBH_FAIL ;
+ AUDIO_HandleTypeDef *AUDIO_Handle;
+
+ AUDIO_Handle = phost->pActiveClass->pData;
+
+ /* Look For AUDIOCONTROL interface */
+ interface = USBH_FindInterface(phost, AC_CLASS, USB_SUBCLASS_AUDIOCONTROL, 0xFF);
+ if(interface != 0xFF)
+ {
+ for (interface = 0; interface < USBH_MAX_NUM_INTERFACES ; interface ++ )
+ {
+ if((phost->device.CfgDesc.Itf_Desc[interface].bInterfaceClass == 0x03)&& /*HID*/
+ (phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[0].wMaxPacketSize > 0))
+ {
+ if((phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[0].bEndpointAddress & 0x80) == 0x80)
+ {
+ AUDIO_Handle->control.Ep = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[0].bEndpointAddress;
+ AUDIO_Handle->control.EpSize = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[0].wMaxPacketSize;
+ AUDIO_Handle->control.interface = phost->device.CfgDesc.Itf_Desc[interface].bInterfaceNumber;
+ AUDIO_Handle->control.Poll = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[0].bInterval;
+ AUDIO_Handle->control.supported = 1;
+ status = USBH_OK;
+ break;
+ }
+ }
+ }
+ }
+ return status;
+}
+
+/**
+ * @brief Parse AC and interfaces Descriptors
+ * @param phost: Host handle
+ * @retval USBH Status
+ */
+static USBH_StatusTypeDef USBH_AUDIO_ParseCSDescriptors(USBH_HandleTypeDef *phost)
+{
+ USBH_DescHeader_t *pdesc ;
+ uint16_t ptr;
+ int8_t itf_index = 0;
+ int8_t itf_number = 0;
+ int8_t alt_setting;
+ AUDIO_HandleTypeDef *AUDIO_Handle;
+
+ AUDIO_Handle = phost->pActiveClass->pData;
+ pdesc = (USBH_DescHeader_t *)(phost->device.CfgDesc_Raw);
+ ptr = USB_LEN_CFG_DESC;
+
+ AUDIO_Handle->class_desc.FeatureUnitNum = 0;
+ AUDIO_Handle->class_desc.InputTerminalNum = 0;
+ AUDIO_Handle->class_desc.OutputTerminalNum = 0;
+ AUDIO_Handle->class_desc.ASNum = 0;
+
+ while(ptr < phost->device.CfgDesc.wTotalLength)
+ {
+ pdesc = USBH_GetNextDesc((void *)pdesc, &ptr);
+
+ switch (pdesc->bDescriptorType)
+ {
+
+ case USB_DESC_TYPE_INTERFACE:
+ itf_number = *((uint8_t *)pdesc + 2);
+ alt_setting = *((uint8_t *)pdesc + 3);
+ itf_index = USBH_FindInterfaceIndex (phost, itf_number, alt_setting);
+ break;
+
+ case USB_DESC_TYPE_CS_INTERFACE:
+ if(itf_number <= phost->device.CfgDesc.bNumInterfaces)
+ {
+
+ ParseCSDescriptors(&AUDIO_Handle->class_desc,
+ phost->device.CfgDesc.Itf_Desc[itf_index].bInterfaceSubClass,
+ (uint8_t *)pdesc);
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ return USBH_OK;
+}
+
+/**
+ * @brief Parse AC interfaces
+ * @param phost: Host handle
+ * @retval USBH Status
+ */
+static USBH_StatusTypeDef ParseCSDescriptors(AUDIO_ClassSpecificDescTypedef *class_desc,
+ uint8_t ac_subclass,
+ uint8_t *pdesc)
+{
+ if(ac_subclass == USB_SUBCLASS_AUDIOCONTROL)
+ {
+ switch(pdesc[2])
+ {
+ case UAC_HEADER:
+ class_desc->cs_desc.HeaderDesc = (AUDIO_HeaderDescTypeDef *)pdesc;
+ break;
+
+ case UAC_INPUT_TERMINAL:
+ class_desc->cs_desc.InputTerminalDesc[class_desc->InputTerminalNum++] = (AUDIO_ITDescTypeDef*) pdesc;
+ break;
+
+ case UAC_OUTPUT_TERMINAL:
+ class_desc->cs_desc.OutputTerminalDesc[class_desc->OutputTerminalNum++] = (AUDIO_OTDescTypeDef*) pdesc;
+ break;
+
+ case UAC_FEATURE_UNIT:
+ class_desc->cs_desc.FeatureUnitDesc[class_desc->FeatureUnitNum++] = (AUDIO_FeatureDescTypeDef*) pdesc;
+ break;
+
+ case UAC_SELECTOR_UNIT:
+ class_desc->cs_desc.SelectorUnitDesc[class_desc->SelectorUnitNum++] = (AUDIO_SelectorDescTypeDef*) pdesc;
+ break;
+
+ case UAC_MIXER_UNIT:
+ class_desc->cs_desc.MixerUnitDesc[class_desc->MixerUnitNum++] = (AUDIO_MixerDescTypeDef*) pdesc;
+ break;
+
+ default:
+ break;
+ }
+ }
+ else if(ac_subclass == USB_SUBCLASS_AUDIOSTREAMING)
+ {
+ switch(pdesc[2])
+ {
+ case UAC_AS_GENERAL:
+ class_desc->as_desc[class_desc->ASNum].GeneralDesc = (AUDIO_ASGeneralDescTypeDef*) pdesc;
+ break;
+ case UAC_FORMAT_TYPE:
+ class_desc->as_desc[class_desc->ASNum++].FormatTypeDesc = (AUDIO_ASFormatTypeDescTypeDef*) pdesc;
+ break;
+ default:
+ break;
+ }
+ }
+
+ return USBH_OK;
+}
+
+
+/**
+ * @brief Link a Unit to next associated one
+ * @param phost: Host handle
+ * @param UnitID: Unit identifer
+ * @retval UnitID, Index and Type of the assicated Unit
+ */
+static int32_t USBH_AUDIO_FindLinkedUnit(USBH_HandleTypeDef *phost, uint8_t UnitID)
+{
+ uint8_t Index;
+ AUDIO_HandleTypeDef *AUDIO_Handle;
+
+ AUDIO_Handle = phost->pActiveClass->pData;
+
+ /* Find Feature Unit */
+ for(Index = 0; Index < AUDIO_Handle->class_desc.FeatureUnitNum; Index ++)
+ {
+ if(AUDIO_Handle->class_desc.cs_desc.FeatureUnitDesc[Index]->bSourceID == UnitID)
+ {
+ UnitID = AUDIO_Handle->class_desc.cs_desc.FeatureUnitDesc[Index]->bUnitID;
+
+ return ((UnitID << 16) | (UAC_FEATURE_UNIT << 8) | Index);
+ }
+ }
+
+ /* Find Mixer Unit */
+ for(Index = 0; Index < AUDIO_Handle->class_desc.MixerUnitNum; Index ++)
+ {
+ if((AUDIO_Handle->class_desc.cs_desc.MixerUnitDesc[Index]->bSourceID0 == UnitID)||
+ (AUDIO_Handle->class_desc.cs_desc.MixerUnitDesc[Index]->bSourceID1 == UnitID))
+ {
+ UnitID = AUDIO_Handle->class_desc.cs_desc.MixerUnitDesc[Index]->bUnitID;
+
+ return ((UnitID << 16) | (UAC_MIXER_UNIT << 8) | Index);
+ }
+ }
+
+
+ /* Find Selector Unit */
+ for(Index = 0; Index < AUDIO_Handle->class_desc.SelectorUnitNum; Index ++)
+ {
+ if(AUDIO_Handle->class_desc.cs_desc.SelectorUnitDesc[Index]->bSourceID0 == UnitID)
+ {
+ UnitID = AUDIO_Handle->class_desc.cs_desc.SelectorUnitDesc[Index]->bUnitID;
+
+ return ((UnitID << 16) | (UAC_SELECTOR_UNIT << 8) | Index);
+ }
+ }
+
+
+ /* Find OT Unit */
+ for(Index = 0; Index < AUDIO_Handle->class_desc.OutputTerminalNum; Index ++)
+ {
+ if(AUDIO_Handle->class_desc.cs_desc.OutputTerminalDesc[Index]->bSourceID == UnitID)
+ {
+ UnitID = AUDIO_Handle->class_desc.cs_desc.OutputTerminalDesc[Index]->bTerminalID;
+
+ return ((UnitID << 16) | (UAC_OUTPUT_TERMINAL << 8) | Index);
+ }
+ }
+
+ /* No associated Unit found */
+ return -1;
+}
+
+/**
+ * @brief Build full path for Microphone device
+ * @param phost: Host handle
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_AUDIO_BuildMicrophonePath(USBH_HandleTypeDef *phost)
+{
+ uint8_t UnitID = 0, Type, Index;
+ uint32_t value;
+ uint8_t terminalIndex;
+ AUDIO_HandleTypeDef *AUDIO_Handle;
+
+ AUDIO_Handle = phost->pActiveClass->pData;
+
+ /*Find microphone IT*/
+ for(terminalIndex = 0; terminalIndex < AUDIO_Handle->class_desc.InputTerminalNum; terminalIndex++)
+ {
+ if(LE16(AUDIO_Handle->class_desc.cs_desc.InputTerminalDesc[terminalIndex]->wTerminalType) == 0x201)
+ {
+ UnitID = AUDIO_Handle->class_desc.cs_desc.InputTerminalDesc[terminalIndex]->bTerminalID;
+ AUDIO_Handle->microphone.asociated_channels = AUDIO_Handle->class_desc.cs_desc.InputTerminalDesc[terminalIndex]->bNrChannels;
+ break;
+ }
+ }
+
+ do
+ {
+ value = USBH_AUDIO_FindLinkedUnit(phost, UnitID);
+ Index = value & 0xFF;
+ Type = (value >> 8) & 0xFF;
+ UnitID = (value >> 16) & 0xFF;
+
+ switch (Type)
+ {
+ case UAC_FEATURE_UNIT:
+ AUDIO_Handle->microphone.asociated_feature = Index;
+ break;
+
+ case UAC_MIXER_UNIT:
+ AUDIO_Handle->microphone.asociated_mixer = Index;
+ break;
+
+ case UAC_SELECTOR_UNIT:
+ AUDIO_Handle->microphone.asociated_selector = Index;
+ break;
+
+ case UAC_OUTPUT_TERMINAL:
+ AUDIO_Handle->microphone.asociated_terminal = Index;
+ break;
+ }
+ }
+ while ((Type != UAC_OUTPUT_TERMINAL) && (value > 0));
+
+
+
+ return USBH_OK;
+}
+
+/**
+ * @brief Build full path for Headphone device
+ * @param phost: Host handle
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_AUDIO_BuildHeadphonePath(USBH_HandleTypeDef *phost)
+{
+ uint8_t UnitID = 0, Type, Index;
+ uint32_t value;
+ uint8_t terminalIndex;
+ AUDIO_HandleTypeDef *AUDIO_Handle;
+
+ AUDIO_Handle = phost->pActiveClass->pData;
+
+ /*Find association betwen audio streaming and microphone*/
+ for(terminalIndex = 0; terminalIndex < AUDIO_Handle->class_desc.InputTerminalNum; terminalIndex++)
+ {
+ if(LE16(AUDIO_Handle->class_desc.cs_desc.InputTerminalDesc[terminalIndex]->wTerminalType) == 0x101)
+ {
+ UnitID = AUDIO_Handle->class_desc.cs_desc.InputTerminalDesc[terminalIndex]->bTerminalID;
+ AUDIO_Handle->headphone.asociated_channels = AUDIO_Handle->class_desc.cs_desc.InputTerminalDesc[terminalIndex]->bNrChannels;
+ break;
+ }
+ }
+
+ for(Index = 0; Index < AUDIO_Handle->class_desc.ASNum; Index++)
+ {
+ if(AUDIO_Handle->class_desc.as_desc[Index].GeneralDesc->bTerminalLink == UnitID)
+ {
+ AUDIO_Handle->headphone.asociated_as = Index;
+ break;
+ }
+ }
+
+ do
+ {
+ value = USBH_AUDIO_FindLinkedUnit(phost, UnitID);
+ Index = value & 0xFF;
+ Type = (value >> 8) & 0xFF;
+ UnitID = (value >> 16) & 0xFF;
+
+ switch (Type)
+ {
+ case UAC_FEATURE_UNIT:
+ AUDIO_Handle->headphone.asociated_feature = Index;
+ break;
+
+ case UAC_MIXER_UNIT:
+ AUDIO_Handle->headphone.asociated_mixer = Index;
+ break;
+
+ case UAC_SELECTOR_UNIT:
+ AUDIO_Handle->headphone.asociated_selector = Index;
+ break;
+
+ case UAC_OUTPUT_TERMINAL:
+ AUDIO_Handle->headphone.asociated_terminal = Index;
+ if(LE16(AUDIO_Handle->class_desc.cs_desc.OutputTerminalDesc[Index]->wTerminalType) != 0x103)
+ {
+ return USBH_OK;
+ }
+ break;
+ }
+ }
+ while ((Type != UAC_OUTPUT_TERMINAL) && (value > 0));
+
+ return USBH_FAIL;
+}
+
+
+/**
+ * @brief Handle Set Cur request
+ * @param phost: Host handle
+ * @param subtype: subtype index
+ * @param feature: feature index
+ * @param controlSelector: control code
+ * @param channel: channel index
+ * @param length: Command length
+ * @retval USBH Status
+ */
+static USBH_StatusTypeDef USBH_AC_SetCur(USBH_HandleTypeDef *phost,
+ uint8_t subtype,
+ uint8_t feature,
+ uint8_t controlSelector,
+ uint8_t channel,
+ uint16_t length)
+{
+ uint16_t wValue,wIndex,wLength;
+ uint8_t UnitID,InterfaceNum;
+ AUDIO_HandleTypeDef *AUDIO_Handle;
+ AUDIO_Handle = phost->pActiveClass->pData;
+
+ switch(subtype)
+ {
+ case UAC_INPUT_TERMINAL:
+ UnitID = AUDIO_Handle->class_desc.cs_desc.InputTerminalDesc[0]->bTerminalID;
+ InterfaceNum = 0; /*Always zero Control Interface */
+ wIndex = ( UnitID << 8 ) | InterfaceNum ;
+ wValue = (COPY_PROTECT_CONTROL << 8 ) ;
+ AUDIO_Handle->mem[0] = 0x00;
+
+ wLength = 1;
+ break;
+ case UAC_FEATURE_UNIT:
+ UnitID = AUDIO_Handle->class_desc.cs_desc.FeatureUnitDesc[feature]->bUnitID;
+ InterfaceNum = 0; /*Always zero Control Interface */
+ wIndex = ( UnitID << 8 ) | InterfaceNum ;
+ /*holds the CS(control selector ) and CN (channel number)*/
+ wValue = (controlSelector << 8) | channel;
+ wLength = length;
+ break;
+ }
+
+ phost->Control.setup.b.bmRequestType = USB_H2D | USB_REQ_RECIPIENT_INTERFACE | \
+ USB_REQ_TYPE_CLASS;
+
+ phost->Control.setup.b.bRequest = UAC_SET_CUR;
+ phost->Control.setup.b.wValue.w = wValue;
+ phost->Control.setup.b.wIndex.w = wIndex;
+ phost->Control.setup.b.wLength.w = wLength;
+
+ return(USBH_CtlReq(phost, (uint8_t *)(AUDIO_Handle->mem) , wLength ));
+
+}
+
+/**
+ * @brief Handle Get Cur request
+ * @param phost: Host handle
+ * @param subtype: subtype index
+ * @param feature: feature index
+ * @param controlSelector: control code
+ * @param channel: channel index
+ * @param length: Command length
+ * @retval USBH Status
+ */
+static USBH_StatusTypeDef USBH_AC_GetCur(USBH_HandleTypeDef *phost,
+ uint8_t subtype,
+ uint8_t feature,
+ uint8_t controlSelector,
+ uint8_t channel,
+ uint16_t length)
+{
+ uint16_t wValue = 0, wIndex = 0,wLength = 0;
+ uint8_t UnitID = 0, InterfaceNum = 0;
+ AUDIO_HandleTypeDef *AUDIO_Handle;
+ AUDIO_Handle = phost->pActiveClass->pData;
+
+ switch(subtype)
+ {
+ case UAC_INPUT_TERMINAL:
+ UnitID = AUDIO_Handle->class_desc.cs_desc.InputTerminalDesc[0]->bTerminalID;
+ InterfaceNum = 0; /*Always zero Control Interface */
+ wIndex = ( UnitID << 8 ) | InterfaceNum ;
+ wValue = (COPY_PROTECT_CONTROL << 8 ) ;
+ AUDIO_Handle->mem[0] = 0x00;
+
+ wLength = 1;
+ break;
+ case UAC_FEATURE_UNIT:
+ UnitID = AUDIO_Handle->class_desc.cs_desc.FeatureUnitDesc[feature]->bUnitID;
+ InterfaceNum = 0; /*Always zero Control Interface */
+ wIndex = ( UnitID << 8 ) | InterfaceNum ;
+ /*holds the CS(control selector ) and CN (channel number)*/
+ wValue = (controlSelector << 8) | channel;
+ wLength = length;
+ break;
+
+ case UAC_OUTPUT_TERMINAL:
+ UnitID = AUDIO_Handle->class_desc.cs_desc.OutputTerminalDesc[0]->bTerminalID;
+ InterfaceNum = 0; /*Always zero Control Interface */
+ wIndex = ( UnitID << 8 ) | InterfaceNum ;
+ wValue = (COPY_PROTECT_CONTROL << 8 ) ;
+ wLength = 1;
+ break;
+ }
+
+ phost->Control.setup.b.bmRequestType = USB_D2H | USB_REQ_RECIPIENT_INTERFACE | \
+ USB_REQ_TYPE_CLASS;
+
+ phost->Control.setup.b.bRequest = UAC_GET_CUR;
+ phost->Control.setup.b.wValue.w = wValue;
+ phost->Control.setup.b.wIndex.w = wIndex;
+ phost->Control.setup.b.wLength.w = wLength;
+
+ return(USBH_CtlReq(phost, (uint8_t *)(AUDIO_Handle->mem) , wLength ));
+
+}
+
+
+/**
+ * @brief Handle Get Max request
+ * @param phost: Host handle
+ * @param subtype: subtype index
+ * @param feature: feature index
+ * @param controlSelector: control code
+ * @param channel: channel index
+ * @param length: Command length
+ * @retval USBH Status
+ */
+static USBH_StatusTypeDef USBH_AC_GetMax(USBH_HandleTypeDef *phost,
+ uint8_t subtype,
+ uint8_t feature,
+ uint8_t controlSelector,
+ uint8_t channel,
+ uint16_t length)
+{
+ uint16_t wValue = 0, wIndex = 0, wLength = 0;
+ uint8_t UnitID = 0, InterfaceNum = 0;
+ AUDIO_HandleTypeDef *AUDIO_Handle;
+ AUDIO_Handle = phost->pActiveClass->pData;
+
+ switch(subtype)
+ {
+ case UAC_INPUT_TERMINAL:
+ UnitID = AUDIO_Handle->class_desc.cs_desc.InputTerminalDesc[0]->bTerminalID;
+ InterfaceNum = 0; /*Always zero Control Interface */
+ wIndex = ( UnitID << 8 ) | InterfaceNum ;
+ wValue = (COPY_PROTECT_CONTROL << 8 ) ;
+ AUDIO_Handle->mem[0] = 0x00;
+
+ wLength = 1;
+ break;
+ case UAC_FEATURE_UNIT:
+ UnitID = AUDIO_Handle->class_desc.cs_desc.FeatureUnitDesc[feature]->bUnitID;
+ InterfaceNum = 0; /*Always zero Control Interface */
+ wIndex = ( UnitID << 8 ) | InterfaceNum ;
+ /*holds the CS(control selector ) and CN (channel number)*/
+ wValue = (controlSelector << 8) | channel;
+ wLength = length;
+ break;
+
+ case UAC_OUTPUT_TERMINAL:
+ UnitID = AUDIO_Handle->class_desc.cs_desc.OutputTerminalDesc[0]->bTerminalID;
+ InterfaceNum = 0; /*Always zero Control Interface */
+ wIndex = ( UnitID << 8 ) | InterfaceNum ;
+ wValue = (COPY_PROTECT_CONTROL << 8 ) ;
+ wLength = 1;
+ break;
+ }
+
+ phost->Control.setup.b.bmRequestType = USB_D2H | USB_REQ_RECIPIENT_INTERFACE | \
+ USB_REQ_TYPE_CLASS;
+
+ phost->Control.setup.b.bRequest = UAC_GET_MAX;
+ phost->Control.setup.b.wValue.w = wValue;
+ phost->Control.setup.b.wIndex.w = wIndex;
+ phost->Control.setup.b.wLength.w = wLength;
+
+ return(USBH_CtlReq(phost, (uint8_t *)(AUDIO_Handle->mem) , wLength ));
+
+}
+
+
+
+/**
+ * @brief Handle Get Res request
+ * @param phost: Host handle
+ * @param subtype: subtype index
+ * @param feature: feature index
+ * @param controlSelector: control code
+ * @param channel: channel index
+ * @param length: Command length
+ * @retval USBH Status
+ */
+static USBH_StatusTypeDef USBH_AC_GetRes(USBH_HandleTypeDef *phost,
+ uint8_t subtype,
+ uint8_t feature,
+ uint8_t controlSelector,
+ uint8_t channel,
+ uint16_t length)
+{
+ uint16_t wValue = 0, wIndex = 0, wLength = 0;
+ uint8_t UnitID = 0, InterfaceNum = 0;
+ AUDIO_HandleTypeDef *AUDIO_Handle;
+ AUDIO_Handle = phost->pActiveClass->pData;
+
+ switch(subtype)
+ {
+ case UAC_INPUT_TERMINAL:
+ UnitID = AUDIO_Handle->class_desc.cs_desc.InputTerminalDesc[0]->bTerminalID;
+ InterfaceNum = 0; /*Always zero Control Interface */
+ wIndex = ( UnitID << 8 ) | InterfaceNum ;
+ wValue = (COPY_PROTECT_CONTROL << 8 ) ;
+ AUDIO_Handle->mem[0] = 0x00;
+
+ wLength = 1;
+ break;
+ case UAC_FEATURE_UNIT:
+ UnitID = AUDIO_Handle->class_desc.cs_desc.FeatureUnitDesc[feature]->bUnitID;
+ InterfaceNum = 0; /*Always zero Control Interface */
+ wIndex = ( UnitID << 8 ) | InterfaceNum ;
+ /*holds the CS(control selector ) and CN (channel number)*/
+ wValue = (controlSelector << 8) | channel;
+ wLength = length;
+ break;
+
+ case UAC_OUTPUT_TERMINAL:
+ UnitID = AUDIO_Handle->class_desc.cs_desc.OutputTerminalDesc[0]->bTerminalID;
+ InterfaceNum = 0; /*Always zero Control Interface */
+ wIndex = ( UnitID << 8 ) | InterfaceNum ;
+ wValue = (COPY_PROTECT_CONTROL << 8 ) ;
+ wLength = 1;
+ break;
+ }
+
+ phost->Control.setup.b.bmRequestType = USB_D2H | USB_REQ_RECIPIENT_INTERFACE | \
+ USB_REQ_TYPE_CLASS;
+
+ phost->Control.setup.b.bRequest = UAC_GET_RES;
+ phost->Control.setup.b.wValue.w = wValue;
+ phost->Control.setup.b.wIndex.w = wIndex;
+ phost->Control.setup.b.wLength.w = wLength;
+
+ return(USBH_CtlReq(phost, (uint8_t *)(AUDIO_Handle->mem) , wLength ));
+
+}
+
+/**
+ * @brief Handle Get Min request
+ * @param phost: Host handle
+ * @param subtype: subtype index
+ * @param feature: feature index
+ * @param controlSelector: control code
+ * @param channel: channel index
+ * @param length: Command length
+ * @retval USBH Status
+ */
+static USBH_StatusTypeDef USBH_AC_GetMin(USBH_HandleTypeDef *phost,
+ uint8_t subtype,
+ uint8_t feature,
+ uint8_t controlSelector,
+ uint8_t channel,
+ uint16_t length)
+{
+ uint16_t wValue = 0, wIndex = 0, wLength = 0;
+ uint8_t UnitID = 0, InterfaceNum = 0;
+ AUDIO_HandleTypeDef *AUDIO_Handle;
+ AUDIO_Handle = phost->pActiveClass->pData;
+
+ switch(subtype)
+ {
+ case UAC_INPUT_TERMINAL:
+ UnitID = AUDIO_Handle->class_desc.cs_desc.InputTerminalDesc[0]->bTerminalID;
+ InterfaceNum = 0; /*Always zero Control Interface */
+ wIndex = ( UnitID << 8 ) | InterfaceNum ;
+ wValue = (COPY_PROTECT_CONTROL << 8 ) ;
+ AUDIO_Handle->mem[0] = 0x00;
+
+ wLength = 1;
+ break;
+ case UAC_FEATURE_UNIT:
+ UnitID = AUDIO_Handle->class_desc.cs_desc.FeatureUnitDesc[feature]->bUnitID;
+ InterfaceNum = 0; /*Always zero Control Interface */
+ wIndex = ( UnitID << 8 ) | InterfaceNum ;
+ /*holds the CS(control selector ) and CN (channel number)*/
+ wValue = (controlSelector << 8) | channel;
+ wLength = length;
+ break;
+
+ case UAC_OUTPUT_TERMINAL:
+ UnitID = AUDIO_Handle->class_desc.cs_desc.OutputTerminalDesc[0]->bTerminalID;
+ InterfaceNum = 0; /*Always zero Control Interface */
+ wIndex = ( UnitID << 8 ) | InterfaceNum ;
+ wValue = (COPY_PROTECT_CONTROL << 8 ) ;
+ wLength = 1;
+ break;
+ }
+
+ phost->Control.setup.b.bmRequestType = USB_D2H | USB_REQ_RECIPIENT_INTERFACE | \
+ USB_REQ_TYPE_CLASS;
+
+ phost->Control.setup.b.bRequest = UAC_GET_MIN;
+ phost->Control.setup.b.wValue.w = wValue;
+ phost->Control.setup.b.wIndex.w = wIndex;
+ phost->Control.setup.b.wLength.w = wLength;
+
+ return(USBH_CtlReq(phost, (uint8_t *)(AUDIO_Handle->mem) , wLength ));
+
+}
+
+/**
+ * @brief Handle Set Endpoint Controls Request
+ * @param phost: Host handle
+ * @param Ep: Endpoint address
+ * @param buf: pointer to data
+ * @retval USBH Status
+ */
+static USBH_StatusTypeDef USBH_AUDIO_SetEndpointControls(USBH_HandleTypeDef *phost,
+ uint8_t Ep,
+ uint8_t *buff)
+{
+ uint16_t wValue, wIndex, wLength;
+
+
+ wValue = SAMPLING_FREQ_CONTROL << 8;
+ wIndex = Ep;
+ wLength = 3; /*length of the frequency parameter*/
+
+ phost->Control.setup.b.bmRequestType = USB_H2D | USB_REQ_RECIPIENT_ENDPOINT | \
+ USB_REQ_TYPE_CLASS;
+
+ phost->Control.setup.b.bRequest = UAC_SET_CUR;
+ phost->Control.setup.b.wValue.w = wValue;
+ phost->Control.setup.b.wIndex.w = wIndex;
+ phost->Control.setup.b.wLength.w = wLength;
+
+ return(USBH_CtlReq(phost, (uint8_t *)buff, wLength ));
+
+}
+
+/**
+ * @brief Handle Input stream process
+ * @param phost: Host handle
+ * @retval USBH Status
+ */
+static USBH_StatusTypeDef USBH_AUDIO_InputStream (USBH_HandleTypeDef *phost)
+{
+ USBH_StatusTypeDef status = USBH_BUSY ;
+
+ return status;
+}
+
+/**
+ * @brief Handle HID Control process
+ * @param phost: Host handle
+ * @retval USBH Status
+ */
+static USBH_StatusTypeDef USBH_AUDIO_Control (USBH_HandleTypeDef *phost)
+{
+ USBH_StatusTypeDef status = USBH_BUSY ;
+ AUDIO_HandleTypeDef *AUDIO_Handle = phost->pActiveClass->pData;
+ uint16_t attribute = 0;
+
+
+ switch(AUDIO_Handle->control_state)
+ {
+ case AUDIO_CONTROL_INIT:
+ if((phost->Timer & 1) == 0)
+ {
+ AUDIO_Handle->control.timer = phost->Timer;
+ USBH_InterruptReceiveData(phost,
+ (uint8_t *)(AUDIO_Handle->mem),
+ AUDIO_Handle->control.EpSize,
+ AUDIO_Handle->control.Pipe);
+
+ AUDIO_Handle->temp_feature = AUDIO_Handle->headphone.asociated_feature;
+ AUDIO_Handle->temp_channels = AUDIO_Handle->headphone.asociated_channels;
+
+ AUDIO_Handle->control_state = AUDIO_CONTROL_CHANGE ;
+ }
+ break;
+ case AUDIO_CONTROL_CHANGE:
+ if(USBH_LL_GetURBState(phost , AUDIO_Handle->control.Pipe) == USBH_URB_DONE)
+ {
+ attribute = LE16(&AUDIO_Handle->mem[0]);
+ if(USBH_AUDIO_SetControlAttribute (phost, attribute) == USBH_BUSY)
+ {
+ break;
+ }
+ }
+
+ if(( phost->Timer - AUDIO_Handle->control.timer) >= AUDIO_Handle->control.Poll)
+ {
+ AUDIO_Handle->control.timer = phost->Timer;
+
+ USBH_InterruptReceiveData(phost,
+ (uint8_t *)(AUDIO_Handle->mem),
+ AUDIO_Handle->control.EpSize,
+ AUDIO_Handle->control.Pipe);
+
+ }
+ break;
+
+ case AUDIO_CONTROL_VOLUME_UP:
+ if( USBH_AUDIO_SetControlAttribute (phost, 1) == USBH_OK)
+ {
+ AUDIO_Handle->control_state = AUDIO_CONTROL_INIT;
+ status = USBH_OK;
+ }
+ break;
+
+ case AUDIO_CONTROL_VOLUME_DOWN:
+ if( USBH_AUDIO_SetControlAttribute (phost, 2) == USBH_OK)
+ {
+ AUDIO_Handle->control_state = AUDIO_CONTROL_INIT;
+ status = USBH_OK;
+ }
+ break;
+
+ case AUDIO_CONTROL_IDLE:
+ default:
+ break;
+ }
+
+ return status;
+}
+
+/**
+ * @brief Handle Output stream process
+ * @param phost: Host handle
+ * @retval USBH Status
+ */
+static USBH_StatusTypeDef USBH_AUDIO_OutputStream (USBH_HandleTypeDef *phost)
+{
+ USBH_StatusTypeDef status = USBH_BUSY ;
+ AUDIO_HandleTypeDef *AUDIO_Handle = phost->pActiveClass->pData;
+ uint8_t *buff;
+
+
+ switch(AUDIO_Handle->play_state)
+ {
+ case AUDIO_PLAYBACK_INIT:
+
+ if( AUDIO_Handle->class_desc.as_desc[AUDIO_Handle->headphone.asociated_as].FormatTypeDesc->bSamFreqType == 0)
+ {
+ AUDIO_Handle->play_state = AUDIO_PLAYBACK_SET_EP_FREQ;
+ }
+ else
+ {
+ AUDIO_Handle->play_state = AUDIO_PLAYBACK_SET_EP;
+ }
+#if (USBH_USE_OS == 1)
+ osMessagePut ( phost->os_event, USBH_URB_EVENT, 0);
+#endif
+ break;
+
+ case AUDIO_PLAYBACK_SET_EP_FREQ:
+
+ buff = (uint8_t*)AUDIO_Handle->class_desc.as_desc[AUDIO_Handle->headphone.asociated_as].FormatTypeDesc->tSamFreq[0];
+
+ status = USBH_AUDIO_SetEndpointControls(phost, AUDIO_Handle->headphone.Ep, buff);
+ if(status == USBH_OK)
+ {
+ AUDIO_Handle->play_state = AUDIO_PLAYBACK_IDLE;
+ }
+ break;
+
+ case AUDIO_PLAYBACK_SET_EP:
+ buff = (uint8_t *)&AUDIO_Handle->headphone.frequency;
+ status = USBH_AUDIO_SetEndpointControls(phost,AUDIO_Handle->headphone.Ep, buff);
+ if(status == USBH_OK)
+ {
+ AUDIO_Handle->play_state = AUDIO_PLAYBACK_IDLE;
+ USBH_AUDIO_FrequencySet(phost);
+ }
+ break;
+ case AUDIO_PLAYBACK_IDLE:
+#if (USBH_USE_OS == 1)
+ osMessagePut ( phost->os_event, USBH_CLASS_EVENT, 0);
+#endif
+ status = USBH_OK;
+ break;
+
+ case AUDIO_PLAYBACK_PLAY:
+ USBH_AUDIO_Transmit(phost);
+ status = USBH_OK;
+ break;
+
+ default:
+ break;
+ }
+
+ return status;
+}
+
+/**
+ * @brief Handle Transmission process
+ * @param phost: Host handle
+ * @retval USBH Status
+ */
+static USBH_StatusTypeDef USBH_AUDIO_Transmit (USBH_HandleTypeDef *phost)
+{
+ USBH_StatusTypeDef status = USBH_BUSY ;
+ AUDIO_HandleTypeDef *AUDIO_Handle = phost->pActiveClass->pData;
+
+ switch(AUDIO_Handle->processing_state)
+ {
+ case AUDIO_DATA_START_OUT:
+ /* Sync with start of Even Frame */
+ if((phost->Timer & 1) == 0)
+ {
+ AUDIO_Handle->headphone.timer = phost->Timer;
+ AUDIO_Handle->processing_state = AUDIO_DATA_OUT;
+ USBH_IsocSendData(phost,
+ AUDIO_Handle->headphone.buf,
+ AUDIO_Handle->headphone.frame_length,
+ AUDIO_Handle->headphone.Pipe);
+
+ AUDIO_Handle->headphone.partial_ptr = AUDIO_Handle->headphone.frame_length;
+ AUDIO_Handle->headphone.global_ptr = AUDIO_Handle->headphone.frame_length;
+ AUDIO_Handle->headphone.cbuf = AUDIO_Handle->headphone.buf;
+
+ }
+ break;
+
+ case AUDIO_DATA_OUT:
+ if((USBH_LL_GetURBState(phost , AUDIO_Handle->headphone.Pipe) == USBH_URB_DONE)&&
+ (( phost->Timer - AUDIO_Handle->headphone.timer) >= AUDIO_Handle->headphone.Poll))
+ {
+ AUDIO_Handle->headphone.timer = phost->Timer;
+
+ if(AUDIO_Handle->control.supported == 1)
+ {
+ USBH_AUDIO_Control (phost);
+ }
+
+ if(AUDIO_Handle->headphone.global_ptr <= AUDIO_Handle->headphone.total_length)
+ {
+ USBH_IsocSendData(phost,
+ AUDIO_Handle->headphone.cbuf,
+ AUDIO_Handle->headphone.frame_length,
+ AUDIO_Handle->headphone.Pipe);
+
+ AUDIO_Handle->headphone.cbuf += AUDIO_Handle->headphone.frame_length;
+ AUDIO_Handle->headphone.partial_ptr += AUDIO_Handle->headphone.frame_length;
+ AUDIO_Handle->headphone.global_ptr += AUDIO_Handle->headphone.frame_length;
+ }
+ else
+ {
+ AUDIO_Handle->headphone.partial_ptr = 0xFFFFFFFF;
+ AUDIO_Handle->play_state = AUDIO_PLAYBACK_IDLE;
+ }
+ }
+ break;
+ }
+ return status;
+}
+
+/**
+ * @brief USBH_AUDIO_SetFrequency
+ * Set Audio sampling parameters
+ * @param phost: Host handle
+ * @param SampleRate: Sample Rate
+ * @param NbrChannels: Number of Channels
+ * @param BitPerSample: Bit Per Sample
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_AUDIO_SetFrequency (USBH_HandleTypeDef *phost,
+ uint16_t SampleRate,
+ uint8_t NbrChannels,
+ uint8_t BitPerSample)
+{
+ USBH_StatusTypeDef Status = USBH_BUSY;
+ AUDIO_HandleTypeDef *AUDIO_Handle;
+ uint8_t index;
+ uint8_t change_freq = FALSE;
+ uint32_t freq_min, freq_max;
+ uint8_t num_supported_freq;
+
+ if(phost->gState == HOST_CLASS)
+ {
+ AUDIO_Handle = phost->pActiveClass->pData;
+ if(AUDIO_Handle->play_state == AUDIO_PLAYBACK_IDLE)
+ {
+
+ if(AUDIO_Handle->class_desc.as_desc[AUDIO_Handle->headphone.asociated_as].FormatTypeDesc->bSamFreqType == 0)
+ {
+ freq_min = LE24(AUDIO_Handle->class_desc.as_desc[AUDIO_Handle->headphone.asociated_as].FormatTypeDesc->tSamFreq[0]);
+ freq_max = LE24(AUDIO_Handle->class_desc.as_desc[AUDIO_Handle->headphone.asociated_as].FormatTypeDesc->tSamFreq[1]);
+
+ if(( SampleRate >= freq_min)&& (SampleRate <= freq_max))
+ {
+ change_freq = TRUE;
+ }
+ }
+ else
+ {
+
+ num_supported_freq = (AUDIO_Handle->class_desc.as_desc[AUDIO_Handle->headphone.asociated_as].FormatTypeDesc->bLength - 8)/3;
+
+
+ for(index = 0; index < num_supported_freq; index++)
+ {
+ if(SampleRate == LE24(AUDIO_Handle->class_desc.as_desc[AUDIO_Handle->headphone.asociated_as].FormatTypeDesc->tSamFreq[index]))
+ {
+ change_freq = TRUE;
+ break;
+ }
+ }
+ }
+
+ if(change_freq == TRUE)
+ {
+ AUDIO_Handle->headphone.frequency = SampleRate;
+ AUDIO_Handle->headphone.frame_length = (SampleRate * BitPerSample * NbrChannels) / 8000;
+ AUDIO_Handle->play_state = AUDIO_PLAYBACK_SET_EP;
+ Status = USBH_OK;
+
+ }
+ }
+ }
+ return Status;
+}
+
+/**
+ * @brief USBH_AUDIO_Play
+ * Start playback process
+ * @param phost: Host handle
+ * @param buf: pointer to raw audio data
+ * @param length: total length of the audio data
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_AUDIO_Play (USBH_HandleTypeDef *phost, uint8_t *buf, uint32_t length)
+{
+ USBH_StatusTypeDef Status = USBH_FAIL;
+ AUDIO_HandleTypeDef *AUDIO_Handle;
+
+ if(phost->gState == HOST_CLASS)
+ {
+ AUDIO_Handle = phost->pActiveClass->pData;
+ if(AUDIO_Handle->play_state == AUDIO_PLAYBACK_IDLE)
+ {
+ AUDIO_Handle->headphone.buf = buf;
+ AUDIO_Handle->headphone.total_length = length;
+ AUDIO_Handle->play_state = AUDIO_PLAYBACK_PLAY;
+ AUDIO_Handle->control_state = AUDIO_CONTROL_INIT;
+ AUDIO_Handle->processing_state = AUDIO_DATA_START_OUT;
+ Status = USBH_OK;
+ }
+ }
+ return Status;
+}
+
+/**
+ * @brief USBH_AUDIO_Pause
+ * Stop the playback process
+ * @param phost: Host handle
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_AUDIO_Stop (USBH_HandleTypeDef *phost)
+{
+ USBH_StatusTypeDef Status = USBH_FAIL;
+ Status = USBH_AUDIO_Suspend(phost);
+ return Status;
+}
+
+/**
+ * @brief USBH_AUDIO_Suspend
+ * Suspend the playback process
+ * @param phost: Host handle
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_AUDIO_Suspend (USBH_HandleTypeDef *phost)
+{
+ USBH_StatusTypeDef Status = USBH_FAIL;
+ AUDIO_HandleTypeDef *AUDIO_Handle;
+
+ if(phost->gState == HOST_CLASS)
+ {
+ AUDIO_Handle = phost->pActiveClass->pData;
+ if(AUDIO_Handle->play_state == AUDIO_PLAYBACK_PLAY)
+ {
+ AUDIO_Handle->control_state = AUDIO_CONTROL_IDLE;
+ AUDIO_Handle->play_state = AUDIO_PLAYBACK_IDLE;
+ Status = USBH_OK;
+ }
+ }
+ return Status;
+}
+/**
+ * @brief USBH_AUDIO_Resume
+ * Resume the playback process
+ * @param phost: Host handle
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_AUDIO_Resume (USBH_HandleTypeDef *phost)
+{
+ USBH_StatusTypeDef Status = USBH_FAIL;
+ AUDIO_HandleTypeDef *AUDIO_Handle;
+
+ if(phost->gState == HOST_CLASS)
+ {
+ AUDIO_Handle = phost->pActiveClass->pData;
+ if(AUDIO_Handle->play_state == AUDIO_PLAYBACK_IDLE)
+ {
+ AUDIO_Handle->control_state = AUDIO_CONTROL_INIT;
+ AUDIO_Handle->play_state = AUDIO_PLAYBACK_PLAY;
+ }
+ }
+ return Status;
+}
+/**
+ * @brief USBH_AUDIO_GetOutOffset
+ * return the current buffer pointer for OUT proces
+ * @param phost: Host handle
+ * @retval USBH Status
+ */
+int32_t USBH_AUDIO_GetOutOffset (USBH_HandleTypeDef *phost)
+{
+ AUDIO_HandleTypeDef *AUDIO_Handle;
+
+ if(phost->gState == HOST_CLASS)
+ {
+ AUDIO_Handle = phost->pActiveClass->pData;
+ if(AUDIO_Handle->play_state == AUDIO_PLAYBACK_PLAY)
+ {
+ return AUDIO_Handle->headphone.partial_ptr;
+ }
+ }
+ return -1;
+}
+
+/**
+ * @brief USBH_AUDIO_ChangeOutBuffer
+ * Change audio data buffer address
+ * @param phost: Host handle
+ * @param buf: buffer address
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_AUDIO_ChangeOutBuffer (USBH_HandleTypeDef *phost, uint8_t *buf)
+{
+ USBH_StatusTypeDef Status = USBH_FAIL;
+ AUDIO_HandleTypeDef *AUDIO_Handle;
+
+ if(phost->gState == HOST_CLASS)
+ {
+ AUDIO_Handle = phost->pActiveClass->pData;
+ if(AUDIO_Handle->play_state == AUDIO_PLAYBACK_PLAY)
+ {
+ if(AUDIO_Handle->headphone.buf <= buf)
+ {
+ AUDIO_Handle->headphone.cbuf = buf;
+ if ( AUDIO_Handle->headphone.buf == buf)
+ {
+ AUDIO_Handle->headphone.partial_ptr = 0;
+ }
+ Status = USBH_OK;
+ }
+ }
+ }
+ return Status;
+}
+
+/**
+ * @brief USBH_AUDIO_SetControlAttribute
+ * Set Control Attribute
+ * @param phost: Host handle
+ * @param attrib: control attribute
+ * @retval USBH Status
+ */
+static USBH_StatusTypeDef USBH_AUDIO_SetControlAttribute (USBH_HandleTypeDef *phost, uint8_t attrib)
+{
+ USBH_StatusTypeDef status = USBH_BUSY ;
+ AUDIO_HandleTypeDef *AUDIO_Handle;
+
+
+ AUDIO_Handle = phost->pActiveClass->pData;
+
+ switch (attrib)
+ {
+ case 0x01:
+ AUDIO_Handle->headphone.attribute.volume += AUDIO_Handle->headphone.attribute.resolution;
+ break;
+
+ case 0x02:
+ AUDIO_Handle->headphone.attribute.volume -= AUDIO_Handle->headphone.attribute.resolution;
+ break;
+
+ }
+
+ if(AUDIO_Handle->headphone.attribute.volume > AUDIO_Handle->headphone.attribute.volumeMax)
+ {
+ AUDIO_Handle->headphone.attribute.volume =AUDIO_Handle->headphone.attribute.volumeMax;
+ }
+
+ if(AUDIO_Handle->headphone.attribute.volume < AUDIO_Handle->headphone.attribute.volumeMin)
+ {
+ AUDIO_Handle->headphone.attribute.volume =AUDIO_Handle->headphone.attribute.volumeMin;
+ }
+
+ if(AUDIO_SetVolume (phost,
+ AUDIO_Handle->temp_feature,
+ AUDIO_Handle->temp_channels,
+ AUDIO_Handle->headphone.attribute.volume) != USBH_BUSY)
+ {
+
+ if(AUDIO_Handle->temp_channels == 1)
+ {
+ AUDIO_Handle->temp_feature = AUDIO_Handle->headphone.asociated_feature;
+ AUDIO_Handle->temp_channels = AUDIO_Handle->headphone.asociated_channels;
+ status = USBH_OK;
+ }
+ else
+ {
+ AUDIO_Handle->temp_channels--;
+ }
+ AUDIO_Handle->cs_req_state = AUDIO_REQ_GET_VOLUME;
+ }
+
+
+ return status;
+}
+
+
+/**
+ * @brief USBH_AUDIO_SetVolume
+ * Set Volume
+ * @param phost: Host handle
+ * @param volume: VOLUME_UP/ VOLUME_DOWN
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_AUDIO_SetVolume (USBH_HandleTypeDef *phost, AUDIO_VolumeCtrlTypeDef volume_ctl)
+{
+ AUDIO_HandleTypeDef *AUDIO_Handle = phost->pActiveClass->pData;
+
+ if((volume_ctl == VOLUME_UP) || (volume_ctl == VOLUME_DOWN))
+ {
+ if(phost->gState == HOST_CLASS)
+ {
+ AUDIO_Handle = phost->pActiveClass->pData;
+ if(AUDIO_Handle->play_state == AUDIO_PLAYBACK_PLAY)
+ {
+ AUDIO_Handle->control_state = (volume_ctl == VOLUME_UP)? AUDIO_CONTROL_VOLUME_UP : AUDIO_CONTROL_VOLUME_DOWN;
+ return USBH_OK;
+ }
+ }
+ }
+ return USBH_FAIL;
+}
+/**
+ * @brief AUDIO_SetVolume
+ * Set Volume
+ * @param phost: Host handle
+ * @param feature: feature Unit index
+ * @param channel: channel index
+ * @param volume: new volume
+ * @retval USBH Status
+ */
+static USBH_StatusTypeDef AUDIO_SetVolume (USBH_HandleTypeDef *phost, uint8_t feature, uint8_t channel, uint16_t volume)
+{
+ USBH_StatusTypeDef status = USBH_BUSY ;
+ AUDIO_HandleTypeDef *AUDIO_Handle;
+
+
+ AUDIO_Handle = phost->pActiveClass->pData;
+
+ AUDIO_Handle->mem[0] = volume;
+
+ status = USBH_AC_SetCur(phost,
+ UAC_FEATURE_UNIT,
+ feature,
+ VOLUME_CONTROL,
+ channel,
+ 2);
+
+ return status;
+}
+
+/**
+ * @brief The function informs user that Settings have been changed
+ * @param pdev: Selected device
+ * @retval None
+ */
+__weak void USBH_AUDIO_FrequencySet(USBH_HandleTypeDef *phost)
+{
+
+}
+/**
+* @}
+*/
+
+/**
+* @}
+*/
+
+/**
+* @}
+*/
+
+
+/**
+* @}
+*/
+
+
+/**
+* @}
+*/
+
+/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/
diff --git a/ports/stm32/usbhost/Class/CDC/Inc/usbh_cdc.h b/ports/stm32/usbhost/Class/CDC/Inc/usbh_cdc.h
new file mode 100644
index 000000000..df11bfdda
--- /dev/null
+++ b/ports/stm32/usbhost/Class/CDC/Inc/usbh_cdc.h
@@ -0,0 +1,449 @@
+/**
+ ******************************************************************************
+ * @file usbh_cdc.h
+ * @author MCD Application Team
+ * @version V3.0.0
+ * @date 18-February-2014
+ * @brief This file contains all the prototypes for the usbh_cdc.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 ----------------------------------------------*/
+#ifndef __USBH_CDC_CORE_H
+#define __USBH_CDC_CORE_H
+
+/* Includes ------------------------------------------------------------------*/
+#include "usbh_core.h"
+
+
+/** @addtogroup USBH_LIB
+* @{
+*/
+
+/** @addtogroup USBH_CLASS
+* @{
+*/
+
+/** @addtogroup USBH_CDC_CLASS
+* @{
+*/
+
+/** @defgroup USBH_CDC_CORE
+* @brief This file is the Header file for USBH_CDC_CORE.c
+* @{
+*/
+
+
+
+
+/*Communication Class codes*/
+#define USB_CDC_CLASS 0x02
+#define COMMUNICATION_INTERFACE_CLASS_CODE 0x02
+
+/*Data Interface Class Codes*/
+#define DATA_INTERFACE_CLASS_CODE 0x0A
+
+/*Communcation sub class codes*/
+#define RESERVED 0x00
+#define DIRECT_LINE_CONTROL_MODEL 0x01
+#define ABSTRACT_CONTROL_MODEL 0x02
+#define TELEPHONE_CONTROL_MODEL 0x03
+#define MULTICHANNEL_CONTROL_MODEL 0x04
+#define CAPI_CONTROL_MODEL 0x05
+#define ETHERNET_NETWORKING_CONTROL_MODEL 0x06
+#define ATM_NETWORKING_CONTROL_MODEL 0x07
+
+
+/*Communication Interface Class Control Protocol Codes*/
+#define NO_CLASS_SPECIFIC_PROTOCOL_CODE 0x00
+#define COMMON_AT_COMMAND 0x01
+#define VENDOR_SPECIFIC 0xFF
+
+
+#define CS_INTERFACE 0x24
+#define CDC_PAGE_SIZE_64 0x40
+
+/*Class-Specific Request Codes*/
+#define CDC_SEND_ENCAPSULATED_COMMAND 0x00
+#define CDC_GET_ENCAPSULATED_RESPONSE 0x01
+#define CDC_SET_COMM_FEATURE 0x02
+#define CDC_GET_COMM_FEATURE 0x03
+#define CDC_CLEAR_COMM_FEATURE 0x04
+
+#define CDC_SET_AUX_LINE_STATE 0x10
+#define CDC_SET_HOOK_STATE 0x11
+#define CDC_PULSE_SETUP 0x12
+#define CDC_SEND_PULSE 0x13
+#define CDC_SET_PULSE_TIME 0x14
+#define CDC_RING_AUX_JACK 0x15
+
+#define CDC_SET_LINE_CODING 0x20
+#define CDC_GET_LINE_CODING 0x21
+#define CDC_SET_CONTROL_LINE_STATE 0x22
+#define CDC_SEND_BREAK 0x23
+
+#define CDC_SET_RINGER_PARMS 0x30
+#define CDC_GET_RINGER_PARMS 0x31
+#define CDC_SET_OPERATION_PARMS 0x32
+#define CDC_GET_OPERATION_PARMS 0x33
+#define CDC_SET_LINE_PARMS 0x34
+#define CDC_GET_LINE_PARMS 0x35
+#define CDC_DIAL_DIGITS 0x36
+#define CDC_SET_UNIT_PARAMETER 0x37
+#define CDC_GET_UNIT_PARAMETER 0x38
+#define CDC_CLEAR_UNIT_PARAMETER 0x39
+#define CDC_GET_PROFILE 0x3A
+
+#define CDC_SET_ETHERNET_MULTICAST_FILTERS 0x40
+#define CDC_SET_ETHERNET_POWER_MANAGEMENT_PATTERN FILTER 0x41
+#define CDC_GET_ETHERNET_POWER_MANAGEMENT_PATTERN FILTER 0x42
+#define CDC_SET_ETHERNET_PACKET_FILTER 0x43
+#define CDC_GET_ETHERNET_STATISTIC 0x44
+
+#define CDC_SET_ATM_DATA_FORMAT 0x50
+#define CDC_GET_ATM_DEVICE_STATISTICS 0x51
+#define CDC_SET_ATM_DEFAULT_VC 0x52
+#define CDC_GET_ATM_VC_STATISTICS 0x53
+
+
+/* wValue for SetControlLineState*/
+#define CDC_ACTIVATE_CARRIER_SIGNAL_RTS 0x0002
+#define CDC_DEACTIVATE_CARRIER_SIGNAL_RTS 0x0000
+#define CDC_ACTIVATE_SIGNAL_DTR 0x0001
+#define CDC_DEACTIVATE_SIGNAL_DTR 0x0000
+
+#define LINE_CODING_STRUCTURE_SIZE 0x07
+/**
+ * @}
+ */
+
+/** @defgroup USBH_CDC_CORE_Exported_Types
+* @{
+*/
+
+/* States for CDC State Machine */
+typedef enum
+{
+ CDC_IDLE= 0,
+ CDC_SEND_DATA,
+ CDC_SEND_DATA_WAIT,
+ CDC_RECEIVE_DATA,
+ CDC_RECEIVE_DATA_WAIT,
+}
+CDC_DataStateTypeDef;
+
+typedef enum
+{
+ CDC_IDLE_STATE= 0,
+ CDC_SET_LINE_CODING_STATE,
+ CDC_GET_LAST_LINE_CODING_STATE,
+ CDC_TRANSFER_DATA,
+ CDC_ERROR_STATE,
+}
+CDC_StateTypeDef;
+
+
+/*Line coding structure*/
+typedef union _CDC_LineCodingStructure
+{
+ uint8_t Array[LINE_CODING_STRUCTURE_SIZE];
+
+ struct
+ {
+
+ uint32_t dwDTERate; /*Data terminal rate, in bits per second*/
+ uint8_t bCharFormat; /*Stop bits
+ 0 - 1 Stop bit
+ 1 - 1.5 Stop bits
+ 2 - 2 Stop bits*/
+ uint8_t bParityType; /* Parity
+ 0 - None
+ 1 - Odd
+ 2 - Even
+ 3 - Mark
+ 4 - Space*/
+ uint8_t bDataBits; /* Data bits (5, 6, 7, 8 or 16). */
+ }b;
+}
+CDC_LineCodingTypeDef;
+
+
+
+/* Header Functional Descriptor
+--------------------------------------------------------------------------------
+Offset| field | Size | Value | Description
+------|---------------------|-------|------------|------------------------------
+0 | bFunctionLength | 1 | number | Size of this descriptor.
+1 | bDescriptorType | 1 | Constant | CS_INTERFACE (0x24)
+2 | bDescriptorSubtype | 1 | Constant | Identifier (ID) of functional
+ | | | | descriptor.
+3 | bcdCDC | 2 | |
+ | | | Number | USB Class Definitions for
+ | | | | Communication Devices Specification
+ | | | | release number in binary-coded
+ | | | | decimal
+------|---------------------|-------|------------|------------------------------
+*/
+typedef struct _FunctionalDescriptorHeader
+{
+ uint8_t bLength; /*Size of this descriptor.*/
+ uint8_t bDescriptorType; /*CS_INTERFACE (0x24)*/
+ uint8_t bDescriptorSubType; /* Header functional descriptor subtype as*/
+ uint16_t bcdCDC; /* USB Class Definitions for Communication
+ Devices Specification release number in
+ binary-coded decimal. */
+}
+CDC_HeaderFuncDesc_TypeDef;
+/* Call Management Functional Descriptor
+--------------------------------------------------------------------------------
+Offset| field | Size | Value | Description
+------|---------------------|-------|------------|------------------------------
+0 | bFunctionLength | 1 | number | Size of this descriptor.
+1 | bDescriptorType | 1 | Constant | CS_INTERFACE (0x24)
+2 | bDescriptorSubtype | 1 | Constant | Call Management functional
+ | | | | descriptor subtype.
+3 | bmCapabilities | 1 | Bitmap | The capabilities that this configuration
+ | | | | supports:
+ | | | | D7..D2: RESERVED (Reset to zero)
+ | | | | D1: 0 - Device sends/receives call
+ | | | | management information only over
+ | | | | the Communication Class
+ | | | | interface.
+ | | | | 1 - Device can send/receive call
+ | \ | | management information over a
+ | | | | Data Class interface.
+ | | | | D0: 0 - Device does not handle call
+ | | | | management itself.
+ | | | | 1 - Device handles call
+ | | | | management itself.
+ | | | | The previous bits, in combination, identify
+ | | | | which call management scenario is used. If bit
+ | | | | D0 is reset to 0, then the value of bit D1 is
+ | | | | ignored. In this case, bit D1 is reset to zero for
+ | | | | future compatibility.
+4 | bDataInterface | 1 | Number | Interface number of Data Class interface
+ | | | | optionally used for call management.
+------|---------------------|-------|------------|------------------------------
+*/
+typedef struct _CallMgmtFunctionalDescriptor
+{
+ uint8_t bLength; /*Size of this functional descriptor, in bytes.*/
+ uint8_t bDescriptorType; /*CS_INTERFACE (0x24)*/
+ uint8_t bDescriptorSubType; /* Call Management functional descriptor subtype*/
+ uint8_t bmCapabilities; /* bmCapabilities: D0+D1 */
+ uint8_t bDataInterface; /*bDataInterface: 1*/
+}
+CDC_CallMgmtFuncDesc_TypeDef;
+/* Abstract Control Management Functional Descriptor
+--------------------------------------------------------------------------------
+Offset| field | Size | Value | Description
+------|---------------------|-------|------------|------------------------------
+0 | bFunctionLength | 1 | number | Size of functional descriptor, in bytes.
+1 | bDescriptorType | 1 | Constant | CS_INTERFACE (0x24)
+2 | bDescriptorSubtype | 1 | Constant | Abstract Control Management
+ | | | | functional descriptor subtype.
+3 | bmCapabilities | 1 | Bitmap | The capabilities that this configuration
+ | | | | supports ((A bit value of zero means that the
+ | | | | request is not supported.) )
+ D7..D4: RESERVED (Reset to zero)
+ | | | | D3: 1 - Device supports the notification
+ | | | | Network_Connection.
+ | | | | D2: 1 - Device supports the request
+ | | | | Send_Break
+ | | | | D1: 1 - Device supports the request
+ | \ | | combination of Set_Line_Coding,
+ | | | | Set_Control_Line_State, Get_Line_Coding, and the
+ notification Serial_State.
+ | | | | D0: 1 - Device supports the request
+ | | | | combination of Set_Comm_Feature,
+ | | | | Clear_Comm_Feature, and Get_Comm_Feature.
+ | | | | The previous bits, in combination, identify
+ | | | | which requests/notifications are supported by
+ | | | | a Communication Class interface with the
+ | | | | SubClass code of Abstract Control Model.
+------|---------------------|-------|------------|------------------------------
+*/
+typedef struct _AbstractCntrlMgmtFunctionalDescriptor
+{
+ uint8_t bLength; /*Size of this functional descriptor, in bytes.*/
+ uint8_t bDescriptorType; /*CS_INTERFACE (0x24)*/
+ uint8_t bDescriptorSubType; /* Abstract Control Management functional
+ descriptor subtype*/
+ uint8_t bmCapabilities; /* The capabilities that this configuration supports */
+}
+CDC_AbstCntrlMgmtFuncDesc_TypeDef;
+/* Union Functional Descriptor
+--------------------------------------------------------------------------------
+Offset| field | Size | Value | Description
+------|---------------------|-------|------------|------------------------------
+0 | bFunctionLength | 1 | number | Size of this descriptor.
+1 | bDescriptorType | 1 | Constant | CS_INTERFACE (0x24)
+2 | bDescriptorSubtype | 1 | Constant | Union functional
+ | | | | descriptor subtype.
+3 | bMasterInterface | 1 | Constant | The interface number of the
+ | | | | Communication or Data Class interface
+4 | bSlaveInterface0 | 1 | Number | nterface number of first slave or associated
+ | | | | interface in the union.
+------|---------------------|-------|------------|------------------------------
+*/
+typedef struct _UnionFunctionalDescriptor
+{
+ uint8_t bLength; /*Size of this functional descriptor, in bytes*/
+ uint8_t bDescriptorType; /*CS_INTERFACE (0x24)*/
+ uint8_t bDescriptorSubType; /* Union functional descriptor SubType*/
+ uint8_t bMasterInterface; /* The interface number of the Communication or
+ Data Class interface,*/
+ uint8_t bSlaveInterface0; /*Interface number of first slave*/
+}
+CDC_UnionFuncDesc_TypeDef;
+
+typedef struct _USBH_CDCInterfaceDesc
+{
+ CDC_HeaderFuncDesc_TypeDef CDC_HeaderFuncDesc;
+ CDC_CallMgmtFuncDesc_TypeDef CDC_CallMgmtFuncDesc;
+ CDC_AbstCntrlMgmtFuncDesc_TypeDef CDC_AbstCntrlMgmtFuncDesc;
+ CDC_UnionFuncDesc_TypeDef CDC_UnionFuncDesc;
+}
+CDC_InterfaceDesc_Typedef;
+
+
+/* Structure for CDC process */
+typedef struct
+{
+ uint8_t NotifPipe;
+ uint8_t NotifEp;
+ uint8_t buff[8];
+ uint16_t NotifEpSize;
+}
+CDC_CommItfTypedef ;
+
+typedef struct
+{
+ uint8_t InPipe;
+ uint8_t OutPipe;
+ uint8_t OutEp;
+ uint8_t InEp;
+ uint8_t buff[8];
+ uint16_t OutEpSize;
+ uint16_t InEpSize;
+}
+CDC_DataItfTypedef ;
+
+/* Structure for CDC process */
+typedef struct _CDC_Process
+{
+ CDC_CommItfTypedef CommItf;
+ CDC_DataItfTypedef DataItf;
+ uint8_t *pTxData;
+ uint8_t *pRxData;
+ uint32_t TxDataLength;
+ uint32_t RxDataLength;
+ CDC_InterfaceDesc_Typedef CDC_Desc;
+ CDC_LineCodingTypeDef LineCoding;
+ CDC_LineCodingTypeDef *pUserLineCoding;
+ CDC_StateTypeDef state;
+ CDC_DataStateTypeDef data_tx_state;
+ CDC_DataStateTypeDef data_rx_state;
+ uint8_t Rx_Poll;
+}
+CDC_HandleTypeDef;
+
+/**
+* @}
+*/
+
+/** @defgroup USBH_CDC_CORE_Exported_Defines
+* @{
+*/
+
+/**
+* @}
+*/
+
+/** @defgroup USBH_CDC_CORE_Exported_Macros
+* @{
+*/
+/**
+* @}
+*/
+
+/** @defgroup USBH_CDC_CORE_Exported_Variables
+* @{
+*/
+extern USBH_ClassTypeDef CDC_Class;
+#define USBH_CDC_CLASS &CDC_Class
+
+/**
+* @}
+*/
+
+/** @defgroup USBH_CDC_CORE_Exported_FunctionsPrototype
+* @{
+*/
+
+USBH_StatusTypeDef USBH_CDC_SetLineCoding(USBH_HandleTypeDef *phost,
+ CDC_LineCodingTypeDef *linecoding);
+
+USBH_StatusTypeDef USBH_CDC_GetLineCoding(USBH_HandleTypeDef *phost,
+ CDC_LineCodingTypeDef *linecoding);
+
+USBH_StatusTypeDef USBH_CDC_Transmit(USBH_HandleTypeDef *phost,
+ uint8_t *pbuff,
+ uint32_t length);
+
+USBH_StatusTypeDef USBH_CDC_Receive(USBH_HandleTypeDef *phost,
+ uint8_t *pbuff,
+ uint32_t length);
+
+
+uint16_t USBH_CDC_GetLastReceivedDataSize(USBH_HandleTypeDef *phost);
+
+USBH_StatusTypeDef USBH_CDC_Stop(USBH_HandleTypeDef *phost);
+
+void USBH_CDC_LineCodingChanged(USBH_HandleTypeDef *phost);
+
+void USBH_CDC_TransmitCallback(USBH_HandleTypeDef *phost);
+
+void USBH_CDC_ReceiveCallback(USBH_HandleTypeDef *phost);
+
+/**
+* @}
+*/
+
+
+#endif /* __USBH_CDC_CORE_H */
+
+/**
+* @}
+*/
+
+/**
+* @}
+*/
+
+/**
+* @}
+*/
+
+/**
+* @}
+*/
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
+
diff --git a/ports/stm32/usbhost/Class/CDC/Src/usbh_cdc.c b/ports/stm32/usbhost/Class/CDC/Src/usbh_cdc.c
new file mode 100644
index 000000000..250e1fc7b
--- /dev/null
+++ b/ports/stm32/usbhost/Class/CDC/Src/usbh_cdc.c
@@ -0,0 +1,755 @@
+/**
+ ******************************************************************************
+ * @file usbh_cdc.c
+ * @author MCD Application Team
+ * @version V3.0.0
+ * @date 18-February-2014
+ * @brief This file is the CDC Layer Handlers for USB Host CDC class.
+ *
+ * @verbatim
+ *
+ * ===================================================================
+ * CDC Class Description
+ * ===================================================================
+ * This module manages the MSC class V1.11 following the "Device Class Definition
+ * for Human Interface Devices (CDC) Version 1.11 Jun 27, 2001".
+ * This driver implements the following aspects of the specification:
+ * - The Boot Interface Subclass
+ * - The Mouse and Keyboard protocols
+ *
+ * @endverbatim
+ *
+ ******************************************************************************
+ * @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 "usbh_cdc.h"
+
+/** @addtogroup USBH_LIB
+* @{
+*/
+
+/** @addtogroup USBH_CLASS
+* @{
+*/
+
+/** @addtogroup USBH_CDC_CLASS
+* @{
+*/
+
+/** @defgroup USBH_CDC_CORE
+* @brief This file includes CDC Layer Handlers for USB Host CDC class.
+* @{
+*/
+
+/** @defgroup USBH_CDC_CORE_Private_TypesDefinitions
+* @{
+*/
+/**
+* @}
+*/
+
+
+/** @defgroup USBH_CDC_CORE_Private_Defines
+* @{
+*/
+#define USBH_CDC_BUFFER_SIZE 1024
+/**
+* @}
+*/
+
+
+/** @defgroup USBH_CDC_CORE_Private_Macros
+* @{
+*/
+/**
+* @}
+*/
+
+
+/** @defgroup USBH_CDC_CORE_Private_Variables
+* @{
+*/
+/**
+* @}
+*/
+
+
+/** @defgroup USBH_CDC_CORE_Private_FunctionPrototypes
+* @{
+*/
+
+static USBH_StatusTypeDef USBH_CDC_InterfaceInit (USBH_HandleTypeDef *phost);
+
+static USBH_StatusTypeDef USBH_CDC_InterfaceDeInit (USBH_HandleTypeDef *phost);
+
+static USBH_StatusTypeDef USBH_CDC_Process(USBH_HandleTypeDef *phost);
+
+static USBH_StatusTypeDef USBH_CDC_SOFProcess(USBH_HandleTypeDef *phost);
+
+static USBH_StatusTypeDef USBH_CDC_ClassRequest (USBH_HandleTypeDef *phost);
+
+static USBH_StatusTypeDef GetLineCoding(USBH_HandleTypeDef *phost,
+ CDC_LineCodingTypeDef *linecoding);
+
+static USBH_StatusTypeDef SetLineCoding(USBH_HandleTypeDef *phost,
+ CDC_LineCodingTypeDef *linecoding);
+
+static void CDC_ProcessTransmission(USBH_HandleTypeDef *phost);
+
+static void CDC_ProcessReception(USBH_HandleTypeDef *phost);
+
+USBH_ClassTypeDef CDC_Class =
+{
+ "CDC",
+ USB_CDC_CLASS,
+ USBH_CDC_InterfaceInit,
+ USBH_CDC_InterfaceDeInit,
+ USBH_CDC_ClassRequest,
+ USBH_CDC_Process,
+ USBH_CDC_SOFProcess,
+ NULL,
+};
+/**
+* @}
+*/
+
+
+/** @defgroup USBH_CDC_CORE_Private_Functions
+* @{
+*/
+
+/**
+ * @brief USBH_CDC_InterfaceInit
+ * The function init the CDC class.
+ * @param phost: Host handle
+ * @retval USBH Status
+ */
+static USBH_StatusTypeDef USBH_CDC_InterfaceInit (USBH_HandleTypeDef *phost)
+{
+
+ USBH_StatusTypeDef status = USBH_FAIL ;
+ uint8_t interface;
+ CDC_HandleTypeDef *CDC_Handle;
+
+ interface = USBH_FindInterface(phost,
+ COMMUNICATION_INTERFACE_CLASS_CODE,
+ ABSTRACT_CONTROL_MODEL,
+ COMMON_AT_COMMAND);
+
+ if(interface == 0xFF) /* No Valid Interface */
+ {
+ USBH_DbgLog ("Cannot Find the interface for Communication Interface Class.", phost->pActiveClass->Name);
+ }
+ else
+ {
+ USBH_SelectInterface (phost, interface);
+ phost->pActiveClass->pData = (CDC_HandleTypeDef *)USBH_malloc (sizeof(CDC_HandleTypeDef));
+ CDC_Handle = phost->pActiveClass->pData;
+
+ /*Collect the notification endpoint address and length*/
+ if(phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[0].bEndpointAddress & 0x80)
+ {
+ CDC_Handle->CommItf.NotifEp = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[0].bEndpointAddress;
+ CDC_Handle->CommItf.NotifEpSize = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[0].wMaxPacketSize;
+ }
+
+ /*Allocate the length for host channel number in*/
+ CDC_Handle->CommItf.NotifPipe = USBH_AllocPipe(phost, CDC_Handle->CommItf.NotifEp);
+
+ /* Open pipe for Notification endpoint */
+ USBH_OpenPipe (phost,
+ CDC_Handle->CommItf.NotifPipe,
+ CDC_Handle->CommItf.NotifEp,
+ phost->device.address,
+ phost->device.speed,
+ USB_EP_TYPE_INTR,
+ CDC_Handle->CommItf.NotifEpSize);
+
+ USBH_LL_SetToggle (phost, CDC_Handle->CommItf.NotifPipe, 0);
+
+ interface = USBH_FindInterface(phost,
+ DATA_INTERFACE_CLASS_CODE,
+ RESERVED,
+ NO_CLASS_SPECIFIC_PROTOCOL_CODE);
+
+ if(interface == 0xFF) /* No Valid Interface */
+ {
+ USBH_DbgLog ("Cannot Find the interface for Data Interface Class.", phost->pActiveClass->Name);
+ }
+ else
+ {
+ /*Collect the class specific endpoint address and length*/
+ if(phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[0].bEndpointAddress & 0x80)
+ {
+ CDC_Handle->DataItf.InEp = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[0].bEndpointAddress;
+ CDC_Handle->DataItf.InEpSize = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[0].wMaxPacketSize;
+ }
+ else
+ {
+ CDC_Handle->DataItf.OutEp = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[0].bEndpointAddress;
+ CDC_Handle->DataItf.OutEpSize = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[0].wMaxPacketSize;
+ }
+
+ if(phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[1].bEndpointAddress & 0x80)
+ {
+ CDC_Handle->DataItf.InEp = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[1].bEndpointAddress;
+ CDC_Handle->DataItf.InEpSize = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[1].wMaxPacketSize;
+ }
+ else
+ {
+ CDC_Handle->DataItf.OutEp = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[1].bEndpointAddress;
+ CDC_Handle->DataItf.OutEpSize = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[1].wMaxPacketSize;
+ }
+
+ /*Allocate the length for host channel number out*/
+ CDC_Handle->DataItf.OutPipe = USBH_AllocPipe(phost, CDC_Handle->DataItf.OutEp);
+
+ /*Allocate the length for host channel number in*/
+ CDC_Handle->DataItf.InPipe = USBH_AllocPipe(phost, CDC_Handle->DataItf.InEp);
+
+ /* Open channel for OUT endpoint */
+ USBH_OpenPipe (phost,
+ CDC_Handle->DataItf.OutPipe,
+ CDC_Handle->DataItf.OutEp,
+ phost->device.address,
+ phost->device.speed,
+ USB_EP_TYPE_BULK,
+ CDC_Handle->DataItf.OutEpSize);
+ /* Open channel for IN endpoint */
+ USBH_OpenPipe (phost,
+ CDC_Handle->DataItf.InPipe,
+ CDC_Handle->DataItf.InEp,
+ phost->device.address,
+ phost->device.speed,
+ USB_EP_TYPE_BULK,
+ CDC_Handle->DataItf.InEpSize);
+
+ CDC_Handle->state = CDC_IDLE_STATE;
+
+ USBH_LL_SetToggle (phost, CDC_Handle->DataItf.OutPipe,0);
+ USBH_LL_SetToggle (phost, CDC_Handle->DataItf.InPipe,0);
+ status = USBH_OK;
+ }
+ }
+ return status;
+}
+
+
+
+/**
+ * @brief USBH_CDC_InterfaceDeInit
+ * The function DeInit the Pipes used for the CDC class.
+ * @param phost: Host handle
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_CDC_InterfaceDeInit (USBH_HandleTypeDef *phost)
+{
+ CDC_HandleTypeDef *CDC_Handle = phost->pActiveClass->pData;
+
+ if ( CDC_Handle->CommItf.NotifPipe)
+ {
+ USBH_ClosePipe(phost, CDC_Handle->CommItf.NotifPipe);
+ USBH_FreePipe (phost, CDC_Handle->CommItf.NotifPipe);
+ CDC_Handle->CommItf.NotifPipe = 0; /* Reset the Channel as Free */
+ }
+
+ if ( CDC_Handle->DataItf.InPipe)
+ {
+ USBH_ClosePipe(phost, CDC_Handle->DataItf.InPipe);
+ USBH_FreePipe (phost, CDC_Handle->DataItf.InPipe);
+ CDC_Handle->DataItf.InPipe = 0; /* Reset the Channel as Free */
+ }
+
+ if ( CDC_Handle->DataItf.OutPipe)
+ {
+ USBH_ClosePipe(phost, CDC_Handle->DataItf.OutPipe);
+ USBH_FreePipe (phost, CDC_Handle->DataItf.OutPipe);
+ CDC_Handle->DataItf.OutPipe = 0; /* Reset the Channel as Free */
+ }
+
+ if(phost->pActiveClass->pData)
+ {
+ USBH_free (phost->pActiveClass->pData);
+ phost->pActiveClass->pData = 0;
+ }
+
+ return USBH_OK;
+}
+
+/**
+ * @brief USBH_CDC_ClassRequest
+ * The function is responsible for handling Standard requests
+ * for CDC class.
+ * @param phost: Host handle
+ * @retval USBH Status
+ */
+static USBH_StatusTypeDef USBH_CDC_ClassRequest (USBH_HandleTypeDef *phost)
+{
+ USBH_StatusTypeDef status = USBH_FAIL ;
+ CDC_HandleTypeDef *CDC_Handle = phost->pActiveClass->pData;
+
+ /*Issue the get line coding request*/
+ status = GetLineCoding(phost, &CDC_Handle->LineCoding);
+ if(status == USBH_OK)
+ {
+ phost->pUser(phost, HOST_USER_CLASS_ACTIVE);
+ }
+ return status;
+}
+
+
+/**
+ * @brief USBH_CDC_Process
+ * The function is for managing state machine for CDC data transfers
+ * @param phost: Host handle
+ * @retval USBH Status
+ */
+static USBH_StatusTypeDef USBH_CDC_Process (USBH_HandleTypeDef *phost)
+{
+ USBH_StatusTypeDef status = USBH_BUSY;
+ USBH_StatusTypeDef req_status = USBH_OK;
+ CDC_HandleTypeDef *CDC_Handle = phost->pActiveClass->pData;
+
+ switch(CDC_Handle->state)
+ {
+
+ case CDC_IDLE_STATE:
+ status = USBH_OK;
+ break;
+
+ case CDC_SET_LINE_CODING_STATE:
+ req_status = SetLineCoding(phost, CDC_Handle->pUserLineCoding);
+
+ if(req_status == USBH_OK)
+ {
+ CDC_Handle->state = CDC_GET_LAST_LINE_CODING_STATE;
+ }
+
+ else if(req_status != USBH_BUSY)
+ {
+ CDC_Handle->state = CDC_ERROR_STATE;
+ }
+ break;
+
+
+ case CDC_GET_LAST_LINE_CODING_STATE:
+ req_status = GetLineCoding(phost, &(CDC_Handle->LineCoding));
+
+ if(req_status == USBH_OK)
+ {
+ CDC_Handle->state = CDC_IDLE_STATE;
+
+ if((CDC_Handle->LineCoding.b.bCharFormat == CDC_Handle->pUserLineCoding->b.bCharFormat) &&
+ (CDC_Handle->LineCoding.b.bDataBits == CDC_Handle->pUserLineCoding->b.bDataBits) &&
+ (CDC_Handle->LineCoding.b.bParityType == CDC_Handle->pUserLineCoding->b.bParityType) &&
+ (CDC_Handle->LineCoding.b.dwDTERate == CDC_Handle->pUserLineCoding->b.dwDTERate))
+ {
+ USBH_CDC_LineCodingChanged(phost);
+ }
+ }
+
+ else if(req_status != USBH_BUSY)
+ {
+ CDC_Handle->state = CDC_ERROR_STATE;
+ }
+
+ break;
+
+ case CDC_TRANSFER_DATA:
+ CDC_ProcessTransmission(phost);
+ CDC_ProcessReception(phost);
+ break;
+
+ case CDC_ERROR_STATE:
+ req_status = USBH_ClrFeature(phost, 0x00);
+
+ if(req_status == USBH_OK )
+ {
+ /*Change the state to waiting*/
+ CDC_Handle->state = CDC_IDLE_STATE ;
+ }
+ break;
+
+ default:
+ break;
+
+ }
+
+ return status;
+}
+
+/**
+ * @brief USBH_CDC_SOFProcess
+ * The function is for managing SOF callback
+ * @param phost: Host handle
+ * @retval USBH Status
+ */
+static USBH_StatusTypeDef USBH_CDC_SOFProcess (USBH_HandleTypeDef *phost)
+{
+ return USBH_OK;
+}
+
+
+ /**
+ * @brief USBH_CDC_Stop
+ * Stop current CDC Transmission
+ * @param phost: Host handle
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_CDC_Stop(USBH_HandleTypeDef *phost)
+{
+ CDC_HandleTypeDef *CDC_Handle = phost->pActiveClass->pData;
+
+ if(phost->gState == HOST_CLASS)
+ {
+ CDC_Handle->state = CDC_IDLE_STATE;
+
+ USBH_ClosePipe(phost, CDC_Handle->CommItf.NotifPipe);
+ USBH_ClosePipe(phost, CDC_Handle->DataItf.InPipe);
+ USBH_ClosePipe(phost, CDC_Handle->DataItf.OutPipe);
+ }
+ return USBH_OK;
+}
+/**
+ * @brief This request allows the host to find out the currently
+ * configured line coding.
+ * @param pdev: Selected device
+ * @retval USBH_StatusTypeDef : USB ctl xfer status
+ */
+static USBH_StatusTypeDef GetLineCoding(USBH_HandleTypeDef *phost, CDC_LineCodingTypeDef *linecoding)
+{
+
+ phost->Control.setup.b.bmRequestType = USB_D2H | USB_REQ_TYPE_CLASS | \
+ USB_REQ_RECIPIENT_INTERFACE;
+
+ phost->Control.setup.b.bRequest = CDC_GET_LINE_CODING;
+ phost->Control.setup.b.wValue.w = 0;
+ phost->Control.setup.b.wIndex.w = 0;
+ phost->Control.setup.b.wLength.w = LINE_CODING_STRUCTURE_SIZE;
+
+ return USBH_CtlReq(phost, linecoding->Array, LINE_CODING_STRUCTURE_SIZE);
+}
+
+
+/**
+ * @brief This request allows the host to specify typical asynchronous
+ * line-character formatting properties
+ * This request applies to asynchronous byte stream data class interfaces
+ * and endpoints
+ * @param pdev: Selected device
+ * @retval USBH_StatusTypeDef : USB ctl xfer status
+ */
+static USBH_StatusTypeDef SetLineCoding(USBH_HandleTypeDef *phost, CDC_LineCodingTypeDef *linecodin)
+{
+ phost->Control.setup.b.bmRequestType = USB_H2D | USB_REQ_TYPE_CLASS | \
+ USB_REQ_RECIPIENT_INTERFACE;
+
+ phost->Control.setup.b.bRequest = CDC_SET_LINE_CODING;
+ phost->Control.setup.b.wValue.w = 0;
+
+ phost->Control.setup.b.wIndex.w = 0;
+
+ phost->Control.setup.b.wLength.w = LINE_CODING_STRUCTURE_SIZE;
+
+ return USBH_CtlReq(phost, linecodin->Array , LINE_CODING_STRUCTURE_SIZE );
+}
+
+/**
+* @brief This function prepares the state before issuing the class specific commands
+* @param None
+* @retval None
+*/
+USBH_StatusTypeDef USBH_CDC_SetLineCoding(USBH_HandleTypeDef *phost, CDC_LineCodingTypeDef *linecodin)
+{
+ CDC_HandleTypeDef *CDC_Handle = phost->pActiveClass->pData;
+ if(phost->gState == HOST_CLASS)
+ {
+ CDC_Handle->state = CDC_SET_LINE_CODING_STATE;
+ CDC_Handle->pUserLineCoding = linecodin;
+
+#if (USBH_USE_OS == 1)
+ osMessagePut ( phost->os_event, USBH_CLASS_EVENT, 0);
+#endif
+ }
+ return USBH_OK;
+}
+
+/**
+* @brief This function prepares the state before issuing the class specific commands
+* @param None
+* @retval None
+*/
+USBH_StatusTypeDef USBH_CDC_GetLineCoding(USBH_HandleTypeDef *phost, CDC_LineCodingTypeDef *linecodin)
+{
+ CDC_HandleTypeDef *CDC_Handle = phost->pActiveClass->pData;
+
+ if((phost->gState == HOST_CLASS) ||(phost->gState == HOST_CLASS_REQUEST))
+ {
+ *linecodin = CDC_Handle->LineCoding;
+ return USBH_OK;
+ }
+ else
+ {
+ return USBH_FAIL;
+ }
+}
+
+/**
+ * @brief This function return last recieved data size
+ * @param None
+ * @retval None
+ */
+uint16_t USBH_CDC_GetLastReceivedDataSize(USBH_HandleTypeDef *phost)
+{
+ CDC_HandleTypeDef *CDC_Handle = phost->pActiveClass->pData;
+
+ if(phost->gState == HOST_CLASS)
+ {
+ return USBH_LL_GetLastXferSize(phost, CDC_Handle->DataItf.InPipe);;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+/**
+ * @brief This function prepares the state before issuing the class specific commands
+ * @param None
+ * @retval None
+ */
+USBH_StatusTypeDef USBH_CDC_Transmit(USBH_HandleTypeDef *phost, uint8_t *pbuff, uint32_t length)
+{
+ USBH_StatusTypeDef Status = USBH_BUSY;
+ CDC_HandleTypeDef *CDC_Handle = phost->pActiveClass->pData;
+
+ if((CDC_Handle->state == CDC_IDLE_STATE) || (CDC_Handle->state == CDC_TRANSFER_DATA))
+ {
+ CDC_Handle->pTxData = pbuff;
+ CDC_Handle->TxDataLength = length;
+ CDC_Handle->state = CDC_TRANSFER_DATA;
+ CDC_Handle->data_tx_state = CDC_SEND_DATA;
+ Status = USBH_OK;
+ }
+ return Status;
+}
+
+
+/**
+* @brief This function prepares the state before issuing the class specific commands
+* @param None
+* @retval None
+*/
+USBH_StatusTypeDef USBH_CDC_Receive(USBH_HandleTypeDef *phost, uint8_t *pbuff, uint32_t length)
+{
+ USBH_StatusTypeDef Status = USBH_BUSY;
+ CDC_HandleTypeDef *CDC_Handle = phost->pActiveClass->pData;
+
+ if((CDC_Handle->state == CDC_IDLE_STATE) || (CDC_Handle->state == CDC_TRANSFER_DATA))
+ {
+ CDC_Handle->pRxData = pbuff;
+ CDC_Handle->RxDataLength = length;
+ CDC_Handle->state = CDC_TRANSFER_DATA;
+ CDC_Handle->data_rx_state = CDC_RECEIVE_DATA;
+ Status = USBH_OK;
+ }
+ return Status;
+}
+
+/**
+* @brief The function is responsible for sending data to the device
+* @param pdev: Selected device
+* @retval None
+*/
+static void CDC_ProcessTransmission(USBH_HandleTypeDef *phost)
+{
+ CDC_HandleTypeDef *CDC_Handle = phost->pActiveClass->pData;
+ USBH_URBStateTypeDef URB_Status = USBH_URB_IDLE;
+
+ switch(CDC_Handle->data_tx_state)
+ {
+
+ case CDC_SEND_DATA:
+ if(CDC_Handle->TxDataLength > CDC_Handle->DataItf.OutEpSize)
+ {
+ USBH_BulkSendData (phost,
+ CDC_Handle->pTxData,
+ CDC_Handle->DataItf.OutEpSize,
+ CDC_Handle->DataItf.OutPipe,
+ 1);
+ }
+ else
+ {
+ USBH_BulkSendData (phost,
+ CDC_Handle->pTxData,
+ CDC_Handle->TxDataLength,
+ CDC_Handle->DataItf.OutPipe,
+ 1);
+ }
+
+ CDC_Handle->data_tx_state = CDC_SEND_DATA_WAIT;
+
+ break;
+
+ case CDC_SEND_DATA_WAIT:
+
+ URB_Status = USBH_LL_GetURBState(phost, CDC_Handle->DataItf.OutPipe);
+
+ /*Check the status done for transmssion*/
+ if(URB_Status == USBH_URB_DONE )
+ {
+ if(CDC_Handle->TxDataLength > CDC_Handle->DataItf.OutEpSize)
+ {
+ CDC_Handle->TxDataLength -= CDC_Handle->DataItf.OutEpSize ;
+ CDC_Handle->pTxData += CDC_Handle->DataItf.OutEpSize;
+ }
+ else
+ {
+ CDC_Handle->TxDataLength = 0;
+ }
+
+ if( CDC_Handle->TxDataLength > 0)
+ {
+ CDC_Handle->data_tx_state = CDC_SEND_DATA;
+ }
+ else
+ {
+ CDC_Handle->data_tx_state = CDC_IDLE;
+ USBH_CDC_TransmitCallback(phost);
+
+ }
+ }
+ else if( URB_Status == USBH_URB_NOTREADY )
+ {
+ CDC_Handle->data_tx_state = CDC_SEND_DATA;
+ }
+ break;
+ default:
+ break;
+ }
+}
+/**
+* @brief This function responsible for reception of data from the device
+* @param pdev: Selected device
+* @retval None
+*/
+
+static void CDC_ProcessReception(USBH_HandleTypeDef *phost)
+{
+ CDC_HandleTypeDef *CDC_Handle = phost->pActiveClass->pData;
+ USBH_URBStateTypeDef URB_Status = USBH_URB_IDLE;
+ uint16_t length;
+
+ switch(CDC_Handle->data_rx_state)
+ {
+
+ case CDC_RECEIVE_DATA:
+
+ USBH_BulkReceiveData (phost,
+ CDC_Handle->pRxData,
+ CDC_Handle->DataItf.InEpSize,
+ CDC_Handle->DataItf.InPipe);
+
+ CDC_Handle->data_rx_state = CDC_RECEIVE_DATA_WAIT;
+
+ break;
+
+ case CDC_RECEIVE_DATA_WAIT:
+
+ URB_Status = USBH_LL_GetURBState(phost, CDC_Handle->DataItf.InPipe);
+
+ /*Check the status done for reception*/
+ if(URB_Status == USBH_URB_DONE )
+ {
+ length = USBH_LL_GetLastXferSize(phost, CDC_Handle->DataItf.InPipe);
+
+ if(((CDC_Handle->RxDataLength - length) > 0) && (length > CDC_Handle->DataItf.InEpSize))
+ {
+ CDC_Handle->RxDataLength -= length ;
+ CDC_Handle->pRxData += length;
+ CDC_Handle->data_rx_state = CDC_RECEIVE_DATA;
+ }
+ else
+ {
+ CDC_Handle->data_rx_state = CDC_IDLE;
+ USBH_CDC_ReceiveCallback(phost);
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+/**
+* @brief The function informs user that data have been received
+* @param pdev: Selected device
+* @retval None
+*/
+__weak void USBH_CDC_TransmitCallback(USBH_HandleTypeDef *phost)
+{
+
+}
+
+ /**
+* @brief The function informs user that data have been sent
+* @param pdev: Selected device
+* @retval None
+*/
+__weak void USBH_CDC_ReceiveCallback(USBH_HandleTypeDef *phost)
+{
+
+}
+
+ /**
+* @brief The function informs user that Settings have been changed
+* @param pdev: Selected device
+* @retval None
+*/
+__weak void USBH_CDC_LineCodingChanged(USBH_HandleTypeDef *phost)
+{
+
+}
+
+/**
+* @}
+*/
+
+/**
+* @}
+*/
+
+/**
+* @}
+*/
+
+
+/**
+* @}
+*/
+
+
+/**
+* @}
+*/
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/ports/stm32/usbhost/Class/HID/Inc/usbh_hid.h b/ports/stm32/usbhost/Class/HID/Inc/usbh_hid.h
new file mode 100644
index 000000000..38302ad0d
--- /dev/null
+++ b/ports/stm32/usbhost/Class/HID/Inc/usbh_hid.h
@@ -0,0 +1,341 @@
+/**
+ ******************************************************************************
+ * @file usbh_hid.h
+ * @author MCD Application Team
+ * @version V3.0.0
+ * @date 18-February-2014
+ * @brief This file contains all the prototypes for the usbh_hid.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 ----------------------------------------------*/
+#ifndef __USBH_HID_H
+#define __USBH_HID_H
+
+/* Includes ------------------------------------------------------------------*/
+#include "usbh_core.h"
+#include "usbh_hid_mouse.h"
+#include "usbh_hid_keybd.h"
+
+/** @addtogroup USBH_LIB
+ * @{
+ */
+
+/** @addtogroup USBH_CLASS
+ * @{
+ */
+
+/** @addtogroup USBH_HID_CLASS
+ * @{
+ */
+
+/** @defgroup USBH_HID_CORE
+ * @brief This file is the Header file for USBH_HID_CORE.c
+ * @{
+ */
+
+
+/** @defgroup USBH_HID_CORE_Exported_Types
+ * @{
+ */
+
+#define HID_MIN_POLL 10
+#define HID_REPORT_SIZE 16
+#define HID_MAX_USAGE 10
+#define HID_MAX_NBR_REPORT_FMT 10
+#define HID_QUEUE_SIZE 10
+
+#define HID_ITEM_LONG 0xFE
+
+#define HID_ITEM_TYPE_MAIN 0x00
+#define HID_ITEM_TYPE_GLOBAL 0x01
+#define HID_ITEM_TYPE_LOCAL 0x02
+#define HID_ITEM_TYPE_RESERVED 0x03
+
+
+#define HID_MAIN_ITEM_TAG_INPUT 0x08
+#define HID_MAIN_ITEM_TAG_OUTPUT 0x09
+#define HID_MAIN_ITEM_TAG_COLLECTION 0x0A
+#define HID_MAIN_ITEM_TAG_FEATURE 0x0B
+#define HID_MAIN_ITEM_TAG_ENDCOLLECTION 0x0C
+
+
+#define HID_GLOBAL_ITEM_TAG_USAGE_PAGE 0x00
+#define HID_GLOBAL_ITEM_TAG_LOG_MIN 0x01
+#define HID_GLOBAL_ITEM_TAG_LOG_MAX 0x02
+#define HID_GLOBAL_ITEM_TAG_PHY_MIN 0x03
+#define HID_GLOBAL_ITEM_TAG_PHY_MAX 0x04
+#define HID_GLOBAL_ITEM_TAG_UNIT_EXPONENT 0x05
+#define HID_GLOBAL_ITEM_TAG_UNIT 0x06
+#define HID_GLOBAL_ITEM_TAG_REPORT_SIZE 0x07
+#define HID_GLOBAL_ITEM_TAG_REPORT_ID 0x08
+#define HID_GLOBAL_ITEM_TAG_REPORT_COUNT 0x09
+#define HID_GLOBAL_ITEM_TAG_PUSH 0x0A
+#define HID_GLOBAL_ITEM_TAG_POP 0x0B
+
+
+#define HID_LOCAL_ITEM_TAG_USAGE 0x00
+#define HID_LOCAL_ITEM_TAG_USAGE_MIN 0x01
+#define HID_LOCAL_ITEM_TAG_USAGE_MAX 0x02
+#define HID_LOCAL_ITEM_TAG_DESIGNATOR_INDEX 0x03
+#define HID_LOCAL_ITEM_TAG_DESIGNATOR_MIN 0x04
+#define HID_LOCAL_ITEM_TAG_DESIGNATOR_MAX 0x05
+#define HID_LOCAL_ITEM_TAG_STRING_INDEX 0x07
+#define HID_LOCAL_ITEM_TAG_STRING_MIN 0x08
+#define HID_LOCAL_ITEM_TAG_STRING_MAX 0x09
+#define HID_LOCAL_ITEM_TAG_DELIMITER 0x0A
+
+
+/* States for HID State Machine */
+typedef enum
+{
+ HID_INIT= 0,
+ HID_IDLE,
+ HID_SEND_DATA,
+ HID_BUSY,
+ HID_GET_DATA,
+ HID_SYNC,
+ HID_POLL,
+ HID_ERROR,
+}
+HID_StateTypeDef;
+
+typedef enum
+{
+ HID_REQ_INIT = 0,
+ HID_REQ_IDLE,
+ HID_REQ_GET_REPORT_DESC,
+ HID_REQ_GET_HID_DESC,
+ HID_REQ_SET_IDLE,
+ HID_REQ_SET_PROTOCOL,
+ HID_REQ_SET_REPORT,
+
+}
+HID_CtlStateTypeDef;
+
+typedef enum
+{
+ HID_MOUSE = 0x01,
+ HID_KEYBOARD = 0x02,
+ HID_UNKNOWN = 0xFF,
+}
+HID_TypeTypeDef;
+
+
+typedef struct _HID_ReportData
+{
+ uint8_t ReportID;
+ uint8_t ReportType;
+ uint16_t UsagePage;
+ uint32_t Usage[HID_MAX_USAGE];
+ uint32_t NbrUsage;
+ uint32_t UsageMin;
+ uint32_t UsageMax;
+ int32_t LogMin;
+ int32_t LogMax;
+ int32_t PhyMin;
+ int32_t PhyMax;
+ int32_t UnitExp;
+ uint32_t Unit;
+ uint32_t ReportSize;
+ uint32_t ReportCnt;
+ uint32_t Flag;
+ uint32_t PhyUsage;
+ uint32_t AppUsage;
+ uint32_t LogUsage;
+}
+HID_ReportDataTypeDef;
+
+typedef struct _HID_ReportIDTypeDef {
+ uint8_t Size; /* Report size return by the device id */
+ uint8_t ReportID; /* Report Id */
+ uint8_t Type; /* Report Type (INPUT/OUTPUT/FEATURE) */
+} HID_ReportIDTypeDef;
+
+typedef struct _HID_CollectionTypeDef
+{
+ uint32_t Usage;
+ uint8_t Type;
+ struct _HID_CollectionTypeDef *NextPtr;
+} HID_CollectionTypeDef;
+
+
+typedef struct _HID_AppCollectionTypeDef {
+ uint32_t Usage;
+ uint8_t Type;
+ uint8_t NbrReportFmt;
+ HID_ReportDataTypeDef ReportData[HID_MAX_NBR_REPORT_FMT];
+} HID_AppCollectionTypeDef;
+
+
+typedef struct _HIDDescriptor
+{
+ uint8_t bLength;
+ uint8_t bDescriptorType;
+ uint16_t bcdHID; /* indicates what endpoint this descriptor is describing */
+ uint8_t bCountryCode; /* specifies the transfer type. */
+ uint8_t bNumDescriptors; /* specifies the transfer type. */
+ uint8_t bReportDescriptorType; /* Maximum Packet Size this endpoint is capable of sending or receiving */
+ uint16_t wItemLength; /* is used to specify the polling interval of certain transfers. */
+}
+HID_DescTypeDef;
+
+
+typedef struct
+{
+ uint8_t *buf;
+ uint16_t head;
+ uint16_t tail;
+ uint16_t size;
+ uint8_t lock;
+} FIFO_TypeDef;
+
+
+/* Structure for HID process */
+typedef struct _HID_Process
+{
+ uint8_t OutPipe;
+ uint8_t InPipe;
+ HID_StateTypeDef state;
+ uint8_t OutEp;
+ uint8_t InEp;
+ HID_CtlStateTypeDef ctl_state;
+ FIFO_TypeDef fifo;
+ uint8_t *pData;
+ uint16_t length;
+ uint8_t ep_addr;
+ uint16_t poll;
+ uint16_t timer;
+ uint8_t DataReady;
+ HID_DescTypeDef HID_Desc;
+ USBH_StatusTypeDef ( * Init)(USBH_HandleTypeDef *phost);
+}
+HID_HandleTypeDef;
+
+/**
+ * @}
+ */
+
+/** @defgroup USBH_HID_CORE_Exported_Defines
+ * @{
+ */
+
+#define USB_HID_GET_REPORT 0x01
+#define USB_HID_GET_IDLE 0x02
+#define USB_HID_GET_PROTOCOL 0x03
+#define USB_HID_SET_REPORT 0x09
+#define USB_HID_SET_IDLE 0x0A
+#define USB_HID_SET_PROTOCOL 0x0B
+
+
+
+
+/* HID Class Codes */
+#define USB_HID_CLASS 0x03
+
+/* Interface Descriptor field values for HID Boot Protocol */
+#define HID_BOOT_CODE 0x01
+#define HID_KEYBRD_BOOT_CODE 0x01
+#define HID_MOUSE_BOOT_CODE 0x02
+
+
+/**
+ * @}
+ */
+
+/** @defgroup USBH_HID_CORE_Exported_Macros
+ * @{
+ */
+/**
+ * @}
+ */
+
+/** @defgroup USBH_HID_CORE_Exported_Variables
+ * @{
+ */
+extern USBH_ClassTypeDef HID_Class;
+#define USBH_HID_CLASS &HID_Class
+/**
+ * @}
+ */
+
+/** @defgroup USBH_HID_CORE_Exported_FunctionsPrototype
+ * @{
+ */
+
+USBH_StatusTypeDef USBH_HID_SetReport (USBH_HandleTypeDef *phost,
+ uint8_t reportType,
+ uint8_t reportId,
+ uint8_t* reportBuff,
+ uint8_t reportLen);
+
+USBH_StatusTypeDef USBH_HID_GetReport (USBH_HandleTypeDef *phost,
+ uint8_t reportType,
+ uint8_t reportId,
+ uint8_t* reportBuff,
+ uint8_t reportLen);
+
+USBH_StatusTypeDef USBH_HID_GetHIDReportDescriptor (USBH_HandleTypeDef *phost,
+ uint16_t length);
+
+USBH_StatusTypeDef USBH_HID_GetHIDDescriptor (USBH_HandleTypeDef *phost,
+ uint16_t length);
+
+USBH_StatusTypeDef USBH_HID_SetIdle (USBH_HandleTypeDef *phost,
+ uint8_t duration,
+ uint8_t reportId);
+
+USBH_StatusTypeDef USBH_HID_SetProtocol (USBH_HandleTypeDef *phost,
+ uint8_t protocol);
+
+void USBH_HID_EventCallback(USBH_HandleTypeDef *phost);
+
+HID_TypeTypeDef USBH_HID_GetDeviceType(USBH_HandleTypeDef *phost);
+
+void fifo_init(FIFO_TypeDef * f, uint8_t * buf, uint16_t size);
+
+uint16_t fifo_read(FIFO_TypeDef * f, void * buf, uint16_t nbytes);
+
+uint16_t fifo_write(FIFO_TypeDef * f, const void * buf, uint16_t nbytes);
+
+/**
+ * @}
+ */
+
+
+#endif /* __USBH_HID_H */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
+
diff --git a/ports/stm32/usbhost/Class/HID/Inc/usbh_hid_keybd.h b/ports/stm32/usbhost/Class/HID/Inc/usbh_hid_keybd.h
new file mode 100644
index 000000000..dc72ebb26
--- /dev/null
+++ b/ports/stm32/usbhost/Class/HID/Inc/usbh_hid_keybd.h
@@ -0,0 +1,318 @@
+/**
+ ******************************************************************************
+ * @file usbh_hid_keybd.h
+ * @author MCD Application Team
+ * @version V3.0.0
+ * @date 18-February-2014
+ * @brief This file contains all the prototypes for the usbh_hid_keybd.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 -----------------------------------------------*/
+#ifndef __USBH_HID_KEYBD_H
+#define __USBH_HID_KEYBD_H
+
+/* Includes ------------------------------------------------------------------*/
+#include "usbh_hid.h"
+#include "usbh_hid_keybd.h"
+
+/** @addtogroup USBH_LIB
+ * @{
+ */
+
+/** @addtogroup USBH_CLASS
+ * @{
+ */
+
+/** @addtogroup USBH_HID_CLASS
+ * @{
+ */
+
+/** @defgroup USBH_HID_KEYBD
+ * @brief This file is the Header file for USBH_HID_KEYBD.c
+ * @{
+ */
+
+
+/** @defgroup USBH_HID_KEYBD_Exported_Types
+ * @{
+ */
+#define KEY_NONE 0x00
+#define KEY_ERRORROLLOVER 0x01
+#define KEY_POSTFAIL 0x02
+#define KEY_ERRORUNDEFINED 0x03
+#define KEY_A 0x04
+#define KEY_B 0x05
+#define KEY_C 0x06
+#define KEY_D 0x07
+#define KEY_E 0x08
+#define KEY_F 0x09
+#define KEY_G 0x0A
+#define KEY_H 0x0B
+#define KEY_I 0x0C
+#define KEY_J 0x0D
+#define KEY_K 0x0E
+#define KEY_L 0x0F
+#define KEY_M 0x10
+#define KEY_N 0x11
+#define KEY_O 0x12
+#define KEY_P 0x13
+#define KEY_Q 0x14
+#define KEY_R 0x15
+#define KEY_S 0x16
+#define KEY_T 0x17
+#define KEY_U 0x18
+#define KEY_V 0x19
+#define KEY_W 0x1A
+#define KEY_X 0x1B
+#define KEY_Y 0x1C
+#define KEY_Z 0x1D
+#define KEY_1_EXCLAMATION_MARK 0x1E
+#define KEY_2_AT 0x1F
+#define KEY_3_NUMBER_SIGN 0x20
+#define KEY_4_DOLLAR 0x21
+#define KEY_5_PERCENT 0x22
+#define KEY_6_CARET 0x23
+#define KEY_7_AMPERSAND 0x24
+#define KEY_8_ASTERISK 0x25
+#define KEY_9_OPARENTHESIS 0x26
+#define KEY_0_CPARENTHESIS 0x27
+#define KEY_ENTER 0x28
+#define KEY_ESCAPE 0x29
+#define KEY_BACKSPACE 0x2A
+#define KEY_TAB 0x2B
+#define KEY_SPACEBAR 0x2C
+#define KEY_MINUS_UNDERSCORE 0x2D
+#define KEY_EQUAL_PLUS 0x2E
+#define KEY_OBRACKET_AND_OBRACE 0x2F
+#define KEY_CBRACKET_AND_CBRACE 0x30
+#define KEY_BACKSLASH_VERTICAL_BAR 0x31
+#define KEY_NONUS_NUMBER_SIGN_TILDE 0x32
+#define KEY_SEMICOLON_COLON 0x33
+#define KEY_SINGLE_AND_DOUBLE_QUOTE 0x34
+#define KEY_GRAVE ACCENT AND TILDE 0x35
+#define KEY_COMMA_AND_LESS 0x36
+#define KEY_DOT_GREATER 0x37
+#define KEY_SLASH_QUESTION 0x38
+#define KEY_CAPS LOCK 0x39
+#define KEY_F1 0x3A
+#define KEY_F2 0x3B
+#define KEY_F3 0x3C
+#define KEY_F4 0x3D
+#define KEY_F5 0x3E
+#define KEY_F6 0x3F
+#define KEY_F7 0x40
+#define KEY_F8 0x41
+#define KEY_F9 0x42
+#define KEY_F10 0x43
+#define KEY_F11 0x44
+#define KEY_F12 0x45
+#define KEY_PRINTSCREEN 0x46
+#define KEY_SCROLL LOCK 0x47
+#define KEY_PAUSE 0x48
+#define KEY_INSERT 0x49
+#define KEY_HOME 0x4A
+#define KEY_PAGEUP 0x4B
+#define KEY_DELETE 0x4C
+#define KEY_END1 0x4D
+#define KEY_PAGEDOWN 0x4E
+#define KEY_RIGHTARROW 0x4F
+#define KEY_LEFTARROW 0x50
+#define KEY_DOWNARROW 0x51
+#define KEY_UPARROW 0x52
+#define KEY_KEYPAD_NUM_LOCK_AND_CLEAR 0x53
+#define KEY_KEYPAD_SLASH 0x54
+#define KEY_KEYPAD_ASTERIKS 0x55
+#define KEY_KEYPAD_MINUS 0x56
+#define KEY_KEYPAD_PLUS 0x57
+#define KEY_KEYPAD_ENTER 0x58
+#define KEY_KEYPAD_1_END 0x59
+#define KEY_KEYPAD_2_DOWN_ARROW 0x5A
+#define KEY_KEYPAD_3_PAGEDN 0x5B
+#define KEY_KEYPAD_4_LEFT_ARROW 0x5C
+#define KEY_KEYPAD_5 0x5D
+#define KEY_KEYPAD_6_RIGHT_ARROW 0x5E
+#define KEY_KEYPAD_7_HOME 0x5F
+#define KEY_KEYPAD_8_UP_ARROW 0x60
+#define KEY_KEYPAD_9_PAGEUP 0x61
+#define KEY_KEYPAD_0_INSERT 0x62
+#define KEY_KEYPAD_DECIMAL_SEPARATOR_DELETE 0x63
+#define KEY_NONUS_BACK_SLASH_VERTICAL_BAR 0x64
+#define KEY_APPLICATION 0x65
+#define KEY_POWER 0x66
+#define KEY_KEYPAD_EQUAL 0x67
+#define KEY_F13 0x68
+#define KEY_F14 0x69
+#define KEY_F15 0x6A
+#define KEY_F16 0x6B
+#define KEY_F17 0x6C
+#define KEY_F18 0x6D
+#define KEY_F19 0x6E
+#define KEY_F20 0x6F
+#define KEY_F21 0x70
+#define KEY_F22 0x71
+#define KEY_F23 0x72
+#define KEY_F24 0x73
+#define KEY_EXECUTE 0x74
+#define KEY_HELP 0x75
+#define KEY_MENU 0x76
+#define KEY_SELECT 0x77
+#define KEY_STOP 0x78
+#define KEY_AGAIN 0x79
+#define KEY_UNDO 0x7A
+#define KEY_CUT 0x7B
+#define KEY_COPY 0x7C
+#define KEY_PASTE 0x7D
+#define KEY_FIND 0x7E
+#define KEY_MUTE 0x7F
+#define KEY_VOLUME_UP 0x80
+#define KEY_VOLUME_DOWN 0x81
+#define KEY_LOCKING_CAPS_LOCK 0x82
+#define KEY_LOCKING_NUM_LOCK 0x83
+#define KEY_LOCKING_SCROLL_LOCK 0x84
+#define KEY_KEYPAD_COMMA 0x85
+#define KEY_KEYPAD_EQUAL_SIGN 0x86
+#define KEY_INTERNATIONAL1 0x87
+#define KEY_INTERNATIONAL2 0x88
+#define KEY_INTERNATIONAL3 0x89
+#define KEY_INTERNATIONAL4 0x8A
+#define KEY_INTERNATIONAL5 0x8B
+#define KEY_INTERNATIONAL6 0x8C
+#define KEY_INTERNATIONAL7 0x8D
+#define KEY_INTERNATIONAL8 0x8E
+#define KEY_INTERNATIONAL9 0x8F
+#define KEY_LANG1 0x90
+#define KEY_LANG2 0x91
+#define KEY_LANG3 0x92
+#define KEY_LANG4 0x93
+#define KEY_LANG5 0x94
+#define KEY_LANG6 0x95
+#define KEY_LANG7 0x96
+#define KEY_LANG8 0x97
+#define KEY_LANG9 0x98
+#define KEY_ALTERNATE_ERASE 0x99
+#define KEY_SYSREQ 0x9A
+#define KEY_CANCEL 0x9B
+#define KEY_CLEAR 0x9C
+#define KEY_PRIOR 0x9D
+#define KEY_RETURN 0x9E
+#define KEY_SEPARATOR 0x9F
+#define KEY_OUT 0xA0
+#define KEY_OPER 0xA1
+#define KEY_CLEAR_AGAIN 0xA2
+#define KEY_CRSEL 0xA3
+#define KEY_EXSEL 0xA4
+#define KEY_KEYPAD_00 0xB0
+#define KEY_KEYPAD_000 0xB1
+#define KEY_THOUSANDS_SEPARATOR 0xB2
+#define KEY_DECIMAL_SEPARATOR 0xB3
+#define KEY_CURRENCY_UNIT 0xB4
+#define KEY_CURRENCY_SUB_UNIT 0xB5
+#define KEY_KEYPAD_OPARENTHESIS 0xB6
+#define KEY_KEYPAD_CPARENTHESIS 0xB7
+#define KEY_KEYPAD_OBRACE 0xB8
+#define KEY_KEYPAD_CBRACE 0xB9
+#define KEY_KEYPAD_TAB 0xBA
+#define KEY_KEYPAD_BACKSPACE 0xBB
+#define KEY_KEYPAD_A 0xBC
+#define KEY_KEYPAD_B 0xBD
+#define KEY_KEYPAD_C 0xBE
+#define KEY_KEYPAD_D 0xBF
+#define KEY_KEYPAD_E 0xC0
+#define KEY_KEYPAD_F 0xC1
+#define KEY_KEYPAD_XOR 0xC2
+#define KEY_KEYPAD_CARET 0xC3
+#define KEY_KEYPAD_PERCENT 0xC4
+#define KEY_KEYPAD_LESS 0xC5
+#define KEY_KEYPAD_GREATER 0xC6
+#define KEY_KEYPAD_AMPERSAND 0xC7
+#define KEY_KEYPAD_LOGICAL_AND 0xC8
+#define KEY_KEYPAD_VERTICAL_BAR 0xC9
+#define KEY_KEYPAD_LOGIACL_OR 0xCA
+#define KEY_KEYPAD_COLON 0xCB
+#define KEY_KEYPAD_NUMBER_SIGN 0xCC
+#define KEY_KEYPAD_SPACE 0xCD
+#define KEY_KEYPAD_AT 0xCE
+#define KEY_KEYPAD_EXCLAMATION_MARK 0xCF
+#define KEY_KEYPAD_MEMORY_STORE 0xD0
+#define KEY_KEYPAD_MEMORY_RECALL 0xD1
+#define KEY_KEYPAD_MEMORY_CLEAR 0xD2
+#define KEY_KEYPAD_MEMORY_ADD 0xD3
+#define KEY_KEYPAD_MEMORY_SUBTRACT 0xD4
+#define KEY_KEYPAD_MEMORY_MULTIPLY 0xD5
+#define KEY_KEYPAD_MEMORY_DIVIDE 0xD6
+#define KEY_KEYPAD_PLUSMINUS 0xD7
+#define KEY_KEYPAD_CLEAR 0xD8
+#define KEY_KEYPAD_CLEAR_ENTRY 0xD9
+#define KEY_KEYPAD_BINARY 0xDA
+#define KEY_KEYPAD_OCTAL 0xDB
+#define KEY_KEYPAD_DECIMAL 0xDC
+#define KEY_KEYPAD_HEXADECIMAL 0xDD
+#define KEY_LEFTCONTROL 0xE0
+#define KEY_LEFTSHIFT 0xE1
+#define KEY_LEFTALT 0xE2
+#define KEY_LEFT_GUI 0xE3
+#define KEY_RIGHTCONTROL 0xE4
+#define KEY_RIGHTSHIFT 0xE5
+#define KEY_RIGHTALT 0xE6
+#define KEY_RIGHT_GUI 0xE7
+
+typedef struct
+{
+ uint8_t state;
+ uint8_t lctrl;
+ uint8_t lshift;
+ uint8_t lalt;
+ uint8_t lgui;
+ uint8_t rctrl;
+ uint8_t rshift;
+ uint8_t ralt;
+ uint8_t rgui;
+ uint8_t keys[6];
+}
+HID_KEYBD_Info_TypeDef;
+
+USBH_StatusTypeDef USBH_HID_KeybdInit(USBH_HandleTypeDef *phost);
+HID_KEYBD_Info_TypeDef *USBH_HID_GetKeybdInfo(USBH_HandleTypeDef *phost);
+uint8_t USBH_HID_GetASCIICode(HID_KEYBD_Info_TypeDef *info);
+
+/**
+ * @}
+ */
+
+#endif /* __USBH_HID_KEYBD_H */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
+
diff --git a/ports/stm32/usbhost/Class/HID/Inc/usbh_hid_mouse.h b/ports/stm32/usbhost/Class/HID/Inc/usbh_hid_mouse.h
new file mode 100644
index 000000000..3a87d1a2d
--- /dev/null
+++ b/ports/stm32/usbhost/Class/HID/Inc/usbh_hid_mouse.h
@@ -0,0 +1,118 @@
+/**
+ ******************************************************************************
+ * @file usbh_hid_mouse.h
+ * @author MCD Application Team
+ * @version V3.0.0
+ * @date 18-February-2014
+ * @brief This file contains all the prototypes for the usbh_hid_mouse.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 ----------------------------------------------*/
+#ifndef __USBH_HID_MOUSE_H
+#define __USBH_HID_MOUSE_H
+
+/* Includes ------------------------------------------------------------------*/
+#include "usbh_hid.h"
+
+/** @addtogroup USBH_LIB
+ * @{
+ */
+
+/** @addtogroup USBH_CLASS
+ * @{
+ */
+
+/** @addtogroup USBH_HID_CLASS
+ * @{
+ */
+
+/** @defgroup USBH_HID_MOUSE
+ * @brief This file is the Header file for USBH_HID_MOUSE.c
+ * @{
+ */
+
+
+/** @defgroup USBH_HID_MOUSE_Exported_Types
+ * @{
+ */
+
+typedef struct _HID_MOUSE_Info
+{
+ uint8_t x;
+ uint8_t y;
+ uint8_t buttons[3];
+}
+HID_MOUSE_Info_TypeDef;
+
+/**
+ * @}
+ */
+
+/** @defgroup USBH_HID_MOUSE_Exported_Defines
+ * @{
+ */
+/**
+ * @}
+ */
+
+/** @defgroup USBH_HID_MOUSE_Exported_Macros
+ * @{
+ */
+/**
+ * @}
+ */
+
+/** @defgroup USBH_HID_MOUSE_Exported_Variables
+ * @{
+ */
+/**
+ * @}
+ */
+
+/** @defgroup USBH_HID_MOUSE_Exported_FunctionsPrototype
+ * @{
+ */
+USBH_StatusTypeDef USBH_HID_MouseInit(USBH_HandleTypeDef *phost);
+HID_MOUSE_Info_TypeDef *USBH_HID_GetMouseInfo(USBH_HandleTypeDef *phost);
+
+/**
+ * @}
+ */
+
+#endif /* __USBH_HID_MOUSE_H */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/ports/stm32/usbhost/Class/HID/Inc/usbh_hid_parser.h b/ports/stm32/usbhost/Class/HID/Inc/usbh_hid_parser.h
new file mode 100644
index 000000000..0bf5739af
--- /dev/null
+++ b/ports/stm32/usbhost/Class/HID/Inc/usbh_hid_parser.h
@@ -0,0 +1,96 @@
+/**
+ ******************************************************************************
+ * @file usbh_hid_parser.c
+ * @author MCD Application Team
+ * @version V3.0.0
+ * @date 18-February-2014
+ * @brief This file is the header file of the usbh_hid_parser.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.
+ *
+ ******************************************************************************
+ */
+#ifndef _HID_PARSER_H_
+#define _HID_PARSER_H_
+
+/* Includes ------------------------------------------------------------------*/
+#include "usbh_hid.h"
+#include "usbh_hid_usage.h"
+
+/** @addtogroup USBH_LIB
+ * @{
+ */
+
+/** @addtogroup USBH_CLASS
+ * @{
+ */
+
+/** @addtogroup USBH_HID_CLASS
+ * @{
+ */
+
+/** @defgroup USBH_HID_PARSER
+ * @brief This file is the Header file for USBH_HID_PARSER.c
+ * @{
+ */
+
+
+/** @defgroup USBH_HID_PARSER_Exported_Types
+ * @{
+ */
+typedef struct
+{
+ uint8_t *data;
+ uint32_t size;
+ uint8_t shift;
+ uint8_t count;
+ uint8_t sign;
+ uint32_t logical_min; /*min value device can return*/
+ uint32_t logical_max; /*max value device can return*/
+ uint32_t physical_min; /*min vale read can report*/
+ uint32_t physical_max; /*max value read can report*/
+ uint32_t resolution;
+}
+HID_Report_ItemTypedef;
+
+
+uint32_t HID_ReadItem (HID_Report_ItemTypedef *ri, uint8_t ndx);
+uint32_t HID_WriteItem(HID_Report_ItemTypedef *ri, uint32_t value, uint8_t ndx);
+
+
+/**
+ * @}
+ */
+
+#endif /* _HID_PARSER_H_ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/ports/stm32/usbhost/Class/HID/Inc/usbh_hid_usage.h b/ports/stm32/usbhost/Class/HID/Inc/usbh_hid_usage.h
new file mode 100644
index 000000000..e1f7762f3
--- /dev/null
+++ b/ports/stm32/usbhost/Class/HID/Inc/usbh_hid_usage.h
@@ -0,0 +1,191 @@
+/**
+ ******************************************************************************
+ * @file usbh_hid_keybd.c
+ * @author MCD Application Team
+ * @version V3.0.0
+ * @date 18-February-2014
+ * @brief This file contain the USAGE page codes
+ ******************************************************************************
+ * @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.
+ *
+ ******************************************************************************
+ */
+#ifndef _HID_USAGE_H_
+#define _HID_USAGE_H_
+
+/** @addtogroup USBH_LIB
+ * @{
+ */
+
+/** @addtogroup USBH_CLASS
+ * @{
+ */
+
+/** @addtogroup USBH_HID_CLASS
+ * @{
+ */
+
+/** @defgroup USBH_HID_USAGE
+ * @brief This file is the Header file for USBH_HID_USAGE.c
+ * @{
+ */
+
+
+/** @defgroup USBH_HID_USAGE_Exported_Types
+ * @{
+ */
+
+/****************************************************/
+/* HID 1.11 usage pages */
+/****************************************************/
+
+#define HID_USAGE_PAGE_UNDEFINED uint16_t (0x00) /* Undefined */
+/**** Top level pages */
+#define HID_USAGE_PAGE_GEN_DES uint16_t (0x01) /* Generic Desktop Controls*/
+#define HID_USAGE_PAGE_SIM_CTR uint16_t (0x02) /* Simulation Controls */
+#define HID_USAGE_PAGE_VR_CTR uint16_t (0x03) /* VR Controls */
+#define HID_USAGE_PAGE_SPORT_CTR uint16_t (0x04) /* Sport Controls */
+#define HID_USAGE_PAGE_GAME_CTR uint16_t (0x05) /* Game Controls */
+#define HID_USAGE_PAGE_GEN_DEV uint16_t (0x06) /* Generic Device Controls */
+#define HID_USAGE_PAGE_KEYB uint16_t (0x07) /* Keyboard/Keypad */
+#define HID_USAGE_PAGE_LED uint16_t (0x08) /* LEDs */
+#define HID_USAGE_PAGE_BUTTON uint16_t (0x09) /* Button */
+#define HID_USAGE_PAGE_ORDINAL uint16_t (0x0A) /* Ordinal */
+#define HID_USAGE_PAGE_PHONE uint16_t (0x0B) /* Telephony */
+#define HID_USAGE_PAGE_CONSUMER uint16_t (0x0C) /* Consumer */
+#define HID_USAGE_PAGE_DIGITIZER uint16_t (0x0D) /* Digitizer*/
+/* 0E Reserved */
+#define HID_USAGE_PAGE_PID uint16_t (0x0F) /* PID Page (force feedback and related devices) */
+#define HID_USAGE_PAGE_UNICODE uint16_t (0x10) /* Unicode */
+/* 11-13 Reserved */
+#define HID_USAGE_PAGE_ALNUM_DISP uint16_t (0x14) /* Alphanumeric Display */
+/* 15-1f Reserved */
+/**** END of top level pages */
+/* 25-3f Reserved */
+#define HID_USAGE_PAGE_MEDICAL uint16_t (0x40) /* Medical Instruments */
+/* 41-7F Reserved */
+/*80-83 Monitor pages USB Device Class Definition for Monitor Devices
+ 84-87 Power pages USB Device Class Definition for Power Devices */
+/* 88-8B Reserved */
+#define HID_USAGE_PAGE_BARCODE uint16_t (0x8C) /* Bar Code Scanner page */
+#define HID_USAGE_PAGE_SCALE uint16_t (0x8D) /* Scale page */
+#define HID_USAGE_PAGE_MSR uint16_t (0x8E) /* Magnetic Stripe Reading (MSR) Devices */
+#define HID_USAGE_PAGE_POS uint16_t (0x8F) /* Reserved Point of Sale pages */
+#define HID_USAGE_PAGE_CAMERA_CTR uint16_t (0x90) /* Camera Control Page */
+#define HID_USAGE_PAGE_ARCADE uint16_t (0x91) /* Arcade Page */
+
+/****************************************************/
+/* Usage definitions for the "Generic Decktop" page */
+/****************************************************/
+#define HID_USAGE_UNDEFINED uint16_t (0x00) /* Undefined */
+#define HID_USAGE_POINTER uint16_t (0x01) /* Pointer (Physical Collection) */
+#define HID_USAGE_MOUSE uint16_t (0x02) /* Mouse (Application Collection) */
+/* 03 Reserved */
+#define HID_USAGE_JOYSTICK uint16_t (0x04) /* Joystick (Application Collection) */
+#define HID_USAGE_GAMEPAD uint16_t (0x05) /* Game Pad (Application Collection) */
+#define HID_USAGE_KBD uint16_t (0x06) /* Keyboard (Application Collection) */
+#define HID_USAGE_KEYPAD uint16_t (0x07) /* Keypad (Application Collection) */
+#define HID_USAGE_MAX_CTR uint16_t (0x08) /* Multi-axis Controller (Application Collection) */
+/* 09-2F Reserved */
+#define HID_USAGE_X uint16_t (0x30) /* X (Dynamic Value) */
+#define HID_USAGE_Y uint16_t (0x31) /* Y (Dynamic Value) */
+#define HID_USAGE_Z uint16_t (0x32) /* Z (Dynamic Value) */
+#define HID_USAGE_RX uint16_t (0x33) /* Rx (Dynamic Value) */
+#define HID_USAGE_RY uint16_t (0x34) /* Ry (Dynamic Value) */
+#define HID_USAGE_RZ uint16_t (0x35) /* Rz (Dynamic Value) */
+#define HID_USAGE_SLIDER uint16_t (0x36) /* Slider (Dynamic Value) */
+#define HID_USAGE_DIAL uint16_t (0x37) /* Dial (Dynamic Value) */
+#define HID_USAGE_WHEEL uint16_t (0x38) /* Wheel (Dynamic Value) */
+#define HID_USAGE_HATSW uint16_t (0x39) /* Hat switch (Dynamic Value) */
+#define HID_USAGE_COUNTEDBUF uint16_t (0x3A) /* Counted Buffer (Logical Collection) */
+#define HID_USAGE_BYTECOUNT uint16_t (0x3B) /* Byte Count (Dynamic Value) */
+#define HID_USAGE_MOTIONWAKE uint16_t (0x3C) /* Motion Wakeup (One Shot Control) */
+#define HID_USAGE_START uint16_t (0x3D) /* Start (On/Off Control) */
+#define HID_USAGE_SELECT uint16_t (0x3E) /* Select (On/Off Control) */
+/* 3F Reserved */
+#define HID_USAGE_VX uint16_t (0x40) /* Vx (Dynamic Value) */
+#define HID_USAGE_VY uint16_t (0x41) /* Vy (Dynamic Value) */
+#define HID_USAGE_VZ uint16_t (0x42) /* Vz (Dynamic Value) */
+#define HID_USAGE_VBRX uint16_t (0x43) /* Vbrx (Dynamic Value) */
+#define HID_USAGE_VBRY uint16_t (0x44) /* Vbry (Dynamic Value) */
+#define HID_USAGE_VBRZ uint16_t (0x45) /* Vbrz (Dynamic Value) */
+#define HID_USAGE_VNO uint16_t (0x46) /* Vno (Dynamic Value) */
+#define HID_USAGE_FEATNOTIF uint16_t (0x47) /* Feature Notification (Dynamic Value),(Dynamic Flag) */
+/* 48-7F Reserved */
+#define HID_USAGE_SYSCTL uint16_t (0x80) /* System Control (Application Collection) */
+#define HID_USAGE_PWDOWN uint16_t (0x81) /* System Power Down (One Shot Control) */
+#define HID_USAGE_SLEEP uint16_t (0x82) /* System Sleep (One Shot Control) */
+#define HID_USAGE_WAKEUP uint16_t (0x83) /* System Wake Up (One Shot Control) */
+#define HID_USAGE_CONTEXTM uint16_t (0x84) /* System Context Menu (One Shot Control) */
+#define HID_USAGE_MAINM uint16_t (0x85) /* System Main Menu (One Shot Control) */
+#define HID_USAGE_APPM uint16_t (0x86) /* System App Menu (One Shot Control) */
+#define HID_USAGE_MENUHELP uint16_t (0x87) /* System Menu Help (One Shot Control) */
+#define HID_USAGE_MENUEXIT uint16_t (0x88) /* System Menu Exit (One Shot Control) */
+#define HID_USAGE_MENUSELECT uint16_t (0x89) /* System Menu Select (One Shot Control) */
+#define HID_USAGE_SYSM_RIGHT uint16_t (0x8A) /* System Menu Right (Re-Trigger Control) */
+#define HID_USAGE_SYSM_LEFT uint16_t (0x8B) /* System Menu Left (Re-Trigger Control) */
+#define HID_USAGE_SYSM_UP uint16_t (0x8C) /* System Menu Up (Re-Trigger Control) */
+#define HID_USAGE_SYSM_DOWN uint16_t (0x8D) /* System Menu Down (Re-Trigger Control) */
+#define HID_USAGE_COLDRESET uint16_t (0x8E) /* System Cold Restart (One Shot Control) */
+#define HID_USAGE_WARMRESET uint16_t (0x8F) /* System Warm Restart (One Shot Control) */
+#define HID_USAGE_DUP uint16_t (0x90) /* D-pad Up (On/Off Control) */
+#define HID_USAGE_DDOWN uint16_t (0x91) /* D-pad Down (On/Off Control) */
+#define HID_USAGE_DRIGHT uint16_t (0x92) /* D-pad Right (On/Off Control) */
+#define HID_USAGE_DLEFT uint16_t (0x93) /* D-pad Left (On/Off Control) */
+/* 94-9F Reserved */
+#define HID_USAGE_SYS_DOCK uint16_t (0xA0) /* System Dock (One Shot Control) */
+#define HID_USAGE_SYS_UNDOCK uint16_t (0xA1) /* System Undock (One Shot Control) */
+#define HID_USAGE_SYS_SETUP uint16_t (0xA2) /* System Setup (One Shot Control) */
+#define HID_USAGE_SYS_BREAK uint16_t (0xA3) /* System Break (One Shot Control) */
+#define HID_USAGE_SYS_DBGBRK uint16_t (0xA4) /* System Debugger Break (One Shot Control) */
+#define HID_USAGE_APP_BRK uint16_t (0xA5) /* Application Break (One Shot Control) */
+#define HID_USAGE_APP_DBGBRK uint16_t (0xA6) /* Application Debugger Break (One Shot Control) */
+#define HID_USAGE_SYS_SPKMUTE uint16_t (0xA7) /* System Speaker Mute (One Shot Control) */
+#define HID_USAGE_SYS_HIBERN uint16_t (0xA8) /* System Hibernate (One Shot Control) */
+/* A9-AF Reserved */
+#define HID_USAGE_SYS_SIDPINV uint16_t (0xB0) /* System Display Invert (One Shot Control) */
+#define HID_USAGE_SYS_DISPINT uint16_t (0xB1) /* System Display Internal (One Shot Control) */
+#define HID_USAGE_SYS_DISPEXT uint16_t (0xB2) /* System Display External (One Shot Control) */
+#define HID_USAGE_SYS_DISPBOTH uint16_t (0xB3) /* System Display Both (One Shot Control) */
+#define HID_USAGE_SYS_DISPDUAL uint16_t (0xB4) /* System Display Dual (One Shot Control) */
+#define HID_USAGE_SYS_DISPTGLIE uint16_t (0xB5) /* System Display Toggle Int/Ext (One Shot Control) */
+#define HID_USAGE_SYS_DISP_SWAP uint16_t (0xB6) /* System Display Swap Primary/Secondary (One Shot Control) */
+#define HID_USAGE_SYS_DIPS_LCDA uint16_t (0xB7) /* System Display LCD Autoscale (One Shot Control) */
+/* B8-FFFF Reserved */
+
+/**
+ * @}
+ */
+
+#endif /* _HID_USAGE_H_ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/ports/stm32/usbhost/Class/HID/Src/usbh_hid.c b/ports/stm32/usbhost/Class/HID/Src/usbh_hid.c
new file mode 100644
index 000000000..a56f45c5c
--- /dev/null
+++ b/ports/stm32/usbhost/Class/HID/Src/usbh_hid.c
@@ -0,0 +1,800 @@
+/**
+ ******************************************************************************
+ * @file usbh_hid.c
+ * @author MCD Application Team
+ * @version V3.0.0
+ * @date 18-February-2014
+ * @brief This file is the HID Layer Handlers for USB Host HID class.
+ *
+ * @verbatim
+ *
+ * ===================================================================
+ * HID Class Description
+ * ===================================================================
+ * This module manages the MSC class V1.11 following the "Device Class Definition
+ * for Human Interface Devices (HID) Version 1.11 Jun 27, 2001".
+ * This driver implements the following aspects of the specification:
+ * - The Boot Interface Subclass
+ * - The Mouse and Keyboard protocols
+ *
+ * @endverbatim
+ *
+ ******************************************************************************
+ * @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 "usbh_hid.h"
+#include "usbh_hid_parser.h"
+
+
+/** @addtogroup USBH_LIB
+* @{
+*/
+
+/** @addtogroup USBH_CLASS
+* @{
+*/
+
+/** @addtogroup USBH_HID_CLASS
+* @{
+*/
+
+/** @defgroup USBH_HID_CORE
+* @brief This file includes HID Layer Handlers for USB Host HID class.
+* @{
+*/
+
+/** @defgroup USBH_HID_CORE_Private_TypesDefinitions
+* @{
+*/
+/**
+* @}
+*/
+
+
+/** @defgroup USBH_HID_CORE_Private_Defines
+* @{
+*/
+/**
+* @}
+*/
+
+
+/** @defgroup USBH_HID_CORE_Private_Macros
+* @{
+*/
+/**
+* @}
+*/
+
+
+/** @defgroup USBH_HID_CORE_Private_Variables
+* @{
+*/
+
+/**
+* @}
+*/
+
+
+/** @defgroup USBH_HID_CORE_Private_FunctionPrototypes
+* @{
+*/
+
+static USBH_StatusTypeDef USBH_HID_InterfaceInit (USBH_HandleTypeDef *phost);
+static USBH_StatusTypeDef USBH_HID_InterfaceDeInit (USBH_HandleTypeDef *phost);
+static USBH_StatusTypeDef USBH_HID_ClassRequest(USBH_HandleTypeDef *phost);
+static USBH_StatusTypeDef USBH_HID_Process(USBH_HandleTypeDef *phost);
+static USBH_StatusTypeDef USBH_HID_SOFProcess(USBH_HandleTypeDef *phost);
+static void USBH_HID_ParseHIDDesc (HID_DescTypeDef *desc, uint8_t *buf);
+
+extern USBH_StatusTypeDef USBH_HID_MouseInit(USBH_HandleTypeDef *phost);
+extern USBH_StatusTypeDef USBH_HID_KeybdInit(USBH_HandleTypeDef *phost);
+
+USBH_ClassTypeDef HID_Class =
+{
+ "HID",
+ USB_HID_CLASS,
+ USBH_HID_InterfaceInit,
+ USBH_HID_InterfaceDeInit,
+ USBH_HID_ClassRequest,
+ USBH_HID_Process,
+ USBH_HID_SOFProcess,
+ NULL,
+};
+/**
+* @}
+*/
+
+
+/** @defgroup USBH_HID_CORE_Private_Functions
+* @{
+*/
+
+
+/**
+ * @brief USBH_HID_InterfaceInit
+ * The function init the HID class.
+ * @param phost: Host handle
+ * @retval USBH Status
+ */
+static USBH_StatusTypeDef USBH_HID_InterfaceInit (USBH_HandleTypeDef *phost)
+{
+ uint8_t max_ep;
+ uint8_t num = 0;
+ uint8_t interface;
+
+ USBH_StatusTypeDef status = USBH_FAIL ;
+ HID_HandleTypeDef *HID_Handle;
+
+ interface = USBH_FindInterface(phost, phost->pActiveClass->ClassCode, HID_BOOT_CODE, 0xFF);
+
+ if(interface == 0xFF) /* No Valid Interface */
+ {
+ status = USBH_FAIL;
+ USBH_DbgLog ("Cannot Find the interface for %s class.", phost->pActiveClass->Name);
+ }
+ else
+ {
+ USBH_SelectInterface (phost, interface);
+ phost->pActiveClass->pData = (HID_HandleTypeDef *)USBH_malloc (sizeof(HID_HandleTypeDef));
+ HID_Handle = phost->pActiveClass->pData;
+ HID_Handle->state = HID_ERROR;
+
+ /*Decode Bootclass Protocl: Mouse or Keyboard*/
+ if(phost->device.CfgDesc.Itf_Desc[phost->device.current_interface].bInterfaceProtocol == HID_KEYBRD_BOOT_CODE)
+ {
+ USBH_UsrLog ("KeyBoard device found!");
+ HID_Handle->Init = USBH_HID_KeybdInit;
+ }
+ else if(phost->device.CfgDesc.Itf_Desc[phost->device.current_interface].bInterfaceProtocol == HID_MOUSE_BOOT_CODE)
+ {
+ USBH_UsrLog ("Mouse device found!");
+ HID_Handle->Init = USBH_HID_MouseInit;
+ }
+ else
+ {
+ USBH_UsrLog ("Protocol not supported.");
+ return USBH_FAIL;
+ }
+
+ HID_Handle->state = HID_INIT;
+ HID_Handle->ctl_state = HID_REQ_INIT;
+ HID_Handle->ep_addr = phost->device.CfgDesc.Itf_Desc[phost->device.current_interface].Ep_Desc[0].bEndpointAddress;
+ HID_Handle->length = phost->device.CfgDesc.Itf_Desc[phost->device.current_interface].Ep_Desc[0].wMaxPacketSize;
+ HID_Handle->poll = phost->device.CfgDesc.Itf_Desc[phost->device.current_interface].Ep_Desc[0].bInterval ;
+
+ if (HID_Handle->poll < HID_MIN_POLL)
+ {
+ HID_Handle->poll = HID_MIN_POLL;
+ }
+
+ /* Check fo available number of endpoints */
+ /* Find the number of EPs in the Interface Descriptor */
+ /* Choose the lower number in order not to overrun the buffer allocated */
+ max_ep = ( (phost->device.CfgDesc.Itf_Desc[phost->device.current_interface].bNumEndpoints <= USBH_MAX_NUM_ENDPOINTS) ?
+ phost->device.CfgDesc.Itf_Desc[phost->device.current_interface].bNumEndpoints :
+ USBH_MAX_NUM_ENDPOINTS);
+
+
+ /* Decode endpoint IN and OUT address from interface descriptor */
+ for ( ;num < max_ep; num++)
+ {
+ if(phost->device.CfgDesc.Itf_Desc[phost->device.current_interface].Ep_Desc[num].bEndpointAddress & 0x80)
+ {
+ HID_Handle->InEp = (phost->device.CfgDesc.Itf_Desc[phost->device.current_interface].Ep_Desc[num].bEndpointAddress);
+ HID_Handle->InPipe =\
+ USBH_AllocPipe(phost, HID_Handle->InEp);
+
+ /* Open pipe for IN endpoint */
+ USBH_OpenPipe (phost,
+ HID_Handle->InPipe,
+ HID_Handle->InEp,
+ phost->device.address,
+ phost->device.speed,
+ USB_EP_TYPE_INTR,
+ HID_Handle->length);
+
+ USBH_LL_SetToggle (phost, HID_Handle->InPipe, 0);
+
+ }
+ else
+ {
+ HID_Handle->OutEp = (phost->device.CfgDesc.Itf_Desc[phost->device.current_interface].Ep_Desc[num].bEndpointAddress);
+ HID_Handle->OutPipe =\
+ USBH_AllocPipe(phost, HID_Handle->OutEp);
+
+ /* Open pipe for OUT endpoint */
+ USBH_OpenPipe (phost,
+ HID_Handle->OutPipe,
+ HID_Handle->OutEp,
+ phost->device.address,
+ phost->device.speed,
+ USB_EP_TYPE_INTR,
+ HID_Handle->length);
+
+ USBH_LL_SetToggle (phost, HID_Handle->OutPipe, 0);
+ }
+
+ }
+ status = USBH_OK;
+ }
+ return status;
+}
+
+/**
+ * @brief USBH_HID_InterfaceDeInit
+ * The function DeInit the Pipes used for the HID class.
+ * @param phost: Host handle
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_HID_InterfaceDeInit (USBH_HandleTypeDef *phost )
+{
+ HID_HandleTypeDef *HID_Handle = phost->pActiveClass->pData;
+
+ if(HID_Handle->InPipe != 0x00)
+ {
+ USBH_ClosePipe (phost, HID_Handle->InPipe);
+ USBH_FreePipe (phost, HID_Handle->InPipe);
+ HID_Handle->InPipe = 0; /* Reset the pipe as Free */
+ }
+
+ if(HID_Handle->OutPipe != 0x00)
+ {
+ USBH_ClosePipe(phost, HID_Handle->OutPipe);
+ USBH_FreePipe (phost, HID_Handle->OutPipe);
+ HID_Handle->OutPipe = 0; /* Reset the pipe as Free */
+ }
+
+ if(phost->pActiveClass->pData)
+ {
+ USBH_free (phost->pActiveClass->pData);
+ }
+
+ return USBH_OK;
+}
+
+/**
+ * @brief USBH_HID_ClassRequest
+ * The function is responsible for handling Standard requests
+ * for HID class.
+ * @param phost: Host handle
+ * @retval USBH Status
+ */
+static USBH_StatusTypeDef USBH_HID_ClassRequest(USBH_HandleTypeDef *phost)
+{
+
+ USBH_StatusTypeDef status = USBH_BUSY;
+ USBH_StatusTypeDef classReqStatus = USBH_BUSY;
+ HID_HandleTypeDef *HID_Handle = phost->pActiveClass->pData;
+
+ /* Switch HID state machine */
+ switch (HID_Handle->ctl_state)
+ {
+ case HID_REQ_INIT:
+ case HID_REQ_GET_HID_DESC:
+
+ /* Get HID Desc */
+ if (USBH_HID_GetHIDDescriptor (phost, USB_HID_DESC_SIZE)== USBH_OK)
+ {
+
+ USBH_HID_ParseHIDDesc(&HID_Handle->HID_Desc, phost->device.Data);
+ HID_Handle->ctl_state = HID_REQ_GET_REPORT_DESC;
+ }
+
+ break;
+ case HID_REQ_GET_REPORT_DESC:
+
+
+ /* Get Report Desc */
+ if (USBH_HID_GetHIDReportDescriptor(phost, HID_Handle->HID_Desc.wItemLength) == USBH_OK)
+ {
+ /* The decriptor is available in phost->device.Data */
+
+ HID_Handle->ctl_state = HID_REQ_SET_IDLE;
+ }
+
+ break;
+
+ case HID_REQ_SET_IDLE:
+
+ classReqStatus = USBH_HID_SetIdle (phost, 0, 0);
+
+ /* set Idle */
+ if (classReqStatus == USBH_OK)
+ {
+ HID_Handle->ctl_state = HID_REQ_SET_PROTOCOL;
+ }
+ else if(classReqStatus == USBH_NOT_SUPPORTED)
+ {
+ HID_Handle->ctl_state = HID_REQ_SET_PROTOCOL;
+ }
+ break;
+
+ case HID_REQ_SET_PROTOCOL:
+ /* set protocol */
+ if (USBH_HID_SetProtocol (phost, 0) == USBH_OK)
+ {
+ HID_Handle->ctl_state = HID_REQ_IDLE;
+
+ /* all requests performed*/
+ phost->pUser(phost, HOST_USER_CLASS_ACTIVE);
+ status = USBH_OK;
+ }
+ break;
+
+ case HID_REQ_IDLE:
+ default:
+ break;
+ }
+
+ return status;
+}
+
+/**
+ * @brief USBH_HID_Process
+ * The function is for managing state machine for HID data transfers
+ * @param phost: Host handle
+ * @retval USBH Status
+ */
+static USBH_StatusTypeDef USBH_HID_Process(USBH_HandleTypeDef *phost)
+{
+ USBH_StatusTypeDef status = USBH_OK;
+ HID_HandleTypeDef *HID_Handle = phost->pActiveClass->pData;
+
+ switch (HID_Handle->state)
+ {
+ case HID_INIT:
+ HID_Handle->Init(phost);
+ case HID_IDLE:
+ if(USBH_HID_GetReport (phost,
+ 0x01,
+ 0,
+ HID_Handle->pData,
+ HID_Handle->length) == USBH_OK)
+ {
+
+ fifo_write(&HID_Handle->fifo, HID_Handle->pData, HID_Handle->length);
+ HID_Handle->state = HID_SYNC;
+ }
+
+ break;
+
+ case HID_SYNC:
+
+ /* Sync with start of Even Frame */
+ if(phost->Timer & 1)
+ {
+ HID_Handle->state = HID_GET_DATA;
+ }
+#if (USBH_USE_OS == 1)
+ osMessagePut ( phost->os_event, USBH_URB_EVENT, 0);
+#endif
+ break;
+
+ case HID_GET_DATA:
+
+ USBH_InterruptReceiveData(phost,
+ HID_Handle->pData,
+ HID_Handle->length,
+ HID_Handle->InPipe);
+
+ HID_Handle->state = HID_POLL;
+ HID_Handle->timer = phost->Timer;
+ HID_Handle->DataReady = 0;
+ break;
+
+ case HID_POLL:
+
+ if(USBH_LL_GetURBState(phost , HID_Handle->InPipe) == USBH_URB_DONE)
+ {
+ if(HID_Handle->DataReady == 0)
+ {
+ fifo_write(&HID_Handle->fifo, HID_Handle->pData, HID_Handle->length);
+ HID_Handle->DataReady = 1;
+ USBH_HID_EventCallback(phost);
+#if (USBH_USE_OS == 1)
+ osMessagePut ( phost->os_event, USBH_URB_EVENT, 0);
+#endif
+ }
+ }
+ else if(USBH_LL_GetURBState(phost , HID_Handle->InPipe) == USBH_URB_STALL) /* IN Endpoint Stalled */
+ {
+
+ /* Issue Clear Feature on interrupt IN endpoint */
+ if(USBH_ClrFeature(phost,
+ HID_Handle->ep_addr) == USBH_OK)
+ {
+ /* Change state to issue next IN token */
+ HID_Handle->state = HID_GET_DATA;
+ }
+ }
+
+
+ break;
+
+ default:
+ break;
+ }
+ return status;
+}
+
+/**
+ * @brief USBH_HID_SOFProcess
+ * The function is for managing the SOF Process
+ * @param phost: Host handle
+ * @retval USBH Status
+ */
+static USBH_StatusTypeDef USBH_HID_SOFProcess(USBH_HandleTypeDef *phost)
+{
+ HID_HandleTypeDef *HID_Handle = phost->pActiveClass->pData;
+
+ if(HID_Handle->state == HID_POLL)
+ {
+ if(( phost->Timer - HID_Handle->timer) >= HID_Handle->poll)
+ {
+ HID_Handle->state = HID_GET_DATA;
+#if (USBH_USE_OS == 1)
+ osMessagePut ( phost->os_event, USBH_URB_EVENT, 0);
+#endif
+ }
+ }
+ return USBH_OK;
+}
+
+/**
+* @brief USBH_Get_HID_ReportDescriptor
+ * Issue report Descriptor command to the device. Once the response
+ * received, parse the report descriptor and update the status.
+ * @param phost: Host handle
+ * @param Length : HID Report Descriptor Length
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_HID_GetHIDReportDescriptor (USBH_HandleTypeDef *phost,
+ uint16_t length)
+{
+
+ USBH_StatusTypeDef status;
+
+ status = USBH_GetDescriptor(phost,
+ USB_REQ_RECIPIENT_INTERFACE | USB_REQ_TYPE_STANDARD,
+ USB_DESC_HID_REPORT,
+ phost->device.Data,
+ length);
+
+ /* HID report descriptor is available in phost->device.Data.
+ In case of USB Boot Mode devices for In report handling ,
+ HID report descriptor parsing is not required.
+ In case, for supporting Non-Boot Protocol devices and output reports,
+ user may parse the report descriptor*/
+
+
+ return status;
+}
+
+/**
+ * @brief USBH_Get_HID_Descriptor
+ * Issue HID Descriptor command to the device. Once the response
+ * received, parse the report descriptor and update the status.
+ * @param phost: Host handle
+ * @param Length : HID Descriptor Length
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_HID_GetHIDDescriptor (USBH_HandleTypeDef *phost,
+ uint16_t length)
+{
+
+ USBH_StatusTypeDef status;
+
+ status = USBH_GetDescriptor( phost,
+ USB_REQ_RECIPIENT_INTERFACE | USB_REQ_TYPE_STANDARD,
+ USB_DESC_HID,
+ phost->device.Data,
+ length);
+
+ return status;
+}
+
+/**
+ * @brief USBH_Set_Idle
+ * Set Idle State.
+ * @param phost: Host handle
+ * @param duration: Duration for HID Idle request
+ * @param reportId : Targetted report ID for Set Idle request
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_HID_SetIdle (USBH_HandleTypeDef *phost,
+ uint8_t duration,
+ uint8_t reportId)
+{
+
+ phost->Control.setup.b.bmRequestType = USB_H2D | USB_REQ_RECIPIENT_INTERFACE |\
+ USB_REQ_TYPE_CLASS;
+
+
+ phost->Control.setup.b.bRequest = USB_HID_SET_IDLE;
+ phost->Control.setup.b.wValue.w = (duration << 8 ) | reportId;
+
+ phost->Control.setup.b.wIndex.w = 0;
+ phost->Control.setup.b.wLength.w = 0;
+
+ return USBH_CtlReq(phost, 0 , 0 );
+}
+
+
+/**
+ * @brief USBH_HID_Set_Report
+ * Issues Set Report
+ * @param phost: Host handle
+ * @param reportType : Report type to be sent
+ * @param reportId : Targetted report ID for Set Report request
+ * @param reportBuff : Report Buffer
+ * @param reportLen : Length of data report to be send
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_HID_SetReport (USBH_HandleTypeDef *phost,
+ uint8_t reportType,
+ uint8_t reportId,
+ uint8_t* reportBuff,
+ uint8_t reportLen)
+{
+
+ phost->Control.setup.b.bmRequestType = USB_H2D | USB_REQ_RECIPIENT_INTERFACE |\
+ USB_REQ_TYPE_CLASS;
+
+
+ phost->Control.setup.b.bRequest = USB_HID_SET_REPORT;
+ phost->Control.setup.b.wValue.w = (reportType << 8 ) | reportId;
+
+ phost->Control.setup.b.wIndex.w = 0;
+ phost->Control.setup.b.wLength.w = reportLen;
+
+ return USBH_CtlReq(phost, reportBuff , reportLen );
+}
+
+
+/**
+ * @brief USBH_HID_GetReport
+ * retreive Set Report
+ * @param phost: Host handle
+ * @param reportType : Report type to be sent
+ * @param reportId : Targetted report ID for Set Report request
+ * @param reportBuff : Report Buffer
+ * @param reportLen : Length of data report to be send
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_HID_GetReport (USBH_HandleTypeDef *phost,
+ uint8_t reportType,
+ uint8_t reportId,
+ uint8_t* reportBuff,
+ uint8_t reportLen)
+{
+
+ phost->Control.setup.b.bmRequestType = USB_D2H | USB_REQ_RECIPIENT_INTERFACE |\
+ USB_REQ_TYPE_CLASS;
+
+
+ phost->Control.setup.b.bRequest = USB_HID_GET_REPORT;
+ phost->Control.setup.b.wValue.w = (reportType << 8 ) | reportId;
+
+ phost->Control.setup.b.wIndex.w = 0;
+ phost->Control.setup.b.wLength.w = reportLen;
+
+ return USBH_CtlReq(phost, reportBuff , reportLen );
+}
+
+/**
+ * @brief USBH_Set_Protocol
+ * Set protocol State.
+ * @param phost: Host handle
+ * @param protocol : Set Protocol for HID : boot/report protocol
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_HID_SetProtocol(USBH_HandleTypeDef *phost,
+ uint8_t protocol)
+{
+
+
+ phost->Control.setup.b.bmRequestType = USB_H2D | USB_REQ_RECIPIENT_INTERFACE |\
+ USB_REQ_TYPE_CLASS;
+
+
+ phost->Control.setup.b.bRequest = USB_HID_SET_PROTOCOL;
+ phost->Control.setup.b.wValue.w = protocol != 0 ? 0 : 1;
+ phost->Control.setup.b.wIndex.w = 0;
+ phost->Control.setup.b.wLength.w = 0;
+
+ return USBH_CtlReq(phost, 0 , 0 );
+
+}
+
+/**
+ * @brief USBH_ParseHIDDesc
+ * This function Parse the HID descriptor
+ * @param desc: HID Descriptor
+ * @param buf: Buffer where the source descriptor is available
+ * @retval None
+ */
+static void USBH_HID_ParseHIDDesc (HID_DescTypeDef *desc, uint8_t *buf)
+{
+
+ desc->bLength = *(uint8_t *) (buf + 0);
+ desc->bDescriptorType = *(uint8_t *) (buf + 1);
+ desc->bcdHID = LE16 (buf + 2);
+ desc->bCountryCode = *(uint8_t *) (buf + 4);
+ desc->bNumDescriptors = *(uint8_t *) (buf + 5);
+ desc->bReportDescriptorType = *(uint8_t *) (buf + 6);
+ desc->wItemLength = LE16 (buf + 7);
+}
+
+/**
+ * @brief USBH_HID_GetDeviceType
+ * Return Device function.
+ * @param phost: Host handle
+ * @retval HID function: HID_MOUSE / HID_KEYBOARD
+ */
+HID_TypeTypeDef USBH_HID_GetDeviceType(USBH_HandleTypeDef *phost)
+{
+ HID_TypeTypeDef type = HID_UNKNOWN;
+
+ if(phost->gState == HOST_CLASS)
+ {
+
+ if(phost->device.CfgDesc.Itf_Desc[phost->device.current_interface].bInterfaceProtocol \
+ == HID_KEYBRD_BOOT_CODE)
+ {
+ type = HID_KEYBOARD;
+ }
+ else if(phost->device.CfgDesc.Itf_Desc[phost->device.current_interface].bInterfaceProtocol \
+ == HID_MOUSE_BOOT_CODE)
+ {
+ type= HID_MOUSE;
+ }
+ }
+ return type;
+}
+
+/**
+ * @brief fifo_init
+ * Initialize FIFO.
+ * @param f: Fifo address
+ * @param buf: Fifo buffer
+ * @param size: Fifo Size
+ * @retval none
+ */
+void fifo_init(FIFO_TypeDef * f, uint8_t * buf, uint16_t size)
+{
+ f->head = 0;
+ f->tail = 0;
+ f->lock = 0;
+ f->size = size;
+ f->buf = buf;
+}
+
+/**
+ * @brief fifo_read
+ * Read from FIFO.
+ * @param f: Fifo address
+ * @param buf: read buffer
+ * @param nbytes: number of item to read
+ * @retval number of read items
+ */
+uint16_t fifo_read(FIFO_TypeDef * f, void * buf, uint16_t nbytes)
+{
+ uint16_t i;
+ uint8_t * p;
+ p = buf;
+
+ if(f->lock == 0)
+ {
+ f->lock = 1;
+ for(i=0; i < nbytes; i++)
+ {
+ if( f->tail != f->head )
+ {
+ *p++ = f->buf[f->tail];
+ f->tail++;
+ if( f->tail == f->size )
+ {
+ f->tail = 0;
+ }
+ } else
+ {
+ f->lock = 0;
+ return i;
+ }
+ }
+ }
+ f->lock = 0;
+ return nbytes;
+}
+
+/**
+ * @brief fifo_write
+ * Read from FIFO.
+ * @param f: Fifo address
+ * @param buf: read buffer
+ * @param nbytes: number of item to write
+ * @retval number of written items
+ */
+uint16_t fifo_write(FIFO_TypeDef * f, const void * buf, uint16_t nbytes)
+{
+ uint16_t i;
+ const uint8_t * p;
+ p = buf;
+ if(f->lock == 0)
+ {
+ f->lock = 1;
+ for(i=0; i < nbytes; i++)
+ {
+ if( (f->head + 1 == f->tail) ||
+ ( (f->head + 1 == f->size) && (f->tail == 0)) )
+ {
+ f->lock = 0;
+ return i;
+ }
+ else
+ {
+ f->buf[f->head] = *p++;
+ f->head++;
+ if( f->head == f->size )
+ {
+ f->head = 0;
+ }
+ }
+ }
+ }
+ f->lock = 0;
+ return nbytes;
+}
+
+
+/**
+* @brief The function is a callback about HID Data events
+* @param phost: Selected device
+* @retval None
+*/
+__weak void USBH_HID_EventCallback(USBH_HandleTypeDef *phost)
+{
+
+}
+/**
+* @}
+*/
+
+/**
+* @}
+*/
+
+/**
+* @}
+*/
+
+
+/**
+* @}
+*/
+
+
+/**
+* @}
+*/
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/ports/stm32/usbhost/Class/HID/Src/usbh_hid_keybd.c b/ports/stm32/usbhost/Class/HID/Src/usbh_hid_keybd.c
new file mode 100644
index 000000000..79104767b
--- /dev/null
+++ b/ports/stm32/usbhost/Class/HID/Src/usbh_hid_keybd.c
@@ -0,0 +1,418 @@
+/**
+ ******************************************************************************
+ * @file usbh_hid_keybd.c
+ * @author MCD Application Team
+ * @version V3.0.0
+ * @date 18-February-2014
+ * @brief This file is the application layer for USB Host HID Keyboard handling
+ * QWERTY and AZERTY Keyboard are supported as per the selection in
+ * usbh_hid_keybd.h
+ ******************************************************************************
+ * @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 "usbh_hid_keybd.h"
+#include "usbh_hid_parser.h"
+
+/** @addtogroup USBH_LIB
+* @{
+*/
+
+/** @addtogroup USBH_CLASS
+* @{
+*/
+
+/** @addtogroup USBH_HID_CLASS
+* @{
+*/
+
+/** @defgroup USBH_HID_KEYBD
+* @brief This file includes HID Layer Handlers for USB Host HID class.
+* @{
+*/
+
+/** @defgroup USBH_HID_KEYBD_Private_TypesDefinitions
+* @{
+*/
+/**
+* @}
+*/
+
+
+/** @defgroup USBH_HID_KEYBD_Private_Defines
+* @{
+*/
+/**
+* @}
+*/
+#ifndef AZERTY_KEYBOARD
+ #define QWERTY_KEYBOARD
+#endif
+#define KBD_LEFT_CTRL 0x01
+#define KBD_LEFT_SHIFT 0x02
+#define KBD_LEFT_ALT 0x04
+#define KBD_LEFT_GUI 0x08
+#define KBD_RIGHT_CTRL 0x10
+#define KBD_RIGHT_SHIFT 0x20
+#define KBD_RIGHT_ALT 0x40
+#define KBD_RIGHT_GUI 0x80
+#define KBR_MAX_NBR_PRESSED 6
+
+/** @defgroup USBH_HID_KEYBD_Private_Macros
+* @{
+*/
+/**
+* @}
+*/
+
+/** @defgroup USBH_HID_KEYBD_Private_FunctionPrototypes
+* @{
+*/
+static USBH_StatusTypeDef USBH_HID_KeybdDecode(USBH_HandleTypeDef *phost);
+/**
+* @}
+*/
+
+/** @defgroup USBH_HID_KEYBD_Private_Variables
+* @{
+*/
+
+HID_KEYBD_Info_TypeDef keybd_info;
+uint32_t keybd_report_data[2];
+
+static const HID_Report_ItemTypedef imp_0_lctrl={
+ (uint8_t*)keybd_report_data+0, /*data*/
+ 1, /*size*/
+ 0, /*shift*/
+ 0, /*count (only for array items)*/
+ 0, /*signed?*/
+ 0, /*min value read can return*/
+ 1, /*max value read can return*/
+ 0, /*min vale device can report*/
+ 1, /*max value device can report*/
+ 1 /*resolution*/
+};
+static const HID_Report_ItemTypedef imp_0_lshift={
+ (uint8_t*)keybd_report_data+0, /*data*/
+ 1, /*size*/
+ 1, /*shift*/
+ 0, /*count (only for array items)*/
+ 0, /*signed?*/
+ 0, /*min value read can return*/
+ 1, /*max value read can return*/
+ 0, /*min vale device can report*/
+ 1, /*max value device can report*/
+ 1 /*resolution*/
+};
+static const HID_Report_ItemTypedef imp_0_lalt={
+ (uint8_t*)keybd_report_data+0, /*data*/
+ 1, /*size*/
+ 2, /*shift*/
+ 0, /*count (only for array items)*/
+ 0, /*signed?*/
+ 0, /*min value read can return*/
+ 1, /*max value read can return*/
+ 0, /*min vale device can report*/
+ 1, /*max value device can report*/
+ 1 /*resolution*/
+};
+static const HID_Report_ItemTypedef imp_0_lgui={
+ (uint8_t*)keybd_report_data+0, /*data*/
+ 1, /*size*/
+ 3, /*shift*/
+ 0, /*count (only for array items)*/
+ 0, /*signed?*/
+ 0, /*min value read can return*/
+ 1, /*max value read can return*/
+ 0, /*min vale device can report*/
+ 1, /*max value device can report*/
+ 1 /*resolution*/
+};
+static const HID_Report_ItemTypedef imp_0_rctrl={
+ (uint8_t*)keybd_report_data+0, /*data*/
+ 1, /*size*/
+ 4, /*shift*/
+ 0, /*count (only for array items)*/
+ 0, /*signed?*/
+ 0, /*min value read can return*/
+ 1, /*max value read can return*/
+ 0, /*min vale device can report*/
+ 1, /*max value device can report*/
+ 1 /*resolution*/
+};
+static const HID_Report_ItemTypedef imp_0_rshift={
+ (uint8_t*)keybd_report_data+0, /*data*/
+ 1, /*size*/
+ 5, /*shift*/
+ 0, /*count (only for array items)*/
+ 0, /*signed?*/
+ 0, /*min value read can return*/
+ 1, /*max value read can return*/
+ 0, /*min vale device can report*/
+ 1, /*max value device can report*/
+ 1 /*resolution*/
+};
+static const HID_Report_ItemTypedef imp_0_ralt={
+ (uint8_t*)keybd_report_data+0, /*data*/
+ 1, /*size*/
+ 6, /*shift*/
+ 0, /*count (only for array items)*/
+ 0, /*signed?*/
+ 0, /*min value read can return*/
+ 1, /*max value read can return*/
+ 0, /*min vale device can report*/
+ 1, /*max value device can report*/
+ 1 /*resolution*/
+};
+static const HID_Report_ItemTypedef imp_0_rgui={
+ (uint8_t*)keybd_report_data+0, /*data*/
+ 1, /*size*/
+ 7, /*shift*/
+ 0, /*count (only for array items)*/
+ 0, /*signed?*/
+ 0, /*min value read can return*/
+ 1, /*max value read can return*/
+ 0, /*min vale device can report*/
+ 1, /*max value device can report*/
+ 1 /*resolution*/
+};
+
+static const HID_Report_ItemTypedef imp_0_key_array={
+ (uint8_t*)keybd_report_data+2, /*data*/
+ 8, /*size*/
+ 0, /*shift*/
+ 6, /*count (only for array items)*/
+ 0, /*signed?*/
+ 0, /*min value read can return*/
+ 101, /*max value read can return*/
+ 0, /*min vale device can report*/
+ 101, /*max value device can report*/
+ 1 /*resolution*/
+};
+
+#ifdef QWERTY_KEYBOARD
+static const int8_t HID_KEYBRD_Key[] = {
+ '\0', '`', '1', '2', '3', '4', '5', '6',
+ '7', '8', '9', '0', '-', '=', '\0', '\r',
+ '\t', 'q', 'w', 'e', 'r', 't', 'y', 'u',
+ 'i', 'o', 'p', '[', ']', '\\',
+ '\0', 'a', 's', 'd', 'f', 'g', 'h', 'j',
+ 'k', 'l', ';', '\'', '\0', '\n',
+ '\0', '\0', 'z', 'x', 'c', 'v', 'b', 'n',
+ 'm', ',', '.', '/', '\0', '\0',
+ '\0', '\0', '\0', ' ', '\0', '\0', '\0', '\0',
+ '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
+ '\0', '\0', '\0', '\0', '\0', '\r', '\0', '\0',
+ '\0', '\0', '\0', '\0', '\0', '\0',
+ '\0', '\0', '7', '4', '1',
+ '\0', '/', '8', '5', '2',
+ '0', '*', '9', '6', '3',
+ '.', '-', '+', '\0', '\n', '\0', '\0', '\0', '\0', '\0', '\0',
+ '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
+ '\0', '\0', '\0', '\0'
+};
+
+static const int8_t HID_KEYBRD_ShiftKey[] = {
+ '\0', '~', '!', '@', '#', '$', '%', '^', '&', '*', '(', ')',
+ '_', '+', '\0', '\0', '\0', 'Q', 'W', 'E', 'R', 'T', 'Y', 'U',
+ 'I', 'O', 'P', '{', '}', '|', '\0', 'A', 'S', 'D', 'F', 'G',
+ 'H', 'J', 'K', 'L', ':', '"', '\0', '\n', '\0', '\0', 'Z', 'X',
+ 'C', 'V', 'B', 'N', 'M', '<', '>', '?', '\0', '\0', '\0', '\0',
+ '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
+ '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
+ '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
+ '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
+ '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
+ '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0'
+};
+
+#else
+
+static const int8_t HID_KEYBRD_Key[] = {
+ '\0', '`', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0',
+ '-', '=', '\0', '\r', '\t', 'a', 'z', 'e', 'r', 't', 'y', 'u',
+ 'i', 'o', 'p', '[', ']', '\\', '\0', 'q', 's', 'd', 'f', 'g',
+ 'h', 'j', 'k', 'l', 'm', '\0', '\0', '\n', '\0', '\0', 'w', 'x',
+ 'c', 'v', 'b', 'n', ',', ';', ':', '!', '\0', '\0', '\0', '\0',
+ '\0', ' ', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
+ '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\r', '\0', '\0', '\0',
+ '\0', '\0', '\0', '\0', '\0', '\0', '\0', '7', '4', '1','\0', '/',
+ '8', '5', '2', '0', '*', '9', '6', '3', '.', '-', '+', '\0',
+ '\n', '\0', '\0', '\0', '\0', '\0', '\0','\0', '\0', '\0', '\0', '\0', '\0',
+ '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0'
+};
+
+static const int8_t HID_KEYBRD_ShiftKey[] = {
+ '\0', '~', '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_',
+ '+', '\0', '\0', '\0', 'A', 'Z', 'E', 'R', 'T', 'Y', 'U', 'I', 'O',
+ 'P', '{', '}', '*', '\0', 'Q', 'S', 'D', 'F', 'G', 'H', 'J', 'K',
+ 'L', 'M', '%', '\0', '\n', '\0', '\0', 'W', 'X', 'C', 'V', 'B', 'N',
+ '?', '.', '/', '\0', '\0', '\0','\0', '\0', '\0', '\0', '\0', '\0', '\0',
+ '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
+ '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
+ '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
+ '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
+ '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0'
+};
+#endif
+
+static const uint8_t HID_KEYBRD_Codes[] = {
+ 0, 0, 0, 0, 31, 50, 48, 33,
+ 19, 34, 35, 36, 24, 37, 38, 39, /* 0x00 - 0x0F */
+ 52, 51, 25, 26, 17, 20, 32, 21,
+ 23, 49, 18, 47, 22, 46, 2, 3, /* 0x10 - 0x1F */
+ 4, 5, 6, 7, 8, 9, 10, 11,
+ 43, 110, 15, 16, 61, 12, 13, 27, /* 0x20 - 0x2F */
+ 28, 29, 42, 40, 41, 1, 53, 54,
+ 55, 30, 112, 113, 114, 115, 116, 117, /* 0x30 - 0x3F */
+ 118, 119, 120, 121, 122, 123, 124, 125,
+ 126, 75, 80, 85, 76, 81, 86, 89, /* 0x40 - 0x4F */
+ 79, 84, 83, 90, 95, 100, 105, 106,
+ 108, 93, 98, 103, 92, 97, 102, 91, /* 0x50 - 0x5F */
+ 96, 101, 99, 104, 45, 129, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x60 - 0x6F */
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x70 - 0x7F */
+ 0, 0, 0, 0, 0, 107, 0, 56,
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x80 - 0x8F */
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x90 - 0x9F */
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0xA0 - 0xAF */
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0xB0 - 0xBF */
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0xC0 - 0xCF */
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0xD0 - 0xDF */
+ 58, 44, 60, 127, 64, 57, 62, 128 /* 0xE0 - 0xE7 */
+};
+
+/**
+ * @brief USBH_HID_KeybdInit
+ * The function init the HID keyboard.
+ * @param phost: Host handle
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_HID_KeybdInit(USBH_HandleTypeDef *phost)
+{
+ uint32_t x;
+ HID_HandleTypeDef *HID_Handle = phost->pActiveClass->pData;
+
+ keybd_info.lctrl=keybd_info.lshift= 0;
+ keybd_info.lalt=keybd_info.lgui= 0;
+ keybd_info.rctrl=keybd_info.rshift= 0;
+ keybd_info.ralt=keybd_info.rgui=0;
+
+
+ for(x=0; x< (sizeof(keybd_report_data)/sizeof(uint32_t)); x++)
+ {
+ keybd_report_data[x]=0;
+ }
+
+ if(HID_Handle->length > (sizeof(keybd_report_data)/sizeof(uint32_t)))
+ {
+ HID_Handle->length = (sizeof(keybd_report_data)/sizeof(uint32_t));
+ }
+ HID_Handle->pData = (uint8_t*)keybd_report_data;
+ fifo_init(&HID_Handle->fifo, phost->device.Data, HID_QUEUE_SIZE * sizeof(keybd_report_data));
+
+ return USBH_OK;
+}
+
+/**
+ * @brief USBH_HID_GetKeybdInfo
+ * The function return keyboard information.
+ * @param phost: Host handle
+ * @retval keyboard information
+ */
+HID_KEYBD_Info_TypeDef *USBH_HID_GetKeybdInfo(USBH_HandleTypeDef *phost)
+{
+ if(USBH_HID_KeybdDecode(phost) == USBH_OK)
+ {
+ return &keybd_info;
+ }
+ else
+ {
+ return NULL;
+ }
+}
+
+/**
+ * @brief USBH_HID_KeybdDecode
+ * The function decode keyboard data.
+ * @param phost: Host handle
+ * @retval USBH Status
+ */
+static USBH_StatusTypeDef USBH_HID_KeybdDecode(USBH_HandleTypeDef *phost)
+{
+ uint8_t x;
+
+ HID_HandleTypeDef *HID_Handle = phost->pActiveClass->pData;
+ if(HID_Handle->length == 0)
+ {
+ return USBH_FAIL;
+ }
+ /*Fill report */
+ if(fifo_read(&HID_Handle->fifo, &keybd_report_data, HID_Handle->length) == HID_Handle->length)
+ {
+
+ keybd_info.lctrl=(uint8_t)HID_ReadItem((HID_Report_ItemTypedef *) &imp_0_lctrl, 0);
+ keybd_info.lshift=(uint8_t)HID_ReadItem((HID_Report_ItemTypedef *) &imp_0_lshift, 0);
+ keybd_info.lalt=(uint8_t)HID_ReadItem((HID_Report_ItemTypedef *) &imp_0_lalt, 0);
+ keybd_info.lgui=(uint8_t)HID_ReadItem((HID_Report_ItemTypedef *) &imp_0_lgui, 0);
+ keybd_info.rctrl=(uint8_t)HID_ReadItem((HID_Report_ItemTypedef *) &imp_0_rctrl, 0);
+ keybd_info.rshift=(uint8_t)HID_ReadItem((HID_Report_ItemTypedef *) &imp_0_rshift, 0);
+ keybd_info.ralt=(uint8_t)HID_ReadItem((HID_Report_ItemTypedef *) &imp_0_ralt, 0);
+ keybd_info.rgui=(uint8_t)HID_ReadItem((HID_Report_ItemTypedef *) &imp_0_rgui, 0);
+
+ for(x=0; x < sizeof(keybd_info.keys); x++)
+ {
+ keybd_info.keys[x]=(uint8_t)HID_ReadItem((HID_Report_ItemTypedef *) &imp_0_key_array, x);
+ }
+
+ return USBH_OK;
+ }
+ return USBH_FAIL;
+}
+
+/**
+ * @brief USBH_HID_GetASCIICode
+ * The function decode keyboard data into ASCII characters.
+ * @param phost: Host handle
+ * @param info: Keyboard information
+ * @retval ASCII code
+ */
+uint8_t USBH_HID_GetASCIICode(HID_KEYBD_Info_TypeDef *info)
+{
+ uint8_t output;
+ if((info->lshift == 1) || (info->rshift))
+ {
+ output = HID_KEYBRD_ShiftKey[HID_KEYBRD_Codes[info->keys[0]]];
+ }
+ else
+ {
+ output = HID_KEYBRD_Key[HID_KEYBRD_Codes[info->keys[0]]];
+ }
+ return output;
+}
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
+
diff --git a/ports/stm32/usbhost/Class/HID/Src/usbh_hid_mouse.c b/ports/stm32/usbhost/Class/HID/Src/usbh_hid_mouse.c
new file mode 100644
index 000000000..0851714af
--- /dev/null
+++ b/ports/stm32/usbhost/Class/HID/Src/usbh_hid_mouse.c
@@ -0,0 +1,267 @@
+/**
+ ******************************************************************************
+ * @file usbh_hid_mouse.c
+ * @author MCD Application Team
+ * @version V3.0.0
+ * @date 18-February-2014
+ * @brief This file is the application layer for USB Host HID Mouse Handling.
+ ******************************************************************************
+ * @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 "usbh_hid_mouse.h"
+#include "usbh_hid_parser.h"
+
+
+/** @addtogroup USBH_LIB
+ * @{
+ */
+
+/** @addtogroup USBH_CLASS
+ * @{
+ */
+
+/** @addtogroup USBH_HID_CLASS
+ * @{
+ */
+
+/** @defgroup USBH_HID_MOUSE
+ * @brief This file includes HID Layer Handlers for USB Host HID class.
+ * @{
+ */
+
+/** @defgroup USBH_HID_MOUSE_Private_TypesDefinitions
+ * @{
+ */
+/**
+ * @}
+ */
+
+
+/** @defgroup USBH_HID_MOUSE_Private_Defines
+ * @{
+ */
+/**
+ * @}
+ */
+
+
+/** @defgroup USBH_HID_MOUSE_Private_Macros
+ * @{
+ */
+/**
+ * @}
+ */
+
+/** @defgroup USBH_HID_MOUSE_Private_FunctionPrototypes
+ * @{
+ */
+static USBH_StatusTypeDef USBH_HID_MouseDecode(USBH_HandleTypeDef *phost);
+
+/**
+ * @}
+ */
+
+
+/** @defgroup USBH_HID_MOUSE_Private_Variables
+ * @{
+ */
+HID_MOUSE_Info_TypeDef mouse_info;
+uint32_t mouse_report_data[1];
+
+/* Structures defining how to access items in a HID mouse report */
+/* Access button 1 state. */
+static const HID_Report_ItemTypedef prop_b1={
+ (uint8_t *)mouse_report_data+0, /*data*/
+ 1, /*size*/
+ 0, /*shift*/
+ 0, /*count (only for array items)*/
+ 0, /*signed?*/
+ 0, /*min value read can return*/
+ 1, /*max value read can return*/
+ 0, /*min value device can report*/
+ 1, /*max value device can report*/
+ 1 /*resolution*/
+};
+
+/* Access button 2 state. */
+static const HID_Report_ItemTypedef prop_b2={
+ (uint8_t *)mouse_report_data+0, /*data*/
+ 1, /*size*/
+ 1, /*shift*/
+ 0, /*count (only for array items)*/
+ 0, /*signed?*/
+ 0, /*min value read can return*/
+ 1, /*max value read can return*/
+ 0, /*min value device can report*/
+ 1, /*max value device can report*/
+ 1 /*resolution*/
+};
+
+/* Access button 3 state. */
+static const HID_Report_ItemTypedef prop_b3={
+ (uint8_t *)mouse_report_data+0, /*data*/
+ 1, /*size*/
+ 2, /*shift*/
+ 0, /*count (only for array items)*/
+ 0, /*signed?*/
+ 0, /*min value read can return*/
+ 1, /*max value read can return*/
+ 0, /*min vale device can report*/
+ 1, /*max value device can report*/
+ 1 /*resolution*/
+};
+
+/* Access x coordinate change. */
+static const HID_Report_ItemTypedef prop_x={
+ (uint8_t *)mouse_report_data+1, /*data*/
+ 8, /*size*/
+ 0, /*shift*/
+ 0, /*count (only for array items)*/
+ 1, /*signed?*/
+ 0, /*min value read can return*/
+ 0xFFFF,/*max value read can return*/
+ 0, /*min vale device can report*/
+ 0xFFFF,/*max value device can report*/
+ 1 /*resolution*/
+};
+
+/* Access y coordinate change. */
+static const HID_Report_ItemTypedef prop_y={
+ (uint8_t *)mouse_report_data+2, /*data*/
+ 8, /*size*/
+ 0, /*shift*/
+ 0, /*count (only for array items)*/
+ 1, /*signed?*/
+ 0, /*min value read can return*/
+ 0xFFFF,/*max value read can return*/
+ 0, /*min vale device can report*/
+ 0xFFFF,/*max value device can report*/
+ 1 /*resolution*/
+};
+
+
+/**
+ * @}
+ */
+
+
+/** @defgroup USBH_HID_MOUSE_Private_Functions
+ * @{
+ */
+
+/**
+ * @brief USBH_HID_MouseInit
+ * The function init the HID mouse.
+ * @param phost: Host handle
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_HID_MouseInit(USBH_HandleTypeDef *phost)
+{
+ HID_HandleTypeDef *HID_Handle = phost->pActiveClass->pData;
+
+ mouse_info.x=0;
+ mouse_info.y=0;
+ mouse_info.buttons[0]=0;
+ mouse_info.buttons[1]=0;
+ mouse_info.buttons[2]=0;
+
+ mouse_report_data[0]=0;
+
+ if(HID_Handle->length > sizeof(mouse_report_data))
+ {
+ HID_Handle->length = sizeof(mouse_report_data);
+ }
+ HID_Handle->pData = (uint8_t *)mouse_report_data;
+ fifo_init(&HID_Handle->fifo, phost->device.Data, HID_QUEUE_SIZE * sizeof(mouse_report_data));
+
+ return USBH_OK;
+}
+
+/**
+ * @brief USBH_HID_GetMouseInfo
+ * The function return mouse information.
+ * @param phost: Host handle
+ * @retval mouse information
+ */
+HID_MOUSE_Info_TypeDef *USBH_HID_GetMouseInfo(USBH_HandleTypeDef *phost)
+{
+ if(USBH_HID_MouseDecode(phost)== USBH_OK)
+ {
+ return &mouse_info;
+ }
+ else
+ {
+ return NULL;
+ }
+}
+
+/**
+ * @brief USBH_HID_MouseDecode
+ * The function decode mouse data.
+ * @param phost: Host handle
+ * @retval USBH Status
+ */
+static USBH_StatusTypeDef USBH_HID_MouseDecode(USBH_HandleTypeDef *phost)
+{
+ HID_HandleTypeDef *HID_Handle = phost->pActiveClass->pData;
+
+ if(HID_Handle->length == 0)
+ {
+ return USBH_FAIL;
+ }
+ /*Fill report */
+ if(fifo_read(&HID_Handle->fifo, &mouse_report_data, HID_Handle->length) == HID_Handle->length)
+ {
+
+ /*Decode report */
+ mouse_info.x = (int16_t )HID_ReadItem((HID_Report_ItemTypedef *) &prop_x, 0);
+ mouse_info.y = (int16_t )HID_ReadItem((HID_Report_ItemTypedef *) &prop_y, 0);
+
+ mouse_info.buttons[0]=(uint8_t)HID_ReadItem((HID_Report_ItemTypedef *) &prop_b1, 0);
+ mouse_info.buttons[1]=(uint8_t)HID_ReadItem((HID_Report_ItemTypedef *) &prop_b2, 0);
+ mouse_info.buttons[2]=(uint8_t)HID_ReadItem((HID_Report_ItemTypedef *) &prop_b3, 0);
+
+ return USBH_OK;
+ }
+ return USBH_FAIL;
+}
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+
+/**
+ * @}
+ */
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/ports/stm32/usbhost/Class/HID/Src/usbh_hid_parser.c b/ports/stm32/usbhost/Class/HID/Src/usbh_hid_parser.c
new file mode 100644
index 000000000..a050f95e9
--- /dev/null
+++ b/ports/stm32/usbhost/Class/HID/Src/usbh_hid_parser.c
@@ -0,0 +1,235 @@
+/**
+ ******************************************************************************
+ * @file usbh_hid_parser.c
+ * @author MCD Application Team
+ * @version V3.0.0
+ * @date 18-February-2014
+ * @brief This file is the HID Layer Handlers for USB Host HID class.
+ ******************************************************************************
+ * @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 "usbh_hid_parser.h"
+
+
+/** @addtogroup USBH_LIB
+ * @{
+ */
+
+/** @addtogroup USBH_CLASS
+ * @{
+ */
+
+/** @addtogroup USBH_HID_CLASS
+ * @{
+ */
+
+/** @defgroup USBH_HID_PARSER
+ * @brief This file includes HID parsers for USB Host HID class.
+ * @{
+ */
+
+/** @defgroup USBH_HID_PARSER_Private_TypesDefinitions
+ * @{
+ */
+/**
+ * @}
+ */
+
+
+/** @defgroup USBH_HID_PARSER_Private_Defines
+ * @{
+ */
+/**
+ * @}
+ */
+
+
+/** @defgroup USBH_HID_PARSER_Private_Macros
+ * @{
+ */
+/**
+ * @}
+ */
+
+/** @defgroup USBH_HID_PARSER_Private_FunctionPrototypes
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+
+/** @defgroup USBH_HID_PARSER_Private_Variables
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+
+/** @defgroup USBH_HID_PARSER_Private_Functions
+ * @{
+ */
+
+/**
+ * @brief HID_ReadItem
+ * The function read a report item.
+ * @param ri: report item
+ * @param ndx: report index
+* @retval status (0 : fail / otherwise: item value)
+ */
+uint32_t HID_ReadItem(HID_Report_ItemTypedef *ri, uint8_t ndx)
+{
+ uint32_t val=0;
+ uint32_t x=0;
+ uint32_t bofs;
+ uint8_t *data=ri->data;
+ uint8_t shift=ri->shift;
+
+ /* get the logical value of the item */
+
+ /* if this is an array, wee may need to offset ri->data.*/
+ if (ri->count > 0)
+ {
+ /* If app tries to read outside of the array. */
+ if (ri->count <= ndx)
+ {
+ return(0);
+ }
+
+ /* calculate bit offset */
+ bofs = ndx*ri->size;
+ bofs += shift;
+ /* calculate byte offset + shift pair from bit offset. */
+ data+=bofs/8;
+ shift=(uint8_t)(bofs%8);
+ }
+ /* read data bytes in little endian order */
+ for(x=0; x < ((ri->size & 0x7) ? (ri->size/8)+1 : (ri->size/8)); x++)
+ {
+ val=(uint32_t)(*data << (x*8));
+ }
+ val=(val >> shift) & ((1<<ri->size)-1);
+
+ if (val < ri->logical_min || val > ri->logical_max)
+ {
+ return(0);
+ }
+
+ /* convert logical value to physical value */
+ /* See if the number is negative or not. */
+ if ((ri->sign) && (val & (1<<(ri->size-1))))
+ {
+ /* yes, so sign extend value to 32 bits. */
+ int vs=(int)((-1 & ~((1<<(ri->size))-1)) | val);
+
+ if(ri->resolution == 1)
+ {
+ return((uint32_t)vs);
+ }
+ return((uint32_t)(vs*ri->resolution));
+ }
+ else
+ {
+ if(ri->resolution == 1)
+ {
+ return(val);
+ }
+ return(val*ri->resolution);
+ }
+}
+
+/**
+ * @brief HID_WriteItem
+ * The function write a report item.
+ * @param ri: report item
+ * @param ndx: report index
+ * @retval status (1: fail/ 0 : Ok)
+ */
+uint32_t HID_WriteItem(HID_Report_ItemTypedef *ri, uint32_t value, uint8_t ndx)
+{
+ uint32_t x;
+ uint32_t mask;
+ uint32_t bofs;
+ uint8_t *data=ri->data;
+ uint8_t shift=ri->shift;
+
+ if (value < ri->physical_min || value > ri->physical_max)
+ {
+ return(1);
+ }
+
+ /* if this is an array, wee may need to offset ri->data.*/
+ if (ri->count > 0)
+ {
+ /* If app tries to read outside of the array. */
+ if (ri->count >= ndx)
+ {
+ return(0);
+ }
+ /* calculate bit offset */
+ bofs = ndx*ri->size;
+ bofs += shift;
+ /* calculate byte offset + shift pair from bit offset. */
+ data+=bofs/8;
+ shift=(uint8_t)(bofs%8);
+
+ }
+
+ /* Convert physical value to logical value. */
+ if (ri->resolution != 1)
+ {
+ value=value/ri->resolution;
+ }
+
+ /* Write logical value to report in little endian order. */
+ mask=(uint32_t)((1<<ri->size)-1);
+ value = (value & mask) << shift;
+
+ for(x=0; x < ((ri->size & 0x7) ? (ri->size/8)+1 : (ri->size/8)); x++)
+ {
+ *(ri->data+x)=(uint8_t)((*(ri->data+x) & ~(mask>>(x*8))) | ((value>>(x*8)) & (mask>>(x*8))));
+ }
+ return(0);
+}
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+
+/**
+ * @}
+ */
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/ports/stm32/usbhost/Class/MSC/Inc/usbh_msc.h b/ports/stm32/usbhost/Class/MSC/Inc/usbh_msc.h
new file mode 100644
index 000000000..ea173a7da
--- /dev/null
+++ b/ports/stm32/usbhost/Class/MSC/Inc/usbh_msc.h
@@ -0,0 +1,222 @@
+/**
+ ******************************************************************************
+ * @file usbh_msc.h
+ * @author MCD Application Team
+ * @version V3.0.0
+ * @date 18-February-2014
+ * @brief This file contains all the prototypes for the usbh_msc_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 ----------------------------------------------*/
+#ifndef __USBH_MSC_H
+#define __USBH_MSC_H
+
+/* Includes ------------------------------------------------------------------*/
+#include "usbh_core.h"
+#include "usbh_msc_bot.h"
+#include "usbh_msc_scsi.h"
+
+/** @addtogroup USBH_LIB
+ * @{
+ */
+
+/** @addtogroup USBH_CLASS
+ * @{
+ */
+
+/** @addtogroup USBH_MSC_CLASS
+ * @{
+ */
+
+/** @defgroup USBH_MSC_CORE
+ * @brief This file is the Header file for usbh_msc_core.c
+ * @{
+ */
+
+
+/** @defgroup USBH_MSC_CORE_Exported_Types
+ * @{
+ */
+
+typedef enum
+{
+ MSC_INIT = 0,
+ MSC_IDLE,
+ MSC_TEST_UNIT_READY,
+ MSC_READ_CAPACITY10,
+ MSC_READ_INQUIRY,
+ MSC_REQUEST_SENSE,
+ MSC_READ,
+ MSC_WRITE,
+ MSC_UNRECOVERED_ERROR,
+ MSC_PERIODIC_CHECK,
+}
+MSC_StateTypeDef;
+
+typedef enum
+{
+ MSC_OK,
+ MSC_NOT_READY,
+ MSC_ERROR,
+
+}
+MSC_ErrorTypeDef;
+
+typedef enum
+{
+ MSC_REQ_IDLE = 0,
+ MSC_REQ_RESET,
+ MSC_REQ_GET_MAX_LUN,
+ MSC_REQ_ERROR,
+}
+MSC_ReqStateTypeDef;
+
+#define MAX_SUPPORTED_LUN 2
+
+/* Structure for LUN */
+typedef struct
+{
+ MSC_StateTypeDef state;
+ MSC_ErrorTypeDef error;
+ USBH_StatusTypeDef prev_ready_state;
+ SCSI_CapacityTypeDef capacity;
+ SCSI_SenseTypeDef sense;
+ SCSI_StdInquiryDataTypeDef inquiry;
+ uint8_t state_changed;
+
+}
+MSC_LUNTypeDef;
+
+/* Structure for MSC process */
+typedef struct _MSC_Process
+{
+ uint32_t max_lun;
+ uint8_t InPipe;
+ uint8_t OutPipe;
+ uint8_t OutEp;
+ uint8_t InEp;
+ uint16_t OutEpSize;
+ uint16_t InEpSize;
+ MSC_StateTypeDef state;
+ MSC_ErrorTypeDef error;
+ MSC_ReqStateTypeDef req_state;
+ MSC_ReqStateTypeDef prev_req_state;
+ BOT_HandleTypeDef hbot;
+ MSC_LUNTypeDef unit[MAX_SUPPORTED_LUN];
+ uint16_t current_lun;
+ uint16_t rw_lun;
+ uint32_t timer;
+}
+MSC_HandleTypeDef;
+
+
+/**
+ * @}
+ */
+
+
+
+/** @defgroup USBH_MSC_CORE_Exported_Defines
+ * @{
+ */
+
+#define USB_REQ_BOT_RESET 0xFF
+#define USB_REQ_GET_MAX_LUN 0xFE
+
+
+/* MSC Class Codes */
+#define USB_MSC_CLASS 0x08
+
+/* Interface Descriptor field values for HID Boot Protocol */
+#define MSC_BOT 0x50
+#define MSC_TRANSPARENT 0x06
+/**
+ * @}
+ */
+
+/** @defgroup USBH_MSC_CORE_Exported_Macros
+ * @{
+ */
+/**
+ * @}
+ */
+
+/** @defgroup USBH_MSC_CORE_Exported_Variables
+ * @{
+ */
+extern USBH_ClassTypeDef USBH_msc;
+#define USBH_MSC_CLASS &USBH_msc
+
+/**
+ * @}
+ */
+
+/** @defgroup USBH_MSC_CORE_Exported_FunctionsPrototype
+ * @{
+ */
+
+/* Common APIs */
+uint8_t USBH_MSC_IsReady (USBH_HandleTypeDef *phost);
+
+/* APIs for LUN */
+int8_t USBH_MSC_GetMaxLUN (USBH_HandleTypeDef *phost);
+
+uint8_t USBH_MSC_UnitIsReady (USBH_HandleTypeDef *phost, uint8_t lun);
+
+USBH_StatusTypeDef USBH_MSC_GetLUNInfo(USBH_HandleTypeDef *phost, uint8_t lun, MSC_LUNTypeDef *info);
+
+USBH_StatusTypeDef USBH_MSC_Read(USBH_HandleTypeDef *phost,
+ uint8_t lun,
+ uint32_t address,
+ uint8_t *pbuf,
+ uint32_t length);
+
+USBH_StatusTypeDef USBH_MSC_Write(USBH_HandleTypeDef *phost,
+ uint8_t lun,
+ uint32_t address,
+ uint8_t *pbuf,
+ uint32_t length);
+/**
+ * @}
+ */
+
+#endif /* __USBH_MSC_H */
+
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
+
+
+
diff --git a/ports/stm32/usbhost/Class/MSC/Inc/usbh_msc_bot.h b/ports/stm32/usbhost/Class/MSC/Inc/usbh_msc_bot.h
new file mode 100644
index 000000000..5422c80eb
--- /dev/null
+++ b/ports/stm32/usbhost/Class/MSC/Inc/usbh_msc_bot.h
@@ -0,0 +1,233 @@
+/**
+ ******************************************************************************
+ * @file usbh_msc_bot.h
+ * @author MCD Application Team
+ * @version V3.0.0
+ * @date 18-February-2014
+ * @brief Header file for usbh_msc_bot.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 ----------------------------------------------*/
+#ifndef __USBH_MSC_BOT_H__
+#define __USBH_MSC_BOT_H__
+
+/* Includes ------------------------------------------------------------------*/
+#include "usbh_core.h"
+#include "usbh_msc_bot.h"
+
+/** @addtogroup USBH_LIB
+ * @{
+ */
+
+/** @addtogroup USBH_CLASS
+ * @{
+ */
+
+/** @addtogroup USBH_MSC_CLASS
+ * @{
+ */
+
+/** @defgroup USBH_MSC_BOT
+ * @brief This file is the Header file for usbh_msc_core.c
+ * @{
+ */
+
+
+/** @defgroup USBH_MSC_BOT_Exported_Types
+ * @{
+ */
+
+typedef enum {
+ BOT_OK = 0,
+ BOT_FAIL = 1,
+ BOT_PHASE_ERROR = 2,
+ BOT_BUSY = 3
+}
+BOT_StatusTypeDef;
+
+typedef enum {
+ BOT_CMD_IDLE = 0,
+ BOT_CMD_SEND,
+ BOT_CMD_WAIT,
+}
+BOT_CMDStateTypeDef;
+
+/* CSW Status Definitions */
+typedef enum
+{
+
+ BOT_CSW_CMD_PASSED = 0x00,
+ BOT_CSW_CMD_FAILED = 0x01,
+ BOT_CSW_PHASE_ERROR = 0x02,
+}
+BOT_CSWStatusTypeDef;
+
+typedef enum {
+ BOT_SEND_CBW = 1,
+ BOT_SEND_CBW_WAIT,
+ BOT_DATA_IN,
+ BOT_DATA_IN_WAIT,
+ BOT_DATA_OUT,
+ BOT_DATA_OUT_WAIT,
+ BOT_RECEIVE_CSW,
+ BOT_RECEIVE_CSW_WAIT,
+ BOT_ERROR_IN,
+ BOT_ERROR_OUT,
+ BOT_UNRECOVERED_ERROR
+}
+BOT_StateTypeDef;
+
+typedef union
+{
+ struct __CBW
+ {
+ uint32_t Signature;
+ uint32_t Tag;
+ uint32_t DataTransferLength;
+ uint8_t Flags;
+ uint8_t LUN;
+ uint8_t CBLength;
+ uint8_t CB[16];
+ }field;
+ uint8_t data[31];
+}
+BOT_CBWTypeDef;
+
+typedef union
+{
+ struct __CSW
+ {
+ uint32_t Signature;
+ uint32_t Tag;
+ uint32_t DataResidue;
+ uint8_t Status;
+ }field;
+ uint8_t data[13];
+}
+BOT_CSWTypeDef;
+
+typedef struct
+{
+ uint32_t data[16];
+ BOT_StateTypeDef state;
+ BOT_StateTypeDef prev_state;
+ BOT_CMDStateTypeDef cmd_state;
+ BOT_CBWTypeDef cbw;
+ uint8_t Reserved1;
+ BOT_CSWTypeDef csw;
+ uint8_t Reserved2[3];
+ uint8_t *pbuf;
+}
+BOT_HandleTypeDef;
+
+/**
+ * @}
+ */
+
+
+
+/** @defgroup USBH_MSC_BOT_Exported_Defines
+ * @{
+ */
+#define BOT_CBW_SIGNATURE 0x43425355
+#define BOT_CBW_TAG 0x20304050
+#define BOT_CSW_SIGNATURE 0x53425355
+#define BOT_CBW_LENGTH 31
+#define BOT_CSW_LENGTH 13
+
+
+
+#define BOT_SEND_CSW_DISABLE 0
+#define BOT_SEND_CSW_ENABLE 1
+
+#define BOT_DIR_IN 0
+#define BOT_DIR_OUT 1
+#define BOT_DIR_BOTH 2
+
+#define BOT_PAGE_LENGTH 512
+
+
+#define BOT_CBW_CB_LENGTH 16
+
+
+#define USB_REQ_BOT_RESET 0xFF
+#define USB_REQ_GET_MAX_LUN 0xFE
+
+#define MAX_BULK_STALL_COUNT_LIMIT 0x04 /* If STALL is seen on Bulk
+ Endpoint continously, this means
+ that device and Host has phase error
+ Hence a Reset is needed */
+
+/**
+ * @}
+ */
+
+/** @defgroup USBH_MSC_BOT_Exported_Macros
+ * @{
+ */
+/**
+ * @}
+ */
+
+/** @defgroup USBH_MSC_BOT_Exported_Variables
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+/** @defgroup USBH_MSC_BOT_Exported_FunctionsPrototype
+ * @{
+ */
+USBH_StatusTypeDef USBH_MSC_BOT_REQ_Reset(USBH_HandleTypeDef *phost);
+USBH_StatusTypeDef USBH_MSC_BOT_REQ_GetMaxLUN(USBH_HandleTypeDef *phost, uint8_t *Maxlun);
+
+USBH_StatusTypeDef USBH_MSC_BOT_Init(USBH_HandleTypeDef *phost);
+USBH_StatusTypeDef USBH_MSC_BOT_Process (USBH_HandleTypeDef *phost, uint8_t lun);
+USBH_StatusTypeDef USBH_MSC_BOT_Error(USBH_HandleTypeDef *phost, uint8_t lun);
+
+
+
+/**
+ * @}
+ */
+
+#endif //__USBH_MSC_BOT_H__
+
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
+
diff --git a/ports/stm32/usbhost/Class/MSC/Inc/usbh_msc_scsi.h b/ports/stm32/usbhost/Class/MSC/Inc/usbh_msc_scsi.h
new file mode 100644
index 000000000..76b51902a
--- /dev/null
+++ b/ports/stm32/usbhost/Class/MSC/Inc/usbh_msc_scsi.h
@@ -0,0 +1,218 @@
+/**
+ ******************************************************************************
+ * @file usbh_msc_scsi.h
+ * @author MCD Application Team
+ * @version V3.0.0
+ * @date 18-February-2014
+ * @brief Header file for usbh_msc_scsi.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 ----------------------------------------------*/
+#ifndef __USBH_MSC_SCSI_H__
+#define __USBH_MSC_SCSI_H__
+
+/* Includes ------------------------------------------------------------------*/
+#include "usbh_core.h"
+
+
+/** @addtogroup USBH_LIB
+ * @{
+ */
+
+/** @addtogroup USBH_CLASS
+ * @{
+ */
+
+/** @addtogroup USBH_MSC_CLASS
+ * @{
+ */
+
+/** @defgroup USBH_MSC_SCSI
+ * @brief This file is the Header file for usbh_msc_scsi.c
+ * @{
+ */
+
+
+// Capacity data.
+typedef struct
+{
+ uint32_t block_nbr;
+ uint16_t block_size;
+} SCSI_CapacityTypeDef;
+
+
+// Sense data.
+typedef struct
+{
+ uint8_t key;
+ uint8_t asc;
+ uint8_t ascq;
+} SCSI_SenseTypeDef;
+
+// INQUIRY data.
+typedef struct
+{
+ uint8_t PeripheralQualifier;
+ uint8_t DeviceType;
+ uint8_t RemovableMedia;
+ uint8_t vendor_id[9];
+ uint8_t product_id[17];
+ uint8_t revision_id[5];
+}SCSI_StdInquiryDataTypeDef;
+
+/** @defgroup USBH_MSC_SCSI_Exported_Defines
+ * @{
+ */
+#define OPCODE_TEST_UNIT_READY 0x00
+#define OPCODE_READ_CAPACITY10 0x25
+#define OPCODE_READ10 0x28
+#define OPCODE_WRITE10 0x2A
+#define OPCODE_REQUEST_SENSE 0x03
+#define OPCODE_INQUIRY 0x12
+
+#define DATA_LEN_MODE_TEST_UNIT_READY 0
+#define DATA_LEN_READ_CAPACITY10 8
+#define DATA_LEN_INQUIRY 36
+#define DATA_LEN_REQUEST_SENSE 14
+
+#define CBW_CB_LENGTH 16
+#define CBW_LENGTH 10
+
+/** @defgroup USBH_MSC_SCSI_Exported_Defines
+ * @{
+ */
+#define SCSI_SENSE_KEY_NO_SENSE 0x00
+#define SCSI_SENSE_KEY_RECOVERED_ERROR 0x01
+#define SCSI_SENSE_KEY_NOT_READY 0x02
+#define SCSI_SENSE_KEY_MEDIUM_ERROR 0x03
+#define SCSI_SENSE_KEY_HARDWARE_ERROR 0x04
+#define SCSI_SENSE_KEY_ILLEGAL_REQUEST 0x05
+#define SCSI_SENSE_KEY_UNIT_ATTENTION 0x06
+#define SCSI_SENSE_KEY_DATA_PROTECT 0x07
+#define SCSI_SENSE_KEY_BLANK_CHECK 0x08
+#define SCSI_SENSE_KEY_VENDOR_SPECIFIC 0x09
+#define SCSI_SENSE_KEY_COPY_ABORTED 0x0A
+#define SCSI_SENSE_KEY_ABORTED_COMMAND 0x0B
+#define SCSI_SENSE_KEY_VOLUME_OVERFLOW 0x0D
+#define SCSI_SENSE_KEY_MISCOMPARE 0x0E
+/**
+ * @}
+ */
+
+
+/** @defgroup USBH_MSC_SCSI_Exported_Defines
+ * @{
+ */
+#define SCSI_ASC_NO_ADDITIONAL_SENSE_INFORMATION 0x00
+#define SCSI_ASC_LOGICAL_UNIT_NOT_READY 0x04
+#define SCSI_ASC_INVALID_FIELD_IN_CDB 0x24
+#define SCSI_ASC_WRITE_PROTECTED 0x27
+#define SCSI_ASC_FORMAT_ERROR 0x31
+#define SCSI_ASC_INVALID_COMMAND_OPERATION_CODE 0x20
+#define SCSI_ASC_NOT_READY_TO_READY_CHANGE 0x28
+#define SCSI_ASC_MEDIUM_NOT_PRESENT 0x3A
+/**
+ * @}
+ */
+
+
+/** @defgroup USBH_MSC_SCSI_Exported_Defines
+ * @{
+ */
+#define SCSI_ASCQ_FORMAT_COMMAND_FAILED 0x01
+#define SCSI_ASCQ_INITIALIZING_COMMAND_REQUIRED 0x02
+#define SCSI_ASCQ_OPERATION_IN_PROGRESS 0x07
+
+/**
+ * @}
+ */
+
+/** @defgroup USBH_MSC_SCSI_Exported_Macros
+ * @{
+ */
+/**
+ * @}
+ */
+
+/** @defgroup _Exported_Variables
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+/** @defgroup USBH_MSC_SCSI_Exported_FunctionsPrototype
+ * @{
+ */
+USBH_StatusTypeDef USBH_MSC_SCSI_TestUnitReady (USBH_HandleTypeDef *phost,
+ uint8_t lun);
+
+USBH_StatusTypeDef USBH_MSC_SCSI_ReadCapacity (USBH_HandleTypeDef *phost,
+ uint8_t lun,
+ SCSI_CapacityTypeDef *capacity);
+
+USBH_StatusTypeDef USBH_MSC_SCSI_Inquiry (USBH_HandleTypeDef *phost,
+ uint8_t lun,
+ SCSI_StdInquiryDataTypeDef *inquiry);
+
+USBH_StatusTypeDef USBH_MSC_SCSI_RequestSense (USBH_HandleTypeDef *phost,
+ uint8_t lun,
+ SCSI_SenseTypeDef *sense_data);
+
+USBH_StatusTypeDef USBH_MSC_SCSI_Write(USBH_HandleTypeDef *phost,
+ uint8_t lun,
+ uint32_t address,
+ uint8_t *pbuf,
+ uint32_t length);
+
+USBH_StatusTypeDef USBH_MSC_SCSI_Read(USBH_HandleTypeDef *phost,
+ uint8_t lun,
+ uint32_t address,
+ uint8_t *pbuf,
+ uint32_t length);
+
+
+/**
+ * @}
+ */
+
+#endif //__USBH_MSC_SCSI_H__
+
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
+
diff --git a/ports/stm32/usbhost/Class/MSC/Src/usbh_msc.c b/ports/stm32/usbhost/Class/MSC/Src/usbh_msc.c
new file mode 100644
index 000000000..53a2cd81d
--- /dev/null
+++ b/ports/stm32/usbhost/Class/MSC/Src/usbh_msc.c
@@ -0,0 +1,795 @@
+/**
+ ******************************************************************************
+ * @file usbh_msc.c
+ * @author MCD Application Team
+ * @version V3.0.0
+ * @date 18-February-2014
+ * @brief This file implements the MSC class driver functions
+ * ===================================================================
+ * MSC Class Description
+ * ===================================================================
+ * This module manages the MSC class V1.0 following the "Universal
+ * Serial Bus Mass Storage Class (MSC) Bulk-Only Transport (BOT) Version 1.0
+ * Sep. 31, 1999".
+ * This driver implements the following aspects of the specification:
+ * - Bulk-Only Transport protocol
+ * - Subclass : SCSI transparent command set (ref. SCSI Primary Commands - 3 (SPC-3))
+ *
+ * @endverbatim
+ *
+ ******************************************************************************
+ * @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 "usbh_msc.h"
+#include "usbh_msc_bot.h"
+#include "usbh_msc_scsi.h"
+
+
+/** @addtogroup USBH_LIB
+ * @{
+ */
+
+/** @addtogroup USBH_CLASS
+ * @{
+ */
+
+/** @addtogroup USBH_MSC_CLASS
+ * @{
+ */
+
+/** @defgroup USBH_MSC_CORE
+ * @brief This file includes the mass storage related functions
+ * @{
+ */
+
+
+/** @defgroup USBH_MSC_CORE_Private_TypesDefinitions
+ * @{
+ */
+/**
+ * @}
+ */
+
+/** @defgroup USBH_MSC_CORE_Private_Defines
+ * @{
+ */
+/**
+ * @}
+ */
+
+/** @defgroup USBH_MSC_CORE_Private_Macros
+ * @{
+ */
+/**
+ * @}
+ */
+
+
+/** @defgroup USBH_MSC_CORE_Private_Variables
+ * @{
+ */
+/**
+ * @}
+ */
+
+
+/** @defgroup USBH_MSC_CORE_Private_FunctionPrototypes
+ * @{
+ */
+
+static USBH_StatusTypeDef USBH_MSC_InterfaceInit (USBH_HandleTypeDef *phost);
+
+static USBH_StatusTypeDef USBH_MSC_InterfaceDeInit (USBH_HandleTypeDef *phost);
+
+static USBH_StatusTypeDef USBH_MSC_Process(USBH_HandleTypeDef *phost);
+
+static USBH_StatusTypeDef USBH_MSC_ClassRequest(USBH_HandleTypeDef *phost);
+
+static USBH_StatusTypeDef USBH_MSC_SOFProcess(USBH_HandleTypeDef *phost);
+
+static USBH_StatusTypeDef USBH_MSC_RdWrProcess(USBH_HandleTypeDef *phost, uint8_t lun);
+
+USBH_ClassTypeDef USBH_msc =
+{
+ "MSC",
+ USB_MSC_CLASS,
+ USBH_MSC_InterfaceInit,
+ USBH_MSC_InterfaceDeInit,
+ USBH_MSC_ClassRequest,
+ USBH_MSC_Process,
+ USBH_MSC_SOFProcess,
+ NULL,
+};
+
+
+/**
+ * @}
+ */
+
+
+/** @defgroup USBH_MSC_CORE_Exported_Variables
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+
+/** @defgroup USBH_MSC_CORE_Private_Functions
+ * @{
+ */
+
+
+/**
+ * @brief USBH_MSC_InterfaceInit
+ * The function init the MSC class.
+ * @param phost: Host handle
+ * @retval USBH Status
+ */
+static USBH_StatusTypeDef USBH_MSC_InterfaceInit (USBH_HandleTypeDef *phost)
+{
+ uint8_t interface = 0;
+ USBH_StatusTypeDef status = USBH_FAIL ;
+ MSC_HandleTypeDef *MSC_Handle;
+
+ interface = USBH_FindInterface(phost, phost->pActiveClass->ClassCode, MSC_TRANSPARENT, MSC_BOT);
+
+ if(interface == 0xFF) /* Not Valid Interface */
+ {
+ USBH_DbgLog ("Cannot Find the interface for %s class.", phost->pActiveClass->Name);
+ status = USBH_FAIL;
+ }
+ else
+ {
+ USBH_SelectInterface (phost, interface);
+
+ phost->pActiveClass->pData = (MSC_HandleTypeDef *)USBH_malloc (sizeof(MSC_HandleTypeDef));
+ MSC_Handle = phost->pActiveClass->pData;
+
+ if(phost->device.CfgDesc.Itf_Desc[phost->device.current_interface].Ep_Desc[0].bEndpointAddress & 0x80)
+ {
+ MSC_Handle->InEp = (phost->device.CfgDesc.Itf_Desc[phost->device.current_interface].Ep_Desc[0].bEndpointAddress);
+ MSC_Handle->InEpSize = phost->device.CfgDesc.Itf_Desc[phost->device.current_interface].Ep_Desc[0].wMaxPacketSize;
+ }
+ else
+ {
+ MSC_Handle->OutEp = (phost->device.CfgDesc.Itf_Desc[phost->device.current_interface].Ep_Desc[0].bEndpointAddress);
+ MSC_Handle->OutEpSize = phost->device.CfgDesc.Itf_Desc[phost->device.current_interface].Ep_Desc[0].wMaxPacketSize;
+ }
+
+ if(phost->device.CfgDesc.Itf_Desc[phost->device.current_interface].Ep_Desc[1].bEndpointAddress & 0x80)
+ {
+ MSC_Handle->InEp = (phost->device.CfgDesc.Itf_Desc[phost->device.current_interface].Ep_Desc[1].bEndpointAddress);
+ MSC_Handle->InEpSize = phost->device.CfgDesc.Itf_Desc[phost->device.current_interface].Ep_Desc[1].wMaxPacketSize;
+ }
+ else
+ {
+ MSC_Handle->OutEp = (phost->device.CfgDesc.Itf_Desc[phost->device.current_interface].Ep_Desc[1].bEndpointAddress);
+ MSC_Handle->OutEpSize = phost->device.CfgDesc.Itf_Desc[phost->device.current_interface].Ep_Desc[1].wMaxPacketSize;
+ }
+
+ MSC_Handle->current_lun = 0;
+ MSC_Handle->rw_lun = 0;
+ MSC_Handle->state = MSC_INIT;
+ MSC_Handle->error = MSC_OK;
+ MSC_Handle->req_state = MSC_REQ_IDLE;
+ MSC_Handle->OutPipe = USBH_AllocPipe(phost, MSC_Handle->OutEp);
+ MSC_Handle->InPipe = USBH_AllocPipe(phost, MSC_Handle->InEp);
+
+ USBH_MSC_BOT_Init(phost);
+
+ /* De-Initialize LUNs information */
+ USBH_memset(MSC_Handle->unit, 0, sizeof(MSC_Handle->unit));
+
+ /* Open the new channels */
+ USBH_OpenPipe (phost,
+ MSC_Handle->OutPipe,
+ MSC_Handle->OutEp,
+ phost->device.address,
+ phost->device.speed,
+ USB_EP_TYPE_BULK,
+ MSC_Handle->OutEpSize);
+
+ USBH_OpenPipe (phost,
+ MSC_Handle->InPipe,
+ MSC_Handle->InEp,
+ phost->device.address,
+ phost->device.speed,
+ USB_EP_TYPE_BULK,
+ MSC_Handle->InEpSize);
+
+
+ USBH_LL_SetToggle (phost, MSC_Handle->InPipe,0);
+ USBH_LL_SetToggle (phost, MSC_Handle->OutPipe,0);
+ status = USBH_OK;
+ }
+ return status;
+}
+
+/**
+ * @brief USBH_MSC_InterfaceDeInit
+ * The function DeInit the Pipes used for the MSC class.
+ * @param phost: Host handle
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_MSC_InterfaceDeInit (USBH_HandleTypeDef *phost)
+{
+ MSC_HandleTypeDef *MSC_Handle = phost->pActiveClass->pData;
+
+ if ( MSC_Handle->OutPipe)
+ {
+ USBH_ClosePipe(phost, MSC_Handle->OutPipe);
+ USBH_FreePipe (phost, MSC_Handle->OutPipe);
+ MSC_Handle->OutPipe = 0; /* Reset the Channel as Free */
+ }
+
+ if ( MSC_Handle->InPipe)
+ {
+ USBH_ClosePipe(phost, MSC_Handle->InPipe);
+ USBH_FreePipe (phost, MSC_Handle->InPipe);
+ MSC_Handle->InPipe = 0; /* Reset the Channel as Free */
+ }
+
+ if(phost->pActiveClass->pData)
+ {
+ USBH_free (phost->pActiveClass->pData);
+ phost->pActiveClass->pData = 0;
+ }
+
+ return USBH_OK;
+}
+
+/**
+ * @brief USBH_MSC_ClassRequest
+ * The function is responsible for handling Standard requests
+ * for MSC class.
+ * @param phost: Host handle
+ * @retval USBH Status
+ */
+static USBH_StatusTypeDef USBH_MSC_ClassRequest(USBH_HandleTypeDef *phost)
+{
+ MSC_HandleTypeDef *MSC_Handle = phost->pActiveClass->pData;
+ USBH_StatusTypeDef status = USBH_BUSY;
+ uint8_t i;
+
+ /* Switch MSC REQ state machine */
+ switch (MSC_Handle->req_state)
+ {
+ case MSC_REQ_IDLE:
+ case MSC_REQ_GET_MAX_LUN:
+ /* Issue GetMaxLUN request */
+ if(USBH_MSC_BOT_REQ_GetMaxLUN(phost, (uint8_t *)&MSC_Handle->max_lun) == USBH_OK )
+ {
+ MSC_Handle->max_lun = (uint8_t )(MSC_Handle->max_lun) + 1;
+ USBH_UsrLog ("Number of supported LUN: %lu", (int32_t)(MSC_Handle->max_lun));
+
+ for(i = 0; i < MSC_Handle->max_lun; i++)
+ {
+ MSC_Handle->unit[i].prev_ready_state = USBH_FAIL;
+ MSC_Handle->unit[i].state_changed = 0;
+ }
+ status = USBH_OK;
+ }
+ break;
+
+ case MSC_REQ_ERROR :
+ /* a Clear Feature should be issued here */
+ if(USBH_ClrFeature(phost, 0x00) == USBH_OK)
+ {
+ MSC_Handle->req_state = MSC_Handle->prev_req_state;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return status;
+}
+
+/**
+ * @brief USBH_MSC_Process
+ * The function is for managing state machine for MSC data transfers
+ * @param phost: Host handle
+ * @retval USBH Status
+ */
+static USBH_StatusTypeDef USBH_MSC_Process(USBH_HandleTypeDef *phost)
+{
+ MSC_HandleTypeDef *MSC_Handle = phost->pActiveClass->pData;
+ USBH_StatusTypeDef error = USBH_BUSY ;
+ USBH_StatusTypeDef scsi_status = USBH_BUSY ;
+ USBH_StatusTypeDef ready_status = USBH_BUSY ;
+
+ switch (MSC_Handle->state)
+ {
+ case MSC_INIT:
+
+ if(MSC_Handle->current_lun < MSC_Handle->max_lun)
+ {
+
+ MSC_Handle->unit[MSC_Handle->current_lun].error = MSC_NOT_READY;
+ /* Switch MSC REQ state machine */
+ switch (MSC_Handle->unit[MSC_Handle->current_lun].state)
+ {
+ case MSC_INIT:
+ USBH_UsrLog ("LUN #%d: ", MSC_Handle->current_lun);
+ MSC_Handle->unit[MSC_Handle->current_lun].state = MSC_READ_INQUIRY;
+ MSC_Handle->timer = phost->Timer + 10000;
+
+ case MSC_READ_INQUIRY:
+ scsi_status = USBH_MSC_SCSI_Inquiry(phost, MSC_Handle->current_lun, &MSC_Handle->unit[MSC_Handle->current_lun].inquiry);
+
+ if( scsi_status == USBH_OK)
+ {
+ USBH_UsrLog ("Inquiry Vendor : %s", MSC_Handle->unit[MSC_Handle->current_lun].inquiry.vendor_id);
+ USBH_UsrLog ("Inquiry Product : %s", MSC_Handle->unit[MSC_Handle->current_lun].inquiry.product_id);
+ USBH_UsrLog ("Inquiry Version : %s", MSC_Handle->unit[MSC_Handle->current_lun].inquiry.revision_id);
+ MSC_Handle->unit[MSC_Handle->current_lun].state = MSC_TEST_UNIT_READY;
+ }
+ if( scsi_status == USBH_FAIL)
+ {
+ MSC_Handle->unit[MSC_Handle->current_lun].state = MSC_REQUEST_SENSE;
+ }
+ else if(scsi_status == USBH_UNRECOVERED_ERROR)
+ {
+ MSC_Handle->unit[MSC_Handle->current_lun].state = MSC_IDLE;
+ MSC_Handle->unit[MSC_Handle->current_lun].error = MSC_ERROR;
+ }
+ break;
+
+ case MSC_TEST_UNIT_READY:
+ ready_status = USBH_MSC_SCSI_TestUnitReady(phost, MSC_Handle->current_lun);
+
+ if( ready_status == USBH_OK)
+ {
+ if( MSC_Handle->unit[MSC_Handle->current_lun].prev_ready_state != USBH_OK)
+ {
+ MSC_Handle->unit[MSC_Handle->current_lun].state_changed = 1;
+ USBH_UsrLog ("Mass Storage Device ready");
+ }
+ else
+ {
+ MSC_Handle->unit[MSC_Handle->current_lun].state_changed = 0;
+ }
+ MSC_Handle->unit[MSC_Handle->current_lun].state = MSC_READ_CAPACITY10;
+ MSC_Handle->unit[MSC_Handle->current_lun].error = MSC_OK;
+ MSC_Handle->unit[MSC_Handle->current_lun].prev_ready_state = USBH_OK;
+ }
+ if( ready_status == USBH_FAIL)
+ {
+ /* Media not ready, so try to check again during 10s */
+ if( MSC_Handle->unit[MSC_Handle->current_lun].prev_ready_state != USBH_FAIL)
+ {
+ MSC_Handle->unit[MSC_Handle->current_lun].state_changed = 1;
+ USBH_UsrLog ("Mass Storage Device NOT ready");
+ }
+ else
+ {
+ MSC_Handle->unit[MSC_Handle->current_lun].state_changed = 0;
+ }
+ MSC_Handle->unit[MSC_Handle->current_lun].state = MSC_REQUEST_SENSE;
+ MSC_Handle->unit[MSC_Handle->current_lun].error = MSC_NOT_READY;
+ MSC_Handle->unit[MSC_Handle->current_lun].prev_ready_state = USBH_FAIL;
+ }
+ else if(ready_status == USBH_UNRECOVERED_ERROR)
+ {
+ MSC_Handle->unit[MSC_Handle->current_lun].state = MSC_IDLE;
+ MSC_Handle->unit[MSC_Handle->current_lun].error = MSC_ERROR;
+ }
+ break;
+
+ case MSC_READ_CAPACITY10:
+ scsi_status = USBH_MSC_SCSI_ReadCapacity(phost,MSC_Handle->current_lun, &MSC_Handle->unit[MSC_Handle->current_lun].capacity) ;
+
+ if(scsi_status == USBH_OK)
+ {
+ if(MSC_Handle->unit[MSC_Handle->current_lun].state_changed == 1)
+ {
+ USBH_UsrLog ("Mass Storage Device capacity : %lu MB", \
+ (int32_t)((MSC_Handle->unit[MSC_Handle->current_lun].capacity.block_nbr * MSC_Handle->unit[MSC_Handle->current_lun].capacity.block_size)/1024/1024));
+ USBH_UsrLog ("Block number : %lu", (int32_t)(MSC_Handle->unit[MSC_Handle->current_lun].capacity.block_nbr));
+ USBH_UsrLog ("Block Size : %lu", (int32_t)(MSC_Handle->unit[MSC_Handle->current_lun].capacity.block_size));
+ }
+ MSC_Handle->unit[MSC_Handle->current_lun].state = MSC_IDLE;
+ MSC_Handle->unit[MSC_Handle->current_lun].error = MSC_OK;
+ MSC_Handle->current_lun++;
+ }
+ else if( scsi_status == USBH_FAIL)
+ {
+ MSC_Handle->unit[MSC_Handle->current_lun].state = MSC_REQUEST_SENSE;
+ }
+ else if(scsi_status == USBH_UNRECOVERED_ERROR)
+ {
+ MSC_Handle->unit[MSC_Handle->current_lun].state = MSC_IDLE;
+ MSC_Handle->unit[MSC_Handle->current_lun].error = MSC_ERROR;
+ }
+ break;
+
+ case MSC_REQUEST_SENSE:
+ scsi_status = USBH_MSC_SCSI_RequestSense(phost, MSC_Handle->current_lun, &MSC_Handle->unit[MSC_Handle->current_lun].sense);
+
+ if( scsi_status == USBH_OK)
+ {
+ if((MSC_Handle->unit[MSC_Handle->current_lun].sense.key == SCSI_SENSE_KEY_UNIT_ATTENTION) ||
+ (MSC_Handle->unit[MSC_Handle->current_lun].sense.key == SCSI_SENSE_KEY_NOT_READY) )
+ {
+
+ if(phost->Timer <= MSC_Handle->timer)
+ {
+ MSC_Handle->unit[MSC_Handle->current_lun].state = MSC_TEST_UNIT_READY;
+ break;
+ }
+ }
+
+ USBH_UsrLog ("Sense Key : %x", MSC_Handle->unit[MSC_Handle->current_lun].sense.key);
+ USBH_UsrLog ("Additional Sense Code : %x", MSC_Handle->unit[MSC_Handle->current_lun].sense.asc);
+ USBH_UsrLog ("Additional Sense Code Qualifier: %x", MSC_Handle->unit[MSC_Handle->current_lun].sense.ascq);
+ MSC_Handle->unit[MSC_Handle->current_lun].state = MSC_IDLE;
+ MSC_Handle->current_lun++;
+ }
+ if( scsi_status == USBH_FAIL)
+ {
+ USBH_UsrLog ("Mass Storage Device NOT ready");
+ MSC_Handle->unit[MSC_Handle->current_lun].state = MSC_UNRECOVERED_ERROR;
+ }
+ else if(scsi_status == USBH_UNRECOVERED_ERROR)
+ {
+ MSC_Handle->unit[MSC_Handle->current_lun].state = MSC_IDLE;
+ MSC_Handle->unit[MSC_Handle->current_lun].error = MSC_ERROR;
+ }
+ break;
+
+ case MSC_UNRECOVERED_ERROR:
+ MSC_Handle->current_lun++;
+ break;
+
+ default:
+ break;
+ }
+
+#if (USBH_USE_OS == 1)
+ osMessagePut ( phost->os_event, USBH_CLASS_EVENT, 0);
+#endif
+ }
+ else
+ {
+ MSC_Handle->current_lun = 0;
+ MSC_Handle->state = MSC_IDLE;
+#if (USBH_USE_OS == 1)
+ osMessagePut ( phost->os_event, USBH_CLASS_EVENT, 0);
+#endif
+ phost->pUser(phost, HOST_USER_CLASS_ACTIVE);
+ }
+ break;
+
+ case MSC_IDLE:
+ error = USBH_OK;
+ break;
+
+ default:
+ break;
+ }
+ return error;
+}
+
+
+/**
+ * @brief USBH_MSC_SOFProcess
+ * The function is for SOF state
+ * @param phost: Host handle
+ * @retval USBH Status
+ */
+static USBH_StatusTypeDef USBH_MSC_SOFProcess(USBH_HandleTypeDef *phost)
+{
+
+ return USBH_OK;
+}
+/**
+ * @brief USBH_MSC_RdWrProcess
+ * The function is for managing state machine for MSC I/O Process
+ * @param phost: Host handle
+ * @param lun: logical Unit Number
+ * @retval USBH Status
+ */
+static USBH_StatusTypeDef USBH_MSC_RdWrProcess(USBH_HandleTypeDef *phost, uint8_t lun)
+{
+ MSC_HandleTypeDef *MSC_Handle = phost->pActiveClass->pData;
+ USBH_StatusTypeDef error = USBH_BUSY ;
+ USBH_StatusTypeDef scsi_status = USBH_BUSY ;
+
+ /* Switch MSC REQ state machine */
+ switch (MSC_Handle->unit[lun].state)
+ {
+
+ case MSC_READ:
+ scsi_status = USBH_MSC_SCSI_Read(phost,lun, 0, NULL, 0) ;
+
+ if(scsi_status == USBH_OK)
+ {
+ MSC_Handle->unit[lun].state = MSC_IDLE;
+ error = USBH_OK;
+ }
+ else if( scsi_status == USBH_FAIL)
+ {
+ MSC_Handle->unit[lun].state = MSC_REQUEST_SENSE;
+ }
+ else if(scsi_status == USBH_UNRECOVERED_ERROR)
+ {
+ MSC_Handle->unit[lun].state = MSC_UNRECOVERED_ERROR;
+ error = USBH_FAIL;
+ }
+#if (USBH_USE_OS == 1)
+ osMessagePut ( phost->os_event, USBH_CLASS_EVENT, 0);
+#endif
+ break;
+
+ case MSC_WRITE:
+ scsi_status = USBH_MSC_SCSI_Write(phost,lun, 0, NULL, 0) ;
+
+ if(scsi_status == USBH_OK)
+ {
+ MSC_Handle->unit[lun].state = MSC_IDLE;
+ error = USBH_OK;
+ }
+ else if( scsi_status == USBH_FAIL)
+ {
+ MSC_Handle->unit[lun].state = MSC_REQUEST_SENSE;
+ }
+ else if(scsi_status == USBH_UNRECOVERED_ERROR)
+ {
+ MSC_Handle->unit[lun].state = MSC_UNRECOVERED_ERROR;
+ error = USBH_FAIL;
+ }
+#if (USBH_USE_OS == 1)
+ osMessagePut ( phost->os_event, USBH_CLASS_EVENT, 0);
+#endif
+ break;
+
+ case MSC_REQUEST_SENSE:
+ scsi_status = USBH_MSC_SCSI_RequestSense(phost, lun, &MSC_Handle->unit[lun].sense);
+
+ if( scsi_status == USBH_OK)
+ {
+ USBH_UsrLog ("Sense Key : %x", MSC_Handle->unit[lun].sense.key);
+ USBH_UsrLog ("Additional Sense Code : %x", MSC_Handle->unit[lun].sense.asc);
+ USBH_UsrLog ("Additional Sense Code Qualifier: %x", MSC_Handle->unit[lun].sense.ascq);
+ MSC_Handle->unit[lun].state = MSC_IDLE;
+ MSC_Handle->unit[lun].error = MSC_ERROR;
+
+ error = USBH_FAIL;
+ }
+ if( scsi_status == USBH_FAIL)
+ {
+ USBH_UsrLog ("Mass Storage Device NOT ready");
+ }
+ else if(scsi_status == USBH_UNRECOVERED_ERROR)
+ {
+ MSC_Handle->unit[lun].state = MSC_UNRECOVERED_ERROR;
+ error = USBH_FAIL;
+ }
+#if (USBH_USE_OS == 1)
+ osMessagePut ( phost->os_event, USBH_CLASS_EVENT, 0);
+#endif
+ break;
+
+ default:
+ break;
+
+ }
+ return error;
+}
+
+/**
+ * @brief USBH_MSC_IsReady
+ * The function check if the MSC function is ready
+ * @param phost: Host handle
+ * @retval USBH Status
+ */
+uint8_t USBH_MSC_IsReady (USBH_HandleTypeDef *phost)
+{
+ MSC_HandleTypeDef *MSC_Handle = phost->pActiveClass->pData;
+
+ if(phost->gState == HOST_CLASS)
+ {
+ return (MSC_Handle->state == MSC_IDLE);
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+/**
+ * @brief USBH_MSC_GetMaxLUN
+ * The function return the Max LUN supported
+ * @param phost: Host handle
+ * @retval logical Unit Number supported
+ */
+int8_t USBH_MSC_GetMaxLUN (USBH_HandleTypeDef *phost)
+{
+ MSC_HandleTypeDef *MSC_Handle = phost->pActiveClass->pData;
+
+ if ((phost->gState != HOST_CLASS) && (MSC_Handle->state == MSC_IDLE))
+ {
+ return MSC_Handle->max_lun;
+ }
+ return 0xFF;
+}
+
+/**
+ * @brief USBH_MSC_UnitIsReady
+ * The function check whether a LUN is ready
+ * @param phost: Host handle
+ * @param lun: logical Unit Number
+ * @retval Lun status (0: not ready / 1: ready)
+ */
+uint8_t USBH_MSC_UnitIsReady (USBH_HandleTypeDef *phost, uint8_t lun)
+{
+ MSC_HandleTypeDef *MSC_Handle = phost->pActiveClass->pData;
+
+ if(phost->gState == HOST_CLASS)
+ {
+ return (MSC_Handle->unit[lun].error == MSC_OK);
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+/**
+ * @brief USBH_MSC_GetLUNInfo
+ * The function return a LUN information
+ * @param phost: Host handle
+ * @param lun: logical Unit Number
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_MSC_GetLUNInfo(USBH_HandleTypeDef *phost, uint8_t lun, MSC_LUNTypeDef *info)
+{
+ MSC_HandleTypeDef *MSC_Handle = phost->pActiveClass->pData;
+ if(phost->gState == HOST_CLASS)
+ {
+ USBH_memcpy(info,&MSC_Handle->unit[lun], sizeof(MSC_LUNTypeDef));
+ return USBH_OK;
+ }
+ else
+ {
+ return USBH_FAIL;
+ }
+}
+
+/**
+ * @brief USBH_MSC_Read
+ * The function performs a Read operation
+ * @param phost: Host handle
+ * @param lun: logical Unit Number
+ * @param address: sector address
+ * @param pbuf: pointer to data
+ * @param length: number of sector to read
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_MSC_Read(USBH_HandleTypeDef *phost,
+ uint8_t lun,
+ uint32_t address,
+ uint8_t *pbuf,
+ uint32_t length)
+{
+ uint32_t timeout;
+ MSC_HandleTypeDef *MSC_Handle = phost->pActiveClass->pData;
+
+ if ((phost->device.is_connected == 0) ||
+ (phost->gState != HOST_CLASS) ||
+ (MSC_Handle->unit[lun].state != MSC_IDLE))
+ {
+ return USBH_FAIL;
+ }
+ MSC_Handle->state = MSC_READ;
+ MSC_Handle->unit[lun].state = MSC_READ;
+ MSC_Handle->rw_lun = lun;
+ USBH_MSC_SCSI_Read(phost,
+ lun,
+ address,
+ pbuf,
+ length);
+
+ timeout = phost->Timer + (10000 * length);
+ while (USBH_MSC_RdWrProcess(phost, lun) == USBH_BUSY)
+ {
+ if((phost->Timer > timeout) || (phost->device.is_connected == 0))
+ {
+ MSC_Handle->state = MSC_IDLE;
+ return USBH_FAIL;
+ }
+ }
+ MSC_Handle->state = MSC_IDLE;
+ return USBH_OK;
+}
+
+/**
+ * @brief USBH_MSC_Write
+ * The function performs a Write operation
+ * @param phost: Host handle
+ * @param lun: logical Unit Number
+ * @param address: sector address
+ * @param pbuf: pointer to data
+ * @param length: number of sector to write
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_MSC_Write(USBH_HandleTypeDef *phost,
+ uint8_t lun,
+ uint32_t address,
+ uint8_t *pbuf,
+ uint32_t length)
+{
+ uint32_t timeout;
+ MSC_HandleTypeDef *MSC_Handle = phost->pActiveClass->pData;
+
+ if ((phost->device.is_connected == 0) ||
+ (phost->gState != HOST_CLASS) ||
+ (MSC_Handle->unit[lun].state != MSC_IDLE))
+ {
+ return USBH_FAIL;
+ }
+ MSC_Handle->state = MSC_WRITE;
+ MSC_Handle->unit[lun].state = MSC_WRITE;
+ MSC_Handle->rw_lun = lun;
+ USBH_MSC_SCSI_Write(phost,
+ lun,
+ address,
+ pbuf,
+ length);
+
+ timeout = phost->Timer + (10000 * length);
+ while (USBH_MSC_RdWrProcess(phost, lun) == USBH_BUSY)
+ {
+ if((phost->Timer > timeout) || (phost->device.is_connected == 0))
+ {
+ MSC_Handle->state = MSC_IDLE;
+ return USBH_FAIL;
+ }
+ }
+ MSC_Handle->state = MSC_IDLE;
+ return USBH_OK;
+}
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/ports/stm32/usbhost/Class/MSC/Src/usbh_msc_bot.c b/ports/stm32/usbhost/Class/MSC/Src/usbh_msc_bot.c
new file mode 100644
index 000000000..5489ce297
--- /dev/null
+++ b/ports/stm32/usbhost/Class/MSC/Src/usbh_msc_bot.c
@@ -0,0 +1,633 @@
+/**
+ ******************************************************************************
+ * @file usbh_msc_bot.c
+ * @author MCD Application Team
+ * @version V3.0.0
+ * @date 18-February-2014
+ * @brief This file includes the BOT protocol related 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 "usbh_msc_bot.h"
+#include "usbh_msc.h"
+
+/** @addtogroup USBH_LIB
+* @{
+*/
+
+/** @addtogroup USBH_CLASS
+* @{
+*/
+
+/** @addtogroup USBH_MSC_CLASS
+* @{
+*/
+
+/** @defgroup USBH_MSC_BOT
+* @brief This file includes the mass storage related functions
+* @{
+*/
+
+
+/** @defgroup USBH_MSC_BOT_Private_TypesDefinitions
+* @{
+*/
+/**
+* @}
+*/
+
+/** @defgroup USBH_MSC_BOT_Private_Defines
+* @{
+*/
+/**
+* @}
+*/
+
+/** @defgroup USBH_MSC_BOT_Private_Macros
+* @{
+*/
+/**
+* @}
+*/
+
+
+/** @defgroup USBH_MSC_BOT_Private_Variables
+* @{
+*/
+
+/**
+* @}
+*/
+
+
+/** @defgroup USBH_MSC_BOT_Private_FunctionPrototypes
+* @{
+*/
+static USBH_StatusTypeDef USBH_MSC_BOT_Abort(USBH_HandleTypeDef *phost, uint8_t lun, uint8_t dir);
+static BOT_CSWStatusTypeDef USBH_MSC_DecodeCSW(USBH_HandleTypeDef *phost);
+/**
+* @}
+*/
+
+
+/** @defgroup USBH_MSC_BOT_Exported_Variables
+* @{
+*/
+/**
+* @}
+*/
+
+
+/** @defgroup USBH_MSC_BOT_Private_Functions
+* @{
+*/
+
+/**
+ * @brief USBH_MSC_BOT_REQ_Reset
+ * The function the MSC BOT Reset request.
+ * @param phost: Host handle
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_MSC_BOT_REQ_Reset(USBH_HandleTypeDef *phost)
+{
+
+ phost->Control.setup.b.bmRequestType = USB_H2D | USB_REQ_TYPE_CLASS | \
+ USB_REQ_RECIPIENT_INTERFACE;
+
+ phost->Control.setup.b.bRequest = USB_REQ_BOT_RESET;
+ phost->Control.setup.b.wValue.w = 0;
+ phost->Control.setup.b.wIndex.w = 0;
+ phost->Control.setup.b.wLength.w = 0;
+
+ return USBH_CtlReq(phost, 0 , 0 );
+}
+
+/**
+ * @brief USBH_MSC_BOT_REQ_GetMaxLUN
+ * The function the MSC BOT GetMaxLUN request.
+ * @param phost: Host handle
+ * @param Maxlun: pointer to Maxlun variable
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_MSC_BOT_REQ_GetMaxLUN(USBH_HandleTypeDef *phost, uint8_t *Maxlun)
+{
+ phost->Control.setup.b.bmRequestType = USB_D2H | USB_REQ_TYPE_CLASS | \
+ USB_REQ_RECIPIENT_INTERFACE;
+
+ phost->Control.setup.b.bRequest = USB_REQ_GET_MAX_LUN;
+ phost->Control.setup.b.wValue.w = 0;
+ phost->Control.setup.b.wIndex.w = 0;
+ phost->Control.setup.b.wLength.w = 1;
+
+ return USBH_CtlReq(phost, Maxlun , 1 );
+}
+
+
+
+/**
+ * @brief USBH_MSC_BOT_Init
+ * The function Initializes the BOT protocol.
+ * @param phost: Host handle
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_MSC_BOT_Init(USBH_HandleTypeDef *phost)
+{
+
+ MSC_HandleTypeDef *MSC_Handle = phost->pActiveClass->pData;
+
+ MSC_Handle->hbot.cbw.field.Signature = BOT_CBW_SIGNATURE;
+ MSC_Handle->hbot.cbw.field.Tag = BOT_CBW_TAG;
+ MSC_Handle->hbot.state = BOT_SEND_CBW;
+ MSC_Handle->hbot.cmd_state = BOT_CMD_SEND;
+
+ return USBH_OK;
+}
+
+
+
+/**
+ * @brief USBH_MSC_BOT_Process
+ * The function handle the BOT protocol.
+ * @param phost: Host handle
+ * @param lun: Logical Unit Number
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_MSC_BOT_Process (USBH_HandleTypeDef *phost, uint8_t lun)
+{
+ USBH_StatusTypeDef status = USBH_BUSY;
+ USBH_StatusTypeDef error = USBH_BUSY;
+ BOT_CSWStatusTypeDef CSW_Status = BOT_CSW_CMD_FAILED;
+ USBH_URBStateTypeDef URB_Status = USBH_URB_IDLE;
+ MSC_HandleTypeDef *MSC_Handle = phost->pActiveClass->pData;
+ uint8_t toggle = 0;
+
+ switch (MSC_Handle->hbot.state)
+ {
+ case BOT_SEND_CBW:
+ MSC_Handle->hbot.cbw.field.LUN = lun;
+ MSC_Handle->hbot.state = BOT_SEND_CBW_WAIT;
+ USBH_BulkSendData (phost,
+ MSC_Handle->hbot.cbw.data,
+ BOT_CBW_LENGTH,
+ MSC_Handle->OutPipe,
+ 1);
+
+ break;
+
+ case BOT_SEND_CBW_WAIT:
+
+ URB_Status = USBH_LL_GetURBState(phost, MSC_Handle->OutPipe);
+
+ if(URB_Status == USBH_URB_DONE)
+ {
+ if ( MSC_Handle->hbot.cbw.field.DataTransferLength != 0 )
+ {
+ /* If there is Data Transfer Stage */
+ if (((MSC_Handle->hbot.cbw.field.Flags) & USB_REQ_DIR_MASK) == USB_D2H)
+ {
+ /* Data Direction is IN */
+ MSC_Handle->hbot.state = BOT_DATA_IN;
+ }
+ else
+ {
+ /* Data Direction is OUT */
+ MSC_Handle->hbot.state = BOT_DATA_OUT;
+ }
+ }
+
+ else
+ {/* If there is NO Data Transfer Stage */
+ MSC_Handle->hbot.state = BOT_RECEIVE_CSW;
+ }
+#if (USBH_USE_OS == 1)
+ osMessagePut ( phost->os_event, USBH_URB_EVENT, 0);
+#endif
+
+ }
+ else if(URB_Status == USBH_URB_NOTREADY)
+ {
+ /* Re-send CBW */
+ MSC_Handle->hbot.state = BOT_SEND_CBW;
+#if (USBH_USE_OS == 1)
+ osMessagePut ( phost->os_event, USBH_URB_EVENT, 0);
+#endif
+ }
+ else if(URB_Status == USBH_URB_STALL)
+ {
+ MSC_Handle->hbot.state = BOT_ERROR_OUT;
+#if (USBH_USE_OS == 1)
+ osMessagePut ( phost->os_event, USBH_URB_EVENT, 0);
+#endif
+ }
+ break;
+
+ case BOT_DATA_IN:
+ /* Send first packet */
+ USBH_BulkReceiveData (phost,
+ MSC_Handle->hbot.pbuf,
+ MSC_Handle->InEpSize ,
+ MSC_Handle->InPipe);
+
+ MSC_Handle->hbot.state = BOT_DATA_IN_WAIT;
+
+ break;
+
+ case BOT_DATA_IN_WAIT:
+
+ URB_Status = USBH_LL_GetURBState(phost, MSC_Handle->InPipe);
+
+ if(URB_Status == USBH_URB_DONE)
+ {
+ /* Adjudt Data pointer and data length */
+ if(MSC_Handle->hbot.cbw.field.DataTransferLength > MSC_Handle->InEpSize)
+ {
+ MSC_Handle->hbot.pbuf += MSC_Handle->InEpSize;
+ MSC_Handle->hbot.cbw.field.DataTransferLength -= MSC_Handle->InEpSize;
+ }
+ else
+ {
+ MSC_Handle->hbot.cbw.field.DataTransferLength = 0;
+ }
+
+ /* More Data To be Received */
+ if(MSC_Handle->hbot.cbw.field.DataTransferLength > 0)
+ {
+ /* Send next packet */
+ USBH_BulkReceiveData (phost,
+ MSC_Handle->hbot.pbuf,
+ MSC_Handle->InEpSize ,
+ MSC_Handle->InPipe);
+
+ }
+ else
+ {
+ /* If value was 0, and successful transfer, then change the state */
+ MSC_Handle->hbot.state = BOT_RECEIVE_CSW;
+#if (USBH_USE_OS == 1)
+ osMessagePut ( phost->os_event, USBH_URB_EVENT, 0);
+#endif
+ }
+ }
+ else if(URB_Status == USBH_URB_STALL)
+ {
+ /* This is Data IN Stage STALL Condition */
+ MSC_Handle->hbot.state = BOT_ERROR_IN;
+
+ /* Refer to USB Mass-Storage Class : BOT (www.usb.org)
+ 6.7.2 Host expects to receive data from the device
+ 3. On a STALL condition receiving data, then:
+ The host shall accept the data received.
+ The host shall clear the Bulk-In pipe.
+ 4. The host shall attempt to receive a CSW.*/
+
+#if (USBH_USE_OS == 1)
+ osMessagePut ( phost->os_event, USBH_URB_EVENT, 0);
+#endif
+ }
+ break;
+
+ case BOT_DATA_OUT:
+
+ USBH_BulkSendData (phost,
+ MSC_Handle->hbot.pbuf,
+ MSC_Handle->OutEpSize ,
+ MSC_Handle->OutPipe,
+ 1);
+
+
+ MSC_Handle->hbot.state = BOT_DATA_OUT_WAIT;
+ break;
+
+ case BOT_DATA_OUT_WAIT:
+ URB_Status = USBH_LL_GetURBState(phost, MSC_Handle->OutPipe);
+
+ if(URB_Status == USBH_URB_DONE)
+ {
+ /* Adjudt Data pointer and data length */
+ if(MSC_Handle->hbot.cbw.field.DataTransferLength > MSC_Handle->OutEpSize)
+ {
+ MSC_Handle->hbot.pbuf += MSC_Handle->OutEpSize;
+ MSC_Handle->hbot.cbw.field.DataTransferLength -= MSC_Handle->OutEpSize;
+ }
+ else
+ {
+ MSC_Handle->hbot.cbw.field.DataTransferLength = 0;
+ }
+
+ /* More Data To be Sent */
+ if(MSC_Handle->hbot.cbw.field.DataTransferLength > 0)
+ {
+ USBH_BulkSendData (phost,
+ MSC_Handle->hbot.pbuf,
+ MSC_Handle->OutEpSize ,
+ MSC_Handle->OutPipe,
+ 1);
+ }
+ else
+ {
+ /* If value was 0, and successful transfer, then change the state */
+ MSC_Handle->hbot.state = BOT_RECEIVE_CSW;
+ }
+#if (USBH_USE_OS == 1)
+ osMessagePut ( phost->os_event, USBH_URB_EVENT, 0);
+#endif
+ }
+
+ else if(URB_Status == USBH_URB_NOTREADY)
+ {
+ /* Re-send same data */
+ MSC_Handle->hbot.state = BOT_DATA_OUT;
+#if (USBH_USE_OS == 1)
+ osMessagePut ( phost->os_event, USBH_URB_EVENT, 0);
+#endif
+ }
+
+ else if(URB_Status == USBH_URB_STALL)
+ {
+ MSC_Handle->hbot.state = BOT_ERROR_OUT;
+
+ /* Refer to USB Mass-Storage Class : BOT (www.usb.org)
+ 6.7.3 Ho - Host expects to send data to the device
+ 3. On a STALL condition sending data, then:
+ " The host shall clear the Bulk-Out pipe.
+ 4. The host shall attempt to receive a CSW.
+ */
+#if (USBH_USE_OS == 1)
+ osMessagePut ( phost->os_event, USBH_URB_EVENT, 0);
+#endif
+ }
+ break;
+
+ case BOT_RECEIVE_CSW:
+
+ USBH_BulkReceiveData (phost,
+ MSC_Handle->hbot.csw.data,
+ BOT_CSW_LENGTH ,
+ MSC_Handle->InPipe);
+
+ MSC_Handle->hbot.state = BOT_RECEIVE_CSW_WAIT;
+ break;
+
+ case BOT_RECEIVE_CSW_WAIT:
+
+ URB_Status = USBH_LL_GetURBState(phost, MSC_Handle->InPipe);
+
+ /* Decode CSW */
+ if(URB_Status == USBH_URB_DONE)
+ {
+ MSC_Handle->hbot.state = BOT_SEND_CBW;
+ MSC_Handle->hbot.cmd_state = BOT_CMD_SEND;
+ CSW_Status = USBH_MSC_DecodeCSW(phost);
+
+ if(CSW_Status == BOT_CSW_CMD_PASSED)
+ {
+ status = USBH_OK;
+ }
+ else
+ {
+ status = USBH_FAIL;
+ }
+#if (USBH_USE_OS == 1)
+ osMessagePut ( phost->os_event, USBH_URB_EVENT, 0);
+#endif
+ }
+ else if(URB_Status == USBH_URB_STALL)
+ {
+ MSC_Handle->hbot.state = BOT_ERROR_IN;
+#if (USBH_USE_OS == 1)
+ osMessagePut ( phost->os_event, USBH_URB_EVENT, 0);
+#endif
+ }
+ break;
+
+ case BOT_ERROR_IN:
+ error = USBH_MSC_BOT_Abort(phost, lun, BOT_DIR_IN);
+
+ if (error == USBH_OK)
+ {
+ MSC_Handle->hbot.state = BOT_RECEIVE_CSW;
+ }
+ else if (error == USBH_UNRECOVERED_ERROR)
+ {
+ /* This means that there is a STALL Error limit, Do Reset Recovery */
+ MSC_Handle->hbot.state = BOT_UNRECOVERED_ERROR;
+ }
+ break;
+
+ case BOT_ERROR_OUT:
+ error = USBH_MSC_BOT_Abort(phost, lun, BOT_DIR_OUT);
+
+ if ( error == USBH_OK)
+ {
+
+ toggle = USBH_LL_GetToggle(phost, MSC_Handle->OutPipe);
+ USBH_LL_SetToggle(phost, MSC_Handle->OutPipe, 1- toggle);
+ USBH_LL_SetToggle(phost, MSC_Handle->InPipe, 0);
+ MSC_Handle->hbot.state = BOT_ERROR_IN;
+ }
+ else if (error == USBH_UNRECOVERED_ERROR)
+ {
+ MSC_Handle->hbot.state = BOT_UNRECOVERED_ERROR;
+ }
+ break;
+
+
+ case BOT_UNRECOVERED_ERROR:
+ status = USBH_MSC_BOT_REQ_Reset(phost);
+ if ( status == USBH_OK)
+ {
+ MSC_Handle->hbot.state = BOT_SEND_CBW;
+ }
+ break;
+
+ default:
+ break;
+ }
+ return status;
+}
+
+/**
+ * @brief USBH_MSC_BOT_Abort
+ * The function handle the BOT Abort process.
+ * @param phost: Host handle
+ * @param lun: Logical Unit Number
+ * @param dir: direction (0: out / 1 : in)
+ * @retval USBH Status
+ */
+static USBH_StatusTypeDef USBH_MSC_BOT_Abort(USBH_HandleTypeDef *phost, uint8_t lun, uint8_t dir)
+{
+ USBH_StatusTypeDef status = USBH_FAIL;
+ MSC_HandleTypeDef *MSC_Handle = phost->pActiveClass->pData;
+
+ switch (dir)
+ {
+ case BOT_DIR_IN :
+ /* send ClrFeture on Bulk IN endpoint */
+ status = USBH_ClrFeature(phost, MSC_Handle->InEp);
+
+ break;
+
+ case BOT_DIR_OUT :
+ /*send ClrFeature on Bulk OUT endpoint */
+ status = USBH_ClrFeature(phost, MSC_Handle->OutEp);
+ break;
+
+ default:
+ break;
+ }
+ return status;
+}
+
+/**
+ * @brief USBH_MSC_BOT_DecodeCSW
+ * This function decodes the CSW received by the device and updates the
+ * same to upper layer.
+ * @param phost: Host handle
+ * @retval USBH Status
+ * @notes
+ * Refer to USB Mass-Storage Class : BOT (www.usb.org)
+ * 6.3.1 Valid CSW Conditions :
+ * The host shall consider the CSW valid when:
+ * 1. dCSWSignature is equal to 53425355h
+ * 2. the CSW is 13 (Dh) bytes in length,
+ * 3. dCSWTag matches the dCBWTag from the corresponding CBW.
+ */
+
+static BOT_CSWStatusTypeDef USBH_MSC_DecodeCSW(USBH_HandleTypeDef *phost)
+{
+ MSC_HandleTypeDef *MSC_Handle = phost->pActiveClass->pData;
+ BOT_CSWStatusTypeDef status = BOT_CSW_CMD_FAILED;
+
+ /*Checking if the transfer length is diffrent than 13*/
+ if(USBH_LL_GetLastXferSize(phost, MSC_Handle->InPipe) != BOT_CSW_LENGTH)
+ {
+ /*(4) Hi > Dn (Host expects to receive data from the device,
+ Device intends to transfer no data)
+ (5) Hi > Di (Host expects to receive data from the device,
+ Device intends to send data to the host)
+ (9) Ho > Dn (Host expects to send data to the device,
+ Device intends to transfer no data)
+ (11) Ho > Do (Host expects to send data to the device,
+ Device intends to receive data from the host)*/
+
+
+ status = BOT_CSW_PHASE_ERROR;
+ }
+ else
+ { /* CSW length is Correct */
+
+ /* Check validity of the CSW Signature and CSWStatus */
+ if(MSC_Handle->hbot.csw.field.Signature == BOT_CSW_SIGNATURE)
+ {/* Check Condition 1. dCSWSignature is equal to 53425355h */
+
+ if(MSC_Handle->hbot.csw.field.Tag == MSC_Handle->hbot.cbw.field.Tag)
+ {
+ /* Check Condition 3. dCSWTag matches the dCBWTag from the
+ corresponding CBW */
+
+ if(MSC_Handle->hbot.csw.field.Status == 0)
+ {
+ /* Refer to USB Mass-Storage Class : BOT (www.usb.org)
+
+ Hn Host expects no data transfers
+ Hi Host expects to receive data from the device
+ Ho Host expects to send data to the device
+
+ Dn Device intends to transfer no data
+ Di Device intends to send data to the host
+ Do Device intends to receive data from the host
+
+ Section 6.7
+ (1) Hn = Dn (Host expects no data transfers,
+ Device intends to transfer no data)
+ (6) Hi = Di (Host expects to receive data from the device,
+ Device intends to send data to the host)
+ (12) Ho = Do (Host expects to send data to the device,
+ Device intends to receive data from the host)
+
+ */
+
+ status = BOT_CSW_CMD_PASSED;
+ }
+ else if(MSC_Handle->hbot.csw.field.Status == 1)
+ {
+ status = BOT_CSW_CMD_FAILED;
+ }
+
+ else if(MSC_Handle->hbot.csw.field.Status == 2)
+ {
+ /* Refer to USB Mass-Storage Class : BOT (www.usb.org)
+ Section 6.7
+ (2) Hn < Di ( Host expects no data transfers,
+ Device intends to send data to the host)
+ (3) Hn < Do ( Host expects no data transfers,
+ Device intends to receive data from the host)
+ (7) Hi < Di ( Host expects to receive data from the device,
+ Device intends to send data to the host)
+ (8) Hi <> Do ( Host expects to receive data from the device,
+ Device intends to receive data from the host)
+ (10) Ho <> Di (Host expects to send data to the device,
+ Di Device intends to send data to the host)
+ (13) Ho < Do (Host expects to send data to the device,
+ Device intends to receive data from the host)
+ */
+
+ status = BOT_CSW_PHASE_ERROR;
+ }
+ } /* CSW Tag Matching is Checked */
+ } /* CSW Signature Correct Checking */
+ else
+ {
+ /* If the CSW Signature is not valid, We sall return the Phase Error to
+ Upper Layers for Reset Recovery */
+
+ status = BOT_CSW_PHASE_ERROR;
+ }
+ } /* CSW Length Check*/
+
+ return status;
+}
+
+
+/**
+* @}
+*/
+
+/**
+* @}
+*/
+
+/**
+* @}
+*/
+
+/**
+* @}
+*/
+
+/**
+* @}
+*/
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
+
+
+
diff --git a/ports/stm32/usbhost/Class/MSC/Src/usbh_msc_scsi.c b/ports/stm32/usbhost/Class/MSC/Src/usbh_msc_scsi.c
new file mode 100644
index 000000000..5d069b40a
--- /dev/null
+++ b/ports/stm32/usbhost/Class/MSC/Src/usbh_msc_scsi.c
@@ -0,0 +1,458 @@
+/**
+ ******************************************************************************
+ * @file usbh_msc_scsi.c
+ * @author MCD Application Team
+ * @version V3.0.0
+ * @date 18-February-2014
+ * @brief This file implements the SCSI commands
+ ******************************************************************************
+ * @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 "usbh_msc.h"
+#include "usbh_msc_scsi.h"
+#include "usbh_msc_bot.h"
+
+
+/** @addtogroup USBH_LIB
+ * @{
+ */
+
+/** @addtogroup USBH_CLASS
+ * @{
+ */
+
+/** @addtogroup USBH_MSC_CLASS
+ * @{
+ */
+
+/** @defgroup USBH_MSC_SCSI
+ * @brief This file includes the mass storage related functions
+ * @{
+ */
+
+
+/** @defgroup USBH_MSC_SCSI_Private_TypesDefinitions
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+/** @defgroup USBH_MSC_SCSI_Private_Defines
+ * @{
+ */
+/**
+ * @}
+ */
+
+/** @defgroup USBH_MSC_SCSI_Private_Macros
+ * @{
+ */
+/**
+ * @}
+ */
+
+
+/** @defgroup USBH_MSC_SCSI_Private_FunctionPrototypes
+ * @{
+ */
+/**
+ * @}
+ */
+
+
+/** @defgroup USBH_MSC_SCSI_Exported_Variables
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+
+/** @defgroup USBH_MSC_SCSI_Private_Functions
+ * @{
+ */
+
+
+/**
+ * @brief USBH_MSC_SCSI_TestUnitReady
+ * Issue TestUnitReady command.
+ * @param phost: Host handle
+ * @param lun: Logical Unit Number
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_MSC_SCSI_TestUnitReady (USBH_HandleTypeDef *phost,
+ uint8_t lun)
+{
+ USBH_StatusTypeDef error = USBH_FAIL ;
+ MSC_HandleTypeDef *MSC_Handle = phost->pActiveClass->pData;
+
+ switch(MSC_Handle->hbot.cmd_state)
+ {
+ case BOT_CMD_SEND:
+
+ /*Prepare the CBW and relevent field*/
+ MSC_Handle->hbot.cbw.field.DataTransferLength = DATA_LEN_MODE_TEST_UNIT_READY;
+ MSC_Handle->hbot.cbw.field.Flags = USB_EP_DIR_OUT;
+ MSC_Handle->hbot.cbw.field.CBLength = CBW_LENGTH;
+
+ USBH_memset(MSC_Handle->hbot.cbw.field.CB, 0, CBW_CB_LENGTH);
+ MSC_Handle->hbot.cbw.field.CB[0] = OPCODE_TEST_UNIT_READY;
+
+ MSC_Handle->hbot.state = BOT_SEND_CBW;
+ MSC_Handle->hbot.cmd_state = BOT_CMD_WAIT;
+ error = USBH_BUSY;
+ break;
+
+ case BOT_CMD_WAIT:
+ error = USBH_MSC_BOT_Process(phost, lun);
+ break;
+
+ default:
+ break;
+ }
+
+ return error;
+}
+
+/**
+ * @brief USBH_MSC_SCSI_ReadCapacity
+ * Issue Read Capacity command.
+ * @param phost: Host handle
+ * @param lun: Logical Unit Number
+ * @param capacity: pointer to the capacity structure
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_MSC_SCSI_ReadCapacity (USBH_HandleTypeDef *phost,
+ uint8_t lun,
+ SCSI_CapacityTypeDef *capacity)
+{
+ USBH_StatusTypeDef error = USBH_BUSY ;
+ MSC_HandleTypeDef *MSC_Handle = phost->pActiveClass->pData;
+
+ switch(MSC_Handle->hbot.cmd_state)
+ {
+ case BOT_CMD_SEND:
+
+ /*Prepare the CBW and relevent field*/
+ MSC_Handle->hbot.cbw.field.DataTransferLength = DATA_LEN_READ_CAPACITY10;
+ MSC_Handle->hbot.cbw.field.Flags = USB_EP_DIR_IN;
+ MSC_Handle->hbot.cbw.field.CBLength = CBW_LENGTH;
+
+ USBH_memset(MSC_Handle->hbot.cbw.field.CB, 0, CBW_CB_LENGTH);
+ MSC_Handle->hbot.cbw.field.CB[0] = OPCODE_READ_CAPACITY10;
+
+ MSC_Handle->hbot.state = BOT_SEND_CBW;
+
+ MSC_Handle->hbot.cmd_state = BOT_CMD_WAIT;
+ MSC_Handle->hbot.pbuf = (uint8_t *)MSC_Handle->hbot.data;
+ error = USBH_BUSY;
+ break;
+
+ case BOT_CMD_WAIT:
+
+ error = USBH_MSC_BOT_Process(phost, lun);
+
+ if(error == USBH_OK)
+ {
+ /*assign the capacity*/
+ capacity->block_nbr = MSC_Handle->hbot.pbuf[3] | (MSC_Handle->hbot.pbuf[2] << 8) |\
+ (MSC_Handle->hbot.pbuf[1] << 16) | (MSC_Handle->hbot.pbuf[0] << 24);
+
+ /*assign the page length*/
+ capacity->block_size = MSC_Handle->hbot.pbuf[7] | (MSC_Handle->hbot.pbuf[6] << 8);
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return error;
+}
+
+/**
+ * @brief USBH_MSC_SCSI_Inquiry
+ * Issue Inquiry command.
+ * @param phost: Host handle
+ * @param lun: Logical Unit Number
+ * @param capacity: pointer to the inquiry structure
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_MSC_SCSI_Inquiry (USBH_HandleTypeDef *phost,
+ uint8_t lun,
+ SCSI_StdInquiryDataTypeDef *inquiry)
+{
+ USBH_StatusTypeDef error = USBH_FAIL ;
+ MSC_HandleTypeDef *MSC_Handle = phost->pActiveClass->pData;
+ switch(MSC_Handle->hbot.cmd_state)
+ {
+ case BOT_CMD_SEND:
+
+ /*Prepare the CBW and relevent field*/
+ MSC_Handle->hbot.cbw.field.DataTransferLength = DATA_LEN_INQUIRY;
+ MSC_Handle->hbot.cbw.field.Flags = USB_EP_DIR_IN;
+ MSC_Handle->hbot.cbw.field.CBLength = CBW_LENGTH;
+
+ USBH_memset(MSC_Handle->hbot.cbw.field.CB, 0, CBW_LENGTH);
+ MSC_Handle->hbot.cbw.field.CB[0] = OPCODE_INQUIRY;
+ MSC_Handle->hbot.cbw.field.CB[1] = (lun << 5);
+ MSC_Handle->hbot.cbw.field.CB[2] = 0;
+ MSC_Handle->hbot.cbw.field.CB[3] = 0;
+ MSC_Handle->hbot.cbw.field.CB[4] = 0x24;
+ MSC_Handle->hbot.cbw.field.CB[5] = 0;
+
+ MSC_Handle->hbot.state = BOT_SEND_CBW;
+
+ MSC_Handle->hbot.cmd_state = BOT_CMD_WAIT;
+ MSC_Handle->hbot.pbuf = (uint8_t *)MSC_Handle->hbot.data;
+ error = USBH_BUSY;
+ break;
+
+ case BOT_CMD_WAIT:
+
+ error = USBH_MSC_BOT_Process(phost, lun);
+
+ if(error == USBH_OK)
+ {
+ USBH_memset(inquiry, 0, sizeof(SCSI_StdInquiryDataTypeDef));
+ /*assign Inquiry Data */
+ inquiry->DeviceType = MSC_Handle->hbot.pbuf[0] & 0x1F;
+ inquiry->PeripheralQualifier = MSC_Handle->hbot.pbuf[0] >> 5;
+ inquiry->RemovableMedia = (MSC_Handle->hbot.pbuf[1] & 0x80)== 0x80;
+ USBH_memcpy (inquiry->vendor_id, &MSC_Handle->hbot.pbuf[8], 8);
+ USBH_memcpy (inquiry->product_id, &MSC_Handle->hbot.pbuf[16], 16);
+ USBH_memcpy (inquiry->revision_id, &MSC_Handle->hbot.pbuf[32], 4);
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return error;
+}
+
+/**
+ * @brief USBH_MSC_SCSI_RequestSense
+ * Issue RequestSense command.
+ * @param phost: Host handle
+ * @param lun: Logical Unit Number
+ * @param capacity: pointer to the sense data structure
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_MSC_SCSI_RequestSense (USBH_HandleTypeDef *phost,
+ uint8_t lun,
+ SCSI_SenseTypeDef *sense_data)
+{
+ USBH_StatusTypeDef error = USBH_FAIL ;
+ MSC_HandleTypeDef *MSC_Handle = phost->pActiveClass->pData;
+
+ switch(MSC_Handle->hbot.cmd_state)
+ {
+ case BOT_CMD_SEND:
+
+ /*Prepare the CBW and relevent field*/
+ MSC_Handle->hbot.cbw.field.DataTransferLength = DATA_LEN_REQUEST_SENSE;
+ MSC_Handle->hbot.cbw.field.Flags = USB_EP_DIR_IN;
+ MSC_Handle->hbot.cbw.field.CBLength = CBW_LENGTH;
+
+ USBH_memset(MSC_Handle->hbot.cbw.field.CB, 0, CBW_CB_LENGTH);
+ MSC_Handle->hbot.cbw.field.CB[0] = OPCODE_REQUEST_SENSE;
+ MSC_Handle->hbot.cbw.field.CB[1] = (lun << 5);
+ MSC_Handle->hbot.cbw.field.CB[2] = 0;
+ MSC_Handle->hbot.cbw.field.CB[3] = 0;
+ MSC_Handle->hbot.cbw.field.CB[4] = DATA_LEN_REQUEST_SENSE;
+ MSC_Handle->hbot.cbw.field.CB[5] = 0;
+
+ MSC_Handle->hbot.state = BOT_SEND_CBW;
+ MSC_Handle->hbot.cmd_state = BOT_CMD_WAIT;
+ MSC_Handle->hbot.pbuf = (uint8_t *)MSC_Handle->hbot.data;
+ error = USBH_BUSY;
+ break;
+
+ case BOT_CMD_WAIT:
+
+ error = USBH_MSC_BOT_Process(phost, lun);
+
+ if(error == USBH_OK)
+ {
+ sense_data->key = MSC_Handle->hbot.pbuf[2] & 0x0F;
+ sense_data->asc = MSC_Handle->hbot.pbuf[12];
+ sense_data->ascq = MSC_Handle->hbot.pbuf[13];
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return error;
+}
+
+/**
+ * @brief USBH_MSC_SCSI_Write
+ * Issue write10 command.
+ * @param phost: Host handle
+ * @param lun: Logical Unit Number
+ * @param address: sector address
+ * @param pbuf: pointer to data
+ * @param length: number of sector to write
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_MSC_SCSI_Write(USBH_HandleTypeDef *phost,
+ uint8_t lun,
+ uint32_t address,
+ uint8_t *pbuf,
+ uint32_t length)
+{
+ USBH_StatusTypeDef error = USBH_FAIL ;
+
+ MSC_HandleTypeDef *MSC_Handle = phost->pActiveClass->pData;
+
+ switch(MSC_Handle->hbot.cmd_state)
+ {
+ case BOT_CMD_SEND:
+
+ /*Prepare the CBW and relevent field*/
+ MSC_Handle->hbot.cbw.field.DataTransferLength = length * 512;
+ MSC_Handle->hbot.cbw.field.Flags = USB_EP_DIR_OUT;
+ MSC_Handle->hbot.cbw.field.CBLength = CBW_LENGTH;
+
+ USBH_memset(MSC_Handle->hbot.cbw.field.CB, 0, CBW_CB_LENGTH);
+ MSC_Handle->hbot.cbw.field.CB[0] = OPCODE_WRITE10;
+
+ /*logical block address*/
+ MSC_Handle->hbot.cbw.field.CB[2] = (((uint8_t*)&address)[3]);
+ MSC_Handle->hbot.cbw.field.CB[3] = (((uint8_t*)&address)[2]);
+ MSC_Handle->hbot.cbw.field.CB[4] = (((uint8_t*)&address)[1]);
+ MSC_Handle->hbot.cbw.field.CB[5] = (((uint8_t*)&address)[0]);
+
+
+ /*Tranfer length */
+ MSC_Handle->hbot.cbw.field.CB[7] = (((uint8_t *)&length)[1]) ;
+ MSC_Handle->hbot.cbw.field.CB[8] = (((uint8_t *)&length)[0]) ;
+
+
+ MSC_Handle->hbot.state = BOT_SEND_CBW;
+ MSC_Handle->hbot.cmd_state = BOT_CMD_WAIT;
+ MSC_Handle->hbot.pbuf = pbuf;
+ error = USBH_BUSY;
+ break;
+
+ case BOT_CMD_WAIT:
+ error = USBH_MSC_BOT_Process(phost, lun);
+ break;
+
+ default:
+ break;
+ }
+
+ return error;
+}
+
+/**
+ * @brief USBH_MSC_SCSI_Read
+ * Issue Read10 command.
+ * @param phost: Host handle
+ * @param lun: Logical Unit Number
+ * @param address: sector address
+ * @param pbuf: pointer to data
+ * @param length: number of sector to read
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_MSC_SCSI_Read(USBH_HandleTypeDef *phost,
+ uint8_t lun,
+ uint32_t address,
+ uint8_t *pbuf,
+ uint32_t length)
+{
+ USBH_StatusTypeDef error = USBH_FAIL ;
+ MSC_HandleTypeDef *MSC_Handle = phost->pActiveClass->pData;
+
+ switch(MSC_Handle->hbot.cmd_state)
+ {
+ case BOT_CMD_SEND:
+
+ /*Prepare the CBW and relevent field*/
+ MSC_Handle->hbot.cbw.field.DataTransferLength = length * 512;
+ MSC_Handle->hbot.cbw.field.Flags = USB_EP_DIR_IN;
+ MSC_Handle->hbot.cbw.field.CBLength = CBW_LENGTH;
+
+ USBH_memset(MSC_Handle->hbot.cbw.field.CB, 0, CBW_CB_LENGTH);
+ MSC_Handle->hbot.cbw.field.CB[0] = OPCODE_READ10;
+
+ /*logical block address*/
+ MSC_Handle->hbot.cbw.field.CB[2] = (((uint8_t*)&address)[3]);
+ MSC_Handle->hbot.cbw.field.CB[3] = (((uint8_t*)&address)[2]);
+ MSC_Handle->hbot.cbw.field.CB[4] = (((uint8_t*)&address)[1]);
+ MSC_Handle->hbot.cbw.field.CB[5] = (((uint8_t*)&address)[0]);
+
+
+ /*Tranfer length */
+ MSC_Handle->hbot.cbw.field.CB[7] = (((uint8_t *)&length)[1]) ;
+ MSC_Handle->hbot.cbw.field.CB[8] = (((uint8_t *)&length)[0]) ;
+
+
+ MSC_Handle->hbot.state = BOT_SEND_CBW;
+ MSC_Handle->hbot.cmd_state = BOT_CMD_WAIT;
+ MSC_Handle->hbot.pbuf = pbuf;
+ error = USBH_BUSY;
+ break;
+
+ case BOT_CMD_WAIT:
+ error = USBH_MSC_BOT_Process(phost, lun);
+ break;
+
+ default:
+ break;
+ }
+
+ return error;
+}
+
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
+
+
+
diff --git a/ports/stm32/usbhost/Class/MTP/Inc/usbh_mtp.h b/ports/stm32/usbhost/Class/MTP/Inc/usbh_mtp.h
new file mode 100644
index 000000000..704a410fd
--- /dev/null
+++ b/ports/stm32/usbhost/Class/MTP/Inc/usbh_mtp.h
@@ -0,0 +1,263 @@
+/**
+ ******************************************************************************
+ * @file usbh_mtp.h
+ * @author MCD Application Team
+ * @version V3.0.0
+ * @date 18-February-2014
+ * @brief This file contains all the prototypes for the usbh_mtp.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 ----------------------------------------------*/
+#ifndef __USBH_MTP_CORE_H
+#define __USBH_MTP_CORE_H
+
+/* Includes ------------------------------------------------------------------*/
+#include "usbh_mtp_ptp.h"
+#include "usbh_core.h"
+
+
+/** @addtogroup USBH_LIB
+* @{
+*/
+
+/** @addtogroup USBH_CLASS
+* @{
+*/
+
+/** @addtogroup USBH_MTP_CLASS
+* @{
+*/
+
+/** @defgroup USBH_MTP_CORE
+* @brief This file is the Header file for USBH_MTP_CORE.c
+* @{
+*/
+
+
+
+
+/*Communication Class codes*/
+#define USB_MTP_CLASS 0x06 /* Still Image Class)*/
+#define MTP_MAX_STORAGE_UNITS_NBR PTP_MAX_STORAGE_UNITS_NBR
+
+/**
+ * @}
+ */
+
+/** @defgroup USBH_MTP_CORE_Exported_Types
+* @{
+*/
+typedef enum
+{
+ MTP_IDLE = 0,
+ MTP_GETDEVICEINFO ,
+ MTP_OPENSESSION ,
+ MTP_CLOSESESSION ,
+ MTP_GETSTORAGEIDS ,
+ MTP_GETSTORAGEINFO ,
+}
+MTP_StateTypeDef;
+
+
+typedef enum
+{
+ MTP_EVENTS_INIT = 0,
+ MTP_EVENTS_GETDATA ,
+}
+MTP_EventsStateTypeDef;
+
+
+typedef struct
+{
+ MTP_EventsStateTypeDef state;
+ uint32_t timer;
+ uint16_t poll;
+ PTP_EventContainerTypedef container;
+}
+MTP_EventHandleTypedef;
+
+typedef struct
+{
+
+ uint32_t CurrentStorageId;
+ uint32_t ObjectFormatCode;
+ uint32_t CurrentObjectHandler;
+ uint8_t ObjectHandlerNbr;
+ uint32_t Objdepth;
+}
+MTP_ParamsTypedef;
+
+
+typedef struct
+{
+ PTP_DeviceInfoTypedef devinfo;
+ PTP_StorageIDsTypedef storids;
+ PTP_StorageInfoTypedef storinfo[MTP_MAX_STORAGE_UNITS_NBR];
+ PTP_ObjectHandlesTypedef Handles;
+}
+MTP_InfoTypedef;
+
+/* Structure for MTP process */
+typedef struct _MTP_Process
+{
+ MTP_InfoTypedef info;
+ MTP_ParamsTypedef params;
+
+ uint8_t DataInPipe;
+ uint8_t DataOutPipe;
+ uint8_t NotificationPipe;
+
+ uint8_t DataOutEp;
+ uint8_t DataInEp;
+ uint8_t NotificationEp;
+
+ uint16_t DataOutEpSize;
+ uint16_t DataInEpSize;
+ uint16_t NotificationEpSize;
+ MTP_StateTypeDef state;
+ MTP_EventHandleTypedef events;
+ PTP_HandleTypeDef ptp;
+ uint32_t current_storage_unit;
+ uint32_t is_ready;
+}
+MTP_HandleTypeDef;
+
+#define MTP_StorageInfoTypedef PTP_StorageInfoTypedef
+#define MTP_ObjectHandlesTypedef PTP_ObjectHandlesTypedef
+#define MTP_ObjectInfoTypedef PTP_ObjectInfoTypedef
+/**
+* @}
+*/
+
+/** @defgroup USBH_MTP_CORE_Exported_Defines
+* @{
+*/
+
+/**
+* @}
+*/
+
+/** @defgroup USBH_MTP_CORE_Exported_Macros
+* @{
+*/
+/**
+* @}
+*/
+
+/** @defgroup USBH_MTP_CORE_Exported_Variables
+* @{
+*/
+extern USBH_ClassTypeDef MTP_Class;
+#define USBH_MTP_CLASS &MTP_Class
+
+/**
+* @}
+*/
+
+/** @defgroup USBH_MTP_CORE_Exported_FunctionsPrototype
+* @{
+*/
+uint8_t USBH_MTP_IsReady (USBH_HandleTypeDef *phost);
+USBH_StatusTypeDef USBH_MTP_SelectStorage (USBH_HandleTypeDef *phost, uint8_t storage_idx);
+USBH_StatusTypeDef USBH_MTP_GetNumStorage (USBH_HandleTypeDef *phost, uint8_t *storage_num);
+USBH_StatusTypeDef USBH_MTP_GetNumObjects (USBH_HandleTypeDef *phost,
+ uint32_t storage_id,
+ uint32_t objectformatcode,
+ uint32_t associationOH,
+ uint32_t* numobs);
+USBH_StatusTypeDef USBH_MTP_GetStorageInfo (USBH_HandleTypeDef *phost,
+ uint8_t storage_idx,
+ MTP_StorageInfoTypedef *info);
+
+USBH_StatusTypeDef USBH_MTP_GetObjectHandles (USBH_HandleTypeDef *phost,
+ uint32_t storage_id,
+ uint32_t objectformatcode,
+ uint32_t associationOH,
+ PTP_ObjectHandlesTypedef* objecthandles);
+
+USBH_StatusTypeDef USBH_MTP_GetObjectInfo (USBH_HandleTypeDef *phost,
+ uint32_t handle,
+ PTP_ObjectInfoTypedef* objectinfo);
+
+USBH_StatusTypeDef USBH_MTP_DeleteObject (USBH_HandleTypeDef *phost,
+ uint32_t handle,
+ uint32_t objectformatcode);
+
+USBH_StatusTypeDef USBH_MTP_GetObject (USBH_HandleTypeDef *phost,
+ uint32_t handle,
+ uint8_t *object);
+
+USBH_StatusTypeDef USBH_MTP_GetPartialObject(USBH_HandleTypeDef *phost,
+ uint32_t handle,
+ uint32_t offset,
+ uint32_t maxbytes,
+ uint8_t *object,
+ uint32_t *len);
+
+USBH_StatusTypeDef USBH_MTP_GetObjectPropsSupported (USBH_HandleTypeDef *phost,
+ uint16_t ofc,
+ uint32_t *propnum,
+ uint16_t *props);
+
+USBH_StatusTypeDef USBH_MTP_GetObjectPropDesc (USBH_HandleTypeDef *phost,
+ uint16_t opc,
+ uint16_t ofc,
+ PTP_ObjectPropDescTypeDef *opd);
+
+USBH_StatusTypeDef USBH_MTP_GetObjectPropList (USBH_HandleTypeDef *phost,
+ uint32_t handle,
+ MTP_PropertiesTypedef *pprops,
+ uint32_t *nrofprops);
+
+USBH_StatusTypeDef USBH_MTP_SendObject (USBH_HandleTypeDef *phost,
+ uint32_t handle,
+ uint8_t *object,
+ uint32_t size);
+
+USBH_StatusTypeDef USBH_MTP_GetDevicePropDesc (USBH_HandleTypeDef *phost,
+ uint16_t propcode,
+ PTP_DevicePropDescTypdef* devicepropertydesc);
+
+void USBH_MTP_EventsCallback(USBH_HandleTypeDef *phost, uint32_t event, uint32_t param);
+/**
+* @}
+*/
+
+
+#endif /* __USBH_MTP_CORE_H */
+
+/**
+* @}
+*/
+
+/**
+* @}
+*/
+
+/**
+* @}
+*/
+
+/**
+* @}
+*/
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
+
diff --git a/ports/stm32/usbhost/Class/MTP/Inc/usbh_mtp_ptp.h b/ports/stm32/usbhost/Class/MTP/Inc/usbh_mtp_ptp.h
new file mode 100644
index 000000000..3fbddd87b
--- /dev/null
+++ b/ports/stm32/usbhost/Class/MTP/Inc/usbh_mtp_ptp.h
@@ -0,0 +1,1038 @@
+/**
+ ******************************************************************************
+ * @file usbh_mtp_ptp.h
+ * @author MCD Application Team
+ * @version V3.0.0
+ * @date 18-February-2014
+ * @brief Header file for usbh_mtp_ptp.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 ----------------------------------------------*/
+#ifndef __USBH_MTP_PTP_H__
+#define __USBH_MTP_PTP_H__
+
+/* Includes ------------------------------------------------------------------*/
+#include "usbh_core.h"
+
+/** @addtogroup USBH_LIB
+ * @{
+ */
+
+/** @addtogroup USBH_CLASS
+ * @{
+ */
+
+/** @addtogroup USBH_MTP_PTP_CLASS
+ * @{
+ */
+
+/** @defgroup USBH_MTP_PTP
+ * @brief This file is the Header file for usbh_mtp_ptp.c
+ * @{
+ */
+
+
+/* Operation Codes */
+
+/* PTP v1.0 operation codes */
+#define PTP_OC_Undefined 0x1000
+#define PTP_OC_GetDeviceInfo 0x1001
+#define PTP_OC_OpenSession 0x1002
+#define PTP_OC_CloseSession 0x1003
+#define PTP_OC_GetStorageIDs 0x1004
+#define PTP_OC_GetStorageInfo 0x1005
+#define PTP_OC_GetNumObjects 0x1006
+#define PTP_OC_GetObjectHandles 0x1007
+#define PTP_OC_GetObjectInfo 0x1008
+#define PTP_OC_GetObject 0x1009
+#define PTP_OC_GetThumb 0x100A
+#define PTP_OC_DeleteObject 0x100B
+#define PTP_OC_SendObjectInfo 0x100C
+#define PTP_OC_SendObject 0x100D
+#define PTP_OC_InitiateCapture 0x100E
+#define PTP_OC_FormatStore 0x100F
+#define PTP_OC_ResetDevice 0x1010
+#define PTP_OC_SelfTest 0x1011
+#define PTP_OC_SetObjectProtection 0x1012
+#define PTP_OC_PowerDown 0x1013
+#define PTP_OC_GetDevicePropDesc 0x1014
+#define PTP_OC_GetDevicePropValue 0x1015
+#define PTP_OC_SetDevicePropValue 0x1016
+#define PTP_OC_ResetDevicePropValue 0x1017
+#define PTP_OC_TerminateOpenCapture 0x1018
+#define PTP_OC_MoveObject 0x1019
+#define PTP_OC_CopyObject 0x101A
+#define PTP_OC_GetPartialObject 0x101B
+#define PTP_OC_InitiateOpenCapture 0x101C
+
+/* PTP v1.1 operation codes */
+#define PTP_OC_StartEnumHandles 0x101D
+#define PTP_OC_EnumHandles 0x101E
+#define PTP_OC_StopEnumHandles 0x101F
+#define PTP_OC_GetVendorExtensionMaps 0x1020
+#define PTP_OC_GetVendorDeviceInfo 0x1021
+#define PTP_OC_GetResizedImageObject 0x1022
+#define PTP_OC_GetFilesystemManifest 0x1023
+#define PTP_OC_GetStreamInfo 0x1024
+#define PTP_OC_GetStream 0x1025
+
+ /* Microsoft / MTP extension codes */
+#define PTP_OC_GetObjectPropsSupported 0x9801
+#define PTP_OC_GetObjectPropDesc 0x9802
+#define PTP_OC_GetObjectPropValue 0x9803
+#define PTP_OC_SetObjectPropValue 0x9804
+#define PTP_OC_GetObjPropList 0x9805
+#define PTP_OC_SetObjPropList 0x9806
+#define PTP_OC_GetInterdependendPropdesc 0x9807
+#define PTP_OC_SendObjectPropList 0x9808
+#define PTP_OC_GetObjectReferences 0x9810
+#define PTP_OC_SetObjectReferences 0x9811
+#define PTP_OC_UpdateDeviceFirmware 0x9812
+#define PTP_OC_Skip 0x9820
+
+
+/* Response Codes */
+
+/* PTP v1.0 response codes */
+#define PTP_RC_Undefined 0x2000
+#define PTP_RC_OK 0x2001
+#define PTP_RC_GeneralError 0x2002
+#define PTP_RC_SessionNotOpen 0x2003
+#define PTP_RC_InvalidTransactionID 0x2004
+#define PTP_RC_OperationNotSupported 0x2005
+#define PTP_RC_ParameterNotSupported 0x2006
+#define PTP_RC_IncompleteTransfer 0x2007
+#define PTP_RC_InvalidStorageId 0x2008
+#define PTP_RC_InvalidObjectHandle 0x2009
+#define PTP_RC_DevicePropNotSupported 0x200A
+#define PTP_RC_InvalidObjectFormatCode 0x200B
+#define PTP_RC_StoreFull 0x200C
+#define PTP_RC_ObjectWriteProtected 0x200D
+#define PTP_RC_StoreReadOnly 0x200E
+#define PTP_RC_AccessDenied 0x200F
+#define PTP_RC_NoThumbnailPresent 0x2010
+#define PTP_RC_SelfTestFailed 0x2011
+#define PTP_RC_PartialDeletion 0x2012
+#define PTP_RC_StoreNotAvailable 0x2013
+#define PTP_RC_SpecificationByFormatUnsupported 0x2014
+#define PTP_RC_NoValidObjectInfo 0x2015
+#define PTP_RC_InvalidCodeFormat 0x2016
+#define PTP_RC_UnknownVendorCode 0x2017
+#define PTP_RC_CaptureAlreadyTerminated 0x2018
+#define PTP_RC_DeviceBusy 0x2019
+#define PTP_RC_InvalidParentObject 0x201A
+#define PTP_RC_InvalidDevicePropFormat 0x201B
+#define PTP_RC_InvalidDevicePropValue 0x201C
+#define PTP_RC_InvalidParameter 0x201D
+#define PTP_RC_SessionAlreadyOpened 0x201E
+#define PTP_RC_TransactionCanceled 0x201F
+#define PTP_RC_SpecificationOfDestinationUnsupported 0x2020
+/* PTP v1.1 response codes */
+#define PTP_RC_InvalidEnumHandle 0x2021
+#define PTP_RC_NoStreamEnabled 0x2022
+#define PTP_RC_InvalidDataSet 0x2023
+
+/* USB container types */
+
+#define PTP_USB_CONTAINER_UNDEFINED 0x0000
+#define PTP_USB_CONTAINER_COMMAND 0x0001
+#define PTP_USB_CONTAINER_DATA 0x0002
+#define PTP_USB_CONTAINER_RESPONSE 0x0003
+#define PTP_USB_CONTAINER_EVENT 0x0004
+
+/* PTP/IP definitions */
+#define PTPIP_INIT_COMMAND_REQUEST 1
+#define PTPIP_INIT_COMMAND_ACK 2
+#define PTPIP_INIT_EVENT_REQUEST 3
+#define PTPIP_INIT_EVENT_ACK 4
+#define PTPIP_INIT_FAIL 5
+#define PTPIP_CMD_REQUEST 6
+#define PTPIP_CMD_RESPONSE 7
+#define PTPIP_EVENT 8
+#define PTPIP_START_DATA_PACKET 9
+#define PTPIP_DATA_PACKET 10
+#define PTPIP_CANCEL_TRANSACTION 11
+#define PTPIP_END_DATA_PACKET 12
+#define PTPIP_PING 13
+#define PTPIP_PONG 14
+
+/* Transaction data phase description */
+#define PTP_DP_NODATA 0x0000 /* no data phase */
+#define PTP_DP_SENDDATA 0x0001 /* sending data */
+#define PTP_DP_GETDATA 0x0002 /* receiving data */
+#define PTP_DP_DATA_MASK 0x00ff /* data phase mask */
+
+/** @defgroup USBH_MTP_PTP_Exported_Types
+ * @{
+ */
+
+typedef enum
+{
+ PTP_REQ_IDLE = 0,
+ PTP_REQ_SEND = 1,
+ PTP_REQ_WAIT,
+ PTP_REQ_ERROR,
+}
+PTP_RequestStateTypeDef;
+
+typedef enum
+{
+ PTP_IDLE = 0,
+ PTP_OP_REQUEST_STATE,
+ PTP_OP_REQUEST_WAIT_STATE,
+ PTP_DATA_OUT_PHASE_STATE,
+ PTP_DATA_OUT_PHASE_WAIT_STATE,
+ PTP_DATA_IN_PHASE_STATE,
+ PTP_DATA_IN_PHASE_WAIT_STATE,
+ PTP_RESPONSE_STATE,
+ PTP_RESPONSE_WAIT_STATE,
+ PTP_ERROR,
+}
+PTP_ProcessStateTypeDef;
+
+/* PTP request/response/event general PTP container (transport independent) */
+typedef struct
+{
+ uint16_t Code;
+ uint32_t SessionID;
+ uint32_t Transaction_ID;
+ /* params may be of any type of size less or equal to uint32_t */
+ uint32_t Param1;
+ uint32_t Param2;
+ uint32_t Param3;
+ /* events can only have three parameters */
+ uint32_t Param4;
+ uint32_t Param5;
+ /* the number of meaningfull parameters */
+ uint8_t Nparam;
+}
+PTP_ContainerTypedef;
+
+#define PTP_USB_BULK_HS_MAX_PACKET_LEN_WRITE 1024
+#define PTP_USB_BULK_HS_MAX_PACKET_LEN_READ 1024
+#define PTP_USB_BULK_HDR_LEN (2*sizeof(uint32_t)+2*sizeof(uint16_t))
+#define PTP_USB_BULK_PAYLOAD_LEN_WRITE (PTP_USB_BULK_HS_MAX_PACKET_LEN_WRITE-PTP_USB_BULK_HDR_LEN)
+#define PTP_USB_BULK_PAYLOAD_LEN_READ (PTP_USB_BULK_HS_MAX_PACKET_LEN_READ-PTP_USB_BULK_HDR_LEN)
+#define PTP_USB_BULK_REQ_LEN (PTP_USB_BULK_HDR_LEN+5*sizeof(uint32_t))
+#define PTP_USB_BULK_REQ_RESP_MAX_LEN 63
+
+typedef struct
+{
+ uint32_t length;
+ uint16_t type;
+ uint16_t code;
+ uint32_t trans_id;
+ uint32_t param1;
+ uint32_t param2;
+ uint32_t param3;
+ uint32_t param4;
+ uint32_t param5;
+}
+PTP_RespContainerTypedef;
+
+
+typedef struct
+{
+ uint32_t length;
+ uint16_t type;
+ uint16_t code;
+ uint32_t trans_id;
+ uint32_t param1;
+ uint32_t param2;
+ uint32_t param3;
+ uint32_t param4;
+ uint32_t param5;
+}
+PTP_OpContainerTypedef;
+
+typedef struct
+{
+ uint32_t length;
+ uint16_t type;
+ uint16_t code;
+ uint32_t trans_id;
+ union {
+ struct {
+ uint32_t param1;
+ uint32_t param2;
+ uint32_t param3;
+ uint32_t param4;
+ uint32_t param5;
+ } params;
+ uint8_t data[PTP_USB_BULK_PAYLOAD_LEN_READ];
+ }payload;
+}
+PTP_DataContainerTypedef;
+
+/* PTP USB Asynchronous Event Interrupt Data Format */
+typedef struct
+{
+ uint32_t length;
+ uint16_t type;
+ uint16_t code;
+ uint32_t trans_id;
+ uint32_t param1;
+ uint32_t param2;
+ uint32_t param3;
+}
+PTP_EventContainerTypedef;
+
+/* Structure for PTP Transport process */
+typedef struct
+{
+ PTP_ProcessStateTypeDef state;
+ PTP_RequestStateTypeDef req_state;
+ PTP_OpContainerTypedef op_container;
+ PTP_DataContainerTypedef data_container;
+ PTP_RespContainerTypedef resp_container;
+
+ /* ptp transaction ID */
+ uint32_t transaction_id;
+
+ /* ptp session ID */
+ uint32_t session_id;
+
+ /* device flags */
+ uint32_t flags;
+
+ /****** PTP transfer control *******/
+
+ /* Data pointer */
+ uint8_t *data_ptr;
+
+ /* Data length */
+ int32_t data_length;
+
+ /* Data length */
+ uint32_t data_packet;
+
+ /* Data length */
+ uint32_t iteration;
+
+ /* Packet Index */
+ uint32_t data_packet_counter;
+
+ /****** Object transfer control *******/
+
+ /* object pointer */
+ uint8_t *object_ptr;
+
+}
+PTP_HandleTypeDef;
+
+/* DeviceInfo data offset */
+#define PTP_di_StandardVersion 0
+#define PTP_di_VendorExtensionID 2
+#define PTP_di_VendorExtensionVersion 6
+#define PTP_di_VendorExtensionDesc 8
+#define PTP_di_FunctionalMode 8
+#define PTP_di_OperationsSupported 10
+
+/* Max info items size */
+#define PTP_SUPPORTED_OPERATIONS_NBR 100
+#define PTP_SUPPORTED_EVENTS_NBR 100
+#define PTP_SUPPORTED_PROPRIETIES_NBR 100
+#define PTP_CAPTURE_FORMATS_NBR 100
+#define PTP_IMAGE_FORMATS_NBR 100
+#define PTP_MAX_STR_SIZE 255
+/* PTP device info structure */
+typedef struct
+{
+ uint16_t StandardVersion;
+ uint32_t VendorExtensionID;
+ uint16_t VendorExtensionVersion;
+ uint8_t VendorExtensionDesc[PTP_MAX_STR_SIZE];
+ uint16_t FunctionalMode;
+ uint32_t OperationsSupported_len;
+ uint16_t OperationsSupported[PTP_SUPPORTED_OPERATIONS_NBR];
+ uint32_t EventsSupported_len;
+ uint16_t EventsSupported[PTP_SUPPORTED_EVENTS_NBR];
+ uint32_t DevicePropertiesSupported_len;
+ uint16_t DevicePropertiesSupported[PTP_SUPPORTED_PROPRIETIES_NBR];
+ uint32_t CaptureFormats_len;
+ uint16_t CaptureFormats[PTP_CAPTURE_FORMATS_NBR];
+ uint32_t ImageFormats_len;
+ uint16_t ImageFormats[PTP_IMAGE_FORMATS_NBR];
+ uint8_t Manufacturer[PTP_MAX_STR_SIZE];
+ uint8_t Model[PTP_MAX_STR_SIZE];
+ uint8_t DeviceVersion[PTP_MAX_STR_SIZE];
+ uint8_t SerialNumber[PTP_MAX_STR_SIZE];
+}
+PTP_DeviceInfoTypedef;
+
+#define PTP_MAX_STORAGE_UNITS_NBR 5
+/* PTP storageIDs structute (returned by GetStorageIDs) */
+typedef struct
+{
+ uint32_t n;
+ uint32_t Storage [PTP_MAX_STORAGE_UNITS_NBR];
+}
+PTP_StorageIDsTypedef;
+
+/* PTP StorageInfo structure (returned by GetStorageInfo) */
+
+#define PTP_si_StorageType 0
+#define PTP_si_FilesystemType 2
+#define PTP_si_AccessCapability 4
+#define PTP_si_MaxCapability 6
+#define PTP_si_FreeSpaceInBytes 14
+#define PTP_si_FreeSpaceInImages 22
+#define PTP_si_StorageDescription 26
+
+
+/* PTP Storage Types */
+
+#define PTP_ST_Undefined 0x0000
+#define PTP_ST_FixedROM 0x0001
+#define PTP_ST_RemovableROM 0x0002
+#define PTP_ST_FixedRAM 0x0003
+#define PTP_ST_RemovableRAM 0x0004
+
+/* PTP FilesystemType Values */
+
+#define PTP_FST_Undefined 0x0000
+#define PTP_FST_GenericFlat 0x0001
+#define PTP_FST_GenericHierarchical 0x0002
+#define PTP_FST_DCF 0x0003
+
+/* PTP StorageInfo AccessCapability Values */
+
+#define PTP_AC_ReadWrite 0x0000
+#define PTP_AC_ReadOnly 0x0001
+#define PTP_AC_ReadOnly_with_Object_Deletion 0x0002
+
+typedef struct
+{
+ uint16_t StorageType;
+ uint16_t FilesystemType;
+ uint16_t AccessCapability;
+ uint64_t MaxCapability;
+ uint64_t FreeSpaceInBytes;
+ uint32_t FreeSpaceInImages;
+ uint8_t StorageDescription[PTP_MAX_STR_SIZE];
+ uint8_t VolumeLabel[PTP_MAX_STR_SIZE];
+}
+PTP_StorageInfoTypedef;
+
+/* PTP Object Format Codes */
+
+/* ancillary formats */
+#define PTP_OFC_Undefined 0x3000
+#define PTP_OFC_Defined 0x3800
+#define PTP_OFC_Association 0x3001
+#define PTP_OFC_Script 0x3002
+#define PTP_OFC_Executable 0x3003
+#define PTP_OFC_Text 0x3004
+#define PTP_OFC_HTML 0x3005
+#define PTP_OFC_DPOF 0x3006
+#define PTP_OFC_AIFF 0x3007
+#define PTP_OFC_WAV 0x3008
+#define PTP_OFC_MP3 0x3009
+#define PTP_OFC_AVI 0x300A
+#define PTP_OFC_MPEG 0x300B
+#define PTP_OFC_ASF 0x300C
+#define PTP_OFC_QT 0x300D /* guessing */
+/* image formats */
+#define PTP_OFC_EXIF_JPEG 0x3801
+#define PTP_OFC_TIFF_EP 0x3802
+#define PTP_OFC_FlashPix 0x3803
+#define PTP_OFC_BMP 0x3804
+#define PTP_OFC_CIFF 0x3805
+#define PTP_OFC_Undefined_0x3806 0x3806
+#define PTP_OFC_GIF 0x3807
+#define PTP_OFC_JFIF 0x3808
+#define PTP_OFC_PCD 0x3809
+#define PTP_OFC_PICT 0x380A
+#define PTP_OFC_PNG 0x380B
+#define PTP_OFC_Undefined_0x380C 0x380C
+#define PTP_OFC_TIFF 0x380D
+#define PTP_OFC_TIFF_IT 0x380E
+#define PTP_OFC_JP2 0x380F
+#define PTP_OFC_JPX 0x3810
+/* ptp v1.1 has only DNG new */
+#define PTP_OFC_DNG 0x3811
+
+/* MTP extensions */
+#define PTP_OFC_MTP_MediaCard 0xb211
+#define PTP_OFC_MTP_MediaCardGroup 0xb212
+#define PTP_OFC_MTP_Encounter 0xb213
+#define PTP_OFC_MTP_EncounterBox 0xb214
+#define PTP_OFC_MTP_M4A 0xb215
+#define PTP_OFC_MTP_ZUNEUNDEFINED 0xb217 /* Unknown file type */
+#define PTP_OFC_MTP_Firmware 0xb802
+#define PTP_OFC_MTP_WindowsImageFormat 0xb881
+#define PTP_OFC_MTP_UndefinedAudio 0xb900
+#define PTP_OFC_MTP_WMA 0xb901
+#define PTP_OFC_MTP_OGG 0xb902
+#define PTP_OFC_MTP_AAC 0xb903
+#define PTP_OFC_MTP_AudibleCodec 0xb904
+#define PTP_OFC_MTP_FLAC 0xb906
+#define PTP_OFC_MTP_SamsungPlaylist 0xb909
+#define PTP_OFC_MTP_UndefinedVideo 0xb980
+#define PTP_OFC_MTP_WMV 0xb981
+#define PTP_OFC_MTP_MP4 0xb982
+#define PTP_OFC_MTP_MP2 0xb983
+#define PTP_OFC_MTP_3GP 0xb984
+#define PTP_OFC_MTP_UndefinedCollection 0xba00
+#define PTP_OFC_MTP_AbstractMultimediaAlbum 0xba01
+#define PTP_OFC_MTP_AbstractImageAlbum 0xba02
+#define PTP_OFC_MTP_AbstractAudioAlbum 0xba03
+#define PTP_OFC_MTP_AbstractVideoAlbum 0xba04
+#define PTP_OFC_MTP_AbstractAudioVideoPlaylist 0xba05
+#define PTP_OFC_MTP_AbstractContactGroup 0xba06
+#define PTP_OFC_MTP_AbstractMessageFolder 0xba07
+#define PTP_OFC_MTP_AbstractChapteredProduction 0xba08
+#define PTP_OFC_MTP_AbstractAudioPlaylist 0xba09
+#define PTP_OFC_MTP_AbstractVideoPlaylist 0xba0a
+#define PTP_OFC_MTP_AbstractMediacast 0xba0b
+#define PTP_OFC_MTP_WPLPlaylist 0xba10
+#define PTP_OFC_MTP_M3UPlaylist 0xba11
+#define PTP_OFC_MTP_MPLPlaylist 0xba12
+#define PTP_OFC_MTP_ASXPlaylist 0xba13
+#define PTP_OFC_MTP_PLSPlaylist 0xba14
+#define PTP_OFC_MTP_UndefinedDocument 0xba80
+#define PTP_OFC_MTP_AbstractDocument 0xba81
+#define PTP_OFC_MTP_XMLDocument 0xba82
+#define PTP_OFC_MTP_MSWordDocument 0xba83
+#define PTP_OFC_MTP_MHTCompiledHTMLDocument 0xba84
+#define PTP_OFC_MTP_MSExcelSpreadsheetXLS 0xba85
+#define PTP_OFC_MTP_MSPowerpointPresentationPPT 0xba86
+#define PTP_OFC_MTP_UndefinedMessage 0xbb00
+#define PTP_OFC_MTP_AbstractMessage 0xbb01
+#define PTP_OFC_MTP_UndefinedContact 0xbb80
+#define PTP_OFC_MTP_AbstractContact 0xbb81
+#define PTP_OFC_MTP_vCard2 0xbb82
+#define PTP_OFC_MTP_vCard3 0xbb83
+#define PTP_OFC_MTP_UndefinedCalendarItem 0xbe00
+#define PTP_OFC_MTP_AbstractCalendarItem 0xbe01
+#define PTP_OFC_MTP_vCalendar1 0xbe02
+#define PTP_OFC_MTP_vCalendar2 0xbe03
+#define PTP_OFC_MTP_UndefinedWindowsExecutable 0xbe80
+#define PTP_OFC_MTP_MediaCast 0xbe81
+#define PTP_OFC_MTP_Section 0xbe82
+
+/* MTP specific Object Properties */
+#define PTP_OPC_StorageID 0xDC01
+#define PTP_OPC_ObjectFormat 0xDC02
+#define PTP_OPC_ProtectionStatus 0xDC03
+#define PTP_OPC_ObjectSize 0xDC04
+#define PTP_OPC_AssociationType 0xDC05
+#define PTP_OPC_AssociationDesc 0xDC06
+#define PTP_OPC_ObjectFileName 0xDC07
+#define PTP_OPC_DateCreated 0xDC08
+#define PTP_OPC_DateModified 0xDC09
+#define PTP_OPC_Keywords 0xDC0A
+#define PTP_OPC_ParentObject 0xDC0B
+#define PTP_OPC_AllowedFolderContents 0xDC0C
+#define PTP_OPC_Hidden 0xDC0D
+#define PTP_OPC_SystemObject 0xDC0E
+#define PTP_OPC_PersistantUniqueObjectIdentifier 0xDC41
+#define PTP_OPC_SyncID 0xDC42
+#define PTP_OPC_PropertyBag 0xDC43
+#define PTP_OPC_Name 0xDC44
+#define PTP_OPC_CreatedBy 0xDC45
+#define PTP_OPC_Artist 0xDC46
+#define PTP_OPC_DateAuthored 0xDC47
+#define PTP_OPC_Description 0xDC48
+#define PTP_OPC_URLReference 0xDC49
+#define PTP_OPC_LanguageLocale 0xDC4A
+#define PTP_OPC_CopyrightInformation 0xDC4B
+#define PTP_OPC_Source 0xDC4C
+#define PTP_OPC_OriginLocation 0xDC4D
+#define PTP_OPC_DateAdded 0xDC4E
+#define PTP_OPC_NonConsumable 0xDC4F
+#define PTP_OPC_CorruptOrUnplayable 0xDC50
+#define PTP_OPC_ProducerSerialNumber 0xDC51
+#define PTP_OPC_RepresentativeSampleFormat 0xDC81
+#define PTP_OPC_RepresentativeSampleSize 0xDC82
+#define PTP_OPC_RepresentativeSampleHeight 0xDC83
+#define PTP_OPC_RepresentativeSampleWidth 0xDC84
+#define PTP_OPC_RepresentativeSampleDuration 0xDC85
+#define PTP_OPC_RepresentativeSampleData 0xDC86
+#define PTP_OPC_Width 0xDC87
+#define PTP_OPC_Height 0xDC88
+#define PTP_OPC_Duration 0xDC89
+#define PTP_OPC_Rating 0xDC8A
+#define PTP_OPC_Track 0xDC8B
+#define PTP_OPC_Genre 0xDC8C
+#define PTP_OPC_Credits 0xDC8D
+#define PTP_OPC_Lyrics 0xDC8E
+#define PTP_OPC_SubscriptionContentID 0xDC8F
+#define PTP_OPC_ProducedBy 0xDC90
+#define PTP_OPC_UseCount 0xDC91
+#define PTP_OPC_SkipCount 0xDC92
+#define PTP_OPC_LastAccessed 0xDC93
+#define PTP_OPC_ParentalRating 0xDC94
+#define PTP_OPC_MetaGenre 0xDC95
+#define PTP_OPC_Composer 0xDC96
+#define PTP_OPC_EffectiveRating 0xDC97
+#define PTP_OPC_Subtitle 0xDC98
+#define PTP_OPC_OriginalReleaseDate 0xDC99
+#define PTP_OPC_AlbumName 0xDC9A
+#define PTP_OPC_AlbumArtist 0xDC9B
+#define PTP_OPC_Mood 0xDC9C
+#define PTP_OPC_DRMStatus 0xDC9D
+#define PTP_OPC_SubDescription 0xDC9E
+#define PTP_OPC_IsCropped 0xDCD1
+#define PTP_OPC_IsColorCorrected 0xDCD2
+#define PTP_OPC_ImageBitDepth 0xDCD3
+#define PTP_OPC_Fnumber 0xDCD4
+#define PTP_OPC_ExposureTime 0xDCD5
+#define PTP_OPC_ExposureIndex 0xDCD6
+#define PTP_OPC_DisplayName 0xDCE0
+#define PTP_OPC_BodyText 0xDCE1
+#define PTP_OPC_Subject 0xDCE2
+#define PTP_OPC_Priority 0xDCE3
+#define PTP_OPC_GivenName 0xDD00
+#define PTP_OPC_MiddleNames 0xDD01
+#define PTP_OPC_FamilyName 0xDD02
+#define PTP_OPC_Prefix 0xDD03
+#define PTP_OPC_Suffix 0xDD04
+#define PTP_OPC_PhoneticGivenName 0xDD05
+#define PTP_OPC_PhoneticFamilyName 0xDD06
+#define PTP_OPC_EmailPrimary 0xDD07
+#define PTP_OPC_EmailPersonal1 0xDD08
+#define PTP_OPC_EmailPersonal2 0xDD09
+#define PTP_OPC_EmailBusiness1 0xDD0A
+#define PTP_OPC_EmailBusiness2 0xDD0B
+#define PTP_OPC_EmailOthers 0xDD0C
+#define PTP_OPC_PhoneNumberPrimary 0xDD0D
+#define PTP_OPC_PhoneNumberPersonal 0xDD0E
+#define PTP_OPC_PhoneNumberPersonal2 0xDD0F
+#define PTP_OPC_PhoneNumberBusiness 0xDD10
+#define PTP_OPC_PhoneNumberBusiness2 0xDD11
+#define PTP_OPC_PhoneNumberMobile 0xDD12
+#define PTP_OPC_PhoneNumberMobile2 0xDD13
+#define PTP_OPC_FaxNumberPrimary 0xDD14
+#define PTP_OPC_FaxNumberPersonal 0xDD15
+#define PTP_OPC_FaxNumberBusiness 0xDD16
+#define PTP_OPC_PagerNumber 0xDD17
+#define PTP_OPC_PhoneNumberOthers 0xDD18
+#define PTP_OPC_PrimaryWebAddress 0xDD19
+#define PTP_OPC_PersonalWebAddress 0xDD1A
+#define PTP_OPC_BusinessWebAddress 0xDD1B
+#define PTP_OPC_InstantMessengerAddress 0xDD1C
+#define PTP_OPC_InstantMessengerAddress2 0xDD1D
+#define PTP_OPC_InstantMessengerAddress3 0xDD1E
+#define PTP_OPC_PostalAddressPersonalFull 0xDD1F
+#define PTP_OPC_PostalAddressPersonalFullLine1 0xDD20
+#define PTP_OPC_PostalAddressPersonalFullLine2 0xDD21
+#define PTP_OPC_PostalAddressPersonalFullCity 0xDD22
+#define PTP_OPC_PostalAddressPersonalFullRegion 0xDD23
+#define PTP_OPC_PostalAddressPersonalFullPostalCode 0xDD24
+#define PTP_OPC_PostalAddressPersonalFullCountry 0xDD25
+#define PTP_OPC_PostalAddressBusinessFull 0xDD26
+#define PTP_OPC_PostalAddressBusinessLine1 0xDD27
+#define PTP_OPC_PostalAddressBusinessLine2 0xDD28
+#define PTP_OPC_PostalAddressBusinessCity 0xDD29
+#define PTP_OPC_PostalAddressBusinessRegion 0xDD2A
+#define PTP_OPC_PostalAddressBusinessPostalCode 0xDD2B
+#define PTP_OPC_PostalAddressBusinessCountry 0xDD2C
+#define PTP_OPC_PostalAddressOtherFull 0xDD2D
+#define PTP_OPC_PostalAddressOtherLine1 0xDD2E
+#define PTP_OPC_PostalAddressOtherLine2 0xDD2F
+#define PTP_OPC_PostalAddressOtherCity 0xDD30
+#define PTP_OPC_PostalAddressOtherRegion 0xDD31
+#define PTP_OPC_PostalAddressOtherPostalCode 0xDD32
+#define PTP_OPC_PostalAddressOtherCountry 0xDD33
+#define PTP_OPC_OrganizationName 0xDD34
+#define PTP_OPC_PhoneticOrganizationName 0xDD35
+#define PTP_OPC_Role 0xDD36
+#define PTP_OPC_Birthdate 0xDD37
+#define PTP_OPC_MessageTo 0xDD40
+#define PTP_OPC_MessageCC 0xDD41
+#define PTP_OPC_MessageBCC 0xDD42
+#define PTP_OPC_MessageRead 0xDD43
+#define PTP_OPC_MessageReceivedTime 0xDD44
+#define PTP_OPC_MessageSender 0xDD45
+#define PTP_OPC_ActivityBeginTime 0xDD50
+#define PTP_OPC_ActivityEndTime 0xDD51
+#define PTP_OPC_ActivityLocation 0xDD52
+#define PTP_OPC_ActivityRequiredAttendees 0xDD54
+#define PTP_OPC_ActivityOptionalAttendees 0xDD55
+#define PTP_OPC_ActivityResources 0xDD56
+#define PTP_OPC_ActivityAccepted 0xDD57
+#define PTP_OPC_Owner 0xDD5D
+#define PTP_OPC_Editor 0xDD5E
+#define PTP_OPC_Webmaster 0xDD5F
+#define PTP_OPC_URLSource 0xDD60
+#define PTP_OPC_URLDestination 0xDD61
+#define PTP_OPC_TimeBookmark 0xDD62
+#define PTP_OPC_ObjectBookmark 0xDD63
+#define PTP_OPC_ByteBookmark 0xDD64
+#define PTP_OPC_LastBuildDate 0xDD70
+#define PTP_OPC_TimetoLive 0xDD71
+#define PTP_OPC_MediaGUID 0xDD72
+#define PTP_OPC_TotalBitRate 0xDE91
+#define PTP_OPC_BitRateType 0xDE92
+#define PTP_OPC_SampleRate 0xDE93
+#define PTP_OPC_NumberOfChannels 0xDE94
+#define PTP_OPC_AudioBitDepth 0xDE95
+#define PTP_OPC_ScanDepth 0xDE97
+#define PTP_OPC_AudioWAVECodec 0xDE99
+#define PTP_OPC_AudioBitRate 0xDE9A
+#define PTP_OPC_VideoFourCCCodec 0xDE9B
+#define PTP_OPC_VideoBitRate 0xDE9C
+#define PTP_OPC_FramesPerThousandSeconds 0xDE9D
+#define PTP_OPC_KeyFrameDistance 0xDE9E
+#define PTP_OPC_BufferSize 0xDE9F
+#define PTP_OPC_EncodingQuality 0xDEA0
+#define PTP_OPC_EncodingProfile 0xDEA1
+#define PTP_OPC_BuyFlag 0xD901
+
+/* WiFi Provisioning MTP Extension property codes */
+#define PTP_OPC_WirelessConfigurationFile 0xB104
+
+
+/* PTP Association Types */
+#define PTP_AT_Undefined 0x0000
+#define PTP_AT_GenericFolder 0x0001
+#define PTP_AT_Album 0x0002
+#define PTP_AT_TimeSequence 0x0003
+#define PTP_AT_HorizontalPanoramic 0x0004
+#define PTP_AT_VerticalPanoramic 0x0005
+#define PTP_AT_2DPanoramic 0x0006
+#define PTP_AT_AncillaryData 0x0007
+
+#define PTP_MAX_HANDLER_NBR 0x255
+typedef struct
+{
+ uint32_t n;
+ uint32_t Handler[PTP_MAX_HANDLER_NBR];
+}
+PTP_ObjectHandlesTypedef;
+
+
+#define PTP_oi_StorageID 0
+#define PTP_oi_ObjectFormat 4
+#define PTP_oi_ProtectionStatus 6
+#define PTP_oi_ObjectCompressedSize 8
+#define PTP_oi_ThumbFormat 12
+#define PTP_oi_ThumbCompressedSize 14
+#define PTP_oi_ThumbPixWidth 18
+#define PTP_oi_ThumbPixHeight 22
+#define PTP_oi_ImagePixWidth 26
+#define PTP_oi_ImagePixHeight 30
+#define PTP_oi_ImageBitDepth 34
+#define PTP_oi_ParentObject 38
+#define PTP_oi_AssociationType 42
+#define PTP_oi_AssociationDesc 44
+#define PTP_oi_SequenceNumber 48
+#define PTP_oi_filenamelen 52
+#define PTP_oi_Filename 53
+
+typedef struct
+{
+ uint32_t StorageID;
+ uint16_t ObjectFormat;
+ uint16_t ProtectionStatus;
+ /* In the regular objectinfo this is 32bit, but we keep the general object size here
+ that also arrives via other methods and so use 64bit */
+ uint64_t ObjectCompressedSize;
+ uint16_t ThumbFormat;
+ uint32_t ThumbCompressedSize;
+ uint32_t ThumbPixWidth;
+ uint32_t ThumbPixHeight;
+ uint32_t ImagePixWidth;
+ uint32_t ImagePixHeight;
+ uint32_t ImageBitDepth;
+ uint32_t ParentObject;
+ uint16_t AssociationType;
+ uint32_t AssociationDesc;
+ uint32_t SequenceNumber;
+ uint8_t Filename[PTP_MAX_STR_SIZE];
+ uint32_t CaptureDate;
+ uint32_t ModificationDate;
+ uint8_t Keywords[PTP_MAX_STR_SIZE];
+}
+PTP_ObjectInfoTypedef;
+
+/* Object Property Describing Dataset (DevicePropDesc) */
+
+typedef union _PTP_PropertyValueTypedef
+{
+ char str[PTP_MAX_STR_SIZE];
+ uint8_t u8;
+ int8_t i8;
+ uint16_t u16;
+ int16_t i16;
+ uint32_t u32;
+ int32_t i32;
+ uint64_t u64;
+ int64_t i64;
+
+ struct array {
+ uint32_t count;
+ union _PTP_PropertyValueTypedef *v;
+ } a;
+}PTP_PropertyValueTypedef;
+
+typedef struct
+{
+ PTP_PropertyValueTypedef MinimumValue;
+ PTP_PropertyValueTypedef MaximumValue;
+ PTP_PropertyValueTypedef StepSize;
+}
+PTP_PropDescRangeFormTypedef;
+
+/* Property Describing Dataset, Enum Form */
+
+typedef struct
+{
+ uint16_t NumberOfValues;
+ PTP_PropertyValueTypedef SupportedValue[PTP_SUPPORTED_PROPRIETIES_NBR];
+}
+PTP_PropDescEnumFormTypedef;
+
+/* (MTP) Object Property pack/unpack */
+#define PTP_opd_ObjectPropertyCode 0
+#define PTP_opd_DataType 2
+#define PTP_opd_GetSet 4
+#define PTP_opd_FactoryDefaultValue 5
+
+typedef struct
+{
+ uint16_t ObjectPropertyCode;
+ uint16_t DataType;
+ uint8_t GetSet;
+ PTP_PropertyValueTypedef FactoryDefaultValue;
+ uint32_t GroupCode;
+ uint8_t FormFlag;
+ union {
+ PTP_PropDescEnumFormTypedef Enum;
+ PTP_PropDescRangeFormTypedef Range;
+ } FORM;
+}
+PTP_ObjectPropDescTypeDef;
+
+/* Metadata lists for MTP operations */
+typedef struct
+{
+ uint16_t property;
+ uint16_t datatype;
+ uint32_t ObjectHandle;
+ PTP_PropertyValueTypedef propval;
+}
+MTP_PropertiesTypedef;
+
+
+/* Device Property Form Flag */
+
+#define PTP_DPFF_None 0x00
+#define PTP_DPFF_Range 0x01
+#define PTP_DPFF_Enumeration 0x02
+
+/* Object Property Codes used by MTP (first 3 are same as DPFF codes) */
+#define PTP_OPFF_None 0x00
+#define PTP_OPFF_Range 0x01
+#define PTP_OPFF_Enumeration 0x02
+#define PTP_OPFF_DateTime 0x03
+#define PTP_OPFF_FixedLengthArray 0x04
+#define PTP_OPFF_RegularExpression 0x05
+#define PTP_OPFF_ByteArray 0x06
+#define PTP_OPFF_LongString 0xFF
+
+/* Device Property pack/unpack */
+
+#define PTP_dpd_DevicePropertyCode 0
+#define PTP_dpd_DataType 2
+#define PTP_dpd_GetSet 4
+#define PTP_dpd_FactoryDefaultValue 5
+
+/* Device Property Describing Dataset (DevicePropDesc) */
+
+typedef struct
+{
+ uint16_t DevicePropertyCode;
+ uint16_t DataType;
+ uint8_t GetSet;
+ PTP_PropertyValueTypedef FactoryDefaultValue;
+ PTP_PropertyValueTypedef CurrentValue;
+ uint8_t FormFlag;
+ union {
+ PTP_PropDescEnumFormTypedef Enum;
+ PTP_PropDescRangeFormTypedef Range;
+ } FORM;
+}
+PTP_DevicePropDescTypdef;
+
+/* DataType Codes */
+
+#define PTP_DTC_UNDEF 0x0000
+#define PTP_DTC_INT8 0x0001
+#define PTP_DTC_UINT8 0x0002
+#define PTP_DTC_INT16 0x0003
+#define PTP_DTC_UINT16 0x0004
+#define PTP_DTC_INT32 0x0005
+#define PTP_DTC_UINT32 0x0006
+#define PTP_DTC_INT64 0x0007
+#define PTP_DTC_UINT64 0x0008
+#define PTP_DTC_INT128 0x0009
+#define PTP_DTC_UINT128 0x000A
+
+#define PTP_DTC_ARRAY_MASK 0x4000
+
+#define PTP_DTC_AINT8 (PTP_DTC_ARRAY_MASK | PTP_DTC_INT8)
+#define PTP_DTC_AUINT8 (PTP_DTC_ARRAY_MASK | PTP_DTC_UINT8)
+#define PTP_DTC_AINT16 (PTP_DTC_ARRAY_MASK | PTP_DTC_INT16)
+#define PTP_DTC_AUINT16 (PTP_DTC_ARRAY_MASK | PTP_DTC_UINT16)
+#define PTP_DTC_AINT32 (PTP_DTC_ARRAY_MASK | PTP_DTC_INT32)
+#define PTP_DTC_AUINT32 (PTP_DTC_ARRAY_MASK | PTP_DTC_UINT32)
+#define PTP_DTC_AINT64 (PTP_DTC_ARRAY_MASK | PTP_DTC_INT64)
+#define PTP_DTC_AUINT64 (PTP_DTC_ARRAY_MASK | PTP_DTC_UINT64)
+#define PTP_DTC_AINT128 (PTP_DTC_ARRAY_MASK | PTP_DTC_INT128)
+#define PTP_DTC_AUINT128 (PTP_DTC_ARRAY_MASK | PTP_DTC_UINT128)
+
+#define PTP_DTC_STR 0xFFFF
+
+/* PTP Event Codes */
+
+#define PTP_EC_Undefined 0x4000
+#define PTP_EC_CancelTransaction 0x4001
+#define PTP_EC_ObjectAdded 0x4002
+#define PTP_EC_ObjectRemoved 0x4003
+#define PTP_EC_StoreAdded 0x4004
+#define PTP_EC_StoreRemoved 0x4005
+#define PTP_EC_DevicePropChanged 0x4006
+#define PTP_EC_ObjectInfoChanged 0x4007
+#define PTP_EC_DeviceInfoChanged 0x4008
+#define PTP_EC_RequestObjectTransfer 0x4009
+#define PTP_EC_StoreFull 0x400A
+#define PTP_EC_DeviceReset 0x400B
+#define PTP_EC_StorageInfoChanged 0x400C
+#define PTP_EC_CaptureComplete 0x400D
+#define PTP_EC_UnreportedStatus 0x400E
+
+
+/**
+ * @}
+ */
+
+/** @defgroup USBH_MTP_PTP_Exported_Macros
+ * @{
+ */
+/**
+ * @}
+ */
+
+/** @defgroup USBH_MTP_PTP_Exported_Variables
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+/** @defgroup USBH_MTP_PTP_Exported_FunctionsPrototype
+ * @{
+ */
+USBH_StatusTypeDef USBH_PTP_Init(USBH_HandleTypeDef *phost);
+USBH_StatusTypeDef USBH_PTP_Process (USBH_HandleTypeDef *phost);
+
+USBH_StatusTypeDef USBH_PTP_SendRequest (USBH_HandleTypeDef *phost, PTP_ContainerTypedef *req);
+USBH_StatusTypeDef USBH_PTP_GetResponse (USBH_HandleTypeDef *phost, PTP_ContainerTypedef *req);
+
+USBH_StatusTypeDef USBH_PTP_OpenSession (USBH_HandleTypeDef *phost, uint32_t session);
+USBH_StatusTypeDef USBH_PTP_GetDeviceInfo (USBH_HandleTypeDef *phost, PTP_DeviceInfoTypedef *dev_info);
+USBH_StatusTypeDef USBH_PTP_GetStorageIds (USBH_HandleTypeDef *phost, PTP_StorageIDsTypedef *storage_ids);
+
+USBH_StatusTypeDef USBH_PTP_GetStorageInfo (USBH_HandleTypeDef *phost,
+ uint32_t storage_id,
+ PTP_StorageInfoTypedef *storage_info);
+
+USBH_StatusTypeDef USBH_PTP_GetNumObjects (USBH_HandleTypeDef *phost,
+ uint32_t storage_id,
+ uint32_t objectformatcode,
+ uint32_t associationOH,
+ uint32_t* numobs);
+
+USBH_StatusTypeDef USBH_PTP_GetObjectHandles (USBH_HandleTypeDef *phost,
+ uint32_t storage_id,
+ uint32_t objectformatcode,
+ uint32_t associationOH,
+ PTP_ObjectHandlesTypedef* objecthandles);
+
+USBH_StatusTypeDef USBH_PTP_GetObjectInfo (USBH_HandleTypeDef *phost,
+ uint32_t handle,
+ PTP_ObjectInfoTypedef* objectinfo);
+
+USBH_StatusTypeDef USBH_PTP_DeleteObject (USBH_HandleTypeDef *phost,
+ uint32_t handle,
+ uint32_t objectformatcode);
+
+USBH_StatusTypeDef USBH_PTP_GetObject (USBH_HandleTypeDef *phost,
+ uint32_t handle,
+ uint8_t *object);
+
+USBH_StatusTypeDef USBH_PTP_GetPartialObject(USBH_HandleTypeDef *phost,
+ uint32_t handle,
+ uint32_t offset,
+ uint32_t maxbytes, uint8_t *object,
+ uint32_t *len);
+
+USBH_StatusTypeDef USBH_PTP_GetObjectPropsSupported (USBH_HandleTypeDef *phost,
+ uint16_t ofc,
+ uint32_t *propnum,
+ uint16_t *props);
+
+USBH_StatusTypeDef USBH_PTP_GetObjectPropDesc (USBH_HandleTypeDef *phost,
+ uint16_t opc,
+ uint16_t ofc,
+ PTP_ObjectPropDescTypeDef *opd);
+
+USBH_StatusTypeDef USBH_PTP_GetObjectPropList (USBH_HandleTypeDef *phost,
+ uint32_t handle,
+ MTP_PropertiesTypedef *pprops,
+ uint32_t *nrofprops);
+
+USBH_StatusTypeDef USBH_PTP_SendObject (USBH_HandleTypeDef *phost,
+ uint32_t handle,
+ uint8_t *object,
+ uint32_t size);
+
+USBH_StatusTypeDef USBH_PTP_GetDevicePropDesc (USBH_HandleTypeDef *phost,
+ uint16_t propcode,
+ PTP_DevicePropDescTypdef* devicepropertydesc);
+
+/**
+ * @}
+ */
+
+#endif //__USBH_MTP_PTP_H__
+
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
+
diff --git a/ports/stm32/usbhost/Class/MTP/Src/usbh_mtp.c b/ports/stm32/usbhost/Class/MTP/Src/usbh_mtp.c
new file mode 100644
index 000000000..d93aa4238
--- /dev/null
+++ b/ports/stm32/usbhost/Class/MTP/Src/usbh_mtp.c
@@ -0,0 +1,1065 @@
+/**
+ ******************************************************************************
+ * @file usbh_mtp.c
+ * @author MCD Application Team
+ * @version V3.0.0
+ * @date 18-February-2014
+ * @brief This file is the MTP Layer Handlers for USB Host MTP class.
+ *
+ * @verbatim
+ *
+ * ===================================================================
+ * MTP Class Description
+ * ===================================================================
+ * This module manages the MSC class V1.11 following the "Device Class Definition
+ * for Human Interface Devices (MTP) Version 1.11 Jun 27, 2001".
+ * This driver implements the following aspects of the specification:
+ * - The Boot Interface Subclass
+ * - The Mouse and Keyboard protocols
+ *
+ * @endverbatim
+ *
+ ******************************************************************************
+ * @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 "usbh_mtp.h"
+
+/** @addtogroup USBH_LIB
+* @{
+*/
+
+/** @addtogroup USBH_CLASS
+* @{
+*/
+
+/** @addtogroup USBH_MTP_CLASS
+* @{
+*/
+
+/** @defgroup USBH_MTP_CORE
+* @brief This file includes MTP Layer Handlers for USB Host MTP class.
+* @{
+*/
+
+/** @defgroup USBH_MTP_CORE_Private_TypesDefinitions
+* @{
+*/
+/**
+* @}
+*/
+
+
+/** @defgroup USBH_MTP_CORE_Private_Defines
+* @{
+*/
+/**
+* @}
+*/
+
+
+/** @defgroup USBH_MTP_CORE_Private_Macros
+* @{
+*/
+/**
+* @}
+*/
+
+
+/** @defgroup USBH_MTP_CORE_Private_Variables
+* @{
+*/
+/**
+* @}
+*/
+
+
+/** @defgroup USBH_MTP_CORE_Private_FunctionPrototypes
+* @{
+*/
+
+static USBH_StatusTypeDef USBH_MTP_InterfaceInit (USBH_HandleTypeDef *phost);
+
+static USBH_StatusTypeDef USBH_MTP_InterfaceDeInit (USBH_HandleTypeDef *phost);
+
+static USBH_StatusTypeDef USBH_MTP_Process(USBH_HandleTypeDef *phost);
+
+static USBH_StatusTypeDef USBH_MTP_ClassRequest (USBH_HandleTypeDef *phost);
+
+static uint8_t MTP_FindCtlEndpoint(USBH_HandleTypeDef *phost);
+
+static uint8_t MTP_FindDataOutEndpoint(USBH_HandleTypeDef *phost);
+
+static uint8_t MTP_FindDataInEndpoint(USBH_HandleTypeDef *phost);
+
+static USBH_StatusTypeDef USBH_MTP_SOFProcess (USBH_HandleTypeDef *phost);
+
+static USBH_StatusTypeDef USBH_MTP_Events (USBH_HandleTypeDef *phost);
+
+static void MTP_DecodeEvent (USBH_HandleTypeDef *phost) ;
+
+USBH_ClassTypeDef MTP_Class =
+{
+ "MTP",
+ USB_MTP_CLASS,
+ USBH_MTP_InterfaceInit,
+ USBH_MTP_InterfaceDeInit,
+ USBH_MTP_ClassRequest,
+ USBH_MTP_Process,
+ USBH_MTP_SOFProcess,
+ NULL,
+};
+/**
+* @}
+*/
+
+
+/** @defgroup USBH_MTP_CORE_Private_Functions
+* @{
+*/
+
+/**
+ * @brief USBH_MTP_InterfaceInit
+ * The function init the MTP class.
+ * @param phost: Host handle
+ * @retval USBH Status
+ */
+static USBH_StatusTypeDef USBH_MTP_InterfaceInit (USBH_HandleTypeDef *phost)
+{
+ USBH_StatusTypeDef status = USBH_OK ;
+ uint8_t interface, endpoint;
+
+ MTP_HandleTypeDef *MTP_Handle;
+
+ interface = USBH_FindInterface(phost,
+ USB_MTP_CLASS,
+ 1,
+ 1);
+
+ if(interface == 0xFF) /* No Valid Interface */
+ {
+ status = USBH_FAIL;
+ USBH_DbgLog ("Cannot Find the interface for Still Image Class.");
+ }
+ else
+ {
+ USBH_SelectInterface (phost, interface);
+
+ endpoint = MTP_FindCtlEndpoint(phost);
+
+ phost->pActiveClass->pData = (MTP_HandleTypeDef *)USBH_malloc (sizeof(MTP_HandleTypeDef));
+ MTP_Handle = phost->pActiveClass->pData;
+
+ if( MTP_Handle == NULL)
+ {
+ status = USBH_FAIL;
+ USBH_DbgLog ("Cannot allocate RAM for MTP Handle");
+ }
+
+ /*Collect the control endpoint address and length*/
+ MTP_Handle->NotificationEp = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[endpoint].bEndpointAddress;
+ MTP_Handle->NotificationEpSize = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[endpoint].wMaxPacketSize;
+ MTP_Handle->NotificationPipe = USBH_AllocPipe(phost, MTP_Handle->NotificationEp);
+ MTP_Handle->events.poll = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[endpoint].bInterval;
+
+ /* Open pipe for Notification endpoint */
+ USBH_OpenPipe (phost,
+ MTP_Handle->NotificationPipe,
+ MTP_Handle->NotificationEp,
+ phost->device.address,
+ phost->device.speed,
+ USB_EP_TYPE_INTR,
+ MTP_Handle->NotificationEpSize);
+
+ USBH_LL_SetToggle (phost, MTP_Handle->NotificationPipe, 0);
+
+
+ endpoint = MTP_FindDataInEndpoint(phost);
+
+ /*Collect the control endpoint address and length*/
+ MTP_Handle->DataInEp = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[endpoint].bEndpointAddress;
+ MTP_Handle->DataInEpSize = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[endpoint].wMaxPacketSize;
+ MTP_Handle->DataInPipe = USBH_AllocPipe(phost, MTP_Handle->DataInEp);
+
+ /* Open pipe for DATA IN endpoint */
+ USBH_OpenPipe (phost,
+ MTP_Handle->DataInPipe,
+ MTP_Handle->DataInEp,
+ phost->device.address,
+ phost->device.speed,
+ USB_EP_TYPE_BULK,
+ MTP_Handle->DataInEpSize);
+
+ USBH_LL_SetToggle (phost, MTP_Handle->DataInPipe, 0);
+
+ endpoint = MTP_FindDataOutEndpoint(phost);
+
+ /*Collect the DATA OUT endpoint address and length*/
+ MTP_Handle->DataOutEp = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[endpoint].bEndpointAddress;
+ MTP_Handle->DataOutEpSize = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[endpoint].wMaxPacketSize;
+ MTP_Handle->DataOutPipe = USBH_AllocPipe(phost, MTP_Handle->DataOutEp);
+
+ /* Open pipe for DATA OUT endpoint */
+ USBH_OpenPipe (phost,
+ MTP_Handle->DataOutPipe,
+ MTP_Handle->DataOutEp,
+ phost->device.address,
+ phost->device.speed,
+ USB_EP_TYPE_BULK,
+ MTP_Handle->DataOutEpSize);
+
+ USBH_LL_SetToggle (phost, MTP_Handle->DataOutPipe, 0);
+
+
+ MTP_Handle->state = MTP_OPENSESSION;
+ MTP_Handle->is_ready = 0;
+ MTP_Handle->events.state = MTP_EVENTS_INIT;
+ return USBH_PTP_Init(phost);
+
+ }
+ return status;
+}
+
+/**
+ * @brief Find MTP Ctl interface
+ * @param phost: Host handle
+ * @retval USBH Status
+ */
+static uint8_t MTP_FindCtlEndpoint(USBH_HandleTypeDef *phost)
+{
+ uint8_t interface, endpoint;
+
+ for (interface = 0; interface < USBH_MAX_NUM_INTERFACES ; interface ++ )
+ {
+ if(phost->device.CfgDesc.Itf_Desc[interface].bInterfaceClass == USB_MTP_CLASS)
+ {
+ for (endpoint = 0; endpoint < USBH_MAX_NUM_ENDPOINTS ; endpoint ++ )
+ {
+ if((phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[endpoint].bEndpointAddress & 0x80)&&
+ (phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[endpoint].wMaxPacketSize > 0)&&
+ ((phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[endpoint].bmAttributes & USBH_EP_INTERRUPT) == USBH_EP_INTERRUPT))
+ {
+ return endpoint;
+ }
+ }
+ }
+ }
+
+ return 0xFF; /* Invalid Endpoint */
+}
+
+
+/**
+ * @brief Find MTP DATA OUT interface
+ * @param phost: Host handle
+ * @retval USBH Status
+ */
+static uint8_t MTP_FindDataOutEndpoint(USBH_HandleTypeDef *phost)
+{
+ uint8_t interface, endpoint;
+
+ for (interface = 0; interface < USBH_MAX_NUM_INTERFACES ; interface ++ )
+ {
+ if(phost->device.CfgDesc.Itf_Desc[interface].bInterfaceClass == USB_MTP_CLASS)
+ {
+ for (endpoint = 0; endpoint < USBH_MAX_NUM_ENDPOINTS ; endpoint ++ )
+ {
+
+ if(((phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[endpoint].bEndpointAddress & 0x80) == 0)&&
+ (phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[endpoint].wMaxPacketSize > 0)&&
+ ((phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[endpoint].bmAttributes & USBH_EP_BULK) == USBH_EP_BULK))
+ {
+ return endpoint;
+ }
+ }
+ }
+ }
+
+ return 0xFF; /* Invalid Endpoint */
+}
+
+/**
+ * @brief Find MTP DATA IN interface
+ * @param phost: Host handle
+ * @retval USBH Status
+ */
+static uint8_t MTP_FindDataInEndpoint(USBH_HandleTypeDef *phost)
+{
+ uint8_t interface, endpoint;
+
+ for (interface = 0; interface < USBH_MAX_NUM_INTERFACES ; interface ++ )
+ {
+ if(phost->device.CfgDesc.Itf_Desc[interface].bInterfaceClass == USB_MTP_CLASS)
+ {
+ for (endpoint = 0; endpoint < USBH_MAX_NUM_ENDPOINTS ; endpoint ++ )
+ {
+
+ if((phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[endpoint].bEndpointAddress & 0x80)&&
+ (phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[endpoint].wMaxPacketSize > 0)&&
+ ((phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[endpoint].bmAttributes & USBH_EP_BULK) == USBH_EP_BULK))
+ {
+ return endpoint;
+ }
+ }
+ }
+ }
+
+ return 0xFF; /* Invalid Endpoint */
+}
+
+
+/**
+ * @brief USBH_MTP_InterfaceDeInit
+ * The function DeInit the Pipes used for the MTP class.
+ * @param phost: Host handle
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_MTP_InterfaceDeInit (USBH_HandleTypeDef *phost)
+{
+ MTP_HandleTypeDef *MTP_Handle = phost->pActiveClass->pData;
+
+ if (MTP_Handle->DataOutPipe)
+ {
+ USBH_ClosePipe(phost, MTP_Handle->DataOutPipe);
+ USBH_FreePipe (phost, MTP_Handle->DataOutPipe);
+ MTP_Handle->DataOutPipe = 0; /* Reset the Channel as Free */
+ }
+
+ if (MTP_Handle->DataInPipe)
+ {
+ USBH_ClosePipe(phost, MTP_Handle->DataInPipe);
+ USBH_FreePipe (phost, MTP_Handle->DataInPipe);
+ MTP_Handle->DataInPipe = 0; /* Reset the Channel as Free */
+ }
+
+ if (MTP_Handle->NotificationPipe)
+ {
+ USBH_ClosePipe(phost, MTP_Handle->NotificationPipe);
+ USBH_FreePipe (phost, MTP_Handle->NotificationPipe);
+ MTP_Handle->NotificationPipe = 0; /* Reset the Channel as Free */
+ }
+
+ if(phost->pActiveClass->pData)
+ {
+ USBH_free (phost->pActiveClass->pData);
+ phost->pActiveClass->pData = 0;
+ }
+ return USBH_OK;
+}
+
+/**
+ * @brief USBH_MTP_ClassRequest
+ * The function is responsible for handling Standard requests
+ * for MTP class.
+ * @param phost: Host handle
+ * @retval USBH Status
+ */
+static USBH_StatusTypeDef USBH_MTP_ClassRequest (USBH_HandleTypeDef *phost)
+{
+ return USBH_OK;;
+}
+
+
+/**
+ * @brief USBH_MTP_Process
+ * The function is for managing state machine for MTP data transfers
+ * @param phost: Host handle
+ * @retval USBH Status
+ */
+static USBH_StatusTypeDef USBH_MTP_Process (USBH_HandleTypeDef *phost)
+{
+ USBH_StatusTypeDef status = USBH_BUSY;
+ MTP_HandleTypeDef *MTP_Handle = phost->pActiveClass->pData;
+ uint32_t idx = 0;
+
+ switch(MTP_Handle->state)
+ {
+ case MTP_OPENSESSION:
+
+ status = USBH_PTP_OpenSession (phost, 1); /* Session '0' is not valid */
+
+ if(status == USBH_OK)
+ {
+ USBH_UsrLog("MTP Session #0 Opened");
+ MTP_Handle->state = MTP_GETDEVICEINFO;
+ }
+ break;
+
+ case MTP_GETDEVICEINFO:
+ status = USBH_PTP_GetDeviceInfo (phost, &(MTP_Handle->info.devinfo));
+
+ if(status == USBH_OK)
+ {
+ USBH_DbgLog(">>>>> MTP Device Information");
+ USBH_DbgLog("Standard version : %x", MTP_Handle->info.devinfo.StandardVersion);
+ USBH_DbgLog("Vendor ExtID : %s", (MTP_Handle->info.devinfo.VendorExtensionID == 6)?"MTP": "NOT SUPPORTED");
+ USBH_DbgLog("Functional mode : %s", (MTP_Handle->info.devinfo.FunctionalMode == 0) ? "Standard" : "Vendor");
+ USBH_DbgLog("Number of Supported Operation(s) : %d", MTP_Handle->info.devinfo.OperationsSupported_len);
+ USBH_DbgLog("Number of Supported Events(s) : %d", MTP_Handle->info.devinfo.EventsSupported_len);
+ USBH_DbgLog("Number of Supported Proprieties : %d", MTP_Handle->info.devinfo.DevicePropertiesSupported_len);
+ USBH_DbgLog("Manufacturer : %s", MTP_Handle->info.devinfo.Manufacturer);
+ USBH_DbgLog("Model : %s", MTP_Handle->info.devinfo.Model);
+ USBH_DbgLog("Device version : %s", MTP_Handle->info.devinfo.DeviceVersion);
+ USBH_DbgLog("Serial number : %s", MTP_Handle->info.devinfo.SerialNumber);
+
+ MTP_Handle->state = MTP_GETSTORAGEIDS;
+ }
+ break;
+
+ case MTP_GETSTORAGEIDS:
+ status = USBH_PTP_GetStorageIds (phost, &(MTP_Handle->info.storids));
+
+ if(status == USBH_OK)
+ {
+ USBH_DbgLog("Number of storage ID items : %d", MTP_Handle->info.storids.n);
+ for (idx = 0; idx < MTP_Handle->info.storids.n; idx ++)
+ {
+ USBH_DbgLog("storage#%d ID : %x", idx, MTP_Handle->info.storids.Storage[idx]);
+ }
+
+ MTP_Handle->current_storage_unit = 0;
+ MTP_Handle->state = MTP_GETSTORAGEINFO;
+ }
+ break;
+
+ case MTP_GETSTORAGEINFO:
+ status = USBH_PTP_GetStorageInfo (phost,
+ MTP_Handle->info.storids.Storage[MTP_Handle->current_storage_unit],
+ &((MTP_Handle->info.storinfo)[MTP_Handle->current_storage_unit]));
+
+ if(status == USBH_OK)
+ {
+ USBH_UsrLog("Volume#%lu: %s [%s]", MTP_Handle->current_storage_unit,
+ MTP_Handle->info.storinfo[MTP_Handle->current_storage_unit].StorageDescription,
+ MTP_Handle->info.storinfo[MTP_Handle->current_storage_unit].VolumeLabel);
+ if(++MTP_Handle->current_storage_unit >= MTP_Handle->info.storids.n)
+ {
+ MTP_Handle->state = MTP_IDLE;
+ MTP_Handle->is_ready = 1;
+ MTP_Handle->current_storage_unit = 0;
+ MTP_Handle->params.CurrentStorageId = MTP_Handle->info.storids.Storage[0];
+
+ USBH_UsrLog( "MTP Class initialized.");
+ USBH_UsrLog("%s is default storage unit", MTP_Handle->info.storinfo[0].StorageDescription);
+ phost->pUser(phost, HOST_USER_CLASS_ACTIVE);
+ }
+ }
+ break;
+
+ case MTP_IDLE:
+ USBH_MTP_Events(phost);
+ default:
+ status = USBH_OK;
+ break;
+ }
+ return status;
+}
+
+/**
+ * @brief USBH_MTP_SOFProcess
+ * The function is for managing SOF callback
+ * @param phost: Host handle
+ * @retval USBH Status
+ */
+static USBH_StatusTypeDef USBH_MTP_SOFProcess (USBH_HandleTypeDef *phost)
+{
+ USBH_StatusTypeDef status = USBH_OK;
+
+ return status;
+}
+
+/**
+ * @brief USBH_MTP_IsReady
+ * Select the storage Unit to be used
+ * @param phost: Host handle
+ * @retval USBH Status
+ */
+uint8_t USBH_MTP_IsReady (USBH_HandleTypeDef *phost)
+{
+ MTP_HandleTypeDef *MTP_Handle = phost->pActiveClass->pData;
+
+ return (MTP_Handle->is_ready);
+}
+
+/**
+ * @brief USBH_MTP_GetNumStorage
+ * Select the storage Unit to be used
+ * @param phost: Host handle
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_MTP_GetNumStorage (USBH_HandleTypeDef *phost, uint8_t *storage_num)
+{
+ USBH_StatusTypeDef status = USBH_FAIL;
+ MTP_HandleTypeDef *MTP_Handle = phost->pActiveClass->pData;
+
+ if(MTP_Handle->is_ready > 0)
+ {
+ *storage_num = MTP_Handle->info.storids.n;
+ status = USBH_OK;
+ }
+
+ return status;
+}
+
+/**
+ * @brief USBH_MTP_SelectStorage
+ * Select the storage Unit to be used
+ * @param phost: Host handle
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_MTP_SelectStorage (USBH_HandleTypeDef *phost, uint8_t storage_idx)
+{
+ USBH_StatusTypeDef status = USBH_FAIL;
+ MTP_HandleTypeDef *MTP_Handle = phost->pActiveClass->pData;
+
+ if((storage_idx < MTP_Handle->info.storids.n) && (MTP_Handle->is_ready))
+ {
+ MTP_Handle->params.CurrentStorageId = MTP_Handle->info.storids.Storage[storage_idx];
+ status = USBH_OK;
+ }
+
+ return status;
+}
+
+/**
+ * @brief USBH_MTP_GetStorageInfo
+ * Get the storage Unit info
+ * @param phost: Host handle
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_MTP_GetStorageInfo (USBH_HandleTypeDef *phost, uint8_t storage_idx, MTP_StorageInfoTypedef *info)
+{
+ USBH_StatusTypeDef status = USBH_FAIL;
+ MTP_HandleTypeDef *MTP_Handle = phost->pActiveClass->pData;
+
+ if((storage_idx < MTP_Handle->info.storids.n) && (MTP_Handle->is_ready))
+ {
+ *info = MTP_Handle->info.storinfo[storage_idx];
+ status = USBH_OK;
+ }
+ return status;
+}
+
+/**
+ * @brief USBH_MTP_GetStorageInfo
+ * Get the storage Unit info
+ * @param phost: Host handle
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_MTP_GetNumObjects (USBH_HandleTypeDef *phost,
+ uint32_t storage_idx,
+ uint32_t objectformatcode,
+ uint32_t associationOH,
+ uint32_t* numobs)
+{
+ USBH_StatusTypeDef status = USBH_FAIL;
+ MTP_HandleTypeDef *MTP_Handle = phost->pActiveClass->pData;
+ uint32_t timeout = phost->Timer + 5000;
+ if((storage_idx < MTP_Handle->info.storids.n) && (MTP_Handle->is_ready))
+ {
+ while ((status = USBH_PTP_GetNumObjects (phost,
+ MTP_Handle->info.storids.Storage[storage_idx],
+ objectformatcode,
+ associationOH,
+ numobs)) == USBH_BUSY)
+ {
+ if((phost->Timer > timeout) || (phost->device.is_connected == 0))
+ {
+ return USBH_FAIL;
+ }
+ }
+ }
+ return status;
+}
+
+
+/**
+ * @brief USBH_MTP_GetStorageInfo
+ * Get the storage Unit info
+ * @param phost: Host handle
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_MTP_GetObjectHandles (USBH_HandleTypeDef *phost,
+ uint32_t storage_idx,
+ uint32_t objectformatcode,
+ uint32_t associationOH,
+ PTP_ObjectHandlesTypedef* objecthandles)
+{
+ USBH_StatusTypeDef status = USBH_FAIL;
+ MTP_HandleTypeDef *MTP_Handle = phost->pActiveClass->pData;
+ uint32_t timeout = phost->Timer + 5000;
+
+ if((storage_idx < MTP_Handle->info.storids.n) && (MTP_Handle->is_ready))
+ {
+ while ((status = USBH_PTP_GetObjectHandles (phost,
+ MTP_Handle->info.storids.Storage[storage_idx],
+ objectformatcode,
+ associationOH,
+ objecthandles)) == USBH_BUSY)
+ {
+ if((phost->Timer > timeout) || (phost->device.is_connected == 0))
+ {
+ return USBH_FAIL;
+ }
+ }
+ }
+ return status;
+}
+
+/**
+ * @brief USBH_PTP_GetObjectInfo
+ * Gets objert info
+ * @param phost: Host handle
+ * @param dev_info: Device info structure
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_MTP_GetObjectInfo (USBH_HandleTypeDef *phost,
+ uint32_t handle,
+ PTP_ObjectInfoTypedef* objectinfo)
+{
+ USBH_StatusTypeDef status = USBH_FAIL;
+ MTP_HandleTypeDef *MTP_Handle = phost->pActiveClass->pData;
+ uint32_t timeout = phost->Timer + 5000;
+
+ if(MTP_Handle->is_ready)
+ {
+ while ((status = USBH_PTP_GetObjectInfo (phost, handle, objectinfo)) == USBH_BUSY)
+ {
+ if((phost->Timer > timeout) || (phost->device.is_connected == 0))
+ {
+ return USBH_FAIL;
+ }
+ }
+ }
+ return status;
+}
+/**
+ * @brief USBH_MTP_DeleteObject
+ * Delete an object.
+ * @param phost: Host handle
+ * @param handle : Object Handle
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_MTP_DeleteObject (USBH_HandleTypeDef *phost,
+ uint32_t handle,
+ uint32_t objectformatcode)
+{
+ USBH_StatusTypeDef status = USBH_FAIL;
+ MTP_HandleTypeDef *MTP_Handle = phost->pActiveClass->pData;
+ uint32_t timeout = phost->Timer + 5000;
+
+ if(MTP_Handle->is_ready)
+ {
+ while ((status = USBH_PTP_DeleteObject (phost, handle, objectformatcode)) == USBH_BUSY)
+ {
+ if((phost->Timer > timeout) || (phost->device.is_connected == 0))
+ {
+ return USBH_FAIL;
+ }
+ }
+ }
+ return status;
+}
+
+/**
+ * @brief USBH_MTP_GetObject
+ * Gets object
+ * @param phost: Host handle
+ * @param dev_info: Device info structure
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_MTP_GetObject (USBH_HandleTypeDef *phost,
+ uint32_t handle,
+ uint8_t *object)
+{
+ USBH_StatusTypeDef status = USBH_FAIL;
+ MTP_HandleTypeDef *MTP_Handle = phost->pActiveClass->pData;
+ uint32_t timeout = phost->Timer + 5000;
+
+ if(MTP_Handle->is_ready)
+ {
+ while ((status = USBH_PTP_GetObject (phost, handle, object)) == USBH_BUSY)
+ {
+ if((phost->Timer > timeout) || (phost->device.is_connected == 0))
+ {
+ return USBH_FAIL;
+ }
+ }
+ }
+ return status;
+}
+
+/**
+ * @brief USBH_MTP_GetPartialObject
+ * Gets object
+ * @param phost: Host handle
+ * @param dev_info: Device info structure
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_MTP_GetPartialObject(USBH_HandleTypeDef *phost,
+ uint32_t handle,
+ uint32_t offset,
+ uint32_t maxbytes,
+ uint8_t *object,
+ uint32_t *len)
+{
+ USBH_StatusTypeDef status = USBH_FAIL;
+ MTP_HandleTypeDef *MTP_Handle = phost->pActiveClass->pData;
+ uint32_t timeout = phost->Timer + 5000;
+
+ if(MTP_Handle->is_ready)
+ {
+ while ((status = USBH_PTP_GetPartialObject(phost,
+ handle,
+ offset,
+ maxbytes,
+ object,
+ len)) == USBH_BUSY)
+ {
+ if((phost->Timer > timeout) || (phost->device.is_connected == 0))
+ {
+ return USBH_FAIL;
+ }
+ }
+ }
+ return status;
+}
+
+/**
+ * @brief USBH_MTP_GetObjectPropsSupported
+ * Gets object partially
+ * @param phost: Host handle
+ * @param dev_info: Device info structure
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_MTP_GetObjectPropsSupported (USBH_HandleTypeDef *phost,
+ uint16_t ofc,
+ uint32_t *propnum,
+ uint16_t *props)
+{
+ USBH_StatusTypeDef status = USBH_FAIL;
+ MTP_HandleTypeDef *MTP_Handle = phost->pActiveClass->pData;
+ uint32_t timeout = phost->Timer + 5000;
+
+ if(MTP_Handle->is_ready)
+ {
+ while ((status = USBH_PTP_GetObjectPropsSupported (phost,
+ ofc,
+ propnum,
+ props)) == USBH_BUSY)
+ {
+ if((phost->Timer > timeout) || (phost->device.is_connected == 0))
+ {
+ return USBH_FAIL;
+ }
+ }
+ }
+ return status;
+}
+
+/**
+ * @brief USBH_MTP_GetObjectPropDesc
+ * Gets object partially
+ * @param phost: Host handle
+ * @param dev_info: Device info structure
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_MTP_GetObjectPropDesc (USBH_HandleTypeDef *phost,
+ uint16_t opc,
+ uint16_t ofc,
+ PTP_ObjectPropDescTypeDef *opd)
+{
+ USBH_StatusTypeDef status = USBH_FAIL;
+ MTP_HandleTypeDef *MTP_Handle = phost->pActiveClass->pData;
+ uint32_t timeout = phost->Timer + 5000;
+
+ if(MTP_Handle->is_ready)
+ {
+ while ((status = USBH_PTP_GetObjectPropDesc (phost,
+ opc,
+ ofc,
+ opd)) == USBH_BUSY)
+ {
+ if((phost->Timer > timeout) || (phost->device.is_connected == 0))
+ {
+ return USBH_FAIL;
+ }
+ }
+ }
+ return status;
+}
+
+/**
+ * @brief USBH_MTP_GetObjectPropList
+ * Gets object partially
+ * @param phost: Host handle
+ * @param dev_info: Device info structure
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_MTP_GetObjectPropList (USBH_HandleTypeDef *phost,
+ uint32_t handle,
+ MTP_PropertiesTypedef *pprops,
+ uint32_t *nrofprops)
+{
+ USBH_StatusTypeDef status = USBH_FAIL;
+ MTP_HandleTypeDef *MTP_Handle = phost->pActiveClass->pData;
+ uint32_t timeout = phost->Timer + 5000;
+
+ if(MTP_Handle->is_ready)
+ {
+ while ((status = USBH_PTP_GetObjectPropList (phost,
+ handle,
+ pprops,
+ nrofprops)) == USBH_BUSY)
+ {
+ if((phost->Timer > timeout) || (phost->device.is_connected == 0))
+ {
+ return USBH_FAIL;
+ }
+ }
+ }
+ return status;
+}
+
+/**
+ * @brief USBH_MTP_SendObject
+ * Send an object
+ * @param phost: Host handle
+ * @param dev_info: Device info structure
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_MTP_SendObject (USBH_HandleTypeDef *phost,
+ uint32_t handle,
+ uint8_t *object,
+ uint32_t size)
+{
+ USBH_StatusTypeDef status = USBH_FAIL;
+ MTP_HandleTypeDef *MTP_Handle = phost->pActiveClass->pData;
+ uint32_t timeout = phost->Timer + 5000;
+
+ if(MTP_Handle->is_ready)
+ {
+ while ((status = USBH_PTP_SendObject (phost, handle, object, size)) == USBH_BUSY)
+ {
+ if((phost->Timer > timeout) || (phost->device.is_connected == 0))
+ {
+ return USBH_FAIL;
+ }
+ }
+ }
+ return status;
+}
+
+ /**
+ * @brief Handle HID Control process
+ * @param phost: Host handle
+ * @retval USBH Status
+ */
+static USBH_StatusTypeDef USBH_MTP_Events (USBH_HandleTypeDef *phost)
+{
+ USBH_StatusTypeDef status = USBH_BUSY ;
+ MTP_HandleTypeDef *MTP_Handle = phost->pActiveClass->pData;
+
+
+ switch(MTP_Handle->events.state)
+ {
+ case MTP_EVENTS_INIT:
+ if((phost->Timer & 1) == 0)
+ {
+ MTP_Handle->events.timer = phost->Timer;
+ USBH_InterruptReceiveData(phost,
+ (uint8_t *)&(MTP_Handle->events.container),
+ MTP_Handle->NotificationEpSize,
+ MTP_Handle->NotificationPipe);
+
+
+ MTP_Handle->events.state = MTP_EVENTS_GETDATA ;
+ }
+ break;
+ case MTP_EVENTS_GETDATA:
+ if(USBH_LL_GetURBState(phost , MTP_Handle->NotificationPipe) == USBH_URB_DONE)
+ {
+ MTP_DecodeEvent(phost);
+ }
+
+ if(( phost->Timer - MTP_Handle->events.timer) >= MTP_Handle->events.poll)
+ {
+ MTP_Handle->events.timer = phost->Timer;
+
+ USBH_InterruptReceiveData(phost,
+ (uint8_t *)&(MTP_Handle->events.container),
+ MTP_Handle->NotificationEpSize,
+ MTP_Handle->NotificationPipe);
+
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return status;
+}
+
+/**
+ * @brief MTP_DecodeEvent
+ * Decode device event sent by responder
+ * @param phost: Host handle
+ * @retval None
+ */
+static void MTP_DecodeEvent (USBH_HandleTypeDef *phost)
+{
+ MTP_HandleTypeDef *MTP_Handle = phost->pActiveClass->pData;
+
+ uint16_t code;
+ uint32_t param1;
+
+ /* Process the event */
+ code = MTP_Handle->events.container.code;
+ param1 = MTP_Handle->events.container.param1;
+
+ switch(code)
+ {
+ case PTP_EC_Undefined:
+ USBH_DbgLog("EVT: PTP_EC_Undefined in session %u", MTP_Handle->ptp.session_id);
+ break;
+ case PTP_EC_CancelTransaction:
+ USBH_DbgLog("EVT: PTP_EC_CancelTransaction in session %u", MTP_Handle->ptp.session_id);
+ break;
+ case PTP_EC_ObjectAdded:
+ USBH_DbgLog("EVT: PTP_EC_ObjectAdded in session %u", MTP_Handle->ptp.session_id);
+ break;
+
+ case PTP_EC_ObjectRemoved:
+ USBH_DbgLog("EVT: PTP_EC_ObjectRemoved in session %u", MTP_Handle->ptp.session_id);
+ break;
+
+ case PTP_EC_StoreAdded:
+ USBH_DbgLog("EVT: PTP_EC_StoreAdded in session %u", MTP_Handle->ptp.session_id);
+ break;
+
+ case PTP_EC_StoreRemoved:
+ USBH_DbgLog("EVT: PTP_EC_StoreRemoved in session %u", MTP_Handle->ptp.session_id);
+ break;
+
+ case PTP_EC_DevicePropChanged:
+ USBH_DbgLog("EVT: PTP_EC_DevicePropChanged in session %u", MTP_Handle->ptp.session_id);
+ break;
+
+ case PTP_EC_ObjectInfoChanged:
+ USBH_DbgLog("EVT: PTP_EC_ObjectInfoChanged in session %u", MTP_Handle->ptp.session_id);
+ break;
+
+ case PTP_EC_DeviceInfoChanged:
+ USBH_DbgLog("EVT: PTP_EC_DeviceInfoChanged in session %u", MTP_Handle->ptp.session_id);
+ break;
+
+ case PTP_EC_RequestObjectTransfer:
+ USBH_DbgLog("EVT: PTP_EC_RequestObjectTransfer in session %u", MTP_Handle->ptp.session_id);
+ break;
+
+ case PTP_EC_StoreFull:
+ USBH_DbgLog("EVT: PTP_EC_StoreFull in session %u", MTP_Handle->ptp.session_id);
+ break;
+
+ case PTP_EC_DeviceReset:
+ USBH_DbgLog("EVT: PTP_EC_DeviceReset in session %u", MTP_Handle->ptp.session_id);
+ break;
+
+ case PTP_EC_StorageInfoChanged :
+ USBH_DbgLog( "EVT: PTP_EC_StorageInfoChanged in session %u", MTP_Handle->ptp.session_id);
+ break;
+
+ case PTP_EC_CaptureComplete :
+ USBH_DbgLog( "EVT: PTP_EC_CaptureComplete in session %u", MTP_Handle->ptp.session_id);
+ break;
+
+ case PTP_EC_UnreportedStatus :
+ USBH_DbgLog( "EVT: PTP_EC_UnreportedStatus in session %u", MTP_Handle->ptp.session_id);
+ break;
+
+ default :
+ USBH_DbgLog( "Received unknown event in session %u", MTP_Handle->ptp.session_id);
+ break;
+ }
+
+ USBH_MTP_EventsCallback(phost, code, param1);
+}
+
+/**
+ * @brief USBH_MTP_GetDevicePropDesc
+ * Gets object partially
+ * @param phost: Host handle
+ * @param dev_info: Device info structure
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_MTP_GetDevicePropDesc (USBH_HandleTypeDef *phost,
+ uint16_t propcode,
+ PTP_DevicePropDescTypdef* devicepropertydesc)
+
+{
+ USBH_StatusTypeDef status = USBH_FAIL;
+ MTP_HandleTypeDef *MTP_Handle = phost->pActiveClass->pData;
+ uint32_t timeout = phost->Timer + 5000;
+
+ if(MTP_Handle->is_ready)
+ {
+ while ((status = USBH_PTP_GetDevicePropDesc (phost, propcode, devicepropertydesc)) == USBH_BUSY)
+ {
+ if((phost->Timer > timeout) || (phost->device.is_connected == 0))
+ {
+ return USBH_FAIL;
+ }
+ }
+ }
+ return status;
+}
+/**
+ * @brief The function informs that host has rceived an event
+ * @param pdev: Selected device
+ * @retval None
+ */
+__weak void USBH_MTP_EventsCallback(USBH_HandleTypeDef *phost, uint32_t event, uint32_t param)
+{
+
+}
+/**
+* @}
+*/
+
+/**
+* @}
+*/
+
+/**
+* @}
+*/
+
+
+/**
+* @}
+*/
+
+
+/**
+* @}
+*/
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/ports/stm32/usbhost/Class/MTP/Src/usbh_mtp_ptp.c b/ports/stm32/usbhost/Class/MTP/Src/usbh_mtp_ptp.c
new file mode 100644
index 000000000..dd5a293e6
--- /dev/null
+++ b/ports/stm32/usbhost/Class/MTP/Src/usbh_mtp_ptp.c
@@ -0,0 +1,1769 @@
+/**
+ ******************************************************************************
+ * @file usbh_mtp_ptp.c
+ * @author MCD Application Team
+ * @version V3.0.0
+ * @date 18-February-2014
+ * @brief This file includes the PTP operations layer
+ ******************************************************************************
+ * @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 "usbh_mtp_ptp.h"
+#include "usbh_mtp.h"
+/** @addtogroup USBH_LIB
+* @{
+*/
+
+/** @addtogroup USBH_CLASS
+* @{
+*/
+
+/** @addtogroup USBH_MTP_CLASS
+* @{
+*/
+
+/** @defgroup USBH_MTP_PTP
+* @brief This file includes the mass storage related functions
+* @{
+*/
+
+
+/** @defgroup USBH_MTP_PTP_Private_TypesDefinitions
+* @{
+*/
+/**
+* @}
+*/
+
+/** @defgroup USBH_MTP_PTP_Private_Defines
+* @{
+*/
+/**
+* @}
+*/
+
+/** @defgroup USBH_MTP_PTP_Private_Macros
+* @{
+*/
+/**
+* @}
+*/
+
+
+/** @defgroup USBH_MTP_PTP_Private_Variables
+* @{
+*/
+
+/**
+* @}
+*/
+
+
+/** @defgroup USBH_MTP_PTP_Private_FunctionPrototypes
+* @{
+*/
+static void PTP_DecodeDeviceInfo (USBH_HandleTypeDef *phost, PTP_DeviceInfoTypedef *dev_info);
+static void PTP_GetStorageIDs (USBH_HandleTypeDef *phost, PTP_StorageIDsTypedef *stor_ids);
+static void PTP_GetStorageInfo (USBH_HandleTypeDef *phost, uint32_t storage_id, PTP_StorageInfoTypedef *stor_info);
+static void PTP_GetObjectPropDesc (USBH_HandleTypeDef *phost, PTP_ObjectPropDescTypeDef *opd, uint32_t opdlen);
+static void PTP_DecodeDeviceInfo (USBH_HandleTypeDef *phost, PTP_DeviceInfoTypedef *dev_info);
+static void PTP_GetDevicePropValue(USBH_HandleTypeDef *phost,
+ uint32_t *offset,
+ uint32_t total,
+ PTP_PropertyValueTypedef* value,
+ uint16_t datatype);
+
+static uint32_t PTP_GetObjectPropList (USBH_HandleTypeDef *phost,
+ MTP_PropertiesTypedef *props,
+ uint32_t len);
+
+
+static void PTP_BufferFullCallback(USBH_HandleTypeDef *phost);
+static void PTP_GetString(uint8_t *str, uint8_t* data, uint16_t *len);
+static uint32_t PTP_GetArray16 (uint16_t *array, uint8_t *data, uint32_t offset);
+static uint32_t PTP_GetArray32 (uint32_t *array, uint8_t *data, uint32_t offset);
+/**
+* @}
+*/
+
+
+/** @defgroup USBH_MTP_PTP_Exported_Variables
+* @{
+*/
+/**
+* @}
+*/
+
+
+/** @defgroup USBH_MTP_PTP_Private_Functions
+* @{
+*/
+/**
+ * @brief USBH_PTP_Init
+ * The function Initializes the BOT protocol.
+ * @param phost: Host handle
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_PTP_Init(USBH_HandleTypeDef *phost)
+{
+ MTP_HandleTypeDef *MTP_Handle = phost->pActiveClass->pData;
+
+ /* Set state to idle to be ready for operations */
+ MTP_Handle->ptp.state = PTP_IDLE;
+ MTP_Handle->ptp.req_state = PTP_REQ_SEND;
+
+ return USBH_OK;
+}
+
+/**
+ * @brief USBH_PTP_Process
+ * The function handle the BOT protocol.
+ * @param phost: Host handle
+ * @param lun: Logical Unit Number
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_PTP_Process (USBH_HandleTypeDef *phost)
+{
+ USBH_StatusTypeDef status = USBH_BUSY;
+ USBH_URBStateTypeDef URB_Status = USBH_URB_IDLE;
+ MTP_HandleTypeDef *MTP_Handle = phost->pActiveClass->pData;
+ PTP_ContainerTypedef ptp_container;
+ uint32_t len;
+
+ switch (MTP_Handle->ptp.state)
+ {
+ case PTP_IDLE:
+ /*Do Nothing */
+ break;
+
+ case PTP_OP_REQUEST_STATE:
+ USBH_BulkSendData (phost,
+ (uint8_t*)&(MTP_Handle->ptp.op_container),
+ MTP_Handle->ptp.op_container.length,
+ MTP_Handle->DataOutPipe,
+ 1);
+ MTP_Handle->ptp.state = PTP_OP_REQUEST_WAIT_STATE;
+ break;
+
+ case PTP_OP_REQUEST_WAIT_STATE:
+ URB_Status = USBH_LL_GetURBState(phost, MTP_Handle->DataOutPipe);
+
+ if(URB_Status == USBH_URB_DONE)
+ {
+ if(MTP_Handle->ptp.flags == PTP_DP_NODATA)
+ {
+ MTP_Handle->ptp.state = PTP_RESPONSE_STATE;
+ }
+ else if(MTP_Handle->ptp.flags == PTP_DP_SENDDATA)
+ {
+ MTP_Handle->ptp.state = PTP_DATA_OUT_PHASE_STATE;
+ }
+ else if(MTP_Handle->ptp.flags == PTP_DP_GETDATA)
+ {
+ MTP_Handle->ptp.state = PTP_DATA_IN_PHASE_STATE;
+ }
+#if (USBH_USE_OS == 1)
+ osMessagePut ( phost->os_event, USBH_URB_EVENT, 0);
+#endif
+ }
+ else if(URB_Status == USBH_URB_NOTREADY)
+ {
+ /* Re-send Request */
+ MTP_Handle->ptp.state = PTP_OP_REQUEST_STATE;
+#if (USBH_USE_OS == 1)
+ osMessagePut ( phost->os_event, USBH_URB_EVENT, 0);
+#endif
+ }
+ else if(URB_Status == USBH_URB_STALL)
+ {
+ MTP_Handle->ptp.state = PTP_ERROR;
+#if (USBH_USE_OS == 1)
+ osMessagePut ( phost->os_event, USBH_URB_EVENT, 0);
+#endif
+ }
+ break;
+
+ case PTP_DATA_OUT_PHASE_STATE:
+
+ USBH_BulkSendData (phost,
+ MTP_Handle->ptp.data_ptr,
+ MTP_Handle->DataOutEpSize ,
+ MTP_Handle->DataOutPipe,
+ 1);
+
+
+ MTP_Handle->ptp.state = PTP_DATA_OUT_PHASE_WAIT_STATE;
+ break;
+
+ case PTP_DATA_OUT_PHASE_WAIT_STATE:
+ URB_Status = USBH_LL_GetURBState(phost, MTP_Handle->DataOutPipe);
+
+ if(URB_Status == USBH_URB_DONE)
+ {
+ /* Adjudt Data pointer and data length */
+ if(MTP_Handle->ptp.data_length > MTP_Handle->DataOutEpSize)
+ {
+ MTP_Handle->ptp.data_ptr += MTP_Handle->DataOutEpSize;
+ MTP_Handle->ptp.data_length -= MTP_Handle->DataOutEpSize;
+ MTP_Handle->ptp.data_packet += MTP_Handle->DataOutEpSize;
+
+ if(MTP_Handle->ptp.data_packet >= PTP_USB_BULK_PAYLOAD_LEN_READ)
+ {
+ PTP_BufferFullCallback (phost);
+ MTP_Handle->ptp.data_packet = 0;
+ MTP_Handle->ptp.iteration++;
+ }
+
+ }
+ else
+ {
+ MTP_Handle->ptp.data_length = 0;
+ }
+
+ /* More Data To be Sent */
+ if(MTP_Handle->ptp.data_length > 0)
+ {
+ USBH_BulkSendData (phost,
+ MTP_Handle->ptp.data_ptr,
+ MTP_Handle->DataOutEpSize ,
+ MTP_Handle->DataOutPipe,
+ 1);
+ }
+ else
+ {
+ /* If value was 0, and successful transfer, then change the state */
+ MTP_Handle->ptp.state = PTP_RESPONSE_STATE;
+ }
+#if (USBH_USE_OS == 1)
+ osMessagePut ( phost->os_event, USBH_URB_EVENT, 0);
+#endif
+ }
+
+ else if(URB_Status == USBH_URB_NOTREADY)
+ {
+ /* Re-send same data */
+ MTP_Handle->ptp.state = PTP_DATA_OUT_PHASE_STATE;
+#if (USBH_USE_OS == 1)
+ osMessagePut ( phost->os_event, USBH_URB_EVENT, 0);
+#endif
+ }
+
+ else if(URB_Status == USBH_URB_STALL)
+ {
+ MTP_Handle->ptp.state = PTP_ERROR;
+#if (USBH_USE_OS == 1)
+ osMessagePut ( phost->os_event, USBH_URB_EVENT, 0);
+#endif
+ }
+ break;
+
+ case PTP_DATA_IN_PHASE_STATE:
+ /* Send first packet */
+ USBH_BulkReceiveData (phost,
+ MTP_Handle->ptp.data_ptr,
+ MTP_Handle->DataInEpSize,
+ MTP_Handle->DataInPipe);
+
+ MTP_Handle->ptp.state = PTP_DATA_IN_PHASE_WAIT_STATE;
+ break;
+
+ case PTP_DATA_IN_PHASE_WAIT_STATE:
+ URB_Status = USBH_LL_GetURBState(phost, MTP_Handle->DataInPipe);
+
+ if(URB_Status == USBH_URB_DONE)
+ {
+ len = USBH_LL_GetLastXferSize (phost, MTP_Handle->DataInPipe);
+
+ if( MTP_Handle->ptp.data_packet_counter++ == 0)
+ {
+ /* This is the first packet; so retrieve exact data length from payload */
+ MTP_Handle->ptp.data_length = *(uint32_t*)(MTP_Handle->ptp.data_ptr);
+ MTP_Handle->ptp.iteration = 0;
+ }
+
+ if((len >= MTP_Handle->DataInEpSize) && (MTP_Handle->ptp.data_length > 0))
+ {
+ MTP_Handle->ptp.data_ptr += len;
+ MTP_Handle->ptp.data_length -= len;
+ MTP_Handle->ptp.data_packet += len;
+
+ if(MTP_Handle->ptp.data_packet >= PTP_USB_BULK_PAYLOAD_LEN_READ)
+ {
+ PTP_BufferFullCallback (phost);
+ MTP_Handle->ptp.data_packet = 0;
+ MTP_Handle->ptp.iteration++;
+ }
+
+ /* Continue receiving data*/
+ USBH_BulkReceiveData (phost,
+ MTP_Handle->ptp.data_ptr,
+ MTP_Handle->DataInEpSize,
+ MTP_Handle->DataInPipe);
+ }
+ else
+ {
+ MTP_Handle->ptp.data_length -= len;
+ MTP_Handle->ptp.state = PTP_RESPONSE_STATE;
+#if (USBH_USE_OS == 1)
+ osMessagePut ( phost->os_event, USBH_URB_EVENT, 0);
+#endif
+ }
+ }
+ else if(URB_Status == USBH_URB_STALL)
+ {
+ MTP_Handle->ptp.state = PTP_ERROR;
+#if (USBH_USE_OS == 1)
+ osMessagePut ( phost->os_event, USBH_URB_EVENT, 0);
+#endif
+ }
+ break;
+
+ case PTP_RESPONSE_STATE:
+
+ USBH_BulkReceiveData (phost,
+ (uint8_t*)&(MTP_Handle->ptp.resp_container),
+ PTP_USB_BULK_REQ_RESP_MAX_LEN ,
+ MTP_Handle->DataInPipe);
+
+ MTP_Handle->ptp.state = PTP_RESPONSE_WAIT_STATE;
+ break;
+
+ case PTP_RESPONSE_WAIT_STATE:
+ URB_Status = USBH_LL_GetURBState(phost, MTP_Handle->DataInPipe);
+
+ if(URB_Status == USBH_URB_DONE)
+ {
+ USBH_PTP_GetResponse (phost, &ptp_container);
+
+ if(ptp_container.Code == PTP_RC_OK)
+ {
+ status = USBH_OK;
+ }
+ else
+ {
+ status = USBH_FAIL;
+ }
+ MTP_Handle->ptp.req_state = PTP_REQ_SEND;
+ }
+ else if(URB_Status == USBH_URB_STALL)
+ {
+ MTP_Handle->ptp.state = PTP_ERROR;
+#if (USBH_USE_OS == 1)
+ osMessagePut ( phost->os_event, USBH_URB_EVENT, 0);
+#endif
+ }
+ break;
+
+ case PTP_ERROR:
+ MTP_Handle->ptp.req_state = PTP_REQ_SEND;
+ break;
+
+ default:
+ break;
+ }
+ return status;
+}
+
+/**
+ * @brief USBH_PTP_OpenSession
+ * Open a new session
+ * @param phost: Host handle
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_PTP_SendRequest (USBH_HandleTypeDef *phost, PTP_ContainerTypedef *req)
+{
+ USBH_StatusTypeDef status = USBH_OK;
+ MTP_HandleTypeDef *MTP_Handle = phost->pActiveClass->pData;
+
+ /* Clear PTP Data container*/
+ USBH_memset(&(MTP_Handle->ptp.op_container), 0, sizeof(PTP_OpContainerTypedef));
+
+ /* build appropriate USB container */
+ MTP_Handle->ptp.op_container.length = PTP_USB_BULK_REQ_LEN- (sizeof(uint32_t)*(5-req->Nparam));
+ MTP_Handle->ptp.op_container.type = PTP_USB_CONTAINER_COMMAND;
+ MTP_Handle->ptp.op_container.code = req->Code;
+ MTP_Handle->ptp.op_container.trans_id = req->Transaction_ID;
+ MTP_Handle->ptp.op_container.param1 = req->Param1;
+ MTP_Handle->ptp.op_container.param2 = req->Param2;
+ MTP_Handle->ptp.op_container.param3 = req->Param3;
+ MTP_Handle->ptp.op_container.param4 = req->Param4;
+ MTP_Handle->ptp.op_container.param5 = req->Param5;
+
+ return status;
+}
+
+/**
+ * @brief USBH_PTP_OpenSession
+ * Open a new session
+ * @param phost: Host handle
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_PTP_GetResponse (USBH_HandleTypeDef *phost, PTP_ContainerTypedef *resp)
+{
+ USBH_StatusTypeDef status = USBH_OK;
+ MTP_HandleTypeDef *MTP_Handle = phost->pActiveClass->pData;
+
+ /* build an appropriate PTPContainer */
+ resp->Code = MTP_Handle->ptp.resp_container.code;
+ resp->SessionID = MTP_Handle->ptp.session_id;
+ resp->Transaction_ID = MTP_Handle->ptp.resp_container.trans_id;
+ resp->Param1 = MTP_Handle->ptp.resp_container.param1;
+ resp->Param2 = MTP_Handle->ptp.resp_container.param2;
+ resp->Param3 = MTP_Handle->ptp.resp_container.param3;
+ resp->Param4 = MTP_Handle->ptp.resp_container.param4;
+ resp->Param5 = MTP_Handle->ptp.resp_container.param5;
+
+ return status;
+}
+
+/**
+ * @brief The function informs user that data buffer is full
+ * @param phost: host handle
+ * @retval None
+ */
+void PTP_BufferFullCallback(USBH_HandleTypeDef *phost)
+{
+ MTP_HandleTypeDef *MTP_Handle = phost->pActiveClass->pData;
+
+ switch (MTP_Handle->ptp.data_container.code)
+ {
+ case PTP_OC_GetDeviceInfo:
+ PTP_DecodeDeviceInfo (phost, &(MTP_Handle->info.devinfo));
+ break;
+
+ case PTP_OC_GetPartialObject:
+ case PTP_OC_GetObject:
+
+ /* first packet is in the PTP data payload buffer */
+ if(MTP_Handle->ptp.iteration == 0)
+ {
+ /* copy it to object */
+ USBH_memcpy(MTP_Handle->ptp.object_ptr, MTP_Handle->ptp.data_container.payload.data, PTP_USB_BULK_PAYLOAD_LEN_READ);
+
+ /* next packet should be directly copied to object */
+ MTP_Handle->ptp.data_ptr = (MTP_Handle->ptp.object_ptr + PTP_USB_BULK_PAYLOAD_LEN_READ);
+ }
+ break;
+
+ case PTP_OC_SendObject:
+ /* first packet is in the PTP data payload buffer */
+ if(MTP_Handle->ptp.iteration == 0)
+ {
+ /* next packet should be directly copied to object */
+ MTP_Handle->ptp.data_ptr = (MTP_Handle->ptp.object_ptr + PTP_USB_BULK_PAYLOAD_LEN_READ);
+ }
+ break;
+
+ default:
+ break;
+
+
+ }
+}
+
+/**
+ * @brief PTP_GetDeviceInfo
+ * Gets device info dataset and fills deviceinfo structure.
+ * @param phost: Host handle
+ * @param dev_info: Device info structure
+ * @retval None
+ */
+static void PTP_DecodeDeviceInfo (USBH_HandleTypeDef *phost, PTP_DeviceInfoTypedef *dev_info)
+{
+ MTP_HandleTypeDef *MTP_Handle = phost->pActiveClass->pData;
+ uint8_t *data = MTP_Handle->ptp.data_container.payload.data;
+ uint32_t totallen;
+ uint16_t len;
+
+ /* Max device info is PTP_USB_BULK_HS_MAX_PACKET_LEN_READ */
+ USBH_DbgLog (" MTP device info size exceeds internal buffer size.\
+ only available data are decoded.");
+
+ if(MTP_Handle->ptp.iteration == 0)
+ {
+ dev_info->StandardVersion = LE16(&data[PTP_di_StandardVersion]);
+ dev_info->VendorExtensionID = LE32(&data[PTP_di_VendorExtensionID]);
+ dev_info->VendorExtensionVersion = LE16(&data[PTP_di_VendorExtensionVersion]);
+ PTP_GetString(dev_info->VendorExtensionDesc, &data[PTP_di_VendorExtensionDesc], &len);
+
+ totallen=len*2+1;
+ dev_info->FunctionalMode = LE16(&data[PTP_di_FunctionalMode+totallen]);
+ dev_info->OperationsSupported_len = PTP_GetArray16 ((uint16_t *)&dev_info->OperationsSupported,
+ data,
+ PTP_di_OperationsSupported+totallen);
+
+ totallen=totallen+dev_info->OperationsSupported_len*sizeof(uint16_t)+sizeof(uint32_t);
+ dev_info->EventsSupported_len = PTP_GetArray16 ((uint16_t *)&dev_info->EventsSupported,
+ data,
+ PTP_di_OperationsSupported+totallen);
+
+ totallen=totallen+dev_info->EventsSupported_len*sizeof(uint16_t)+sizeof(uint32_t);
+ dev_info->DevicePropertiesSupported_len = PTP_GetArray16 ((uint16_t *)&dev_info->DevicePropertiesSupported,
+ data,
+ PTP_di_OperationsSupported+totallen);
+
+ totallen=totallen+dev_info->DevicePropertiesSupported_len*sizeof(uint16_t)+sizeof(uint32_t);
+
+ dev_info->CaptureFormats_len = PTP_GetArray16 ((uint16_t *)&dev_info->CaptureFormats,
+ data,
+ PTP_di_OperationsSupported+totallen);
+
+ totallen=totallen+dev_info->CaptureFormats_len*sizeof(uint16_t)+sizeof(uint32_t);
+ dev_info->ImageFormats_len = PTP_GetArray16 ((uint16_t *)&dev_info->ImageFormats,
+ data,
+ PTP_di_OperationsSupported+totallen);
+
+ totallen=totallen+dev_info->ImageFormats_len*sizeof(uint16_t)+sizeof(uint32_t);
+ PTP_GetString(dev_info->Manufacturer, &data[PTP_di_OperationsSupported+totallen], &len);
+
+ totallen+=len*2+1;
+ PTP_GetString(dev_info->Model, &data[PTP_di_OperationsSupported+totallen], &len);
+
+ totallen+=len*2+1;
+ PTP_GetString(dev_info->DeviceVersion, &data[PTP_di_OperationsSupported+totallen], &len);
+
+ totallen+=len*2+1;
+ PTP_GetString(dev_info->SerialNumber, &data[PTP_di_OperationsSupported+totallen], &len);
+ }
+}
+
+/**
+ * @brief PTP_GetStorageIDs
+ * Gets Storage Ids and fills stor_ids structure.
+ * @param phost: Host handle
+ * @param stor_ids: Storage IDsstructure
+ * @retval None
+ */
+static void PTP_GetStorageIDs (USBH_HandleTypeDef *phost, PTP_StorageIDsTypedef *stor_ids)
+{
+ MTP_HandleTypeDef *MTP_Handle = phost->pActiveClass->pData;
+ uint8_t *data = MTP_Handle->ptp.data_container.payload.data;
+
+ stor_ids->n = PTP_GetArray32 (stor_ids->Storage, data, 0);
+}
+
+
+/**
+ * @brief PTP_GetStorageInfo
+ * Gets Storage Info and fills stor_info structure.
+ * @param phost: Host handle
+ * @param stor_ids: Storage IDsstructure
+ * @retval None
+ */
+static void PTP_GetStorageInfo (USBH_HandleTypeDef *phost, uint32_t storage_id, PTP_StorageInfoTypedef *stor_info)
+{
+ MTP_HandleTypeDef *MTP_Handle = phost->pActiveClass->pData;
+ uint8_t *data = MTP_Handle->ptp.data_container.payload.data;
+
+ uint16_t len;
+
+ stor_info->StorageType=LE16(&data[PTP_si_StorageType]);
+ stor_info->FilesystemType=LE16(&data[PTP_si_FilesystemType]);
+ stor_info->AccessCapability=LE16(&data[PTP_si_AccessCapability]);
+ stor_info->MaxCapability=LE64(&data[PTP_si_MaxCapability]);
+ stor_info->FreeSpaceInBytes=LE64(&data[PTP_si_FreeSpaceInBytes]);
+ stor_info->FreeSpaceInImages=LE32(&data[PTP_si_FreeSpaceInImages]);
+
+ PTP_GetString(stor_info->StorageDescription, &data[PTP_si_StorageDescription], &len);
+ PTP_GetString(stor_info->VolumeLabel, &data[PTP_si_StorageDescription+len*2+1], &len);
+}
+
+/**
+ * @brief PTP_GetObjectInfo
+ * Gets objectInfo and fills object_info structure.
+ * @param phost: Host handle
+ * @param object_info: object info structure
+ * @retval None
+ */
+static void PTP_GetObjectInfo (USBH_HandleTypeDef *phost, PTP_ObjectInfoTypedef *object_info)
+{
+ MTP_HandleTypeDef *MTP_Handle = phost->pActiveClass->pData;
+ uint8_t *data = MTP_Handle->ptp.data_container.payload.data;
+ uint16_t filenamelen;
+
+ object_info->StorageID=LE32(&data[PTP_oi_StorageID]);
+ object_info->ObjectFormat=LE16(&data[PTP_oi_ObjectFormat]);
+ object_info->ProtectionStatus=LE16(&data[PTP_oi_ProtectionStatus]);
+ object_info->ObjectCompressedSize=LE32(&data[PTP_oi_ObjectCompressedSize]);
+
+ /* For Samsung Galaxy */
+ if ((data[PTP_oi_filenamelen] == 0) && (data[PTP_oi_filenamelen+4] != 0))
+ {
+ data += 4;
+ }
+ object_info->ThumbFormat=LE16(&data[PTP_oi_ThumbFormat]);
+ object_info->ThumbCompressedSize=LE32(&data[PTP_oi_ThumbCompressedSize]);
+ object_info->ThumbPixWidth=LE32(&data[PTP_oi_ThumbPixWidth]);
+ object_info->ThumbPixHeight=LE32(&data[PTP_oi_ThumbPixHeight]);
+ object_info->ImagePixWidth=LE32(&data[PTP_oi_ImagePixWidth]);
+ object_info->ImagePixHeight=LE32(&data[PTP_oi_ImagePixHeight]);
+ object_info->ImageBitDepth=LE32(&data[PTP_oi_ImageBitDepth]);
+ object_info->ParentObject=LE32(&data[PTP_oi_ParentObject]);
+ object_info->AssociationType=LE16(&data[PTP_oi_AssociationType]);
+ object_info->AssociationDesc=LE32(&data[PTP_oi_AssociationDesc]);
+ object_info->SequenceNumber=LE32(&data[PTP_oi_SequenceNumber]);
+ PTP_GetString(object_info->Filename, &data[PTP_oi_filenamelen], &filenamelen);
+}
+
+
+/**
+ * @brief PTP_GetObjectPropDesc
+ * Gets objectInfo and fills object_info structure.
+ * @param phost: Host handle
+ * @param opd: object prop descriptor structure
+ * @retval None
+ */
+static void PTP_GetObjectPropDesc (USBH_HandleTypeDef *phost, PTP_ObjectPropDescTypeDef *opd, uint32_t opdlen)
+{
+ MTP_HandleTypeDef *MTP_Handle = phost->pActiveClass->pData;
+ uint8_t *data = MTP_Handle->ptp.data_container.payload.data;
+ uint32_t offset = 0, i;
+
+ opd->ObjectPropertyCode=LE16(&data[PTP_opd_ObjectPropertyCode]);
+ opd->DataType=LE16(&data[PTP_opd_DataType]);
+ opd->GetSet=*(uint8_t *)(&data[PTP_opd_GetSet]);
+
+ offset = PTP_opd_FactoryDefaultValue;
+ PTP_GetDevicePropValue (phost, &offset, opdlen, &opd->FactoryDefaultValue, opd->DataType);
+
+ opd->GroupCode=LE32(&data[offset]);
+ offset+=sizeof(uint32_t);
+
+ opd->FormFlag=*(uint8_t *)(&data[offset]);
+ offset+=sizeof(uint8_t);
+
+ switch (opd->FormFlag)
+ {
+ case PTP_OPFF_Range:
+ PTP_GetDevicePropValue(phost, &offset, opdlen, &opd->FORM.Range.MinimumValue, opd->DataType);
+ PTP_GetDevicePropValue(phost, &offset, opdlen, &opd->FORM.Range.MaximumValue, opd->DataType);
+ PTP_GetDevicePropValue(phost, &offset, opdlen, &opd->FORM.Range.StepSize, opd->DataType);
+ break;
+
+ case PTP_OPFF_Enumeration:
+
+ opd->FORM.Enum.NumberOfValues = LE16(&data[offset]);
+ offset+=sizeof(uint16_t);
+
+ for (i=0 ; i < opd->FORM.Enum.NumberOfValues ; i++)
+ {
+ PTP_GetDevicePropValue(phost, &offset, opdlen, &opd->FORM.Enum.SupportedValue[i], opd->DataType);
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+/**
+ * @brief PTP_GetDevicePropValue
+ * Gets objectInfo and fills object_info structure.
+ * @param phost: Host handle
+ * @param opd: object prop descriptor structure
+ * @retval None
+ */
+static void PTP_GetDevicePropValue(USBH_HandleTypeDef *phost,
+ uint32_t *offset,
+ uint32_t total,
+ PTP_PropertyValueTypedef* value,
+ uint16_t datatype)
+{
+ MTP_HandleTypeDef *MTP_Handle = phost->pActiveClass->pData;
+ uint8_t *data = MTP_Handle->ptp.data_container.payload.data;
+ uint16_t len;
+ switch (datatype)
+ {
+ case PTP_DTC_INT8:
+ value->i8 = *(uint8_t *)&(data[*offset]);
+ *offset += 1;
+ break;
+ case PTP_DTC_UINT8:
+ value->u8 = *(uint8_t *)&(data[*offset]);
+ *offset += 1;
+ break;
+ case PTP_DTC_INT16:
+
+ value->i16 = LE16(&(data[*offset]));
+ *offset += 2;
+ break;
+ case PTP_DTC_UINT16:
+ value->u16 = LE16(&(data[*offset]));
+ *offset += 2;
+ break;
+ case PTP_DTC_INT32:
+ value->i32 = LE32(&(data[*offset]));
+ *offset += 4;
+ break;
+ case PTP_DTC_UINT32:
+ value->u32 = LE32(&(data[*offset]));
+ *offset += 4;
+ break;
+ case PTP_DTC_INT64:
+ value->i64 = LE64(&(data[*offset]));
+ *offset += 8;
+ break;
+ case PTP_DTC_UINT64:
+ value->u64 = LE64(&(data[*offset]));
+ *offset += 8;
+ break;
+
+ case PTP_DTC_UINT128:
+ *offset += 16;
+ break;
+ case PTP_DTC_INT128:
+ *offset += 16;
+ break;
+
+ case PTP_DTC_STR:
+
+ PTP_GetString((uint8_t *)value->str, (uint8_t *)&(data[*offset]), &len);
+ *offset += len*2+1;
+ break;
+ default:
+ break;
+ }
+}
+
+
+/**
+ * @brief PTP_GetDevicePropValue
+ * Gets objectInfo and fills object_info structure.
+ * @param phost: Host handle
+ * @param opd: object prop descriptor structure
+ * @retval None
+ */
+static uint32_t PTP_GetObjectPropList (USBH_HandleTypeDef *phost,
+ MTP_PropertiesTypedef *props,
+ uint32_t len)
+{
+ MTP_HandleTypeDef *MTP_Handle = phost->pActiveClass->pData;
+ uint8_t *data = MTP_Handle->ptp.data_container.payload.data;
+ uint32_t prop_count;
+ uint32_t offset = 0, i;
+
+ prop_count = LE32(data);
+
+
+ if (prop_count == 0)
+ {
+ return 0;
+ }
+
+ data += sizeof(uint32_t);
+ len -= sizeof(uint32_t);
+
+ for (i = 0; i < prop_count; i++)
+ {
+ if (len <= 0)
+ {
+ return 0;
+ }
+
+ props[i].ObjectHandle = LE32(data);
+ data += sizeof(uint32_t);
+ len -= sizeof(uint32_t);
+
+ props[i].property = LE16(data);
+ data += sizeof(uint16_t);
+ len -= sizeof(uint16_t);
+
+ props[i].datatype = LE16(data);
+ data += sizeof(uint16_t);
+ len -= sizeof(uint16_t);
+
+ offset = 0;
+
+ PTP_GetDevicePropValue(phost, &offset, len, &props[i].propval, props[i].datatype);
+
+ data += offset;
+ len -= offset;
+ }
+
+ return prop_count;
+}
+
+/**
+ * @brief PTP_GetString
+ * Gets SCII String from.
+ * @param str: ascii string
+ * @param data: Device info structure
+ * @retval None
+ */
+static void PTP_GetString (uint8_t *str, uint8_t* data, uint16_t *len)
+{
+ uint16_t strlength;
+ uint16_t idx;
+
+ *len = data[0];
+ strlength = 2 * data[0];
+ data ++; /* Adjust the offset ignoring the String Len */
+
+ for (idx = 0; idx < strlength; idx+=2 )
+ {
+ /* Copy Only the string and ignore the UNICODE ID, hence add the src */
+ *str = data[idx];
+ str++;
+ }
+ *str = 0; /* mark end of string */
+}
+
+/**
+ * @brief PTP_GetString
+ * Gets SCII String from.
+ * @param str: ascii string
+ * @param data: Device info structure
+ * @retval None
+ */
+
+static uint32_t PTP_GetArray16 (uint16_t *array, uint8_t *data, uint32_t offset)
+{
+ uint32_t size, idx = 0;
+
+ size=LE32(&data[offset]);
+ while (size > idx)
+ {
+ array[idx] = LE16(&data[offset+(sizeof(uint16_t)*(idx+2))]);
+ idx++;
+ }
+ return size;
+}
+
+/**
+ * @brief PTP_GetString
+ * Gets SCII String from.
+ * @param str: ascii string
+ * @param data: Device info structure
+ * @retval None
+ */
+
+static uint32_t PTP_GetArray32 (uint32_t *array, uint8_t *data, uint32_t offset)
+{
+ uint32_t size, idx = 0;
+
+ size=LE32(&data[offset]);
+ while (size > idx)
+ {
+ array[idx] = LE32(&data[offset+(sizeof(uint32_t)*(idx+1))]);
+ idx++;
+ }
+ return size;
+}
+
+/*******************************************************************************
+
+ PTP Requests
+
+*******************************************************************************/
+/**
+ * @brief USBH_PTP_OpenSession
+ * Open a new session
+ * @param phost: Host handle
+ * @param session: Session ID (MUST BE > 0)
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_PTP_OpenSession (USBH_HandleTypeDef *phost, uint32_t session)
+{
+ USBH_StatusTypeDef status = USBH_BUSY;
+ MTP_HandleTypeDef *MTP_Handle = phost->pActiveClass->pData;
+ PTP_ContainerTypedef ptp_container;
+
+ switch(MTP_Handle->ptp.req_state)
+ {
+ case PTP_REQ_SEND:
+
+ /* Init session params */
+ MTP_Handle->ptp.transaction_id = 0x00000000;
+ MTP_Handle->ptp.session_id = session;
+ MTP_Handle->ptp.flags = PTP_DP_NODATA;
+
+ /* Fill operation request params */
+ ptp_container.Code = PTP_OC_OpenSession;
+ ptp_container.SessionID = session;
+ ptp_container.Transaction_ID = MTP_Handle->ptp.transaction_id ++;
+ ptp_container.Param1 = session;
+ ptp_container.Nparam = 1;
+
+ /* convert request packet inti USB raw packet*/
+ USBH_PTP_SendRequest (phost, &ptp_container);
+
+ /* Setup State machine and start transfer */
+ MTP_Handle->ptp.state = PTP_OP_REQUEST_STATE;
+ MTP_Handle->ptp.req_state = PTP_REQ_WAIT;
+ status = USBH_BUSY;
+ break;
+
+ case PTP_REQ_WAIT:
+ status = USBH_PTP_Process(phost);
+ break;
+
+ default:
+ break;
+ }
+ return status;
+}
+
+/**
+ * @brief USBH_PTP_GetDevicePropDesc
+ * Gets object partially
+ * @param phost: Host handle
+ * @param dev_info: Device info structure
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_PTP_GetDevicePropDesc (USBH_HandleTypeDef *phost,
+ uint16_t propcode,
+ PTP_DevicePropDescTypdef* devicepropertydesc)
+{
+ USBH_StatusTypeDef status = USBH_BUSY;
+ MTP_HandleTypeDef *MTP_Handle = phost->pActiveClass->pData;
+ PTP_ContainerTypedef ptp_container;
+ uint8_t *data = MTP_Handle->ptp.data_container.payload.data;
+ switch(MTP_Handle->ptp.req_state)
+ {
+ case PTP_REQ_SEND:
+
+ /* Set operation request type */
+ MTP_Handle->ptp.flags = PTP_DP_GETDATA;
+ MTP_Handle->ptp.data_ptr = (uint8_t *)&(MTP_Handle->ptp.data_container);
+ MTP_Handle->ptp.data_length = 0;
+ MTP_Handle->ptp.data_packet_counter = 0;
+ MTP_Handle->ptp.data_packet = 0;
+
+ /* Fill operation request params */
+ ptp_container.Code = PTP_OC_GetDevicePropDesc;
+ ptp_container.SessionID = MTP_Handle->ptp.session_id;
+ ptp_container.Transaction_ID = MTP_Handle->ptp.transaction_id ++;
+ ptp_container.Param1 = propcode;
+ ptp_container.Nparam = 1;
+
+ /* convert request packet into USB raw packet*/
+ USBH_PTP_SendRequest (phost, &ptp_container);
+
+ /* Setup State machine and start transfer */
+ MTP_Handle->ptp.state = PTP_OP_REQUEST_STATE;
+ MTP_Handle->ptp.req_state = PTP_REQ_WAIT;
+ status = USBH_BUSY;
+ break;
+
+ case PTP_REQ_WAIT:
+ status = USBH_PTP_Process(phost);
+
+ if(status == USBH_OK)
+ {
+ devicepropertydesc->DevicePropertyCode = LE16(&data[PTP_dpd_DevicePropertyCode]);
+ devicepropertydesc->DataType = LE16(&data[PTP_dpd_DataType]);
+ devicepropertydesc->GetSet = *(uint8_t *)(&data[PTP_dpd_GetSet]);
+ devicepropertydesc->FormFlag = PTP_DPFF_None;
+ }
+ break;
+
+ default:
+ break;
+ }
+ return status;
+}
+/**
+ * @brief USBH_PTP_GetDeviceInfo
+ * Gets device info dataset and fills deviceinfo structure.
+ * @param phost: Host handle
+ * @param dev_info: Device info structure
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_PTP_GetDeviceInfo (USBH_HandleTypeDef *phost, PTP_DeviceInfoTypedef *dev_info)
+{
+ USBH_StatusTypeDef status = USBH_BUSY;
+ MTP_HandleTypeDef *MTP_Handle = phost->pActiveClass->pData;
+ PTP_ContainerTypedef ptp_container;
+
+ switch(MTP_Handle->ptp.req_state)
+ {
+ case PTP_REQ_SEND:
+
+ /* Set operation request type */
+ MTP_Handle->ptp.flags = PTP_DP_GETDATA;
+ MTP_Handle->ptp.data_ptr = (uint8_t *)&(MTP_Handle->ptp.data_container);
+ MTP_Handle->ptp.data_length = 0;
+ MTP_Handle->ptp.data_packet_counter = 0;
+ MTP_Handle->ptp.data_packet = 0;
+
+ /* Fill operation request params */
+ ptp_container.Code = PTP_OC_GetDeviceInfo;
+ ptp_container.SessionID = MTP_Handle->ptp.session_id;
+ ptp_container.Transaction_ID = MTP_Handle->ptp.transaction_id ++;
+ ptp_container.Nparam = 0;
+
+ /* convert request packet inti USB raw packet*/
+ USBH_PTP_SendRequest (phost, &ptp_container);
+
+ /* Setup State machine and start transfer */
+ MTP_Handle->ptp.state = PTP_OP_REQUEST_STATE;
+ MTP_Handle->ptp.req_state = PTP_REQ_WAIT;
+ status = USBH_BUSY;
+ break;
+
+ case PTP_REQ_WAIT:
+ status = USBH_PTP_Process(phost);
+
+ if(status == USBH_OK)
+ {
+ PTP_DecodeDeviceInfo (phost, dev_info);
+ }
+ break;
+
+ default:
+ break;
+ }
+ return status;
+}
+
+/**
+ * @brief USBH_PTP_GetStorageIds
+ * Gets device info dataset and fills deviceinfo structure.
+ * @param phost: Host handle
+ * @param dev_info: Device info structure
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_PTP_GetStorageIds (USBH_HandleTypeDef *phost, PTP_StorageIDsTypedef *storage_ids)
+{
+ USBH_StatusTypeDef status = USBH_BUSY;
+ MTP_HandleTypeDef *MTP_Handle = phost->pActiveClass->pData;
+ PTP_ContainerTypedef ptp_container;
+
+ switch(MTP_Handle->ptp.req_state)
+ {
+ case PTP_REQ_SEND:
+
+ /* Set operation request type */
+ MTP_Handle->ptp.flags = PTP_DP_GETDATA;
+ MTP_Handle->ptp.data_ptr = (uint8_t *)&(MTP_Handle->ptp.data_container);
+ MTP_Handle->ptp.data_length = 0;
+ MTP_Handle->ptp.data_packet_counter = 0;
+ MTP_Handle->ptp.data_packet = 0;
+
+ /* Fill operation request params */
+ ptp_container.Code = PTP_OC_GetStorageIDs;
+ ptp_container.SessionID = MTP_Handle->ptp.session_id;
+ ptp_container.Transaction_ID = MTP_Handle->ptp.transaction_id ++;
+ ptp_container.Nparam = 0;
+
+ /* convert request packet inti USB raw packet*/
+ USBH_PTP_SendRequest (phost, &ptp_container);
+
+ /* Setup State machine and start transfer */
+ MTP_Handle->ptp.state = PTP_OP_REQUEST_STATE;
+ MTP_Handle->ptp.req_state = PTP_REQ_WAIT;
+ status = USBH_BUSY;
+ break;
+
+ case PTP_REQ_WAIT:
+ status = USBH_PTP_Process(phost);
+
+ if(status == USBH_OK)
+ {
+ PTP_GetStorageIDs (phost, storage_ids);
+ }
+ break;
+
+ default:
+ break;
+ }
+ return status;
+}
+
+/**
+ * @brief USBH_PTP_GetDeviceInfo
+ * Gets device info dataset and fills deviceinfo structure.
+ * @param phost: Host handle
+ * @param dev_info: Device info structure
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_PTP_GetStorageInfo (USBH_HandleTypeDef *phost, uint32_t storage_id, PTP_StorageInfoTypedef *storage_info)
+{
+ USBH_StatusTypeDef status = USBH_BUSY;
+ MTP_HandleTypeDef *MTP_Handle = phost->pActiveClass->pData;
+ PTP_ContainerTypedef ptp_container;
+
+ switch(MTP_Handle->ptp.req_state)
+ {
+ case PTP_REQ_SEND:
+
+ /* Set operation request type */
+ MTP_Handle->ptp.flags = PTP_DP_GETDATA;
+ MTP_Handle->ptp.data_ptr = (uint8_t *)&(MTP_Handle->ptp.data_container);
+ MTP_Handle->ptp.data_length = 0;
+ MTP_Handle->ptp.data_packet_counter = 0;
+ MTP_Handle->ptp.data_packet = 0;
+
+ /* Fill operation request params */
+ ptp_container.Code = PTP_OC_GetStorageInfo;
+ ptp_container.SessionID = MTP_Handle->ptp.session_id;
+ ptp_container.Transaction_ID = MTP_Handle->ptp.transaction_id ++;
+ ptp_container.Param1 = storage_id;
+ ptp_container.Nparam = 1;
+
+ /* convert request packet inti USB raw packet*/
+ USBH_PTP_SendRequest (phost, &ptp_container);
+
+ /* Setup State machine and start transfer */
+ MTP_Handle->ptp.state = PTP_OP_REQUEST_STATE;
+ MTP_Handle->ptp.req_state = PTP_REQ_WAIT;
+ status = USBH_BUSY;
+ break;
+
+ case PTP_REQ_WAIT:
+ status = USBH_PTP_Process(phost);
+
+ if(status == USBH_OK)
+ {
+ PTP_GetStorageInfo (phost, storage_id, storage_info);
+ }
+ break;
+
+ default:
+ break;
+ }
+ return status;
+}
+
+/**
+ * @brief USBH_PTP_GetNumObjects
+ * Gets device info dataset and fills deviceinfo structure.
+ * @param phost: Host handle
+ * @param dev_info: Device info structure
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_PTP_GetNumObjects (USBH_HandleTypeDef *phost,
+ uint32_t storage_id,
+ uint32_t objectformatcode,
+ uint32_t associationOH,
+ uint32_t* numobs)
+{
+ USBH_StatusTypeDef status = USBH_BUSY;
+ MTP_HandleTypeDef *MTP_Handle = phost->pActiveClass->pData;
+ PTP_ContainerTypedef ptp_container;
+
+ switch(MTP_Handle->ptp.req_state)
+ {
+ case PTP_REQ_SEND:
+
+ /* Set operation request type */
+ MTP_Handle->ptp.flags = PTP_DP_NODATA;
+
+ /* Fill operation request params */
+ ptp_container.Code = PTP_OC_GetNumObjects;
+ ptp_container.SessionID = MTP_Handle->ptp.session_id;
+ ptp_container.Transaction_ID = MTP_Handle->ptp.transaction_id ++;
+ ptp_container.Param1 = storage_id;
+ ptp_container.Param2 = objectformatcode;
+ ptp_container.Param3 = associationOH;
+ ptp_container.Nparam = 3;
+
+ /* convert request packet into USB raw packet*/
+ USBH_PTP_SendRequest (phost, &ptp_container);
+
+ /* Setup State machine and start transfer */
+ MTP_Handle->ptp.state = PTP_OP_REQUEST_STATE;
+ MTP_Handle->ptp.req_state = PTP_REQ_WAIT;
+ status = USBH_BUSY;
+ break;
+
+ case PTP_REQ_WAIT:
+ status = USBH_PTP_Process(phost);
+
+ if(status == USBH_OK)
+ {
+ *numobs = MTP_Handle->ptp.resp_container.param1;
+ }
+ break;
+
+ default:
+ break;
+ }
+ return status;
+}
+
+/**
+ * @brief USBH_PTP_GetObjectHandles
+ * Gets device info dataset and fills deviceinfo structure.
+ * @param phost: Host handle
+ * @param dev_info: Device info structure
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_PTP_GetObjectHandles (USBH_HandleTypeDef *phost,
+ uint32_t storage_id,
+ uint32_t objectformatcode,
+ uint32_t associationOH,
+ PTP_ObjectHandlesTypedef* objecthandles)
+{
+ USBH_StatusTypeDef status = USBH_BUSY;
+ MTP_HandleTypeDef *MTP_Handle = phost->pActiveClass->pData;
+ PTP_ContainerTypedef ptp_container;
+
+ switch(MTP_Handle->ptp.req_state)
+ {
+ case PTP_REQ_SEND:
+
+ /* Set operation request type */
+ MTP_Handle->ptp.flags = PTP_DP_GETDATA;
+ MTP_Handle->ptp.data_ptr = (uint8_t *)&(MTP_Handle->ptp.data_container);
+ MTP_Handle->ptp.data_length = 0;
+ MTP_Handle->ptp.data_packet_counter = 0;
+ MTP_Handle->ptp.data_packet = 0;
+
+ /* Fill operation request params */
+ ptp_container.Code = PTP_OC_GetObjectHandles;
+ ptp_container.SessionID = MTP_Handle->ptp.session_id;
+ ptp_container.Transaction_ID = MTP_Handle->ptp.transaction_id ++;
+ ptp_container.Param1 = storage_id;
+ ptp_container.Param2 = objectformatcode;
+ ptp_container.Param3 = associationOH;
+ ptp_container.Nparam = 3;
+
+ /* convert request packet into USB raw packet*/
+ USBH_PTP_SendRequest (phost, &ptp_container);
+
+ /* Setup State machine and start transfer */
+ MTP_Handle->ptp.state = PTP_OP_REQUEST_STATE;
+ MTP_Handle->ptp.req_state = PTP_REQ_WAIT;
+ status = USBH_BUSY;
+ break;
+
+ case PTP_REQ_WAIT:
+ status = USBH_PTP_Process(phost);
+
+ if(status == USBH_OK)
+ {
+ objecthandles->n = PTP_GetArray32 (objecthandles->Handler,
+ MTP_Handle->ptp.data_container.payload.data,
+ 0);
+ }
+ break;
+
+ default:
+ break;
+ }
+ return status;
+}
+
+/**
+ * @brief USBH_PTP_GetObjectInfo
+ * Gets objert info
+ * @param phost: Host handle
+ * @param dev_info: Device info structure
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_PTP_GetObjectInfo (USBH_HandleTypeDef *phost,
+ uint32_t handle,
+ PTP_ObjectInfoTypedef* object_info)
+{
+ USBH_StatusTypeDef status = USBH_BUSY;
+ MTP_HandleTypeDef *MTP_Handle = phost->pActiveClass->pData;
+ PTP_ContainerTypedef ptp_container;
+
+ switch(MTP_Handle->ptp.req_state)
+ {
+ case PTP_REQ_SEND:
+
+ /* Set operation request type */
+ MTP_Handle->ptp.flags = PTP_DP_GETDATA;
+ MTP_Handle->ptp.data_ptr = (uint8_t *)&(MTP_Handle->ptp.data_container);
+ MTP_Handle->ptp.data_length = 0;
+ MTP_Handle->ptp.data_packet_counter = 0;
+ MTP_Handle->ptp.data_packet = 0;
+
+ /* Fill operation request params */
+ ptp_container.Code = PTP_OC_GetObjectInfo;
+ ptp_container.SessionID = MTP_Handle->ptp.session_id;
+ ptp_container.Transaction_ID = MTP_Handle->ptp.transaction_id ++;
+ ptp_container.Param1 = handle;
+ ptp_container.Nparam = 1;
+
+ /* convert request packet into USB raw packet*/
+ USBH_PTP_SendRequest (phost, &ptp_container);
+
+ /* Setup State machine and start transfer */
+ MTP_Handle->ptp.state = PTP_OP_REQUEST_STATE;
+ MTP_Handle->ptp.req_state = PTP_REQ_WAIT;
+ status = USBH_BUSY;
+ break;
+
+ case PTP_REQ_WAIT:
+ status = USBH_PTP_Process(phost);
+
+ if(status == USBH_OK)
+ {
+ PTP_GetObjectInfo (phost, object_info);
+ }
+ break;
+
+ default:
+ break;
+ }
+ return status;
+}
+
+/**
+ * @brief USBH_PTP_DeleteObject
+ * Delete an object.
+ * @param phost: Host handle
+ * @param handle : Object Handle
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_PTP_DeleteObject (USBH_HandleTypeDef *phost,
+ uint32_t handle,
+ uint32_t objectformatcode)
+{
+ USBH_StatusTypeDef status = USBH_BUSY;
+ MTP_HandleTypeDef *MTP_Handle = phost->pActiveClass->pData;
+ PTP_ContainerTypedef ptp_container;
+
+ switch(MTP_Handle->ptp.req_state)
+ {
+ case PTP_REQ_SEND:
+
+ /* Set operation request type */
+ MTP_Handle->ptp.flags = PTP_DP_NODATA;
+
+ /* Fill operation request params */
+ ptp_container.Code = PTP_OC_DeleteObject;
+ ptp_container.SessionID = MTP_Handle->ptp.session_id;
+ ptp_container.Transaction_ID = MTP_Handle->ptp.transaction_id ++;
+ ptp_container.Param1 = handle;
+ ptp_container.Param2 = objectformatcode;
+ ptp_container.Nparam = 2;
+
+ /* convert request packet into USB raw packet*/
+ USBH_PTP_SendRequest (phost, &ptp_container);
+
+ /* Setup State machine and start transfer */
+ MTP_Handle->ptp.state = PTP_OP_REQUEST_STATE;
+ MTP_Handle->ptp.req_state = PTP_REQ_WAIT;
+ status = USBH_BUSY;
+ break;
+
+ case PTP_REQ_WAIT:
+ status = USBH_PTP_Process(phost);
+ break;
+
+ default:
+ break;
+ }
+ return status;
+}
+
+/**
+ * @brief USBH_PTP_GetObject
+ * Gets object
+ * @param phost: Host handle
+ * @param dev_info: Device info structure
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_PTP_GetObject (USBH_HandleTypeDef *phost,
+ uint32_t handle,
+ uint8_t *object)
+{
+ USBH_StatusTypeDef status = USBH_BUSY;
+ MTP_HandleTypeDef *MTP_Handle = phost->pActiveClass->pData;
+ PTP_ContainerTypedef ptp_container;
+
+ switch(MTP_Handle->ptp.req_state)
+ {
+ case PTP_REQ_SEND:
+
+ /* Set operation request type */
+ MTP_Handle->ptp.flags = PTP_DP_GETDATA;
+ MTP_Handle->ptp.data_ptr = (uint8_t *)&(MTP_Handle->ptp.data_container);
+ MTP_Handle->ptp.data_length = 0;
+ MTP_Handle->ptp.data_packet_counter = 0;
+ MTP_Handle->ptp.data_packet = 0;
+
+ /* set object control params */
+ MTP_Handle->ptp.object_ptr = object;
+
+ /* Fill operation request params */
+ ptp_container.Code = PTP_OC_GetObject;
+ ptp_container.SessionID = MTP_Handle->ptp.session_id;
+ ptp_container.Transaction_ID = MTP_Handle->ptp.transaction_id ++;
+ ptp_container.Param1 = handle;
+ ptp_container.Nparam = 1;
+
+
+ /* convert request packet into USB raw packet*/
+ USBH_PTP_SendRequest (phost, &ptp_container);
+
+ /* Setup State machine and start transfer */
+ MTP_Handle->ptp.state = PTP_OP_REQUEST_STATE;
+ MTP_Handle->ptp.req_state = PTP_REQ_WAIT;
+ status = USBH_BUSY;
+ break;
+
+ case PTP_REQ_WAIT:
+ status = USBH_PTP_Process(phost);
+
+ if(status == USBH_OK)
+ {
+ /* first packet is in the PTP data payload buffer */
+ if(MTP_Handle->ptp.iteration == 0)
+ {
+ /* copy it to object */
+ USBH_memcpy(MTP_Handle->ptp.object_ptr, MTP_Handle->ptp.data_container.payload.data, PTP_USB_BULK_PAYLOAD_LEN_READ);
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ return status;
+}
+
+/**
+ * @brief USBH_PTP_GetPartialObject
+ * Gets object partially
+ * @param phost: Host handle
+ * @param dev_info: Device info structure
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_PTP_GetPartialObject(USBH_HandleTypeDef *phost,
+ uint32_t handle,
+ uint32_t offset,
+ uint32_t maxbytes,
+ uint8_t *object,
+ uint32_t *len)
+{
+ USBH_StatusTypeDef status = USBH_BUSY;
+ MTP_HandleTypeDef *MTP_Handle = phost->pActiveClass->pData;
+ PTP_ContainerTypedef ptp_container;
+
+ switch(MTP_Handle->ptp.req_state)
+ {
+ case PTP_REQ_SEND:
+
+ /* Set operation request type */
+ MTP_Handle->ptp.flags = PTP_DP_GETDATA;
+ MTP_Handle->ptp.data_ptr = (uint8_t *)&(MTP_Handle->ptp.data_container);
+ MTP_Handle->ptp.data_length = 0;
+ MTP_Handle->ptp.data_packet_counter = 0;
+ MTP_Handle->ptp.data_packet = 0;
+
+ /* set object control params */
+ MTP_Handle->ptp.object_ptr = object;
+
+ /* Fill operation request params */
+ ptp_container.Code = PTP_OC_GetPartialObject;
+ ptp_container.SessionID = MTP_Handle->ptp.session_id;
+ ptp_container.Transaction_ID = MTP_Handle->ptp.transaction_id ++;
+ ptp_container.Param1 = handle;
+ ptp_container.Param2 = offset;
+ ptp_container.Param3 = maxbytes;
+ ptp_container.Nparam = 3;
+
+ /* convert request packet into USB raw packet*/
+ USBH_PTP_SendRequest (phost, &ptp_container);
+
+ /* Setup State machine and start transfer */
+ MTP_Handle->ptp.state = PTP_OP_REQUEST_STATE;
+ MTP_Handle->ptp.req_state = PTP_REQ_WAIT;
+ status = USBH_BUSY;
+ break;
+
+ case PTP_REQ_WAIT:
+ status = USBH_PTP_Process(phost);
+
+ if(status == USBH_OK)
+ {
+ *len = MTP_Handle->ptp.resp_container.param1;
+ /* first packet is in the PTP data payload buffer */
+ if(MTP_Handle->ptp.iteration == 0)
+ {
+ /* copy it to object */
+ USBH_memcpy(MTP_Handle->ptp.object_ptr, MTP_Handle->ptp.data_container.payload.data, *len);
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ return status;
+}
+
+/**
+ * @brief USBH_PTP_GetObjectPropsSupported
+ * Gets object partially
+ * @param phost: Host handle
+ * @param dev_info: Device info structure
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_PTP_GetObjectPropsSupported (USBH_HandleTypeDef *phost,
+ uint16_t ofc,
+ uint32_t *propnum,
+ uint16_t *props)
+{
+ USBH_StatusTypeDef status = USBH_BUSY;
+ MTP_HandleTypeDef *MTP_Handle = phost->pActiveClass->pData;
+ PTP_ContainerTypedef ptp_container;
+
+ switch(MTP_Handle->ptp.req_state)
+ {
+ case PTP_REQ_SEND:
+
+ /* Set operation request type */
+ MTP_Handle->ptp.flags = PTP_DP_GETDATA;
+ MTP_Handle->ptp.data_ptr = (uint8_t *)&(MTP_Handle->ptp.data_container);
+ MTP_Handle->ptp.data_length = 0;
+ MTP_Handle->ptp.data_packet_counter = 0;
+ MTP_Handle->ptp.data_packet = 0;
+
+ /* Fill operation request params */
+ ptp_container.Code = PTP_OC_GetObjectPropsSupported;
+ ptp_container.SessionID = MTP_Handle->ptp.session_id;
+ ptp_container.Transaction_ID = MTP_Handle->ptp.transaction_id ++;
+ ptp_container.Param1 = ofc;
+ ptp_container.Nparam = 1;
+
+ /* convert request packet into USB raw packet*/
+ USBH_PTP_SendRequest (phost, &ptp_container);
+
+ /* Setup State machine and start transfer */
+ MTP_Handle->ptp.state = PTP_OP_REQUEST_STATE;
+ MTP_Handle->ptp.req_state = PTP_REQ_WAIT;
+ status = USBH_BUSY;
+ break;
+
+ case PTP_REQ_WAIT:
+ status = USBH_PTP_Process(phost);
+
+ if(status == USBH_OK)
+ {
+ *propnum = PTP_GetArray16 (props, MTP_Handle->ptp.data_container.payload.data, 0);
+ }
+ break;
+
+ default:
+ break;
+ }
+ return status;
+}
+
+/**
+ * @brief USBH_PTP_GetObjectPropDesc
+ * Gets object partially
+ * @param phost: Host handle
+ * @param dev_info: Device info structure
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_PTP_GetObjectPropDesc (USBH_HandleTypeDef *phost,
+ uint16_t opc,
+ uint16_t ofc,
+ PTP_ObjectPropDescTypeDef *opd)
+{
+ USBH_StatusTypeDef status = USBH_BUSY;
+ MTP_HandleTypeDef *MTP_Handle = phost->pActiveClass->pData;
+ PTP_ContainerTypedef ptp_container;
+
+ switch(MTP_Handle->ptp.req_state)
+ {
+ case PTP_REQ_SEND:
+
+ /* Set operation request type */
+ MTP_Handle->ptp.flags = PTP_DP_GETDATA;
+ MTP_Handle->ptp.data_ptr = (uint8_t *)&(MTP_Handle->ptp.data_container);
+ MTP_Handle->ptp.data_length = 0;
+ MTP_Handle->ptp.data_packet_counter = 0;
+ MTP_Handle->ptp.data_packet = 0;
+
+ /* Fill operation request params */
+ ptp_container.Code = PTP_OC_GetObjectPropDesc;
+ ptp_container.SessionID = MTP_Handle->ptp.session_id;
+ ptp_container.Transaction_ID = MTP_Handle->ptp.transaction_id ++;
+ ptp_container.Param1 = opc;
+ ptp_container.Param2 = ofc;
+ ptp_container.Nparam = 2;
+
+ /* convert request packet into USB raw packet*/
+ USBH_PTP_SendRequest (phost, &ptp_container);
+
+ /* Setup State machine and start transfer */
+ MTP_Handle->ptp.state = PTP_OP_REQUEST_STATE;
+ MTP_Handle->ptp.req_state = PTP_REQ_WAIT;
+ status = USBH_BUSY;
+ break;
+
+ case PTP_REQ_WAIT:
+ status = USBH_PTP_Process(phost);
+
+ if(status == USBH_OK)
+ {
+ PTP_GetObjectPropDesc(phost, opd, MTP_Handle->ptp.data_length);
+ }
+ break;
+
+ default:
+ break;
+ }
+ return status;
+}
+
+/**
+ * @brief USBH_PTP_GetObjectPropList
+ * Gets object partially
+ * @param phost: Host handle
+ * @param dev_info: Device info structure
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_PTP_GetObjectPropList (USBH_HandleTypeDef *phost,
+ uint32_t handle,
+ MTP_PropertiesTypedef *pprops,
+ uint32_t *nrofprops)
+{
+ USBH_StatusTypeDef status = USBH_BUSY;
+ MTP_HandleTypeDef *MTP_Handle = phost->pActiveClass->pData;
+ PTP_ContainerTypedef ptp_container;
+
+ switch(MTP_Handle->ptp.req_state)
+ {
+ case PTP_REQ_SEND:
+
+ /* Set operation request type */
+ MTP_Handle->ptp.flags = PTP_DP_GETDATA;
+ MTP_Handle->ptp.data_ptr = (uint8_t *)&(MTP_Handle->ptp.data_container);
+ MTP_Handle->ptp.data_length = 0;
+ MTP_Handle->ptp.data_packet_counter = 0;
+ MTP_Handle->ptp.data_packet = 0;
+
+ /* copy first packet of the object into data container */
+ USBH_memcpy(MTP_Handle->ptp.data_container.payload.data, MTP_Handle->ptp.object_ptr, PTP_USB_BULK_PAYLOAD_LEN_READ);
+
+ /* Fill operation request params */
+ ptp_container.Code = PTP_OC_GetObjPropList;
+ ptp_container.SessionID = MTP_Handle->ptp.session_id;
+ ptp_container.Transaction_ID = MTP_Handle->ptp.transaction_id ++;
+ ptp_container.Param1 = handle;
+ ptp_container.Param2 = 0x00000000U; /* 0x00000000U should be "all formats" */
+ ptp_container.Param3 = 0xFFFFFFFFU; /* 0xFFFFFFFFU should be "all properties" */
+ ptp_container.Param4 = 0x00000000U;
+ ptp_container.Param5 = 0xFFFFFFFFU; /* Return full tree below the Param1 handle */
+ ptp_container.Nparam = 5;
+
+ /* convert request packet into USB raw packet*/
+ USBH_PTP_SendRequest (phost, &ptp_container);
+
+ /* Setup State machine and start transfer */
+ MTP_Handle->ptp.state = PTP_OP_REQUEST_STATE;
+ MTP_Handle->ptp.req_state = PTP_REQ_WAIT;
+ status = USBH_BUSY;
+ break;
+
+ case PTP_REQ_WAIT:
+ status = USBH_PTP_Process(phost);
+
+ if(status == USBH_OK)
+ {
+ PTP_GetObjectPropList (phost, pprops, MTP_Handle->ptp.data_length);
+ }
+ break;
+
+ default:
+ break;
+ }
+ return status;
+}
+
+/**
+ * @brief USBH_PTP_SendObject
+ * Send an object
+ * @param phost: Host handle
+ * @param dev_info: Device info structure
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_PTP_SendObject (USBH_HandleTypeDef *phost,
+ uint32_t handle,
+ uint8_t *object,
+ uint32_t size)
+{
+ USBH_StatusTypeDef status = USBH_BUSY;
+ MTP_HandleTypeDef *MTP_Handle = phost->pActiveClass->pData;
+ PTP_ContainerTypedef ptp_container;
+
+ switch(MTP_Handle->ptp.req_state)
+ {
+ case PTP_REQ_SEND:
+
+ /* Set operation request type */
+ MTP_Handle->ptp.flags = PTP_DP_SENDDATA;
+ MTP_Handle->ptp.data_ptr = (uint8_t *)&(MTP_Handle->ptp.data_container);
+ MTP_Handle->ptp.data_packet_counter = 0;
+ MTP_Handle->ptp.data_packet = 0;
+ MTP_Handle->ptp.iteration = 0;
+
+ /* set object control params */
+ MTP_Handle->ptp.object_ptr = object;
+ MTP_Handle->ptp.data_length = size;
+
+ /* Fill operation request params */
+ ptp_container.Code = PTP_OC_SendObject;
+ ptp_container.SessionID = MTP_Handle->ptp.session_id;
+ ptp_container.Transaction_ID = MTP_Handle->ptp.transaction_id ++;
+ ptp_container.Nparam = 0;
+
+
+ /* convert request packet into USB raw packet*/
+ USBH_PTP_SendRequest (phost, &ptp_container);
+
+ /* Setup State machine and start transfer */
+ MTP_Handle->ptp.state = PTP_OP_REQUEST_STATE;
+ MTP_Handle->ptp.req_state = PTP_REQ_WAIT;
+ status = USBH_BUSY;
+ break;
+
+ case PTP_REQ_WAIT:
+ status = USBH_PTP_Process(phost);
+ break;
+
+ default:
+ break;
+ }
+ return status;
+}
+/**
+* @}
+*/
+
+/**
+* @}
+*/
+
+/**
+* @}
+*/
+
+/**
+* @}
+*/
+
+/**
+* @}
+*/
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
+
+
+
diff --git a/ports/stm32/usbhost/Class/Template/Inc/usbh_template.h b/ports/stm32/usbhost/Class/Template/Inc/usbh_template.h
new file mode 100644
index 000000000..728a36c86
--- /dev/null
+++ b/ports/stm32/usbhost/Class/Template/Inc/usbh_template.h
@@ -0,0 +1,122 @@
+/**
+ ******************************************************************************
+ * @file usbh_mtp.h
+ * @author MCD Application Team
+ * @version V3.0.0
+ * @date 18-February-2014
+ * @brief This file contains all the prototypes for the usbh_template.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 ----------------------------------------------*/
+#ifndef __USBH_TEMPLATE_CORE_H
+#define __USBH_TEMPLATE_CORE_H
+
+/* Includes ------------------------------------------------------------------*/
+#include "usbh_core.h"
+
+
+/** @addtogroup USBH_LIB
+* @{
+*/
+
+/** @addtogroup USBH_CLASS
+* @{
+*/
+
+/** @addtogroup USBH_TEMPLATE_CLASS
+* @{
+*/
+
+/** @defgroup USBH_TEMPLATE_CORE
+* @brief This file is the Header file for USBH_TEMPLATE_CORE.c
+* @{
+*/
+
+
+/**
+ * @}
+ */
+
+/** @defgroup USBH_TEMPLATE_CORE_Exported_Types
+* @{
+*/
+
+/* States for TEMPLATE State Machine */
+
+
+/**
+* @}
+*/
+
+/** @defgroup USBH_TEMPLATE_CORE_Exported_Defines
+* @{
+*/
+
+/**
+* @}
+*/
+
+/** @defgroup USBH_TEMPLATE_CORE_Exported_Macros
+* @{
+*/
+/**
+* @}
+*/
+
+/** @defgroup USBH_TEMPLATE_CORE_Exported_Variables
+* @{
+*/
+extern USBH_ClassTypeDef TEMPLATE_Class;
+#define USBH_TEMPLATE_CLASS &TEMPLATE_Class
+
+/**
+* @}
+*/
+
+/** @defgroup USBH_TEMPLATE_CORE_Exported_FunctionsPrototype
+* @{
+*/
+USBH_StatusTypeDef USBH_TEMPLATE_IOProcess (USBH_HandleTypeDef *phost);
+USBH_StatusTypeDef USBH_TEMPLATE_Init (USBH_HandleTypeDef *phost);
+/**
+* @}
+*/
+
+
+#endif /* __USBH_TEMPLATE_CORE_H */
+
+/**
+* @}
+*/
+
+/**
+* @}
+*/
+
+/**
+* @}
+*/
+
+/**
+* @}
+*/
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
+
diff --git a/ports/stm32/usbhost/Class/Template/Src/usbh_template.c b/ports/stm32/usbhost/Class/Template/Src/usbh_template.c
new file mode 100644
index 000000000..2ea14a89e
--- /dev/null
+++ b/ports/stm32/usbhost/Class/Template/Src/usbh_template.c
@@ -0,0 +1,240 @@
+/**
+ ******************************************************************************
+ * @file usbh_mtp.c
+ * @author MCD Application Team
+ * @version V3.0.0
+ * @date 18-February-2014
+ * @brief This file is the MTP Layer Handlers for USB Host MTP class.
+ *
+ *
+ ******************************************************************************
+ * @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 "usbh_template.h"
+
+/** @addtogroup USBH_LIB
+* @{
+*/
+
+/** @addtogroup USBH_CLASS
+* @{
+*/
+
+/** @addtogroup USBH_TEMPLATE_CLASS
+* @{
+*/
+
+/** @defgroup USBH_TEMPLATE_CORE
+* @brief This file includes TEMPLATE Layer Handlers for USB Host TEMPLATE class.
+* @{
+*/
+
+/** @defgroup USBH_TEMPLATE_CORE_Private_TypesDefinitions
+* @{
+*/
+/**
+* @}
+*/
+
+
+/** @defgroup USBH_TEMPLATE_CORE_Private_Defines
+* @{
+*/
+/**
+* @}
+*/
+
+
+/** @defgroup USBH_TEMPLATE_CORE_Private_Macros
+* @{
+*/
+/**
+* @}
+*/
+
+
+/** @defgroup USBH_TEMPLATE_CORE_Private_Variables
+* @{
+*/
+/**
+* @}
+*/
+
+
+/** @defgroup USBH_TEMPLATE_CORE_Private_FunctionPrototypes
+* @{
+*/
+
+static USBH_StatusTypeDef USBH_TEMPLATE_InterfaceInit (USBH_HandleTypeDef *phost);
+
+static USBH_StatusTypeDef USBH_TEMPLATE_InterfaceDeInit (USBH_HandleTypeDef *phost);
+
+static USBH_StatusTypeDef USBH_TEMPLATE_Process(USBH_HandleTypeDef *phost);
+
+static USBH_StatusTypeDef USBH_TEMPLATE_ClassRequest (USBH_HandleTypeDef *phost);
+
+
+USBH_ClassTypeDef TEMPLATE_Class =
+{
+ "TEMPLATE",
+ USB_TEMPLATE_CLASS,
+ USBH_TEMPLATE_InterfaceInit,
+ USBH_TEMPLATE_InterfaceDeInit,
+ USBH_TEMPLATE_ClassRequest,
+ USBH_TEMPLATE_Process
+};
+/**
+* @}
+*/
+
+
+/** @defgroup USBH_TEMPLATE_CORE_Private_Functions
+* @{
+*/
+
+/**
+ * @brief USBH_TEMPLATE_InterfaceInit
+ * The function init the TEMPLATE class.
+ * @param phost: Host handle
+ * @retval USBH Status
+ */
+static USBH_StatusTypeDef USBH_TEMPLATE_InterfaceInit (USBH_HandleTypeDef *phost)
+{
+
+ return USBH_OK;
+}
+
+
+
+/**
+ * @brief USBH_TEMPLATE_InterfaceDeInit
+ * The function DeInit the Pipes used for the TEMPLATE class.
+ * @param phost: Host handle
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_TEMPLATE_InterfaceDeInit (USBH_HandleTypeDef *phost)
+{
+
+ return USBH_OK;
+}
+
+/**
+ * @brief USBH_TEMPLATE_ClassRequest
+ * The function is responsible for handling Standard requests
+ * for TEMPLATE class.
+ * @param phost: Host handle
+ * @retval USBH Status
+ */
+static USBH_StatusTypeDef USBH_TEMPLATE_ClassRequest (USBH_HandleTypeDef *phost)
+{
+
+ return USBH_OK;
+}
+
+
+/**
+ * @brief USBH_TEMPLATE_Process
+ * The function is for managing state machine for TEMPLATE data transfers
+ * @param phost: Host handle
+ * @retval USBH Status
+ */
+static USBH_StatusTypeDef USBH_TEMPLATE_Process (USBH_HandleTypeDef *phost)
+{
+
+ return USBH_OK;
+}
+
+
+/**
+ * @brief USBH_TEMPLATE_Init
+ * The function Initialize the TEMPLATE function
+ * @param phost: Host handle
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_TEMPLATE_Init (USBH_HandleTypeDef *phost)
+{
+ USBH_StatusTypeDef Status = USBH_BUSY;
+#if (USBH_USE_OS == 1)
+ osEvent event;
+
+ event = osMessageGet( phost->class_ready_event, osWaitForever );
+
+ if( event.status == osEventMessage )
+ {
+ if(event.value.v == USBH_CLASS_EVENT)
+ {
+#else
+
+ while ((Status == USBH_BUSY) || (Status == USBH_FAIL))
+ {
+ /* Host background process */
+ USBH_Process(phost);
+ if(phost->gState == HOST_CLASS)
+ {
+#endif
+ Status = USBH_OK;
+ }
+ }
+ return Status;
+}
+
+/**
+ * @brief USBH_TEMPLATE_IOProcess
+ * TEMPLATE TEMPLATE process
+ * @param phost: Host handle
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_TEMPLATE_IOProcess (USBH_HandleTypeDef *phost)
+{
+ if (phost->device.is_connected == 1)
+ {
+ if(phost->gState == HOST_CLASS)
+ {
+ USBH_TEMPLATE_Process(phost);
+ }
+ }
+
+ return USBH_OK;
+}
+
+/**
+* @}
+*/
+
+/**
+* @}
+*/
+
+/**
+* @}
+*/
+
+
+/**
+* @}
+*/
+
+
+/**
+* @}
+*/
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/ports/stm32/usbhost/Core/Inc/usbh_conf_template.h b/ports/stm32/usbhost/Core/Inc/usbh_conf_template.h
new file mode 100644
index 000000000..8f85e1360
--- /dev/null
+++ b/ports/stm32/usbhost/Core/Inc/usbh_conf_template.h
@@ -0,0 +1,151 @@
+/**
+ ******************************************************************************
+ * @file USBH_conf.h
+ * @author MCD Application Team
+ * @version V3.0.0
+ * @date 18-February-2014
+ * @brief General low level driver configuration
+ ******************************************************************************
+ * @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 __USBH_CONF__H__
+#define __USBH_CONF__H__
+
+#include "stm32f4xx.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* Includes ------------------------------------------------------------------*/
+
+/** @addtogroup USBH_OTG_DRIVER
+ * @{
+ */
+
+/** @defgroup USBH_CONF
+ * @brief usb otg low level driver configuration file
+ * @{
+ */
+
+/** @defgroup USBH_CONF_Exported_Defines
+ * @{
+ */
+
+#define USBH_MAX_NUM_ENDPOINTS 2
+#define USBH_MAX_NUM_INTERFACES 2
+#define USBH_MAX_NUM_CONFIGURATION 1
+#define USBH_KEEP_CFG_DESCRIPTOR 1
+#define USBH_MAX_NUM_SUPPORTED_CLASS 1
+#define USBH_MAX_SIZE_CONFIGURATION 0x200
+#define USBH_MAX_DATA_BUFFER 0x200
+#define USBH_DEBUG_LEVEL 2
+#define USBH_USE_OS 1
+
+/** @defgroup USBH_Exported_Macros
+ * @{
+ */
+
+ /* Memory management macros */
+#define USBH_malloc malloc
+#define USBH_free free
+#define USBH_memset memset
+#define USBH_memcpy memcpy
+
+ /* DEBUG macros */
+
+
+#if (USBH_DEBUG_LEVEL > 0)
+#define USBH_UsrLog(...) printf(__VA_ARGS__);\
+ printf("\n");
+#else
+#define USBH_UsrLog(...)
+#endif
+
+
+#if (USBH_DEBUG_LEVEL > 1)
+
+#define USBH_ErrLog(...) printf("ERROR: ") ;\
+ printf(__VA_ARGS__);\
+ printf("\n");
+#else
+#define USBH_ErrLog(...)
+#endif
+
+
+#if (USBH_DEBUG_LEVEL > 2)
+#define USBH_DbgLog(...) printf("DEBUG : ") ;\
+ printf(__VA_ARGS__);\
+ printf("\n");
+#else
+#define USBH_DbgLog(...)
+#endif
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+
+/** @defgroup USBH_CONF_Exported_Types
+ * @{
+ */
+/**
+ * @}
+ */
+
+
+/** @defgroup USBH_CONF_Exported_Macros
+ * @{
+ */
+/**
+ * @}
+ */
+
+/** @defgroup USBH_CONF_Exported_Variables
+ * @{
+ */
+/**
+ * @}
+ */
+
+/** @defgroup USBH_CONF_Exported_FunctionsPrototype
+ * @{
+ */
+/**
+ * @}
+ */
+
+
+#endif //__USBH_CONF__H__
+
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
+
diff --git a/ports/stm32/usbhost/Core/Inc/usbh_core.h b/ports/stm32/usbhost/Core/Inc/usbh_core.h
new file mode 100644
index 000000000..bc3da6d1f
--- /dev/null
+++ b/ports/stm32/usbhost/Core/Inc/usbh_core.h
@@ -0,0 +1,161 @@
+/**
+ ******************************************************************************
+ * @file usbh_core.h
+ * @author MCD Application Team
+ * @version V3.0.0
+ * @date 18-February-2014
+ * @brief Header file for usbh_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 ----------------------------------------------*/
+#ifndef __USBH_CORE_H
+#define __USBH_CORE_H
+
+/* Includes ------------------------------------------------------------------*/
+#include "usbh_conf.h"
+#include "usbh_def.h"
+#include "usbh_ioreq.h"
+#include "usbh_pipes.h"
+#include "usbh_ctlreq.h"
+
+/** @addtogroup USBH_LIB
+ * @{
+ */
+
+/** @addtogroup USBH_LIB_CORE
+* @{
+*/
+
+/** @defgroup USBH_CORE
+ * @brief This file is the Header file for usbh_core.c
+ * @{
+ */
+
+
+/** @defgroup USBH_CORE_Exported_Defines
+ * @{
+ */
+
+/**
+ * @}
+ */
+#define HOST_USER_SELECT_CONFIGURATION 1
+#define HOST_USER_CLASS_ACTIVE 2
+#define HOST_USER_CLASS_SELECTED 3
+#define HOST_USER_CONNECTION 4
+#define HOST_USER_DISCONNECTION 5
+
+
+
+/**
+ * @}
+ */
+
+
+
+/** @defgroup USBH_CORE_Exported_Macros
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+/** @defgroup USBH_CORE_Exported_Variables
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+/** @defgroup USBH_CORE_Exported_FunctionsPrototype
+ * @{
+ */
+
+
+USBH_StatusTypeDef USBH_Init(USBH_HandleTypeDef *phost, void (*pUsrFunc)(USBH_HandleTypeDef *phost, uint8_t ), uint8_t id);
+USBH_StatusTypeDef USBH_DeInit(USBH_HandleTypeDef *phost);
+USBH_StatusTypeDef USBH_RegisterClass(USBH_HandleTypeDef *phost, USBH_ClassTypeDef *pclass);
+USBH_StatusTypeDef USBH_SelectInterface(USBH_HandleTypeDef *phost, uint8_t interface);
+uint8_t USBH_FindInterface(USBH_HandleTypeDef *phost,
+ uint8_t Class,
+ uint8_t SubClass,
+ uint8_t Protocol);
+uint8_t USBH_GetActiveClass(USBH_HandleTypeDef *phost);
+
+uint8_t USBH_FindInterfaceIndex(USBH_HandleTypeDef *phost,
+ uint8_t interface_number,
+ uint8_t alt_settings);
+
+USBH_StatusTypeDef USBH_Start (USBH_HandleTypeDef *phost);
+USBH_StatusTypeDef USBH_Stop (USBH_HandleTypeDef *phost);
+USBH_StatusTypeDef USBH_Process (USBH_HandleTypeDef *phost);
+USBH_StatusTypeDef USBH_ReEnumerate (USBH_HandleTypeDef *phost);
+
+/* USBH Low Level Driver */
+USBH_StatusTypeDef USBH_LL_Init (USBH_HandleTypeDef *phost);
+USBH_StatusTypeDef USBH_LL_DeInit (USBH_HandleTypeDef *phost);
+USBH_StatusTypeDef USBH_LL_Start (USBH_HandleTypeDef *phost);
+USBH_StatusTypeDef USBH_LL_Stop (USBH_HandleTypeDef *phost);
+
+USBH_StatusTypeDef USBH_LL_Connect (USBH_HandleTypeDef *phost);
+USBH_StatusTypeDef USBH_LL_Disconnect (USBH_HandleTypeDef *phost);
+USBH_SpeedTypeDef USBH_LL_GetSpeed (USBH_HandleTypeDef *phost);
+USBH_StatusTypeDef USBH_LL_ResetPort (USBH_HandleTypeDef *phost);
+uint32_t USBH_LL_GetLastXferSize (USBH_HandleTypeDef *phost, uint8_t );
+USBH_StatusTypeDef USBH_LL_DriverVBUS (USBH_HandleTypeDef *phost, uint8_t );
+
+USBH_StatusTypeDef USBH_LL_OpenPipe (USBH_HandleTypeDef *phost, uint8_t, uint8_t, uint8_t, uint8_t , uint8_t, uint16_t );
+USBH_StatusTypeDef USBH_LL_ClosePipe (USBH_HandleTypeDef *phost, uint8_t );
+USBH_StatusTypeDef USBH_LL_SubmitURB (USBH_HandleTypeDef *phost, uint8_t, uint8_t,uint8_t, uint8_t, uint8_t*, uint16_t, uint8_t );
+USBH_URBStateTypeDef USBH_LL_GetURBState (USBH_HandleTypeDef *phost, uint8_t );
+#if (USBH_USE_OS == 1)
+USBH_StatusTypeDef USBH_LL_NotifyURBChange (USBH_HandleTypeDef *phost);
+#endif
+USBH_StatusTypeDef USBH_LL_SetToggle (USBH_HandleTypeDef *phost, uint8_t , uint8_t );
+uint8_t USBH_LL_GetToggle (USBH_HandleTypeDef *phost, uint8_t );
+
+/* USBH Time base */
+void USBH_Delay (uint32_t Delay);
+void USBH_LL_SetTimer (USBH_HandleTypeDef *phost, uint32_t );
+void USBH_LL_IncTimer (USBH_HandleTypeDef *phost);
+/**
+ * @}
+ */
+
+#endif /* __CORE_H */
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+* @}
+*/
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
+
+
+
diff --git a/ports/stm32/usbhost/Core/Inc/usbh_ctlreq.h b/ports/stm32/usbhost/Core/Inc/usbh_ctlreq.h
new file mode 100644
index 000000000..cd61755e3
--- /dev/null
+++ b/ports/stm32/usbhost/Core/Inc/usbh_ctlreq.h
@@ -0,0 +1,147 @@
+/**
+ ******************************************************************************
+ * @file usbh_ctlreq.h
+ * @author MCD Application Team
+ * @version V3.0.0
+ * @date 18-February-2014
+ * @brief Header file for usbh_ctlreq.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 ----------------------------------------------*/
+#ifndef __USBH_CTLREQ_H
+#define __USBH_CTLREQ_H
+
+/* Includes ------------------------------------------------------------------*/
+#include "usbh_core.h"
+
+/** @addtogroup USBH_LIB
+ * @{
+ */
+
+/** @addtogroup USBH_LIB_CORE
+* @{
+*/
+
+/** @defgroup USBH_CTLREQ
+ * @brief This file is the
+ * @{
+ */
+
+
+/** @defgroup USBH_CTLREQ_Exported_Defines
+ * @{
+ */
+/*Standard Feature Selector for clear feature command*/
+#define FEATURE_SELECTOR_ENDPOINT 0X00
+#define FEATURE_SELECTOR_DEVICE 0X01
+
+
+#define INTERFACE_DESC_TYPE 0x04
+#define ENDPOINT_DESC_TYPE 0x05
+#define INTERFACE_DESC_SIZE 0x09
+
+/**
+ * @}
+ */
+
+
+/** @defgroup USBH_CTLREQ_Exported_Types
+ * @{
+ */
+/**
+ * @}
+ */
+
+
+/** @defgroup USBH_CTLREQ_Exported_Macros
+ * @{
+ */
+/**
+ * @}
+ */
+
+/** @defgroup USBH_CTLREQ_Exported_Variables
+ * @{
+ */
+extern uint8_t USBH_CfgDesc[512];
+/**
+ * @}
+ */
+
+/** @defgroup USBH_CTLREQ_Exported_FunctionsPrototype
+ * @{
+ */
+USBH_StatusTypeDef USBH_CtlReq (USBH_HandleTypeDef *phost,
+ uint8_t *buff,
+ uint16_t length);
+
+USBH_StatusTypeDef USBH_GetDescriptor(USBH_HandleTypeDef *phost,
+ uint8_t req_type,
+ uint16_t value_idx,
+ uint8_t* buff,
+ uint16_t length );
+
+USBH_StatusTypeDef USBH_Get_DevDesc(USBH_HandleTypeDef *phost,
+ uint8_t length);
+
+USBH_StatusTypeDef USBH_Get_StringDesc(USBH_HandleTypeDef *phost,
+ uint8_t string_index,
+ uint8_t *buff,
+ uint16_t length);
+
+USBH_StatusTypeDef USBH_SetCfg(USBH_HandleTypeDef *phost,
+ uint16_t configuration_value);
+
+USBH_StatusTypeDef USBH_Get_CfgDesc(USBH_HandleTypeDef *phost,
+ uint16_t length);
+
+USBH_StatusTypeDef USBH_SetAddress(USBH_HandleTypeDef *phost,
+ uint8_t DeviceAddress);
+
+USBH_StatusTypeDef USBH_SetInterface(USBH_HandleTypeDef *phost,
+ uint8_t ep_num, uint8_t altSetting);
+
+USBH_StatusTypeDef USBH_ClrFeature(USBH_HandleTypeDef *phost,
+ uint8_t ep_num);
+
+USBH_DescHeader_t *USBH_GetNextDesc (uint8_t *pbuf,
+ uint16_t *ptr);
+/**
+ * @}
+ */
+
+#endif /* __USBH_CTLREQ_H */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+* @}
+*/
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
+
+
diff --git a/ports/stm32/usbhost/Core/Inc/usbh_def.h b/ports/stm32/usbhost/Core/Inc/usbh_def.h
new file mode 100644
index 000000000..cf24d69f3
--- /dev/null
+++ b/ports/stm32/usbhost/Core/Inc/usbh_def.h
@@ -0,0 +1,480 @@
+/**
+ ******************************************************************************
+ * @file usbh_def.h
+ * @author MCD Application Team
+ * @version V3.0.0
+ * @date 18-February-2014
+ * @brief Definitions used in the USB host 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.
+ *
+ ******************************************************************************
+ */
+
+/** @addtogroup USBH_LIB
+ * @{
+ */
+
+/** @addtogroup USBH_LIB_CORE
+* @{
+*/
+
+/** @defgroup USBH_DEF
+ * @brief This file is includes USB descriptors
+ * @{
+ */
+
+#ifndef USBH_DEF_H
+#define USBH_DEF_H
+
+#include "usbh_conf.h"
+
+#ifndef NULL
+#define NULL ((void *)0)
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+
+#define ValBit(VAR,POS) (VAR & (1 << POS))
+#define SetBit(VAR,POS) (VAR |= (1 << POS))
+#define ClrBit(VAR,POS) (VAR &= ((1 << POS)^255))
+
+#define LE16(addr) (((uint16_t)(*((uint8_t *)(addr))))\
+ + (((uint16_t)(*(((uint8_t *)(addr)) + 1))) << 8))
+
+#define LE16S(addr) (uint16_t)(LE16((addr)))
+
+#define LE32(addr) ((((uint32_t)(*(((uint8_t *)(addr)) + 0))) + \
+ (((uint32_t)(*(((uint8_t *)(addr)) + 1))) << 8) + \
+ (((uint32_t)(*(((uint8_t *)(addr)) + 2))) << 16) + \
+ (((uint32_t)(*(((uint8_t *)(addr)) + 3))) << 24)))
+
+#define LE64(addr) ((((uint64_t)(*(((uint8_t *)(addr)) + 0))) + \
+ (((uint64_t)(*(((uint8_t *)(addr)) + 1))) << 8) +\
+ (((uint64_t)(*(((uint8_t *)(addr)) + 2))) << 16) +\
+ (((uint64_t)(*(((uint8_t *)(addr)) + 3))) << 24) +\
+ (((uint64_t)(*(((uint8_t *)(addr)) + 4))) << 32) +\
+ (((uint64_t)(*(((uint8_t *)(addr)) + 5))) << 40) +\
+ (((uint64_t)(*(((uint8_t *)(addr)) + 6))) << 48) +\
+ (((uint64_t)(*(((uint8_t *)(addr)) + 7))) << 56)))
+
+
+#define LE24(addr) ((((uint32_t)(*(((uint8_t *)(addr)) + 0))) + \
+ (((uint32_t)(*(((uint8_t *)(addr)) + 1))) << 8) + \
+ (((uint32_t)(*(((uint8_t *)(addr)) + 2))) << 16)))
+
+
+#define LE32S(addr) (int32_t)(LE32((addr)))
+
+
+
+#define USB_LEN_DESC_HDR 0x02
+#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_SETUP_PKT 0x08
+
+/* bmRequestType :D7 Data Phase Transfer Direction */
+#define USB_REQ_DIR_MASK 0x80
+#define USB_H2D 0x00
+#define USB_D2H 0x80
+
+/* bmRequestType D6..5 Type */
+#define USB_REQ_TYPE_STANDARD 0x00
+#define USB_REQ_TYPE_CLASS 0x20
+#define USB_REQ_TYPE_VENDOR 0x40
+#define USB_REQ_TYPE_RESERVED 0x60
+
+/* bmRequestType D4..0 Recipient */
+#define USB_REQ_RECIPIENT_DEVICE 0x00
+#define USB_REQ_RECIPIENT_INTERFACE 0x01
+#define USB_REQ_RECIPIENT_ENDPOINT 0x02
+#define USB_REQ_RECIPIENT_OTHER 0x03
+
+/* Table 9-4. Standard Request Codes */
+/* bRequest , Value */
+#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
+
+/* Table 9-5. Descriptor Types of USB Specifications */
+#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_DESC_TYPE_INTERFACE_POWER 8
+#define USB_DESC_TYPE_HID 0x21
+#define USB_DESC_TYPE_HID_REPORT 0x22
+
+
+#define USB_DEVICE_DESC_SIZE 18
+#define USB_CONFIGURATION_DESC_SIZE 9
+#define USB_HID_DESC_SIZE 9
+#define USB_INTERFACE_DESC_SIZE 9
+#define USB_ENDPOINT_DESC_SIZE 7
+
+/* Descriptor Type and Descriptor Index */
+/* Use the following values when calling the function USBH_GetDescriptor */
+#define USB_DESC_DEVICE ((USB_DESC_TYPE_DEVICE << 8) & 0xFF00)
+#define USB_DESC_CONFIGURATION ((USB_DESC_TYPE_CONFIGURATION << 8) & 0xFF00)
+#define USB_DESC_STRING ((USB_DESC_TYPE_STRING << 8) & 0xFF00)
+#define USB_DESC_INTERFACE ((USB_DESC_TYPE_INTERFACE << 8) & 0xFF00)
+#define USB_DESC_ENDPOINT ((USB_DESC_TYPE_INTERFACE << 8) & 0xFF00)
+#define USB_DESC_DEVICE_QUALIFIER ((USB_DESC_TYPE_DEVICE_QUALIFIER << 8) & 0xFF00)
+#define USB_DESC_OTHER_SPEED_CONFIGURATION ((USB_DESC_TYPE_OTHER_SPEED_CONFIGURATION << 8) & 0xFF00)
+#define USB_DESC_INTERFACE_POWER ((USB_DESC_TYPE_INTERFACE_POWER << 8) & 0xFF00)
+#define USB_DESC_HID_REPORT ((USB_DESC_TYPE_HID_REPORT << 8) & 0xFF00)
+#define USB_DESC_HID ((USB_DESC_TYPE_HID << 8) & 0xFF00)
+
+
+#define USB_EP_TYPE_CTRL 0x00
+#define USB_EP_TYPE_ISOC 0x01
+#define USB_EP_TYPE_BULK 0x02
+#define USB_EP_TYPE_INTR 0x03
+
+#define USB_EP_DIR_OUT 0x00
+#define USB_EP_DIR_IN 0x80
+#define USB_EP_DIR_MSK 0x80
+
+#define USBH_MAX_PIPES_NBR 15
+
+
+
+#define USBH_DEVICE_ADDRESS_DEFAULT 0
+#define USBH_MAX_ERROR_COUNT 2
+#define USBH_DEVICE_ADDRESS 1
+
+
+/**
+ * @}
+ */
+
+
+#define USBH_CONFIGURATION_DESCRIPTOR_SIZE (USB_CONFIGURATION_DESC_SIZE \
+ + USB_INTERFACE_DESC_SIZE\
+ + (USBH_MAX_NUM_ENDPOINTS * USB_ENDPOINT_DESC_SIZE))
+
+
+#define CONFIG_DESC_wTOTAL_LENGTH (ConfigurationDescriptorData.ConfigDescfield.\
+ ConfigurationDescriptor.wTotalLength)
+
+
+typedef union
+{
+ uint16_t w;
+ struct BW
+ {
+ uint8_t msb;
+ uint8_t lsb;
+ }
+ bw;
+}
+uint16_t_uint8_t;
+
+
+typedef union _USB_Setup
+{
+ uint32_t d8[2];
+
+ struct _SetupPkt_Struc
+ {
+ uint8_t bmRequestType;
+ uint8_t bRequest;
+ uint16_t_uint8_t wValue;
+ uint16_t_uint8_t wIndex;
+ uint16_t_uint8_t wLength;
+ } b;
+}
+USB_Setup_TypeDef;
+
+typedef struct _DescHeader
+{
+ uint8_t bLength;
+ uint8_t bDescriptorType;
+}
+USBH_DescHeader_t;
+
+typedef struct _DeviceDescriptor
+{
+ uint8_t bLength;
+ uint8_t bDescriptorType;
+ uint16_t bcdUSB; /* USB Specification Number which device complies too */
+ uint8_t bDeviceClass;
+ uint8_t bDeviceSubClass;
+ uint8_t bDeviceProtocol;
+ /* If equal to Zero, each interface specifies its own class
+ code if equal to 0xFF, the class code is vendor specified.
+ Otherwise field is valid Class Code.*/
+ uint8_t bMaxPacketSize;
+ uint16_t idVendor; /* Vendor ID (Assigned by USB Org) */
+ uint16_t idProduct; /* Product ID (Assigned by Manufacturer) */
+ uint16_t bcdDevice; /* Device Release Number */
+ uint8_t iManufacturer; /* Index of Manufacturer String Descriptor */
+ uint8_t iProduct; /* Index of Product String Descriptor */
+ uint8_t iSerialNumber; /* Index of Serial Number String Descriptor */
+ uint8_t bNumConfigurations; /* Number of Possible Configurations */
+}
+USBH_DevDescTypeDef;
+
+typedef struct _EndpointDescriptor
+{
+ uint8_t bLength;
+ uint8_t bDescriptorType;
+ uint8_t bEndpointAddress; /* indicates what endpoint this descriptor is describing */
+ uint8_t bmAttributes; /* specifies the transfer type. */
+ uint16_t wMaxPacketSize; /* Maximum Packet Size this endpoint is capable of sending or receiving */
+ uint8_t bInterval; /* is used to specify the polling interval of certain transfers. */
+}
+USBH_EpDescTypeDef;
+
+typedef struct _InterfaceDescriptor
+{
+ uint8_t bLength;
+ uint8_t bDescriptorType;
+ uint8_t bInterfaceNumber;
+ uint8_t bAlternateSetting; /* Value used to select alternative setting */
+ uint8_t bNumEndpoints; /* Number of Endpoints used for this interface */
+ uint8_t bInterfaceClass; /* Class Code (Assigned by USB Org) */
+ uint8_t bInterfaceSubClass; /* Subclass Code (Assigned by USB Org) */
+ uint8_t bInterfaceProtocol; /* Protocol Code */
+ uint8_t iInterface; /* Index of String Descriptor Describing this interface */
+ USBH_EpDescTypeDef Ep_Desc[USBH_MAX_NUM_ENDPOINTS];
+}
+USBH_InterfaceDescTypeDef;
+
+
+typedef struct _ConfigurationDescriptor
+{
+ uint8_t bLength;
+ uint8_t bDescriptorType;
+ uint16_t wTotalLength; /* Total Length of Data Returned */
+ uint8_t bNumInterfaces; /* Number of Interfaces */
+ uint8_t bConfigurationValue; /* Value to use as an argument to select this configuration*/
+ uint8_t iConfiguration; /*Index of String Descriptor Describing this configuration */
+ uint8_t bmAttributes; /* D7 Bus Powered , D6 Self Powered, D5 Remote Wakeup , D4..0 Reserved (0)*/
+ uint8_t bMaxPower; /*Maximum Power Consumption */
+ USBH_InterfaceDescTypeDef Itf_Desc[USBH_MAX_NUM_INTERFACES];
+}
+USBH_CfgDescTypeDef;
+
+
+/* Following USB Host status */
+typedef enum
+{
+ USBH_OK = 0,
+ USBH_BUSY,
+ USBH_FAIL,
+ USBH_NOT_SUPPORTED,
+ USBH_UNRECOVERED_ERROR,
+ USBH_ERROR_SPEED_UNKNOWN,
+}USBH_StatusTypeDef;
+
+
+/** @defgroup USBH_CORE_Exported_Types
+ * @{
+ */
+
+typedef enum
+{
+ USBH_SPEED_HIGH = 0,
+ USBH_SPEED_FULL = 1,
+ USBH_SPEED_LOW = 2,
+
+}USBH_SpeedTypeDef;
+
+/* Following states are used for gState */
+typedef enum
+{
+ HOST_IDLE =0,
+ HOST_DEV_WAIT_FOR_ATTACHMENT,
+ HOST_DEV_ATTACHED,
+ HOST_DEV_DISCONNECTED,
+ HOST_DETECT_DEVICE_SPEED,
+ HOST_ENUMERATION,
+ HOST_CLASS_REQUEST,
+ HOST_INPUT,
+ HOST_SET_CONFIGURATION,
+ HOST_CHECK_CLASS,
+ HOST_CLASS,
+ HOST_SUSPENDED,
+ HOST_ABORT_STATE,
+}HOST_StateTypeDef;
+
+/* Following states are used for EnumerationState */
+typedef enum
+{
+ ENUM_IDLE = 0,
+ ENUM_GET_FULL_DEV_DESC,
+ ENUM_SET_ADDR,
+ ENUM_GET_CFG_DESC,
+ ENUM_GET_FULL_CFG_DESC,
+ ENUM_GET_MFC_STRING_DESC,
+ ENUM_GET_PRODUCT_STRING_DESC,
+ ENUM_GET_SERIALNUM_STRING_DESC,
+} ENUM_StateTypeDef;
+
+/* Following states are used for CtrlXferStateMachine */
+typedef enum
+{
+ CTRL_IDLE =0,
+ CTRL_SETUP,
+ CTRL_SETUP_WAIT,
+ CTRL_DATA_IN,
+ CTRL_DATA_IN_WAIT,
+ CTRL_DATA_OUT,
+ CTRL_DATA_OUT_WAIT,
+ CTRL_STATUS_IN,
+ CTRL_STATUS_IN_WAIT,
+ CTRL_STATUS_OUT,
+ CTRL_STATUS_OUT_WAIT,
+ CTRL_ERROR,
+ CTRL_STALLED,
+ CTRL_COMPLETE
+}CTRL_StateTypeDef;
+
+
+/* Following states are used for RequestState */
+typedef enum
+{
+ CMD_IDLE =0,
+ CMD_SEND,
+ CMD_WAIT
+} CMD_StateTypeDef;
+
+typedef enum {
+ USBH_URB_IDLE = 0,
+ USBH_URB_DONE,
+ USBH_URB_NOTREADY,
+ USBH_URB_NYET,
+ USBH_URB_ERROR,
+ USBH_URB_STALL
+}USBH_URBStateTypeDef;
+
+typedef enum
+{
+ USBH_PORT_EVENT = 1,
+ USBH_URB_EVENT,
+ USBH_CONTROL_EVENT,
+ USBH_CLASS_EVENT,
+ USBH_STATE_CHANGED_EVENT,
+}
+USBH_OSEventTypeDef;
+
+/* Control request structure */
+typedef struct
+{
+ uint8_t pipe_in;
+ uint8_t pipe_out;
+ uint8_t pipe_size;
+ uint8_t *buff;
+ uint16_t length;
+ uint16_t timer;
+ USB_Setup_TypeDef setup;
+ CTRL_StateTypeDef state;
+ uint8_t errorcount;
+
+} USBH_CtrlTypeDef;
+
+/* Attached device structure */
+typedef struct
+{
+#if (USBH_KEEP_CFG_DESCRIPTOR == 1)
+ uint8_t CfgDesc_Raw[USBH_MAX_SIZE_CONFIGURATION];
+#endif
+ uint8_t Data[USBH_MAX_DATA_BUFFER];
+ uint8_t address;
+ uint8_t speed;
+ __IO uint8_t is_connected;
+ uint8_t current_interface;
+ USBH_DevDescTypeDef DevDesc;
+ USBH_CfgDescTypeDef CfgDesc;
+
+}USBH_DeviceTypeDef;
+
+struct _USBH_HandleTypeDef;
+
+/* USB Host Class structure */
+typedef struct
+{
+ const char *Name;
+ uint8_t ClassCode;
+ USBH_StatusTypeDef (*Init) (struct _USBH_HandleTypeDef *phost);
+ USBH_StatusTypeDef (*DeInit) (struct _USBH_HandleTypeDef *phost);
+ USBH_StatusTypeDef (*Requests) (struct _USBH_HandleTypeDef *phost);
+ USBH_StatusTypeDef (*BgndProcess) (struct _USBH_HandleTypeDef *phost);
+ USBH_StatusTypeDef (*SOFProcess) (struct _USBH_HandleTypeDef *phost);
+ void* pData;
+} USBH_ClassTypeDef;
+
+/* USB Host handle structure */
+typedef struct _USBH_HandleTypeDef
+{
+ __IO HOST_StateTypeDef gState; /* Host State Machine Value */
+ ENUM_StateTypeDef EnumState; /* Enumeration state Machine */
+ CMD_StateTypeDef RequestState;
+ USBH_CtrlTypeDef Control;
+ USBH_DeviceTypeDef device;
+ USBH_ClassTypeDef* pClass[USBH_MAX_NUM_SUPPORTED_CLASS];
+ USBH_ClassTypeDef* pActiveClass;
+ uint32_t ClassNumber;
+ uint32_t Pipes[15];
+ __IO uint32_t Timer;
+ uint8_t id;
+ void* pData;
+ void (* pUser )(struct _USBH_HandleTypeDef *pHandle, uint8_t id);
+
+#if (USBH_USE_OS == 1)
+ osMessageQId os_event;
+ osThreadId thread;
+#endif
+
+} USBH_HandleTypeDef;
+
+
+#if defined ( __GNUC__ )
+ #ifndef __weak
+ #define __weak __attribute__((weak))
+ #endif /* __weak */
+ #ifndef __packed
+ #define __packed __attribute__((__packed__))
+ #endif /* __packed */
+#endif /* __GNUC__ */
+
+#endif
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
+
diff --git a/ports/stm32/usbhost/Core/Inc/usbh_ioreq.h b/ports/stm32/usbhost/Core/Inc/usbh_ioreq.h
new file mode 100644
index 000000000..463d4ea37
--- /dev/null
+++ b/ports/stm32/usbhost/Core/Inc/usbh_ioreq.h
@@ -0,0 +1,159 @@
+/**
+ ******************************************************************************
+ * @file usbh_ioreq.h
+ * @author MCD Application Team
+ * @version V3.0.0
+ * @date 18-February-2014
+ * @brief Header file for usbh_ioreq.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 ----------------------------------------------*/
+#ifndef __USBH_IOREQ_H
+#define __USBH_IOREQ_H
+
+/* Includes ------------------------------------------------------------------*/
+#include "usbh_conf.h"
+#include "usbh_core.h"
+/** @addtogroup USBH_LIB
+ * @{
+ */
+
+/** @addtogroup USBH_LIB_CORE
+* @{
+*/
+
+/** @defgroup USBH_IOREQ
+ * @brief This file is the header file for usbh_ioreq.c
+ * @{
+ */
+
+
+/** @defgroup USBH_IOREQ_Exported_Defines
+ * @{
+ */
+
+#define USBH_PID_SETUP 0
+#define USBH_PID_DATA 1
+
+#define USBH_EP_CONTROL 0
+#define USBH_EP_ISO 1
+#define USBH_EP_BULK 2
+#define USBH_EP_INTERRUPT 3
+
+#define USBH_SETUP_PKT_SIZE 8
+/**
+ * @}
+ */
+
+
+/** @defgroup USBH_IOREQ_Exported_Types
+ * @{
+ */
+/**
+ * @}
+ */
+
+
+/** @defgroup USBH_IOREQ_Exported_Macros
+ * @{
+ */
+/**
+ * @}
+ */
+
+/** @defgroup USBH_IOREQ_Exported_Variables
+ * @{
+ */
+/**
+ * @}
+ */
+
+/** @defgroup USBH_IOREQ_Exported_FunctionsPrototype
+ * @{
+ */
+USBH_StatusTypeDef USBH_CtlSendSetup (USBH_HandleTypeDef *phost,
+ uint8_t *buff,
+ uint8_t hc_num);
+
+USBH_StatusTypeDef USBH_CtlSendData (USBH_HandleTypeDef *phost,
+ uint8_t *buff,
+ uint16_t length,
+ uint8_t hc_num,
+ uint8_t do_ping );
+
+USBH_StatusTypeDef USBH_CtlReceiveData(USBH_HandleTypeDef *phost,
+ uint8_t *buff,
+ uint16_t length,
+ uint8_t hc_num);
+
+USBH_StatusTypeDef USBH_BulkReceiveData(USBH_HandleTypeDef *phost,
+ uint8_t *buff,
+ uint16_t length,
+ uint8_t hc_num);
+
+USBH_StatusTypeDef USBH_BulkSendData (USBH_HandleTypeDef *phost,
+ uint8_t *buff,
+ uint16_t length,
+ uint8_t hc_num,
+ uint8_t do_ping );
+
+USBH_StatusTypeDef USBH_InterruptReceiveData(USBH_HandleTypeDef *phost,
+ uint8_t *buff,
+ uint8_t length,
+ uint8_t hc_num);
+
+USBH_StatusTypeDef USBH_InterruptSendData(USBH_HandleTypeDef *phost,
+ uint8_t *buff,
+ uint8_t length,
+ uint8_t hc_num);
+
+
+USBH_StatusTypeDef USBH_IsocReceiveData(USBH_HandleTypeDef *phost,
+ uint8_t *buff,
+ uint32_t length,
+ uint8_t hc_num);
+
+
+USBH_StatusTypeDef USBH_IsocSendData(USBH_HandleTypeDef *phost,
+ uint8_t *buff,
+ uint32_t length,
+ uint8_t hc_num);
+/**
+ * @}
+ */
+
+#endif /* __USBH_IOREQ_H */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+* @}
+*/
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
+
+
diff --git a/ports/stm32/usbhost/Core/Inc/usbh_pipes.h b/ports/stm32/usbhost/Core/Inc/usbh_pipes.h
new file mode 100644
index 000000000..d72cd5387
--- /dev/null
+++ b/ports/stm32/usbhost/Core/Inc/usbh_pipes.h
@@ -0,0 +1,124 @@
+/**
+ ******************************************************************************
+ * @file usbh_PIPES.h
+ * @author MCD Application Team
+ * @version V3.0.0
+ * @date 18-February-2014
+ * @brief Header file for usbh_pipes.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 ----------------------------------------------*/
+#ifndef __USBH_PIPES_H
+#define __USBH_PIPES_H
+
+/* Includes ------------------------------------------------------------------*/
+#include "usbh_core.h"
+
+/** @addtogroup USBH_LIB
+ * @{
+ */
+
+/** @addtogroup USBH_LIB_CORE
+* @{
+*/
+
+/** @defgroup USBH_PIPES
+ * @brief This file is the header file for usbh_PIPES.c
+ * @{
+ */
+
+/** @defgroup USBH_PIPES_Exported_Defines
+ * @{
+ */
+/**
+ * @}
+ */
+
+/** @defgroup USBH_PIPES_Exported_Types
+ * @{
+ */
+/**
+ * @}
+ */
+
+
+/** @defgroup USBH_PIPES_Exported_Macros
+ * @{
+ */
+/**
+ * @}
+ */
+
+/** @defgroup USBH_PIPES_Exported_Variables
+ * @{
+ */
+/**
+ * @}
+ */
+
+/** @defgroup USBH_PIPES_Exported_FunctionsPrototype
+ * @{
+ */
+
+USBH_StatusTypeDef USBH_OpenPipe (USBH_HandleTypeDef *phost,
+ uint8_t ch_num,
+ uint8_t epnum,
+ uint8_t dev_address,
+ uint8_t speed,
+ uint8_t ep_type,
+ uint16_t mps);
+
+USBH_StatusTypeDef USBH_ClosePipe (USBH_HandleTypeDef *phost,
+ uint8_t pipe_num);
+
+uint8_t USBH_AllocPipe (USBH_HandleTypeDef *phost,
+ uint8_t ep_addr);
+
+USBH_StatusTypeDef USBH_FreePipe (USBH_HandleTypeDef *phost,
+ uint8_t idx);
+
+
+
+
+/**
+ * @}
+ */
+
+
+
+#endif /* __USBH_PIPES_H */
+
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+* @}
+*/
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
+
+
diff --git a/ports/stm32/usbhost/Core/Src/usbh_conf_template.c b/ports/stm32/usbhost/Core/Src/usbh_conf_template.c
new file mode 100644
index 000000000..1c25f7b2e
--- /dev/null
+++ b/ports/stm32/usbhost/Core/Src/usbh_conf_template.c
@@ -0,0 +1,270 @@
+/**
+ ******************************************************************************
+ * @file usb_bsp.c
+ * @author MCD Application Team
+ * @version V3.0.0
+ * @date 18-February-2014
+ * @brief This file implements the board support package for the USB host 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.
+ *
+ ******************************************************************************
+ */
+
+/* Includes ------------------------------------------------------------------*/
+#include "usbh_core.h"
+
+/**
+ * @brief USBH_LL_Init
+ * Initialize the Low Level portion of the Host driver.
+ * @param phost: Host handle
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_LL_Init (USBH_HandleTypeDef *phost)
+{
+
+ return USBH_OK;
+}
+
+/**
+ * @brief USBH_LL_DeInit
+ * De-Initialize the Low Level portion of the Host driver.
+ * @param phost: Host handle
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_LL_DeInit (USBH_HandleTypeDef *phost)
+{
+
+ return USBH_OK;
+}
+
+/**
+ * @brief USBH_LL_Start
+ * Start the Low Level portion of the Host driver.
+ * @param phost: Host handle
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_LL_Start(USBH_HandleTypeDef *phost)
+{
+
+ return USBH_OK;
+}
+
+/**
+ * @brief USBH_LL_Stop
+ * Stop the Low Level portion of the Host driver.
+ * @param phost: Host handle
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_LL_Stop (USBH_HandleTypeDef *phost)
+{
+
+ return USBH_OK;
+}
+
+/**
+ * @brief USBH_LL_GetSpeed
+ * Return the USB Host Speed from the Low Level Driver.
+ * @param phost: Host handle
+ * @retval USBH Speeds
+ */
+USBH_SpeedTypeDef USBH_LL_GetSpeed (USBH_HandleTypeDef *phost)
+{
+ USBH_SpeedTypeDef speed = 0;
+
+
+ return speed;
+}
+
+/**
+ * @brief USBH_LL_ResetPort
+ * Reset the Host Port of the Low Level Driver.
+ * @param phost: Host handle
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_LL_ResetPort (USBH_HandleTypeDef *phost)
+{
+
+ return USBH_OK;
+}
+
+/**
+ * @brief USBH_LL_GetLastXferSize
+ * Return the last transfered packet size.
+ * @param phost: Host handle
+ * @param pipe: Pipe index
+ * @retval Packet Size
+ */
+uint32_t USBH_LL_GetLastXferSize (USBH_HandleTypeDef *phost, uint8_t pipe)
+{
+
+}
+
+/**
+ * @brief USBH_LL_OpenPipe
+ * Open a pipe of the Low Level Driver.
+ * @param phost: Host handle
+ * @param pipe_num: Pipe index
+ * @param epnum: Endpoint Number
+ * @param dev_address: Device USB address
+ * @param speed: Device Speed
+ * @param ep_type: Endpoint Type
+ * @param mps: Endpoint Max Packet Size
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_LL_OpenPipe (USBH_HandleTypeDef *phost,
+ uint8_t pipe_num,
+ uint8_t epnum,
+ uint8_t dev_address,
+ uint8_t speed,
+ uint8_t ep_type,
+ uint16_t mps)
+{
+
+ return USBH_OK;
+}
+
+/**
+ * @brief USBH_LL_ClosePipe
+ * Close a pipe of the Low Level Driver.
+ * @param phost: Host handle
+ * @param pipe_num: Pipe index
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_LL_ClosePipe (USBH_HandleTypeDef *phost, uint8_t pipe)
+{
+
+}
+/**
+ * @brief USBH_LL_SubmitURB
+ * Submit a new URB to the low level driver.
+ * @param phost: Host handle
+ * @param pipe: Pipe index
+ * This parameter can be a value from 1 to 15
+ * @param direction : Channel number
+ * This parameter can be one of the these values:
+ * 0 : Output
+ * 1 : Input
+ * @param ep_type : Endpoint Type
+ * This parameter can be one of the these values:
+ * @arg EP_TYPE_CTRL: Control type
+ * @arg EP_TYPE_ISOC: Isochrounous type
+ * @arg EP_TYPE_BULK: Bulk type
+ * @arg EP_TYPE_INTR: Interrupt type
+ * @param token : Endpoint Type
+ * This parameter can be one of the these values:
+ * @arg 0: PID_SETUP
+ * @arg 1: PID_DATA
+ * @param pbuff : pointer to URB data
+ * @param length : Length of URB data
+ * @param do_ping : activate do ping protocol (for high speed only)
+ * This parameter can be one of the these values:
+ * 0 : do ping inactive
+ * 1 : do ping active
+ * @retval Status
+ */
+
+USBH_StatusTypeDef USBH_LL_SubmitURB (USBH_HandleTypeDef *phost,
+ uint8_t pipe,
+ uint8_t direction ,
+ uint8_t ep_type,
+ uint8_t token,
+ uint8_t* pbuff,
+ uint16_t length,
+ uint8_t do_ping )
+{
+
+ return USBH_OK;
+}
+
+/**
+ * @brief USBH_LL_GetURBState
+ * Get a URB state from the low level driver.
+ * @param phost: Host handle
+ * @param pipe: Pipe index
+ * This parameter can be a value from 1 to 15
+ * @retval URB state
+ * This parameter can be one of the these values:
+ * @arg URB_IDLE
+ * @arg URB_DONE
+ * @arg URB_NOTREADY
+ * @arg URB_NYET
+ * @arg URB_ERROR
+ * @arg URB_STALL
+ */
+USBH_URBStateTypeDef USBH_LL_GetURBState (USBH_HandleTypeDef *phost, uint8_t pipe)
+{
+
+}
+
+/**
+ * @brief USBH_LL_DriverVBUS
+ * Drive VBUS.
+ * @param phost: Host handle
+ * @param state : VBUS state
+ * This parameter can be one of the these values:
+ * 0 : VBUS Active
+ * 1 : VBUS Inactive
+ * @retval Status
+ */
+
+USBH_StatusTypeDef USBH_LL_DriverVBUS (USBH_HandleTypeDef *phost, uint8_t state)
+{
+
+ return USBH_OK;
+}
+
+/**
+ * @brief USBH_LL_SetToggle
+ * Set toggle for a pipe.
+ * @param phost: Host handle
+ * @param pipe: Pipe index
+ * @param pipe_num: Pipe index
+ * @param toggle: toggle (0/1)
+ * @retval Status
+ */
+USBH_StatusTypeDef USBH_LL_SetToggle (USBH_HandleTypeDef *phost, uint8_t pipe, uint8_t toggle)
+{
+
+ return USBH_OK;
+}
+
+/**
+ * @brief USBH_LL_GetToggle
+ * Return the current toggle of a pipe.
+ * @param phost: Host handle
+ * @param pipe: Pipe index
+ * @retval toggle (0/1)
+ */
+uint8_t USBH_LL_GetToggle (USBH_HandleTypeDef *phost, uint8_t pipe)
+{
+ uint8_t toggle = 0;
+
+
+ return toggle;
+}
+/**
+ * @brief USBH_Delay
+ * Delay routine for the USB Host Library
+ * @param Delay: Delay in ms
+ * @retval None
+ */
+void USBH_Delay (uint32_t Delay)
+{
+
+}
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/ports/stm32/usbhost/Core/Src/usbh_core.c b/ports/stm32/usbhost/Core/Src/usbh_core.c
new file mode 100644
index 000000000..9d2727a89
--- /dev/null
+++ b/ports/stm32/usbhost/Core/Src/usbh_core.c
@@ -0,0 +1,936 @@
+/**
+ ******************************************************************************
+ * @file usbh_core.c
+ * @author MCD Application Team
+ * @version V3.0.0
+ * @date 18-February-2014
+ * @brief This file implements the functions for the core state machine process
+ * the enumeration and the control transfer process
+ ******************************************************************************
+ * @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 "usbh_core.h"
+
+
+/** @addtogroup USBH_LIB
+ * @{
+ */
+
+/** @addtogroup USBH_LIB_CORE
+ * @{
+ */
+
+/** @defgroup USBH_CORE
+ * @brief TThis file handles the basic enumaration when a device is connected
+ * to the host.
+ * @{
+ */
+
+
+/** @defgroup USBH_CORE_Private_Defines
+ * @{
+ */
+#define USBH_ADDRESS_DEFAULT 0
+#define USBH_ADDRESS_ASSIGNED 1
+#define USBH_MPS_DEFAULT 0x40
+/**
+ * @}
+ */
+
+/** @defgroup USBH_CORE_Private_Macros
+ * @{
+ */
+/**
+ * @}
+ */
+
+
+/** @defgroup USBH_CORE_Private_Variables
+ * @{
+ */
+/**
+ * @}
+ */
+
+
+/** @defgroup USBH_CORE_Private_Functions
+ * @{
+ */
+static USBH_StatusTypeDef USBH_HandleEnum (USBH_HandleTypeDef *phost);
+static void USBH_HandleSof (USBH_HandleTypeDef *phost);
+static USBH_StatusTypeDef DeInitStateMachine(USBH_HandleTypeDef *phost);
+
+#if (USBH_USE_OS == 1)
+static void USBH_Process_OS(void const * argument);
+#endif
+
+/**
+ * @brief HCD_Init
+ * Initialize the HOST Core.
+ * @param phost: Host Handle
+ * @param pUsrFunc: User Callback
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_Init(USBH_HandleTypeDef *phost, void (*pUsrFunc)(USBH_HandleTypeDef *phost, uint8_t ), uint8_t id)
+{
+ /* Check whether the USB Host handle is valid */
+ if(phost == NULL)
+ {
+ USBH_ErrLog("Invalid Host handle");
+ return USBH_FAIL;
+ }
+
+ /* Set DRiver ID */
+ phost->id = id;
+
+ /* Unlink class*/
+ phost->pActiveClass = NULL;
+ phost->ClassNumber = 0;
+
+ /* Restore default states and prepare EP0 */
+ DeInitStateMachine(phost);
+
+ /* Assign User process */
+ if(pUsrFunc != NULL)
+ {
+ phost->pUser = pUsrFunc;
+ }
+
+#if (USBH_USE_OS == 1)
+
+ /* Create USB Host Queue */
+ osMessageQDef(USBH_Queue, 10, uint16_t);
+ phost->os_event = osMessageCreate (osMessageQ(USBH_Queue), NULL);
+
+ /*Create USB Host Task */
+ osThreadDef(USBH_Thread, USBH_Process_OS, USBH_PROCESS_PRIO, 0, 8 * configMINIMAL_STACK_SIZE);
+ phost->thread = osThreadCreate (osThread(USBH_Thread), phost);
+#endif
+
+ /* Initialize low level driver */
+ USBH_LL_Init(phost);
+ return USBH_OK;
+}
+
+/**
+ * @brief HCD_Init
+ * De-Initialize the Host portion of the driver.
+ * @param phost: Host Handle
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_DeInit(USBH_HandleTypeDef *phost)
+{
+ DeInitStateMachine(phost);
+
+ if(phost->pData != NULL)
+ {
+ phost->pActiveClass->pData = NULL;
+ USBH_LL_Stop(phost);
+ }
+
+ return USBH_OK;
+}
+
+/**
+ * @brief DeInitStateMachine
+ * De-Initialize the Host state machine.
+ * @param phost: Host Handle
+ * @retval USBH Status
+ */
+static USBH_StatusTypeDef DeInitStateMachine(USBH_HandleTypeDef *phost)
+{
+ uint32_t i = 0;
+
+ /* Clear Pipes flags*/
+ for ( ; i < USBH_MAX_PIPES_NBR; i++)
+ {
+ phost->Pipes[i] = 0;
+ }
+
+ for(i = 0; i< USBH_MAX_DATA_BUFFER; i++)
+ {
+ phost->device.Data[i] = 0;
+ }
+
+ phost->gState = HOST_IDLE;
+ phost->EnumState = ENUM_IDLE;
+ phost->RequestState = CMD_SEND;
+ phost->Timer = 0;
+
+ phost->Control.state = CTRL_SETUP;
+ phost->Control.pipe_size = USBH_MPS_DEFAULT;
+ phost->Control.errorcount = 0;
+
+ phost->device.address = USBH_ADDRESS_DEFAULT;
+ phost->device.speed = USBH_SPEED_FULL;
+
+ return USBH_OK;
+}
+
+/**
+ * @brief USBH_RegisterClass
+ * Link class driver to Host Core.
+ * @param phost : Host Handle
+ * @param pclass: Class handle
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_RegisterClass(USBH_HandleTypeDef *phost, USBH_ClassTypeDef *pclass)
+{
+ USBH_StatusTypeDef status = USBH_OK;
+
+ if(pclass != 0)
+ {
+ if(phost->ClassNumber < USBH_MAX_NUM_SUPPORTED_CLASS)
+ {
+ /* link the class tgo the USB Host handle */
+ phost->pClass[phost->ClassNumber++] = pclass;
+ status = USBH_OK;
+ }
+ else
+ {
+ USBH_ErrLog("Max Class Number reached");
+ status = USBH_FAIL;
+ }
+ }
+ else
+ {
+ USBH_ErrLog("Invalid Class handle");
+ status = USBH_FAIL;
+ }
+
+ return status;
+}
+
+/**
+ * @brief USBH_SelectInterface
+ * Select current interface.
+ * @param phost: Host Handle
+ * @param interface: Interface number
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_SelectInterface(USBH_HandleTypeDef *phost, uint8_t interface)
+{
+ USBH_StatusTypeDef status = USBH_OK;
+
+ if(interface < phost->device.CfgDesc.bNumInterfaces)
+ {
+ phost->device.current_interface = interface;
+ USBH_UsrLog ("Switching to Interface (#%d)", interface);
+ USBH_UsrLog ("Class : %xh", phost->device.CfgDesc.Itf_Desc[interface].bInterfaceClass );
+ USBH_UsrLog ("SubClass : %xh", phost->device.CfgDesc.Itf_Desc[interface].bInterfaceSubClass );
+ USBH_UsrLog ("Protocol : %xh", phost->device.CfgDesc.Itf_Desc[interface].bInterfaceProtocol );
+ }
+ else
+ {
+ USBH_ErrLog ("Cannot Select This Interface.");
+ status = USBH_FAIL;
+ }
+ return status;
+}
+
+/**
+ * @brief USBH_GetActiveClass
+ * Return Device Class.
+ * @param phost: Host Handle
+ * @param interface: Interface index
+ * @retval Class Code
+ */
+uint8_t USBH_GetActiveClass(USBH_HandleTypeDef *phost)
+{
+ return (phost->device.CfgDesc.Itf_Desc[0].bInterfaceClass);
+}
+/**
+ * @brief USBH_FindInterface
+ * Find the interface index for a specific class.
+ * @param phost: Host Handle
+ * @param Class: Class code
+ * @param SubClass: SubClass code
+ * @param Protocol: Protocol code
+ * @retval interface index in the configuration structure
+ * @note : (1)interface index 0xFF means interface index not found
+ */
+uint8_t USBH_FindInterface(USBH_HandleTypeDef *phost, uint8_t Class, uint8_t SubClass, uint8_t Protocol)
+{
+ USBH_InterfaceDescTypeDef *pif ;
+ USBH_CfgDescTypeDef *pcfg ;
+ int8_t if_ix = 0;
+
+ pif = (USBH_InterfaceDescTypeDef *)0;
+ pcfg = &phost->device.CfgDesc;
+
+ if((pif->bInterfaceClass == 0xFF) &&(pif->bInterfaceSubClass == 0xFF) && (pif->bInterfaceProtocol == 0xFF))
+ {
+ return 0xFF;
+ }
+
+ while (if_ix < USBH_MAX_NUM_INTERFACES)
+ {
+ pif = &pcfg->Itf_Desc[if_ix];
+ if(((pif->bInterfaceClass == Class) || (Class == 0xFF))&&
+ ((pif->bInterfaceSubClass == SubClass) || (SubClass == 0xFF))&&
+ ((pif->bInterfaceProtocol == Protocol) || (Protocol == 0xFF)))
+ {
+ return if_ix;
+ }
+ if_ix++;
+ }
+ return 0xFF;
+}
+
+/**
+ * @brief USBH_FindInterfaceIndex
+ * Find the interface index for a specific class interface and alternate setting number.
+ * @param phost: Host Handle
+ * @param interface_number: interface number
+ * @param alt_settings : alaternate setting number
+ * @retval interface index in the configuration structure
+ * @note : (1)interface index 0xFF means interface index not found
+ */
+uint8_t USBH_FindInterfaceIndex(USBH_HandleTypeDef *phost, uint8_t interface_number, uint8_t alt_settings)
+{
+ USBH_InterfaceDescTypeDef *pif ;
+ USBH_CfgDescTypeDef *pcfg ;
+ int8_t if_ix = 0;
+
+ pif = (USBH_InterfaceDescTypeDef *)0;
+ pcfg = &phost->device.CfgDesc;
+
+ while (if_ix < USBH_MAX_NUM_INTERFACES)
+ {
+ pif = &pcfg->Itf_Desc[if_ix];
+ if((pif->bInterfaceNumber == interface_number) && (pif->bAlternateSetting == alt_settings))
+ {
+ return if_ix;
+ }
+ if_ix++;
+ }
+ return 0xFF;
+}
+
+/**
+ * @brief USBH_Start
+ * Start the USB Host Core.
+ * @param phost: Host Handle
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_Start (USBH_HandleTypeDef *phost)
+{
+ /* Start the low level driver */
+ USBH_LL_Start(phost);
+
+ /* Activate VBUS on the port */
+ USBH_LL_DriverVBUS (phost, TRUE);
+
+ return USBH_OK;
+}
+
+/**
+ * @brief USBH_Stop
+ * Stop the USB Host Core.
+ * @param phost: Host Handle
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_Stop (USBH_HandleTypeDef *phost)
+{
+ /* Stop and cleanup the low level driver */
+ USBH_LL_Stop(phost);
+
+ /* DeActivate VBUS on the port */
+ USBH_LL_DriverVBUS (phost, FALSE);
+
+ /* FRee Control Pipes */
+ USBH_FreePipe (phost, phost->Control.pipe_in);
+ USBH_FreePipe (phost, phost->Control.pipe_out);
+
+ return USBH_OK;
+}
+
+/**
+ * @brief HCD_ReEnumerate
+ * Perform a new Enumeration phase.
+ * @param phost: Host Handle
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_ReEnumerate (USBH_HandleTypeDef *phost)
+{
+ /*Stop Host */
+ USBH_Stop(phost);
+
+ /*Device has disconnected, so wait for 200 ms */
+ USBH_Delay(200);
+
+ /* Set State machines in default state */
+ DeInitStateMachine(phost);
+
+ /* Start again the host */
+ USBH_Start(phost);
+
+#if (USBH_USE_OS == 1)
+ osMessagePut ( phost->os_event, USBH_PORT_EVENT, 0);
+#endif
+ return USBH_OK;
+}
+
+/**
+ * @brief USBH_Process
+ * Background process of the USB Core.
+ * @param phost: Host Handle
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_Process(USBH_HandleTypeDef *phost)
+{
+ __IO USBH_StatusTypeDef status = USBH_FAIL;
+ uint8_t idx = 0;
+
+ switch (phost->gState)
+ {
+ case HOST_IDLE :
+
+ if (phost->device.is_connected)
+ {
+ /* Wait for 200 ms after connection */
+ phost->gState = HOST_DEV_WAIT_FOR_ATTACHMENT;
+ USBH_Delay(200);
+ USBH_LL_ResetPort(phost);
+#if (USBH_USE_OS == 1)
+ osMessagePut ( phost->os_event, USBH_PORT_EVENT, 0);
+#endif
+ }
+ break;
+
+ case HOST_DEV_WAIT_FOR_ATTACHMENT:
+ break;
+
+ case HOST_DEV_ATTACHED :
+
+ USBH_UsrLog("USB Device Attached");
+
+ /* Wait for 100 ms after Reset */
+ USBH_Delay(100);
+
+ phost->device.speed = USBH_LL_GetSpeed(phost);
+
+ phost->gState = HOST_ENUMERATION;
+
+ phost->Control.pipe_out = USBH_AllocPipe (phost, 0x00);
+ phost->Control.pipe_in = USBH_AllocPipe (phost, 0x80);
+
+
+ /* Open Control pipes */
+ USBH_OpenPipe (phost,
+ phost->Control.pipe_in,
+ 0x80,
+ phost->device.address,
+ phost->device.speed,
+ USBH_EP_CONTROL,
+ phost->Control.pipe_size);
+
+ /* Open Control pipes */
+ USBH_OpenPipe (phost,
+ phost->Control.pipe_out,
+ 0x00,
+ phost->device.address,
+ phost->device.speed,
+ USBH_EP_CONTROL,
+ phost->Control.pipe_size);
+
+#if (USBH_USE_OS == 1)
+ osMessagePut ( phost->os_event, USBH_PORT_EVENT, 0);
+#endif
+
+ break;
+
+ case HOST_ENUMERATION:
+ /* Check for enumeration status */
+ if ( USBH_HandleEnum(phost) == USBH_OK)
+ {
+ /* The function shall return USBH_OK when full enumeration is complete */
+ USBH_UsrLog ("Enumeration done.");
+ phost->device.current_interface = 0;
+ if(phost->device.DevDesc.bNumConfigurations == 1)
+ {
+ USBH_UsrLog ("This device has only 1 configuration.");
+ phost->gState = HOST_SET_CONFIGURATION;
+
+ }
+ else
+ {
+ phost->gState = HOST_INPUT;
+ }
+
+ }
+ break;
+
+ case HOST_INPUT:
+ {
+ /* user callback for end of device basic enumeration */
+ if(phost->pUser != NULL)
+ {
+ phost->pUser(phost, HOST_USER_SELECT_CONFIGURATION);
+ phost->gState = HOST_SET_CONFIGURATION;
+
+#if (USBH_USE_OS == 1)
+ osMessagePut ( phost->os_event, USBH_STATE_CHANGED_EVENT, 0);
+#endif
+ }
+ }
+ break;
+
+ case HOST_SET_CONFIGURATION:
+ /* set configuration */
+ if (USBH_SetCfg(phost, phost->device.CfgDesc.bConfigurationValue) == USBH_OK)
+ {
+ phost->gState = HOST_CHECK_CLASS;
+ USBH_UsrLog ("Default configuration set.");
+
+ }
+
+ break;
+
+ case HOST_CHECK_CLASS:
+
+ if(phost->ClassNumber == 0)
+ {
+ USBH_UsrLog ("No Class has been registered.");
+ }
+ else
+ {
+ phost->pActiveClass = NULL;
+
+ for (idx = 0; idx < USBH_MAX_NUM_SUPPORTED_CLASS ; idx ++)
+ {
+ if(phost->pClass[idx]->ClassCode == phost->device.CfgDesc.Itf_Desc[0].bInterfaceClass)
+ {
+ phost->pActiveClass = phost->pClass[idx];
+ }
+ }
+
+ if(phost->pActiveClass != NULL)
+ {
+ if(phost->pActiveClass->Init(phost)== USBH_OK)
+ {
+ phost->gState = HOST_CLASS_REQUEST;
+ USBH_UsrLog ("%s class started.", phost->pActiveClass->Name);
+
+ /* Inform user that a class has been activated */
+ phost->pUser(phost, HOST_USER_CLASS_SELECTED);
+ }
+ else
+ {
+ phost->gState = HOST_ABORT_STATE;
+ USBH_UsrLog ("Device not supporting %s class.", phost->pActiveClass->Name);
+ }
+ }
+ else
+ {
+ phost->gState = HOST_ABORT_STATE;
+ USBH_UsrLog ("No registered class for this device.");
+ }
+ }
+
+#if (USBH_USE_OS == 1)
+ osMessagePut ( phost->os_event, USBH_STATE_CHANGED_EVENT, 0);
+#endif
+ break;
+
+ case HOST_CLASS_REQUEST:
+ /* process class standard contol requests state machine */
+
+ if(phost->pActiveClass != NULL)
+ {
+ status = phost->pActiveClass->Requests(phost);
+
+ if(status == USBH_OK)
+ {
+ phost->gState = HOST_CLASS;
+ }
+ }
+ else
+ {
+ phost->gState = HOST_ABORT_STATE;
+ USBH_ErrLog ("Invalid Class Driver.");
+
+#if (USBH_USE_OS == 1)
+ osMessagePut ( phost->os_event, USBH_STATE_CHANGED_EVENT, 0);
+#endif
+ }
+
+ break;
+ case HOST_CLASS:
+ /* process class state machine */
+ if(phost->pActiveClass != NULL)
+ {
+ phost->pActiveClass->BgndProcess(phost);
+ }
+ break;
+
+ case HOST_DEV_DISCONNECTED :
+
+ DeInitStateMachine(phost);
+
+ /* Re-Initilaize Host for new Enumeration */
+ if(phost->pActiveClass != NULL)
+ {
+ phost->pActiveClass->DeInit(phost);
+ phost->pActiveClass = NULL;
+ }
+ break;
+
+ case HOST_ABORT_STATE:
+ default :
+ break;
+ }
+ return USBH_OK;
+}
+
+
+/**
+ * @brief USBH_HandleEnum
+ * This function includes the complete enumeration process
+ * @param phost: Host Handle
+ * @retval USBH_Status
+ */
+static USBH_StatusTypeDef USBH_HandleEnum (USBH_HandleTypeDef *phost)
+{
+ USBH_StatusTypeDef Status = USBH_BUSY;
+
+ switch (phost->EnumState)
+ {
+ case ENUM_IDLE:
+ /* Get Device Desc for only 1st 8 bytes : To get EP0 MaxPacketSize */
+ if ( USBH_Get_DevDesc(phost, 8) == USBH_OK)
+ {
+ phost->Control.pipe_size = phost->device.DevDesc.bMaxPacketSize;
+
+ phost->EnumState = ENUM_GET_FULL_DEV_DESC;
+
+ /* modify control channels configuration for MaxPacket size */
+ USBH_OpenPipe (phost,
+ phost->Control.pipe_in,
+ 0x80,
+ phost->device.address,
+ phost->device.speed,
+ USBH_EP_CONTROL,
+ phost->Control.pipe_size);
+
+ /* Open Control pipes */
+ USBH_OpenPipe (phost,
+ phost->Control.pipe_out,
+ 0x00,
+ phost->device.address,
+ phost->device.speed,
+ USBH_EP_CONTROL,
+ phost->Control.pipe_size);
+
+ }
+ break;
+
+ case ENUM_GET_FULL_DEV_DESC:
+ /* Get FULL Device Desc */
+ if ( USBH_Get_DevDesc(phost, USB_DEVICE_DESC_SIZE)== USBH_OK)
+ {
+ USBH_UsrLog("PID: %xh", phost->device.DevDesc.idProduct );
+ USBH_UsrLog("VID: %xh", phost->device.DevDesc.idVendor );
+
+ phost->EnumState = ENUM_SET_ADDR;
+
+ }
+ break;
+
+ case ENUM_SET_ADDR:
+ /* set address */
+ if ( USBH_SetAddress(phost, USBH_DEVICE_ADDRESS) == USBH_OK)
+ {
+ USBH_Delay(2);
+ phost->device.address = USBH_DEVICE_ADDRESS;
+
+ /* user callback for device address assigned */
+ USBH_UsrLog("Address (#%d) assigned.", phost->device.address);
+ phost->EnumState = ENUM_GET_CFG_DESC;
+
+ /* modify control channels to update device address */
+ USBH_OpenPipe (phost,
+ phost->Control.pipe_in,
+ 0x80,
+ phost->device.address,
+ phost->device.speed,
+ USBH_EP_CONTROL,
+ phost->Control.pipe_size);
+
+ /* Open Control pipes */
+ USBH_OpenPipe (phost,
+ phost->Control.pipe_out,
+ 0x00,
+ phost->device.address,
+ phost->device.speed,
+ USBH_EP_CONTROL,
+ phost->Control.pipe_size);
+ }
+ break;
+
+ case ENUM_GET_CFG_DESC:
+ /* get standard configuration descriptor */
+ if ( USBH_Get_CfgDesc(phost,
+ USB_CONFIGURATION_DESC_SIZE) == USBH_OK)
+ {
+ phost->EnumState = ENUM_GET_FULL_CFG_DESC;
+ }
+ break;
+
+ case ENUM_GET_FULL_CFG_DESC:
+ /* get FULL config descriptor (config, interface, endpoints) */
+ if (USBH_Get_CfgDesc(phost,
+ phost->device.CfgDesc.wTotalLength) == USBH_OK)
+ {
+ phost->EnumState = ENUM_GET_MFC_STRING_DESC;
+ }
+ break;
+
+ case ENUM_GET_MFC_STRING_DESC:
+ if (phost->device.DevDesc.iManufacturer != 0)
+ { /* Check that Manufacturer String is available */
+
+ if ( USBH_Get_StringDesc(phost,
+ phost->device.DevDesc.iManufacturer,
+ phost->device.Data ,
+ 0xff) == USBH_OK)
+ {
+ /* User callback for Manufacturing string */
+ USBH_UsrLog("Manufacturer : %s", (char *)phost->device.Data);
+ phost->EnumState = ENUM_GET_PRODUCT_STRING_DESC;
+
+#if (USBH_USE_OS == 1)
+ osMessagePut ( phost->os_event, USBH_STATE_CHANGED_EVENT, 0);
+#endif
+ }
+ }
+ else
+ {
+ USBH_UsrLog("Manufacturer : N/A");
+ phost->EnumState = ENUM_GET_PRODUCT_STRING_DESC;
+#if (USBH_USE_OS == 1)
+ osMessagePut ( phost->os_event, USBH_STATE_CHANGED_EVENT, 0);
+#endif
+ }
+ break;
+
+ case ENUM_GET_PRODUCT_STRING_DESC:
+ if (phost->device.DevDesc.iProduct != 0)
+ { /* Check that Product string is available */
+ if ( USBH_Get_StringDesc(phost,
+ phost->device.DevDesc.iProduct,
+ phost->device.Data,
+ 0xff) == USBH_OK)
+ {
+ /* User callback for Product string */
+ USBH_UsrLog("Product : %s", (char *)phost->device.Data);
+ phost->EnumState = ENUM_GET_SERIALNUM_STRING_DESC;
+ }
+ }
+ else
+ {
+ USBH_UsrLog("Product : N/A");
+ phost->EnumState = ENUM_GET_SERIALNUM_STRING_DESC;
+#if (USBH_USE_OS == 1)
+ osMessagePut ( phost->os_event, USBH_STATE_CHANGED_EVENT, 0);
+#endif
+ }
+ break;
+
+ case ENUM_GET_SERIALNUM_STRING_DESC:
+ if (phost->device.DevDesc.iSerialNumber != 0)
+ { /* Check that Serial number string is available */
+ if ( USBH_Get_StringDesc(phost,
+ phost->device.DevDesc.iSerialNumber,
+ phost->device.Data,
+ 0xff) == USBH_OK)
+ {
+ /* User callback for Serial number string */
+ USBH_UsrLog("Serial Number : %s", (char *)phost->device.Data);
+ Status = USBH_OK;
+ }
+ }
+ else
+ {
+ USBH_UsrLog("Serial Number : N/A");
+ Status = USBH_OK;
+#if (USBH_USE_OS == 1)
+ osMessagePut ( phost->os_event, USBH_STATE_CHANGED_EVENT, 0);
+#endif
+ }
+ break;
+
+ default:
+ break;
+ }
+ return Status;
+}
+
+/**
+ * @brief USBH_LL_SetTimer
+ * Set the initial Host Timer tick
+ * @param phost: Host Handle
+ * @retval None
+ */
+void USBH_LL_SetTimer (USBH_HandleTypeDef *phost, uint32_t time)
+{
+ phost->Timer = time;
+}
+/**
+ * @brief USBH_LL_IncTimer
+ * Increment Host Timer tick
+ * @param phost: Host Handle
+ * @retval None
+ */
+void USBH_LL_IncTimer (USBH_HandleTypeDef *phost)
+{
+ phost->Timer ++;
+ USBH_HandleSof(phost);
+}
+
+/**
+ * @brief USBH_HandleSof
+ * Call SOF process
+ * @param phost: Host Handle
+ * @retval None
+ */
+void USBH_HandleSof (USBH_HandleTypeDef *phost)
+{
+ if((phost->gState == HOST_CLASS)&&(phost->pActiveClass != NULL))
+ {
+ phost->pActiveClass->SOFProcess(phost);
+ }
+}
+/**
+ * @brief USBH_LL_Connect
+ * Handle USB Host connexion event
+ * @param phost: Host Handle
+ * @retval USBH_Status
+ */
+USBH_StatusTypeDef USBH_LL_Connect (USBH_HandleTypeDef *phost)
+{
+ if(phost->gState == HOST_IDLE )
+ {
+ phost->device.is_connected = 1;
+ phost->gState = HOST_IDLE ;
+
+ if(phost->pUser != NULL)
+ {
+ phost->pUser(phost, HOST_USER_CONNECTION);
+ }
+ }
+ else if(phost->gState == HOST_DEV_WAIT_FOR_ATTACHMENT )
+ {
+ phost->gState = HOST_DEV_ATTACHED ;
+ }
+#if (USBH_USE_OS == 1)
+ osMessagePut ( phost->os_event, USBH_PORT_EVENT, 0);
+#endif
+
+ return USBH_OK;
+}
+
+/**
+ * @brief USBH_LL_Disconnect
+ * Handle USB Host disconnexion event
+ * @param phost: Host Handle
+ * @retval USBH_Status
+ */
+USBH_StatusTypeDef USBH_LL_Disconnect (USBH_HandleTypeDef *phost)
+{
+ /*Stop Host */
+ USBH_LL_Stop(phost);
+
+ /* FRee Control Pipes */
+ USBH_FreePipe (phost, phost->Control.pipe_in);
+ USBH_FreePipe (phost, phost->Control.pipe_out);
+
+ phost->device.is_connected = 0;
+
+ if(phost->pUser != NULL)
+ {
+ phost->pUser(phost, HOST_USER_DISCONNECTION);
+ }
+ USBH_UsrLog("USB Device disconnected");
+
+ /* Start the low level driver */
+ USBH_LL_Start(phost);
+
+ phost->gState = HOST_DEV_DISCONNECTED;
+
+#if (USBH_USE_OS == 1)
+ osMessagePut ( phost->os_event, USBH_PORT_EVENT, 0);
+#endif
+
+ return USBH_OK;
+}
+
+
+#if (USBH_USE_OS == 1)
+/**
+ * @brief USB Host Thread task
+ * @param pvParameters not used
+ * @retval None
+ */
+static void USBH_Process_OS(void const * argument)
+{
+ osEvent event;
+
+ for(;;)
+ {
+ event = osMessageGet(((USBH_HandleTypeDef *)argument)->os_event, osWaitForever );
+
+ if( event.status == osEventMessage )
+ {
+ USBH_Process((USBH_HandleTypeDef *)argument);
+ }
+ }
+}
+
+/**
+* @brief USBH_LL_NotifyURBChange
+* Notify URB state Change
+* @param phost: Host handle
+* @retval USBH Status
+*/
+USBH_StatusTypeDef USBH_LL_NotifyURBChange (USBH_HandleTypeDef *phost)
+{
+ osMessagePut ( phost->os_event, USBH_URB_EVENT, 0);
+ return USBH_OK;
+}
+#endif
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/ports/stm32/usbhost/Core/Src/usbh_ctlreq.c b/ports/stm32/usbhost/Core/Src/usbh_ctlreq.c
new file mode 100644
index 000000000..58bc34d64
--- /dev/null
+++ b/ports/stm32/usbhost/Core/Src/usbh_ctlreq.c
@@ -0,0 +1,881 @@
+/**
+ ******************************************************************************
+ * @file usbh_ctlreq.c
+ * @author MCD Application Team
+ * @version V3.0.0
+ * @date 18-February-2014
+ * @brief This file implements the control requests for device enumeration
+ ******************************************************************************
+ * @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 "usbh_ctlreq.h"
+
+/** @addtogroup USBH_LIB
+* @{
+*/
+
+/** @addtogroup USBH_LIB_CORE
+* @{
+*/
+
+/** @defgroup USBH_CTLREQ
+* @brief This file implements the standard requests for device enumeration
+* @{
+*/
+
+
+/** @defgroup USBH_CTLREQ_Private_Defines
+* @{
+*/
+/**
+* @}
+*/
+
+
+/** @defgroup USBH_CTLREQ_Private_TypesDefinitions
+* @{
+*/
+/**
+* @}
+*/
+
+
+
+/** @defgroup USBH_CTLREQ_Private_Macros
+* @{
+*/
+/**
+* @}
+*/
+
+
+/** @defgroup USBH_CTLREQ_Private_Variables
+* @{
+*/
+/**
+* @}
+*/
+
+/** @defgroup USBH_CTLREQ_Private_FunctionPrototypes
+* @{
+*/
+static USBH_StatusTypeDef USBH_HandleControl (USBH_HandleTypeDef *phost);
+
+static void USBH_ParseDevDesc (USBH_DevDescTypeDef* , uint8_t *buf, uint16_t length);
+
+static void USBH_ParseCfgDesc (USBH_CfgDescTypeDef* cfg_desc,
+ uint8_t *buf,
+ uint16_t length);
+
+
+static void USBH_ParseEPDesc (USBH_EpDescTypeDef *ep_descriptor, uint8_t *buf);
+static void USBH_ParseStringDesc (uint8_t* psrc, uint8_t* pdest, uint16_t length);
+static void USBH_ParseInterfaceDesc (USBH_InterfaceDescTypeDef *if_descriptor, uint8_t *buf);
+
+
+/**
+* @}
+*/
+
+
+/** @defgroup USBH_CTLREQ_Private_Functions
+* @{
+*/
+
+
+/**
+ * @brief USBH_Get_DevDesc
+ * Issue Get Device Descriptor command to the device. Once the response
+ * received, it parses the device descriptor and updates the status.
+ * @param phost: Host Handle
+ * @param length: Length of the descriptor
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_Get_DevDesc(USBH_HandleTypeDef *phost, uint8_t length)
+{
+ USBH_StatusTypeDef status;
+
+ if((status = USBH_GetDescriptor(phost,
+ USB_REQ_RECIPIENT_DEVICE | USB_REQ_TYPE_STANDARD,
+ USB_DESC_DEVICE,
+ phost->device.Data,
+ length)) == USBH_OK)
+ {
+ /* Commands successfully sent and Response Received */
+ USBH_ParseDevDesc(&phost->device.DevDesc, phost->device.Data, length);
+ }
+ return status;
+}
+
+/**
+ * @brief USBH_Get_CfgDesc
+ * Issues Configuration Descriptor to the device. Once the response
+ * received, it parses the configuartion descriptor and updates the
+ * status.
+ * @param phost: Host Handle
+ * @param length: Length of the descriptor
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_Get_CfgDesc(USBH_HandleTypeDef *phost,
+ uint16_t length)
+
+{
+ USBH_StatusTypeDef status;
+ uint8_t *pData;
+#if (USBH_KEEP_CFG_DESCRIPTOR == 1)
+ pData = phost->device.CfgDesc_Raw;
+#else
+ pData = phost->device.Data;
+#endif
+ if((status = USBH_GetDescriptor(phost,
+ USB_REQ_RECIPIENT_DEVICE | USB_REQ_TYPE_STANDARD,
+ USB_DESC_CONFIGURATION,
+ pData,
+ length)) == USBH_OK)
+ {
+
+ /* Commands successfully sent and Response Received */
+ USBH_ParseCfgDesc (&phost->device.CfgDesc,
+ pData,
+ length);
+
+ }
+ return status;
+}
+
+
+/**
+ * @brief USBH_Get_StringDesc
+ * Issues string Descriptor command to the device. Once the response
+ * received, it parses the string descriptor and updates the status.
+ * @param phost: Host Handle
+ * @param string_index: String index for the descriptor
+ * @param buff: Buffer address for the descriptor
+ * @param length: Length of the descriptor
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_Get_StringDesc(USBH_HandleTypeDef *phost,
+ uint8_t string_index,
+ uint8_t *buff,
+ uint16_t length)
+{
+ USBH_StatusTypeDef status;
+ if((status = USBH_GetDescriptor(phost,
+ USB_REQ_RECIPIENT_DEVICE | USB_REQ_TYPE_STANDARD,
+ USB_DESC_STRING | string_index,
+ phost->device.Data,
+ length)) == USBH_OK)
+ {
+ /* Commands successfully sent and Response Received */
+ USBH_ParseStringDesc(phost->device.Data,buff, length);
+ }
+ return status;
+}
+
+/**
+ * @brief USBH_GetDescriptor
+ * Issues Descriptor command to the device. Once the response received,
+ * it parses the descriptor and updates the status.
+ * @param phost: Host Handle
+ * @param req_type: Descriptor type
+ * @param value_idx: wValue for the GetDescriptr request
+ * @param buff: Buffer to store the descriptor
+ * @param length: Length of the descriptor
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_GetDescriptor(USBH_HandleTypeDef *phost,
+ uint8_t req_type,
+ uint16_t value_idx,
+ uint8_t* buff,
+ uint16_t length )
+{
+ if(phost->RequestState == CMD_SEND)
+ {
+ phost->Control.setup.b.bmRequestType = USB_D2H | req_type;
+ phost->Control.setup.b.bRequest = USB_REQ_GET_DESCRIPTOR;
+ phost->Control.setup.b.wValue.w = value_idx;
+
+ if ((value_idx & 0xff00) == USB_DESC_STRING)
+ {
+ phost->Control.setup.b.wIndex.w = 0x0409;
+ }
+ else
+ {
+ phost->Control.setup.b.wIndex.w = 0;
+ }
+ phost->Control.setup.b.wLength.w = length;
+ }
+ return USBH_CtlReq(phost, buff , length );
+}
+
+/**
+ * @brief USBH_SetAddress
+ * This command sets the address to the connected device
+ * @param phost: Host Handle
+ * @param DeviceAddress: Device address to assign
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_SetAddress(USBH_HandleTypeDef *phost,
+ uint8_t DeviceAddress)
+{
+ if(phost->RequestState == CMD_SEND)
+ {
+ phost->Control.setup.b.bmRequestType = USB_H2D | USB_REQ_RECIPIENT_DEVICE | \
+ USB_REQ_TYPE_STANDARD;
+
+ phost->Control.setup.b.bRequest = USB_REQ_SET_ADDRESS;
+
+ phost->Control.setup.b.wValue.w = (uint16_t)DeviceAddress;
+ phost->Control.setup.b.wIndex.w = 0;
+ phost->Control.setup.b.wLength.w = 0;
+ }
+ return USBH_CtlReq(phost, 0 , 0 );
+}
+
+/**
+ * @brief USBH_SetCfg
+ * The command sets the configuration value to the connected device
+ * @param phost: Host Handle
+ * @param cfg_idx: Configuration value
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_SetCfg(USBH_HandleTypeDef *phost,
+ uint16_t cfg_idx)
+{
+ if(phost->RequestState == CMD_SEND)
+ {
+ phost->Control.setup.b.bmRequestType = USB_H2D | USB_REQ_RECIPIENT_DEVICE |\
+ USB_REQ_TYPE_STANDARD;
+ phost->Control.setup.b.bRequest = USB_REQ_SET_CONFIGURATION;
+ phost->Control.setup.b.wValue.w = cfg_idx;
+ phost->Control.setup.b.wIndex.w = 0;
+ phost->Control.setup.b.wLength.w = 0;
+ }
+
+ return USBH_CtlReq(phost, 0 , 0 );
+}
+
+/**
+ * @brief USBH_SetInterface
+ * The command sets the Interface value to the connected device
+ * @param phost: Host Handle
+ * @param altSetting: Interface value
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_SetInterface(USBH_HandleTypeDef *phost,
+ uint8_t ep_num, uint8_t altSetting)
+{
+
+ if(phost->RequestState == CMD_SEND)
+ {
+ phost->Control.setup.b.bmRequestType = USB_H2D | USB_REQ_RECIPIENT_INTERFACE | \
+ USB_REQ_TYPE_STANDARD;
+
+ phost->Control.setup.b.bRequest = USB_REQ_SET_INTERFACE;
+ phost->Control.setup.b.wValue.w = altSetting;
+ phost->Control.setup.b.wIndex.w = ep_num;
+ phost->Control.setup.b.wLength.w = 0;
+ }
+ return USBH_CtlReq(phost, 0 , 0 );
+}
+
+/**
+ * @brief USBH_ClrFeature
+ * This request is used to clear or disable a specific feature.
+ * @param phost: Host Handle
+ * @param ep_num: endpoint number
+ * @param hc_num: Host channel number
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_ClrFeature(USBH_HandleTypeDef *phost,
+ uint8_t ep_num)
+{
+ if(phost->RequestState == CMD_SEND)
+ {
+ phost->Control.setup.b.bmRequestType = USB_H2D |
+ USB_REQ_RECIPIENT_ENDPOINT |
+ USB_REQ_TYPE_STANDARD;
+
+ phost->Control.setup.b.bRequest = USB_REQ_CLEAR_FEATURE;
+ phost->Control.setup.b.wValue.w = FEATURE_SELECTOR_ENDPOINT;
+ phost->Control.setup.b.wIndex.w = ep_num;
+ phost->Control.setup.b.wLength.w = 0;
+ }
+ return USBH_CtlReq(phost, 0 , 0 );
+}
+
+/**
+ * @brief USBH_ParseDevDesc
+ * This function Parses the device descriptor
+ * @param dev_desc: device_descriptor destinaton address
+ * @param buf: Buffer where the source descriptor is available
+ * @param length: Length of the descriptor
+ * @retval None
+ */
+static void USBH_ParseDevDesc (USBH_DevDescTypeDef* dev_desc,
+ uint8_t *buf,
+ uint16_t length)
+{
+ dev_desc->bLength = *(uint8_t *) (buf + 0);
+ dev_desc->bDescriptorType = *(uint8_t *) (buf + 1);
+ dev_desc->bcdUSB = LE16 (buf + 2);
+ dev_desc->bDeviceClass = *(uint8_t *) (buf + 4);
+ dev_desc->bDeviceSubClass = *(uint8_t *) (buf + 5);
+ dev_desc->bDeviceProtocol = *(uint8_t *) (buf + 6);
+ dev_desc->bMaxPacketSize = *(uint8_t *) (buf + 7);
+
+ if (length > 8)
+ { /* For 1st time after device connection, Host may issue only 8 bytes for
+ Device Descriptor Length */
+ dev_desc->idVendor = LE16 (buf + 8);
+ dev_desc->idProduct = LE16 (buf + 10);
+ dev_desc->bcdDevice = LE16 (buf + 12);
+ dev_desc->iManufacturer = *(uint8_t *) (buf + 14);
+ dev_desc->iProduct = *(uint8_t *) (buf + 15);
+ dev_desc->iSerialNumber = *(uint8_t *) (buf + 16);
+ dev_desc->bNumConfigurations = *(uint8_t *) (buf + 17);
+ }
+}
+
+/**
+ * @brief USBH_ParseCfgDesc
+ * This function Parses the configuration descriptor
+ * @param cfg_desc: Configuration Descriptor address
+ * @param buf: Buffer where the source descriptor is available
+ * @param length: Length of the descriptor
+ * @retval None
+ */
+static void USBH_ParseCfgDesc (USBH_CfgDescTypeDef* cfg_desc,
+ uint8_t *buf,
+ uint16_t length)
+{
+ USBH_InterfaceDescTypeDef *pif ;
+ USBH_EpDescTypeDef *pep;
+ USBH_DescHeader_t *pdesc = (USBH_DescHeader_t *)buf;
+ uint16_t ptr;
+ int8_t if_ix = 0;
+ int8_t ep_ix = 0;
+
+ pdesc = (USBH_DescHeader_t *)buf;
+
+ /* Parse configuration descriptor */
+ cfg_desc->bLength = *(uint8_t *) (buf + 0);
+ cfg_desc->bDescriptorType = *(uint8_t *) (buf + 1);
+ cfg_desc->wTotalLength = LE16 (buf + 2);
+ cfg_desc->bNumInterfaces = *(uint8_t *) (buf + 4);
+ cfg_desc->bConfigurationValue = *(uint8_t *) (buf + 5);
+ cfg_desc->iConfiguration = *(uint8_t *) (buf + 6);
+ cfg_desc->bmAttributes = *(uint8_t *) (buf + 7);
+ cfg_desc->bMaxPower = *(uint8_t *) (buf + 8);
+
+
+ if (length > USB_CONFIGURATION_DESC_SIZE)
+ {
+ ptr = USB_LEN_CFG_DESC;
+ pif = (USBH_InterfaceDescTypeDef *)0;
+
+
+ while ((if_ix < USBH_MAX_NUM_INTERFACES ) && (ptr < cfg_desc->wTotalLength))
+ {
+ pdesc = USBH_GetNextDesc((uint8_t *)pdesc, &ptr);
+ if (pdesc->bDescriptorType == USB_DESC_TYPE_INTERFACE)
+ {
+ pif = &cfg_desc->Itf_Desc[if_ix];
+ USBH_ParseInterfaceDesc (pif, (uint8_t *)pdesc);
+
+ ep_ix = 0;
+ pep = (USBH_EpDescTypeDef *)0;
+ while ((ep_ix < pif->bNumEndpoints) && (ptr < cfg_desc->wTotalLength))
+ {
+ pdesc = USBH_GetNextDesc((void* )pdesc, &ptr);
+ if (pdesc->bDescriptorType == USB_DESC_TYPE_ENDPOINT)
+ {
+ pep = &cfg_desc->Itf_Desc[if_ix].Ep_Desc[ep_ix];
+ USBH_ParseEPDesc (pep, (uint8_t *)pdesc);
+ ep_ix++;
+ }
+ }
+ if_ix++;
+ }
+ }
+ }
+}
+
+
+
+/**
+ * @brief USBH_ParseInterfaceDesc
+ * This function Parses the interface descriptor
+ * @param if_descriptor : Interface descriptor destination
+ * @param buf: Buffer where the descriptor data is available
+ * @retval None
+ */
+static void USBH_ParseInterfaceDesc (USBH_InterfaceDescTypeDef *if_descriptor,
+ uint8_t *buf)
+{
+ if_descriptor->bLength = *(uint8_t *) (buf + 0);
+ if_descriptor->bDescriptorType = *(uint8_t *) (buf + 1);
+ if_descriptor->bInterfaceNumber = *(uint8_t *) (buf + 2);
+ if_descriptor->bAlternateSetting = *(uint8_t *) (buf + 3);
+ if_descriptor->bNumEndpoints = *(uint8_t *) (buf + 4);
+ if_descriptor->bInterfaceClass = *(uint8_t *) (buf + 5);
+ if_descriptor->bInterfaceSubClass = *(uint8_t *) (buf + 6);
+ if_descriptor->bInterfaceProtocol = *(uint8_t *) (buf + 7);
+ if_descriptor->iInterface = *(uint8_t *) (buf + 8);
+}
+
+/**
+ * @brief USBH_ParseEPDesc
+ * This function Parses the endpoint descriptor
+ * @param ep_descriptor: Endpoint descriptor destination address
+ * @param buf: Buffer where the parsed descriptor stored
+ * @retval None
+ */
+static void USBH_ParseEPDesc (USBH_EpDescTypeDef *ep_descriptor,
+ uint8_t *buf)
+{
+
+ ep_descriptor->bLength = *(uint8_t *) (buf + 0);
+ ep_descriptor->bDescriptorType = *(uint8_t *) (buf + 1);
+ ep_descriptor->bEndpointAddress = *(uint8_t *) (buf + 2);
+ ep_descriptor->bmAttributes = *(uint8_t *) (buf + 3);
+ ep_descriptor->wMaxPacketSize = LE16 (buf + 4);
+ ep_descriptor->bInterval = *(uint8_t *) (buf + 6);
+}
+
+/**
+ * @brief USBH_ParseStringDesc
+ * This function Parses the string descriptor
+ * @param psrc: Source pointer containing the descriptor data
+ * @param pdest: Destination address pointer
+ * @param length: Length of the descriptor
+ * @retval None
+ */
+static void USBH_ParseStringDesc (uint8_t* psrc,
+ uint8_t* pdest,
+ uint16_t length)
+{
+ uint16_t strlength;
+ uint16_t idx;
+
+ /* The UNICODE string descriptor is not NULL-terminated. The string length is
+ computed by substracting two from the value of the first byte of the descriptor.
+ */
+
+ /* Check which is lower size, the Size of string or the length of bytes read
+ from the device */
+
+ if ( psrc[1] == USB_DESC_TYPE_STRING)
+ { /* Make sure the Descriptor is String Type */
+
+ /* psrc[0] contains Size of Descriptor, subtract 2 to get the length of string */
+ strlength = ( ( (psrc[0]-2) <= length) ? (psrc[0]-2) :length);
+ psrc += 2; /* Adjust the offset ignoring the String Len and Descriptor type */
+
+ for (idx = 0; idx < strlength; idx+=2 )
+ {/* Copy Only the string and ignore the UNICODE ID, hence add the src */
+ *pdest = psrc[idx];
+ pdest++;
+ }
+ *pdest = 0; /* mark end of string */
+ }
+}
+
+/**
+ * @brief USBH_GetNextDesc
+ * This function return the next descriptor header
+ * @param buf: Buffer where the cfg descriptor is available
+ * @param ptr: data popinter inside the cfg descriptor
+ * @retval next header
+ */
+USBH_DescHeader_t *USBH_GetNextDesc (uint8_t *pbuf, uint16_t *ptr)
+{
+ USBH_DescHeader_t *pnext;
+
+ *ptr += ((USBH_DescHeader_t *)pbuf)->bLength;
+ pnext = (USBH_DescHeader_t *)((uint8_t *)pbuf + \
+ ((USBH_DescHeader_t *)pbuf)->bLength);
+
+ return(pnext);
+}
+
+
+/**
+ * @brief USBH_CtlReq
+ * USBH_CtlReq sends a control request and provide the status after
+ * completion of the request
+ * @param phost: Host Handle
+ * @param req: Setup Request Structure
+ * @param buff: data buffer address to store the response
+ * @param length: length of the response
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_CtlReq (USBH_HandleTypeDef *phost,
+ uint8_t *buff,
+ uint16_t length)
+{
+ USBH_StatusTypeDef status;
+ status = USBH_BUSY;
+
+ switch (phost->RequestState)
+ {
+ case CMD_SEND:
+ /* Start a SETUP transfer */
+ phost->Control.buff = buff;
+ phost->Control.length = length;
+ phost->Control.state = CTRL_SETUP;
+ phost->RequestState = CMD_WAIT;
+ status = USBH_BUSY;
+#if (USBH_USE_OS == 1)
+ osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0);
+#endif
+ break;
+
+ case CMD_WAIT:
+ status = USBH_HandleControl(phost);
+ if (status == USBH_OK)
+ {
+ /* Commands successfully sent and Response Received */
+ phost->RequestState = CMD_SEND;
+ phost->Control.state =CTRL_IDLE;
+ status = USBH_OK;
+ }
+ else if (status == USBH_FAIL)
+ {
+ /* Failure Mode */
+ phost->RequestState = CMD_SEND;
+ status = USBH_FAIL;
+ }
+ break;
+
+ default:
+ break;
+ }
+ return status;
+}
+
+/**
+ * @brief USBH_HandleControl
+ * Handles the USB control transfer state machine
+ * @param phost: Host Handle
+ * @retval USBH Status
+ */
+static USBH_StatusTypeDef USBH_HandleControl (USBH_HandleTypeDef *phost)
+{
+ uint8_t direction;
+ USBH_StatusTypeDef status = USBH_BUSY;
+ USBH_URBStateTypeDef URB_Status = USBH_URB_IDLE;
+
+ switch (phost->Control.state)
+ {
+ case CTRL_SETUP:
+ /* send a SETUP packet */
+ USBH_CtlSendSetup (phost,
+ (uint8_t *)phost->Control.setup.d8 ,
+ phost->Control.pipe_out);
+
+ phost->Control.state = CTRL_SETUP_WAIT;
+ break;
+
+ case CTRL_SETUP_WAIT:
+
+ URB_Status = USBH_LL_GetURBState(phost, phost->Control.pipe_out);
+ /* case SETUP packet sent successfully */
+ if(URB_Status == USBH_URB_DONE)
+ {
+ direction = (phost->Control.setup.b.bmRequestType & USB_REQ_DIR_MASK);
+
+ /* check if there is a data stage */
+ if (phost->Control.setup.b.wLength.w != 0 )
+ {
+ if (direction == USB_D2H)
+ {
+ /* Data Direction is IN */
+ phost->Control.state = CTRL_DATA_IN;
+ }
+ else
+ {
+ /* Data Direction is OUT */
+ phost->Control.state = CTRL_DATA_OUT;
+ }
+ }
+ /* No DATA stage */
+ else
+ {
+ /* If there is No Data Transfer Stage */
+ if (direction == USB_D2H)
+ {
+ /* Data Direction is IN */
+ phost->Control.state = CTRL_STATUS_OUT;
+ }
+ else
+ {
+ /* Data Direction is OUT */
+ phost->Control.state = CTRL_STATUS_IN;
+ }
+ }
+#if (USBH_USE_OS == 1)
+ osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0);
+#endif
+ }
+ else if(URB_Status == USBH_URB_ERROR)
+ {
+ phost->Control.state = CTRL_ERROR;
+#if (USBH_USE_OS == 1)
+ osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0);
+#endif
+ }
+ break;
+
+ case CTRL_DATA_IN:
+ /* Issue an IN token */
+ phost->Control.timer = phost->Timer;
+ USBH_CtlReceiveData(phost,
+ phost->Control.buff,
+ phost->Control.length,
+ phost->Control.pipe_in);
+
+ phost->Control.state = CTRL_DATA_IN_WAIT;
+ break;
+
+ case CTRL_DATA_IN_WAIT:
+
+ URB_Status = USBH_LL_GetURBState(phost , phost->Control.pipe_in);
+
+ /* check is DATA packet transfered successfully */
+ if (URB_Status == USBH_URB_DONE)
+ {
+ phost->Control.state = CTRL_STATUS_OUT;
+#if (USBH_USE_OS == 1)
+ osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0);
+#endif
+ }
+
+ /* manage error cases*/
+ if (URB_Status == USBH_URB_STALL)
+ {
+ /* In stall case, return to previous machine state*/
+ status = USBH_NOT_SUPPORTED;
+#if (USBH_USE_OS == 1)
+ osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0);
+#endif
+ }
+ else if (URB_Status == USBH_URB_ERROR)
+ {
+ /* Device error */
+ phost->Control.state = CTRL_ERROR;
+#if (USBH_USE_OS == 1)
+ osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0);
+#endif
+ }
+ break;
+
+ case CTRL_DATA_OUT:
+
+ USBH_CtlSendData (phost,
+ phost->Control.buff,
+ phost->Control.length ,
+ phost->Control.pipe_out,
+ 1);
+ phost->Control.timer = phost->Timer;
+ phost->Control.state = CTRL_DATA_OUT_WAIT;
+ break;
+
+ case CTRL_DATA_OUT_WAIT:
+
+ URB_Status = USBH_LL_GetURBState(phost , phost->Control.pipe_out);
+
+ if (URB_Status == USBH_URB_DONE)
+ { /* If the Setup Pkt is sent successful, then change the state */
+ phost->Control.state = CTRL_STATUS_IN;
+#if (USBH_USE_OS == 1)
+ osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0);
+#endif
+ }
+
+ /* handle error cases */
+ else if (URB_Status == USBH_URB_STALL)
+ {
+ /* In stall case, return to previous machine state*/
+ phost->Control.state = CTRL_STALLED;
+ status = USBH_NOT_SUPPORTED;
+#if (USBH_USE_OS == 1)
+ osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0);
+#endif
+ }
+ else if (URB_Status == USBH_URB_NOTREADY)
+ {
+ /* Nack received from device */
+ phost->Control.state = CTRL_DATA_OUT;
+
+#if (USBH_USE_OS == 1)
+ osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0);
+#endif
+ }
+ else if (URB_Status == USBH_URB_ERROR)
+ {
+ /* device error */
+ phost->Control.state = CTRL_ERROR;
+ status = USBH_FAIL;
+
+#if (USBH_USE_OS == 1)
+ osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0);
+#endif
+ }
+ break;
+
+
+ case CTRL_STATUS_IN:
+ /* Send 0 bytes out packet */
+ USBH_CtlReceiveData (phost,
+ 0,
+ 0,
+ phost->Control.pipe_in);
+ phost->Control.timer = phost->Timer;
+ phost->Control.state = CTRL_STATUS_IN_WAIT;
+
+ break;
+
+ case CTRL_STATUS_IN_WAIT:
+
+ URB_Status = USBH_LL_GetURBState(phost , phost->Control.pipe_in);
+
+ if ( URB_Status == USBH_URB_DONE)
+ { /* Control transfers completed, Exit the State Machine */
+ phost->Control.state = CTRL_COMPLETE;
+ status = USBH_OK;
+#if (USBH_USE_OS == 1)
+ osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0);
+#endif
+ }
+
+ else if (URB_Status == USBH_URB_ERROR)
+ {
+ phost->Control.state = CTRL_ERROR;
+#if (USBH_USE_OS == 1)
+ osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0);
+#endif
+ }
+ else if(URB_Status == USBH_URB_STALL)
+ {
+ /* Control transfers completed, Exit the State Machine */
+ status = USBH_NOT_SUPPORTED;
+
+#if (USBH_USE_OS == 1)
+ osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0);
+#endif
+ }
+ break;
+
+ case CTRL_STATUS_OUT:
+ USBH_CtlSendData (phost,
+ 0,
+ 0,
+ phost->Control.pipe_out,
+ 1);
+ phost->Control.timer = phost->Timer;
+ phost->Control.state = CTRL_STATUS_OUT_WAIT;
+ break;
+
+ case CTRL_STATUS_OUT_WAIT:
+
+ URB_Status = USBH_LL_GetURBState(phost , phost->Control.pipe_out);
+ if (URB_Status == USBH_URB_DONE)
+ {
+ status = USBH_OK;
+ phost->Control.state = CTRL_COMPLETE;
+
+#if (USBH_USE_OS == 1)
+ osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0);
+#endif
+ }
+ else if (URB_Status == USBH_URB_NOTREADY)
+ {
+ phost->Control.state = CTRL_STATUS_OUT;
+
+#if (USBH_USE_OS == 1)
+ osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0);
+#endif
+ }
+ else if (URB_Status == USBH_URB_ERROR)
+ {
+ phost->Control.state = CTRL_ERROR;
+
+#if (USBH_USE_OS == 1)
+ osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0);
+#endif
+ }
+ break;
+
+ case CTRL_ERROR:
+ /*
+ After a halt condition is encountered or an error is detected by the
+ host, a control endpoint is allowed to recover by accepting the next Setup
+ PID; i.e., recovery actions via some other pipe are not required for control
+ endpoints. For the Default Control Pipe, a device reset will ultimately be
+ required to clear the halt or error condition if the next Setup PID is not
+ accepted.
+ */
+ if (++ phost->Control.errorcount <= USBH_MAX_ERROR_COUNT)
+ {
+ /* try to recover control */
+ USBH_LL_Stop(phost);
+
+ /* Do the transmission again, starting from SETUP Packet */
+ phost->Control.state = CTRL_SETUP;
+ phost->RequestState = CMD_SEND;
+ }
+ else
+ {
+ phost->Control.errorcount = 0;
+ USBH_ErrLog("Control error");
+ status = USBH_FAIL;
+
+ }
+ break;
+
+ default:
+ break;
+ }
+ return status;
+}
+
+/**
+* @}
+*/
+
+/**
+* @}
+*/
+
+/**
+* @}
+*/
+
+/**
+* @}
+*/
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
+
+
+
+
diff --git a/ports/stm32/usbhost/Core/Src/usbh_ioreq.c b/ports/stm32/usbhost/Core/Src/usbh_ioreq.c
new file mode 100644
index 000000000..280020355
--- /dev/null
+++ b/ports/stm32/usbhost/Core/Src/usbh_ioreq.c
@@ -0,0 +1,358 @@
+/**
+ ******************************************************************************
+ * @file usbh_ioreq.c
+ * @author MCD Application Team
+ * @version V3.0.0
+ * @date 18-February-2014
+ * @brief This file handles the issuing of the USB transactions
+ ******************************************************************************
+ * @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 "usbh_ioreq.h"
+
+/** @addtogroup USBH_LIB
+ * @{
+ */
+
+/** @addtogroup USBH_LIB_CORE
+* @{
+*/
+
+/** @defgroup USBH_IOREQ
+ * @brief This file handles the standard protocol processing (USB v2.0)
+ * @{
+ */
+
+
+/** @defgroup USBH_IOREQ_Private_Defines
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+
+/** @defgroup USBH_IOREQ_Private_TypesDefinitions
+ * @{
+ */
+/**
+ * @}
+ */
+
+
+
+/** @defgroup USBH_IOREQ_Private_Macros
+ * @{
+ */
+/**
+ * @}
+ */
+
+
+/** @defgroup USBH_IOREQ_Private_Variables
+ * @{
+ */
+/**
+ * @}
+ */
+/** @defgroup USBH_IOREQ_Private_FunctionPrototypes
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+
+/** @defgroup USBH_IOREQ_Private_Functions
+ * @{
+ */
+
+
+
+/**
+ * @brief USBH_CtlSendSetup
+ * Sends the Setup Packet to the Device
+ * @param phost: Host Handle
+ * @param buff: Buffer pointer from which the Data will be send to Device
+ * @param pipe_num: Pipe Number
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_CtlSendSetup (USBH_HandleTypeDef *phost,
+ uint8_t *buff,
+ uint8_t pipe_num)
+{
+
+ USBH_LL_SubmitURB (phost, /* Driver handle */
+ pipe_num, /* Pipe index */
+ 0, /* Direction : OUT */
+ USBH_EP_CONTROL, /* EP type */
+ USBH_PID_SETUP, /* Type setup */
+ buff, /* data buffer */
+ USBH_SETUP_PKT_SIZE, /* data length */
+ 0);
+ return USBH_OK;
+}
+
+
+/**
+ * @brief USBH_CtlSendData
+ * Sends a data Packet to the Device
+ * @param phost: Host Handle
+ * @param buff: Buffer pointer from which the Data will be sent to Device
+ * @param length: Length of the data to be sent
+ * @param pipe_num: Pipe Number
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_CtlSendData (USBH_HandleTypeDef *phost,
+ uint8_t *buff,
+ uint16_t length,
+ uint8_t pipe_num,
+ uint8_t do_ping )
+{
+ if(phost->device.speed != USBH_SPEED_HIGH)
+ {
+ do_ping = 0;
+ }
+
+ USBH_LL_SubmitURB (phost, /* Driver handle */
+ pipe_num, /* Pipe index */
+ 0, /* Direction : OUT */
+ USBH_EP_CONTROL, /* EP type */
+ USBH_PID_DATA, /* Type Data */
+ buff, /* data buffer */
+ length, /* data length */
+ do_ping); /* do ping (HS Only)*/
+
+ return USBH_OK;
+}
+
+
+/**
+ * @brief USBH_CtlReceiveData
+ * Receives the Device Response to the Setup Packet
+ * @param phost: Host Handle
+ * @param buff: Buffer pointer in which the response needs to be copied
+ * @param length: Length of the data to be received
+ * @param pipe_num: Pipe Number
+ * @retval USBH Status.
+ */
+USBH_StatusTypeDef USBH_CtlReceiveData(USBH_HandleTypeDef *phost,
+ uint8_t* buff,
+ uint16_t length,
+ uint8_t pipe_num)
+{
+ USBH_LL_SubmitURB (phost, /* Driver handle */
+ pipe_num, /* Pipe index */
+ 1, /* Direction : IN */
+ USBH_EP_CONTROL, /* EP type */
+ USBH_PID_DATA, /* Type Data */
+ buff, /* data buffer */
+ length, /* data length */
+ 0);
+ return USBH_OK;
+
+}
+
+
+/**
+ * @brief USBH_BulkSendData
+ * Sends the Bulk Packet to the device
+ * @param phost: Host Handle
+ * @param buff: Buffer pointer from which the Data will be sent to Device
+ * @param length: Length of the data to be sent
+ * @param pipe_num: Pipe Number
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_BulkSendData (USBH_HandleTypeDef *phost,
+ uint8_t *buff,
+ uint16_t length,
+ uint8_t pipe_num,
+ uint8_t do_ping )
+{
+ if(phost->device.speed != USBH_SPEED_HIGH)
+ {
+ do_ping = 0;
+ }
+
+ USBH_LL_SubmitURB (phost, /* Driver handle */
+ pipe_num, /* Pipe index */
+ 0, /* Direction : IN */
+ USBH_EP_BULK, /* EP type */
+ USBH_PID_DATA, /* Type Data */
+ buff, /* data buffer */
+ length, /* data length */
+ do_ping); /* do ping (HS Only)*/
+ return USBH_OK;
+}
+
+
+/**
+ * @brief USBH_BulkReceiveData
+ * Receives IN bulk packet from device
+ * @param phost: Host Handle
+ * @param buff: Buffer pointer in which the received data packet to be copied
+ * @param length: Length of the data to be received
+ * @param pipe_num: Pipe Number
+ * @retval USBH Status.
+ */
+USBH_StatusTypeDef USBH_BulkReceiveData(USBH_HandleTypeDef *phost,
+ uint8_t *buff,
+ uint16_t length,
+ uint8_t pipe_num)
+{
+ USBH_LL_SubmitURB (phost, /* Driver handle */
+ pipe_num, /* Pipe index */
+ 1, /* Direction : IN */
+ USBH_EP_BULK, /* EP type */
+ USBH_PID_DATA, /* Type Data */
+ buff, /* data buffer */
+ length, /* data length */
+ 0);
+ return USBH_OK;
+}
+
+
+/**
+ * @brief USBH_InterruptReceiveData
+ * Receives the Device Response to the Interrupt IN token
+ * @param phost: Host Handle
+ * @param buff: Buffer pointer in which the response needs to be copied
+ * @param length: Length of the data to be received
+ * @param pipe_num: Pipe Number
+ * @retval USBH Status.
+ */
+USBH_StatusTypeDef USBH_InterruptReceiveData(USBH_HandleTypeDef *phost,
+ uint8_t *buff,
+ uint8_t length,
+ uint8_t pipe_num)
+{
+ USBH_LL_SubmitURB (phost, /* Driver handle */
+ pipe_num, /* Pipe index */
+ 1, /* Direction : IN */
+ USBH_EP_INTERRUPT, /* EP type */
+ USBH_PID_DATA, /* Type Data */
+ buff, /* data buffer */
+ length, /* data length */
+ 0);
+
+ return USBH_OK;
+}
+
+/**
+ * @brief USBH_InterruptSendData
+ * Sends the data on Interrupt OUT Endpoint
+ * @param phost: Host Handle
+ * @param buff: Buffer pointer from where the data needs to be copied
+ * @param length: Length of the data to be sent
+ * @param pipe_num: Pipe Number
+ * @retval USBH Status.
+ */
+USBH_StatusTypeDef USBH_InterruptSendData(USBH_HandleTypeDef *phost,
+ uint8_t *buff,
+ uint8_t length,
+ uint8_t pipe_num)
+{
+ USBH_LL_SubmitURB (phost, /* Driver handle */
+ pipe_num, /* Pipe index */
+ 0, /* Direction : OUT */
+ USBH_EP_INTERRUPT, /* EP type */
+ USBH_PID_DATA, /* Type Data */
+ buff, /* data buffer */
+ length, /* data length */
+ 0);
+
+ return USBH_OK;
+}
+
+/**
+ * @brief USBH_IsocReceiveData
+ * Receives the Device Response to the Isochronous IN token
+ * @param phost: Host Handle
+ * @param buff: Buffer pointer in which the response needs to be copied
+ * @param length: Length of the data to be received
+ * @param pipe_num: Pipe Number
+ * @retval USBH Status.
+ */
+USBH_StatusTypeDef USBH_IsocReceiveData(USBH_HandleTypeDef *phost,
+ uint8_t *buff,
+ uint32_t length,
+ uint8_t pipe_num)
+{
+ USBH_LL_SubmitURB (phost, /* Driver handle */
+ pipe_num, /* Pipe index */
+ 1, /* Direction : IN */
+ USBH_EP_ISO, /* EP type */
+ USBH_PID_DATA, /* Type Data */
+ buff, /* data buffer */
+ length, /* data length */
+ 0);
+
+
+ return USBH_OK;
+}
+
+/**
+ * @brief USBH_IsocSendData
+ * Sends the data on Isochronous OUT Endpoint
+ * @param phost: Host Handle
+ * @param buff: Buffer pointer from where the data needs to be copied
+ * @param length: Length of the data to be sent
+ * @param pipe_num: Pipe Number
+ * @retval USBH Status.
+ */
+USBH_StatusTypeDef USBH_IsocSendData(USBH_HandleTypeDef *phost,
+ uint8_t *buff,
+ uint32_t length,
+ uint8_t pipe_num)
+{
+ USBH_LL_SubmitURB (phost, /* Driver handle */
+ pipe_num, /* Pipe index */
+ 0, /* Direction : OUT */
+ USBH_EP_ISO, /* EP type */
+ USBH_PID_DATA, /* Type Data */
+ buff, /* data buffer */
+ length, /* data length */
+ 0);
+
+ return USBH_OK;
+}
+/**
+* @}
+*/
+
+/**
+* @}
+*/
+
+/**
+* @}
+*/
+
+/**
+* @}
+*/
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
+
+
+
diff --git a/ports/stm32/usbhost/Core/Src/usbh_pipes.c b/ports/stm32/usbhost/Core/Src/usbh_pipes.c
new file mode 100644
index 000000000..9dcc4c517
--- /dev/null
+++ b/ports/stm32/usbhost/Core/Src/usbh_pipes.c
@@ -0,0 +1,204 @@
+/**
+ ******************************************************************************
+ * @file usbh_pipes.c
+ * @author MCD Application Team
+ * @version V3.0.0
+ * @date 18-February-2014
+ * @brief This file implements functions for opening and closing Pipes
+ ******************************************************************************
+ * @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 "usbh_pipes.h"
+
+/** @addtogroup USBH_LIB
+ * @{
+ */
+
+/** @addtogroup USBH_LIB_CORE
+* @{
+*/
+
+/** @defgroup USBH_PIPES
+ * @brief This file includes opening and closing Pipes
+ * @{
+ */
+
+/** @defgroup USBH_PIPES_Private_Defines
+ * @{
+ */
+/**
+ * @}
+ */
+
+/** @defgroup USBH_PIPES_Private_TypesDefinitions
+ * @{
+ */
+/**
+ * @}
+ */
+
+
+/** @defgroup USBH_PIPES_Private_Macros
+ * @{
+ */
+/**
+ * @}
+ */
+
+
+/** @defgroup USBH_PIPES_Private_Variables
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+
+/** @defgroup USBH_PIPES_Private_Functions
+ * @{
+ */
+static uint16_t USBH_GetFreePipe (USBH_HandleTypeDef *phost);
+
+
+/**
+ * @brief USBH_Open_Pipe
+ * Open a pipe
+ * @param phost: Host Handle
+ * @param pipe_num: Pipe Number
+ * @param dev_address: USB Device address allocated to attached device
+ * @param speed : USB device speed (Full/Low)
+ * @param ep_type: end point type (Bulk/int/ctl)
+ * @param mps: max pkt size
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_OpenPipe (USBH_HandleTypeDef *phost,
+ uint8_t pipe_num,
+ uint8_t epnum,
+ uint8_t dev_address,
+ uint8_t speed,
+ uint8_t ep_type,
+ uint16_t mps)
+{
+
+ USBH_LL_OpenPipe(phost,
+ pipe_num,
+ epnum,
+ dev_address,
+ speed,
+ ep_type,
+ mps);
+
+ return USBH_OK;
+
+}
+
+/**
+ * @brief USBH_ClosePipe
+ * Close a pipe
+ * @param phost: Host Handle
+ * @param pipe_num: Pipe Number
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_ClosePipe (USBH_HandleTypeDef *phost,
+ uint8_t pipe_num)
+{
+
+ USBH_LL_ClosePipe(phost, pipe_num);
+
+ return USBH_OK;
+
+}
+
+/**
+ * @brief USBH_Alloc_Pipe
+ * Allocate a new Pipe
+ * @param phost: Host Handle
+ * @param ep_addr: End point for which the Pipe to be allocated
+ * @retval Pipe number
+ */
+uint8_t USBH_AllocPipe (USBH_HandleTypeDef *phost, uint8_t ep_addr)
+{
+ uint16_t pipe;
+
+ pipe = USBH_GetFreePipe(phost);
+
+ if (pipe != 0xFFFF)
+ {
+ phost->Pipes[pipe] = 0x8000 | ep_addr;
+ }
+ return pipe;
+}
+
+/**
+ * @brief USBH_Free_Pipe
+ * Free the USB Pipe
+ * @param phost: Host Handle
+ * @param idx: Pipe number to be freed
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_FreePipe (USBH_HandleTypeDef *phost, uint8_t idx)
+{
+ if(idx < 11)
+ {
+ phost->Pipes[idx] &= 0x7FFF;
+ }
+ return USBH_OK;
+}
+
+/**
+ * @brief USBH_GetFreePipe
+ * @param phost: Host Handle
+ * Get a free Pipe number for allocation to a device endpoint
+ * @retval idx: Free Pipe number
+ */
+static uint16_t USBH_GetFreePipe (USBH_HandleTypeDef *phost)
+{
+ uint8_t idx = 0;
+
+ for (idx = 0 ; idx < 11 ; idx++)
+ {
+ if ((phost->Pipes[idx] & 0x8000) == 0)
+ {
+ return idx;
+ }
+ }
+ return 0xFFFF;
+}
+/**
+* @}
+*/
+
+/**
+* @}
+*/
+
+/**
+* @}
+*/
+
+/**
+* @}
+*/
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
+
+
diff --git a/ports/stm32/usbhost/Release_Notes.html b/ports/stm32/usbhost/Release_Notes.html
new file mode 100644
index 000000000..cbb723ee9
--- /dev/null
+++ b/ports/stm32/usbhost/Release_Notes.html
@@ -0,0 +1,973 @@
+<!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
new file mode 100644
index 000000000..a7721ad77
--- /dev/null
+++ b/ports/stm32/usrsw.c
@@ -0,0 +1,147 @@
+/*
+ * 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 "py/runtime.h"
+#include "py/mphal.h"
+#include "extint.h"
+#include "pin.h"
+#include "genhdr/pins.h"
+#include "usrsw.h"
+
+#if MICROPY_HW_HAS_SWITCH
+
+/// \moduleref pyb
+/// \class Switch - switch object
+///
+/// A Switch object is used to control a push-button switch.
+///
+/// Usage:
+///
+/// sw = pyb.Switch() # create a switch object
+/// sw() # get state (True if pressed, False otherwise)
+/// sw.callback(f) # register a callback to be called when the
+/// # switch is pressed down
+/// sw.callback(None) # remove the callback
+///
+/// Example:
+///
+/// pyb.Switch().callback(lambda: pyb.LED(1).toggle())
+
+// 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);
+}
+
+int switch_get(void) {
+ int val = ((MICROPY_HW_USRSW_PIN.gpio->IDR & MICROPY_HW_USRSW_PIN.pin_mask) != 0);
+ return val == MICROPY_HW_USRSW_PRESSED;
+}
+
+/******************************************************************************/
+// MicroPython bindings
+
+typedef struct _pyb_switch_obj_t {
+ mp_obj_base_t base;
+} pyb_switch_obj_t;
+
+STATIC const pyb_switch_obj_t pyb_switch_obj = {{&pyb_switch_type}};
+
+void pyb_switch_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
+ mp_print_str(print, "Switch()");
+}
+
+/// \classmethod \constructor()
+/// Create and return a switch object.
+STATIC mp_obj_t pyb_switch_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);
+
+ // No need to clear the callback member: if it's already been set and registered
+ // with extint then we don't want to reset that behaviour. If it hasn't been set,
+ // then no extint will be called until it is set via the callback method.
+
+ // return static switch object
+ return (mp_obj_t)&pyb_switch_obj;
+}
+
+/// \method \call()
+/// Return the switch state: `True` if pressed down, `False` otherwise.
+mp_obj_t pyb_switch_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {
+ // get switch state
+ mp_arg_check_num(n_args, n_kw, 0, 0, false);
+ return switch_get() ? mp_const_true : mp_const_false;
+}
+
+mp_obj_t pyb_switch_value(mp_obj_t self_in) {
+ (void)self_in;
+ return mp_obj_new_bool(switch_get());
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_switch_value_obj, pyb_switch_value);
+
+STATIC mp_obj_t switch_callback(mp_obj_t line) {
+ if (MP_STATE_PORT(pyb_switch_callback) != mp_const_none) {
+ mp_call_function_0(MP_STATE_PORT(pyb_switch_callback));
+ }
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(switch_callback_obj, switch_callback);
+
+/// \method callback(fun)
+/// Register the given function to be called when the switch is pressed down.
+/// If `fun` is `None`, then it disables the callback.
+mp_obj_t pyb_switch_callback(mp_obj_t self_in, mp_obj_t callback) {
+ MP_STATE_PORT(pyb_switch_callback) = 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,
+ MICROPY_HW_USRSW_EXTI_MODE,
+ MICROPY_HW_USRSW_PULL,
+ callback == mp_const_none ? mp_const_none : (mp_obj_t)&switch_callback_obj,
+ true);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(pyb_switch_callback_obj, pyb_switch_callback);
+
+STATIC const mp_rom_map_elem_t pyb_switch_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_value), MP_ROM_PTR(&pyb_switch_value_obj) },
+ { MP_ROM_QSTR(MP_QSTR_callback), MP_ROM_PTR(&pyb_switch_callback_obj) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(pyb_switch_locals_dict, pyb_switch_locals_dict_table);
+
+const mp_obj_type_t pyb_switch_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_Switch,
+ .print = pyb_switch_print,
+ .make_new = pyb_switch_make_new,
+ .call = pyb_switch_call,
+ .locals_dict = (mp_obj_dict_t*)&pyb_switch_locals_dict,
+};
+
+#endif // MICROPY_HW_HAS_SWITCH
diff --git a/ports/stm32/usrsw.h b/ports/stm32/usrsw.h
new file mode 100644
index 000000000..d96e3c281
--- /dev/null
+++ b/ports/stm32/usrsw.h
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ */
+#ifndef MICROPY_INCLUDED_STMHAL_USRSW_H
+#define MICROPY_INCLUDED_STMHAL_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
diff --git a/ports/stm32/wdt.c b/ports/stm32/wdt.c
new file mode 100644
index 000000000..2b4967a43
--- /dev/null
+++ b/ports/stm32/wdt.c
@@ -0,0 +1,106 @@
+/*
+ * 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 "py/runtime.h"
+#include "wdt.h"
+
+typedef struct _pyb_wdt_obj_t {
+ mp_obj_base_t base;
+} pyb_wdt_obj_t;
+
+STATIC pyb_wdt_obj_t pyb_wdt = {{&pyb_wdt_type}};
+
+STATIC mp_obj_t pyb_wdt_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
+ // parse arguments
+ enum { ARG_id, ARG_timeout };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_id, MP_ARG_INT, {.u_int = 0} },
+ { MP_QSTR_timeout, MP_ARG_INT, {.u_int = 5000} },
+ };
+ 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);
+
+ mp_int_t id = args[ARG_id].u_int;
+ if (id != 0) {
+ nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "WDT(%d) doesn't exist", id));
+ }
+
+ // timeout is in milliseconds
+ mp_int_t timeout = args[ARG_timeout].u_int;
+
+ // compute prescaler
+ uint32_t prescaler;
+ for (prescaler = 0; prescaler < 6 && timeout >= 512; ++prescaler, timeout /= 2) {
+ }
+
+ // convert milliseconds to ticks
+ timeout *= 8; // 32kHz / 4 = 8 ticks per millisecond (approx)
+ if (timeout <= 0) {
+ mp_raise_ValueError("WDT timeout too short");
+ } else if (timeout > 0xfff) {
+ mp_raise_ValueError("WDT timeout too long");
+ }
+ timeout -= 1;
+
+ // set the reload register
+ while (IWDG->SR & 2) {
+ }
+ IWDG->KR = 0x5555;
+ IWDG->RLR = timeout;
+
+ // set the prescaler
+ while (IWDG->SR & 1) {
+ }
+ IWDG->KR = 0x5555;
+ IWDG->PR = prescaler;
+
+ // start the watch dog
+ IWDG->KR = 0xcccc;
+
+ return (mp_obj_t)&pyb_wdt;
+}
+
+STATIC mp_obj_t pyb_wdt_feed(mp_obj_t self_in) {
+ (void)self_in;
+ IWDG->KR = 0xaaaa;
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_wdt_feed_obj, pyb_wdt_feed);
+
+STATIC const mp_rom_map_elem_t pyb_wdt_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_feed), MP_ROM_PTR(&pyb_wdt_feed_obj) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(pyb_wdt_locals_dict, pyb_wdt_locals_dict_table);
+
+const mp_obj_type_t pyb_wdt_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_WDT,
+ .make_new = pyb_wdt_make_new,
+ .locals_dict = (mp_obj_dict_t*)&pyb_wdt_locals_dict,
+};
diff --git a/ports/stm32/wdt.h b/ports/stm32/wdt.h
new file mode 100644
index 000000000..0a486f704
--- /dev/null
+++ b/ports/stm32/wdt.h
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ */
+#ifndef MICROPY_INCLUDED_STMHAL_WDT_H
+#define MICROPY_INCLUDED_STMHAL_WDT_H
+
+extern const mp_obj_type_t pyb_wdt_type;
+
+#endif // MICROPY_INCLUDED_STMHAL_WDT_H