diff options
| author | Damien George | 2017-09-06 13:40:51 +1000 |
|---|---|---|
| committer | Damien George | 2017-09-06 13:40:51 +1000 |
| commit | 01dd7804b87d60b2deab16712eccb3b97351a9b7 (patch) | |
| tree | 1aa21f38a872b8e62a3d4e4f74f68033c6f827e4 /ports/stm32 | |
| parent | a9862b30068fc9df1022f08019fb35aaa5085f64 (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')
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>© 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>© 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>© 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>© 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>© 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>© 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>© 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>© 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>© 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>© 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>© 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>© 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>© 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>© 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>© 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>© 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>© 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>© 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>© 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>© 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>© 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>© 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>© 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>© 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, ¶ms); + 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>© 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>© 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>© 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>© 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>© 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>© 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>© 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>© 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>© 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>© 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>© 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="--"/>
+ <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: "Arial","sans-serif";"><o:p> </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: "Arial","sans-serif"; 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: "Verdana","sans-serif"; color: rgb(51, 102, 255);">Release Notes for STM32 USB Device Library</span><span style="font-size: 20pt; font-family: "Verdana","sans-serif";"><o:p></o:p></span></h1>
+ <p class="MsoNormal" style="text-align: center;" align="center"><span style="font-size: 10pt; font-family: "Arial","sans-serif"; 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: "Arial","sans-serif"; 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: "Arial","sans-serif"; display: none;"><o:p> </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: "Verdana","sans-serif";"></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: "Verdana","sans-serif"; color: black;">Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); You may not use this </span><span style="font-size: 10pt; font-family: "Verdana","sans-serif"; color: black;">package</span><span style="font-size: 10pt; font-family: "Verdana","sans-serif"; 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: "Verdana","sans-serif"; color: black;"> <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: "Verdana","sans-serif"; color: black;"></span></div><span style="font-size: 10pt; font-family: "Verdana","sans-serif"; 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: "Verdana","sans-serif"; color: black;">For
+ complete documentation on </span><span style="font-size: 10pt; font-family: "Verdana","sans-serif";">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: "Verdana","sans-serif";"><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> </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>© 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>© 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>© 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>© 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>© 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>© 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>© 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>© 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>© 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>© 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>© 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>© 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>© 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>© 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>© 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>© 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>© 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>© 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>© 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>© 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>© 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>© 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>© 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>© 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>© 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>© 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>© 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>© 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>© 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>© 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>© 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>© 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>© 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>© 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>© 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>© 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>© 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>© 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>© 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>© 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>© 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>© 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>© 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>© 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>© 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>© 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>© 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>© 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>© 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>© 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="--"/>
+ <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: "Arial","sans-serif";"><o:p> </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: "Arial","sans-serif"; 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: "Verdana","sans-serif"; color: rgb(51, 102, 255);">Release Notes for STM32 USB Host Library</span><span style="font-size: 20pt; font-family: "Verdana","sans-serif";"><o:p></o:p></span></h1>
+ <p class="MsoNormal" style="text-align: center;" align="center"><span style="font-size: 10pt; font-family: "Arial","sans-serif"; 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: "Arial","sans-serif"; 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: "Arial","sans-serif"; display: none;"><o:p> </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 < 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 - 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 </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: "Verdana","sans-serif"; color: black;">Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); You may not use this </span><span style="font-size: 10pt; font-family: "Verdana","sans-serif"; color: black;">package</span><span style="font-size: 10pt; font-family: "Verdana","sans-serif"; 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: "Verdana","sans-serif"; color: black;"> <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: "Verdana","sans-serif"; color: black;"></span></div><span style="font-size: 10pt; font-family: "Verdana","sans-serif"; 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: "Verdana","sans-serif"; color: black;">For
+ complete documentation on </span><span style="font-size: 10pt; font-family: "Verdana","sans-serif";">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: "Verdana","sans-serif";"><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> </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 |
