From 9e4b78c1e8c6324f1b7f0482dfde8c40b2ad7b70 Mon Sep 17 00:00:00 2001 From: Jim Huang Date: Wed, 25 Mar 2026 15:30:04 +0800 Subject: [PATCH] Switch QEMU from NETDUINOPLUS2 to B-L475E-IOT01A This replaces Netduino Plus 2 (STM32F4) QEMU target with B-L475E-IOT01A Discovery (STM32L475VG) for proper FPU/MPU emulation, eliminating the mock infrastructure (mpu_mock, scb_mock, safe_mmio) that was papering over the old target's incomplete peripheral emulation. Platform changes: - Add STM32L4 platform support (registers, GPIO, RCC, USART, NVIC, linker scripts with correct L4 memory map and no CCM RAM) - Fix L4 register addresses: USART1 at 0x40013800, RCC enable registers at correct L4 offsets, GPIO clocks on AHB2 (not AHB1), PLL source set to MSI (not HSE), USART_IT_CR offsets for L4 - Add full L4 USART register ops (ISR/RDR/TDR layout) - Add ARM semihosting for console I/O under QEMU FPU support: - Fix irq_restore: single asm block with __builtin_offsetof prevents compiler from reusing clobbered registers after ldm {r4-r11} - Add -mgeneral-regs-only to kernel CFLAGS to prevent GCC from emitting VFP instructions for non-FP operations in handler mode - Add FPU lazy context save/restore (d8-d15) in PendSV handler IPC fix: - Fix L4_Ipc naked function: reload UTCB MR pointer from current_utcb after SVC return instead of reusing LR (which the exception frame restores to the caller's return address) KDB: - Add USART1 RX interrupt path for KDB input under QEMU semihosting (CONFIG_KDB_UART_INPUT, gated on CONFIG_QEMU) - Improve hard fault handler to read correct stack (MSP vs PSP) Build/test: - Update qemu-test.py: auto-detect board, add -semihosting for L4, fail on unsupported boards instead of silent fallback - Bootstrap Kconfig tools in CI test job before direct Python usage - Update CI workflow: replace netduinoplus2 with b-l475e-iot01a - Remove Netduino Plus 2 board, STM32F1 platform, mock infrastructure --- .github/workflows/build.yml | 54 +- .github/workflows/qemu-build.yml | 76 + Documentation/quick-start.md | 18 +- Makefile | 17 +- README.md | 14 +- board/Kconfig | 54 +- .../{netduinoplus2 => b-l475e-iot01a}/board.c | 6 +- board/b-l475e-iot01a/board.h | 29 + .../build.mk | 4 +- board/b-l475e-iot01a/defconfig | 2 + board/netduinoplus2/board.h | 62 - board/netduinoplus2/defconfig | 166 -- include/platform/cortex_m.h | 3 + include/platform/debug_device.h | 8 +- include/platform/debug_semihosting.h | 13 + include/platform/irq.h | 133 +- include/platform/stm32f1/gpio.h | 82 - include/platform/stm32f1/nvic_private.h | 217 -- include/platform/stm32f1/registers.h | 767 -------- include/platform/stm32f1/syscfg.h | 9 - include/platform/{stm32f1 => stm32l4}/exti.h | 8 +- include/platform/stm32l4/gpio.h | 84 + .../platform/{stm32f1 => stm32l4}/hwtimer.h | 8 +- include/platform/{stm32f1 => stm32l4}/nvic.h | 152 +- include/platform/stm32l4/nvic_private.h | 410 ++++ .../{stm32f1 => stm32l4}/nvic_table.h | 2 +- include/platform/{stm32f1 => stm32l4}/rcc.h | 16 +- include/platform/stm32l4/registers.h | 1744 +++++++++++++++++ include/platform/stm32l4/syscfg.h | 27 + .../platform/{stm32f1 => stm32l4}/systick.h | 8 +- include/platform/{stm32f1 => stm32l4}/usart.h | 21 +- include/thread.h | 17 +- kernel/Kconfig | 1 - kernel/init.c | 35 + kernel/ipc.c | 111 +- kernel/memory.c | 23 +- kernel/start.c | 12 + kernel/syscall.c | 8 +- kernel/systhread.c | 22 + kernel/thread.c | 138 +- mk/generic.mk | 21 +- mk/toolchain.mk | 2 +- platform/Kconfig | 21 +- platform/Kconfig.debug | 43 +- platform/build.mk | 17 +- platform/debug_device.c | 28 +- platform/debug_semihosting.c | 53 + platform/debug_uart.c | 2 +- platform/kdb_uart.c | 88 + platform/semihosting.c | 72 + platform/stm32-common/build.mk | 5 +- platform/stm32-common/gpio-f1.c | 106 - platform/stm32-common/gpio-l4.c | 167 ++ platform/stm32-common/mpu.c | 31 +- platform/stm32-common/rcc.c | 130 +- platform/stm32-common/usart.c | 12 + platform/stm32f1/Kconfig | 175 -- platform/stm32f1/usart.c | 1 - platform/stm32l4/Kconfig | 330 ++++ platform/{stm32f1 => stm32l4}/build.mk | 6 +- platform/{stm32f1 => stm32l4}/f9.ld | 28 +- platform/{stm32f1 => stm32l4}/f9_flash.ld | 30 +- platform/{stm32f1 => stm32l4}/f9_mem.ld | 2 +- platform/{stm32f1 => stm32l4}/f9_sram.ld | 28 +- platform/{stm32f1 => stm32l4}/gpio.c | 0 platform/{stm32f1 => stm32l4}/hwtimer.c | 0 platform/{stm32f1 => stm32l4}/mpu.c | 0 platform/{stm32f1 => stm32l4}/nvic.c | 0 platform/{stm32f1 => stm32l4}/rcc.c | 0 platform/{stm32f1 => stm32l4}/systick.c | 0 platform/stm32l4/usart.c | 102 + scripts/qemu-kdb-auto.py | 159 ++ scripts/qemu-kdb.sh | 77 + scripts/qemu-test.py | 193 +- user/apps/tests/main.c | 14 +- user/apps/tests/test-arm.c | 2 +- user/apps/tests/test-fault.c | 4 +- user/include/l4/pager.h | 1 + user/include/platform/safe_mmio.h | 227 --- user/lib/build.mk | 3 - user/lib/io/semihost-io.c | 13 + user/lib/l4/pager.c | 69 +- user/lib/l4/platform/syscalls.c | 103 +- user/lib/mpu_mock.c | 61 - user/lib/scb_mock.c | 66 - user/root_thread.c | 196 +- 86 files changed, 4737 insertions(+), 2532 deletions(-) create mode 100644 .github/workflows/qemu-build.yml rename board/{netduinoplus2 => b-l475e-iot01a}/board.c (91%) create mode 100644 board/b-l475e-iot01a/board.h rename board/{netduinoplus2 => b-l475e-iot01a}/build.mk (87%) create mode 100644 board/b-l475e-iot01a/defconfig delete mode 100644 board/netduinoplus2/board.h delete mode 100644 board/netduinoplus2/defconfig create mode 100644 include/platform/debug_semihosting.h delete mode 100644 include/platform/stm32f1/gpio.h delete mode 100644 include/platform/stm32f1/nvic_private.h delete mode 100644 include/platform/stm32f1/registers.h delete mode 100644 include/platform/stm32f1/syscfg.h rename include/platform/{stm32f1 => stm32l4}/exti.h (76%) create mode 100644 include/platform/stm32l4/gpio.h rename include/platform/{stm32f1 => stm32l4}/hwtimer.h (52%) rename include/platform/{stm32f1 => stm32l4}/nvic.h (52%) create mode 100644 include/platform/stm32l4/nvic_private.h rename include/platform/{stm32f1 => stm32l4}/nvic_table.h (77%) rename include/platform/{stm32f1 => stm32l4}/rcc.h (64%) create mode 100644 include/platform/stm32l4/registers.h create mode 100644 include/platform/stm32l4/syscfg.h rename include/platform/{stm32f1 => stm32l4}/systick.h (52%) rename include/platform/{stm32f1 => stm32l4}/usart.h (79%) create mode 100644 platform/debug_semihosting.c create mode 100644 platform/kdb_uart.c create mode 100644 platform/semihosting.c delete mode 100644 platform/stm32-common/gpio-f1.c create mode 100644 platform/stm32-common/gpio-l4.c delete mode 100644 platform/stm32f1/Kconfig delete mode 100644 platform/stm32f1/usart.c create mode 100644 platform/stm32l4/Kconfig rename platform/{stm32f1 => stm32l4}/build.mk (84%) rename platform/{stm32f1 => stm32l4}/f9.ld (84%) rename platform/{stm32f1 => stm32l4}/f9_flash.ld (82%) rename platform/{stm32f1 => stm32l4}/f9_mem.ld (64%) rename platform/{stm32f1 => stm32l4}/f9_sram.ld (84%) rename platform/{stm32f1 => stm32l4}/gpio.c (100%) rename platform/{stm32f1 => stm32l4}/hwtimer.c (100%) rename platform/{stm32f1 => stm32l4}/mpu.c (100%) rename platform/{stm32f1 => stm32l4}/nvic.c (100%) rename platform/{stm32f1 => stm32l4}/rcc.c (100%) rename platform/{stm32f1 => stm32l4}/systick.c (100%) create mode 100644 platform/stm32l4/usart.c create mode 100755 scripts/qemu-kdb-auto.py create mode 100755 scripts/qemu-kdb.sh delete mode 100644 user/include/platform/safe_mmio.h delete mode 100644 user/lib/mpu_mock.c delete mode 100644 user/lib/scb_mock.c diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2b193d23..b85a09fe 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -14,7 +14,7 @@ jobs: runs-on: ubuntu-24.04 strategy: matrix: - board: [discoveryf4, discoveryf429, netduinoplus2] + board: [discoveryf4, discoveryf429, b-l475e-iot01a] steps: - uses: actions/checkout@v6 @@ -52,9 +52,13 @@ jobs: - app: tests name: "Kernel Test Suite" config: USER_APP_TESTS + config_extra: "" - app: posix name: "POSIX Compliance (PSE51+PSE52)" config: USER_APP_POSIX + # POSIX test suite is larger; disable symbol map and kprobes + # to fit kernel + user code in 96KB SRAM1. + config_extra: "SYMMAP=n KPROBES=n" name: test (${{ matrix.app }}) steps: @@ -66,15 +70,47 @@ jobs: release: '15.2.Rel1' - name: Install QEMU - run: sudo apt-get update && sudo apt-get install -y qemu-system-arm - - - name: Configure for netduinoplus2 with ${{ matrix.name }} + env: + GH_TOKEN: ${{ github.token }} + QEMU_VERSION: '10.2.2' + run: | + asset="qemu-${QEMU_VERSION}-arm-softmmu-linux-x86_64.tar.gz" + + # Try prebuilt binary from GitHub release first, fall back to + # building from source (needed until qemu-build.yml has run once). + dl_err=$(gh release download "qemu-v${QEMU_VERSION}" \ + --pattern "$asset" --dir /tmp 2>&1) && dl_ok=1 || dl_ok=0 + if [ "$dl_ok" = 1 ]; then + echo "[QEMU] Using prebuilt binary from release" + sudo tar -xzf "/tmp/${asset}" -C /opt + elif echo "$dl_err" | grep -qi "release not found"; then + echo "[QEMU] Release not found, building from source..." + sudo apt-get update + sudo apt-get install -y ninja-build pkg-config libglib2.0-dev libpixman-1-dev + curl -fsSL "https://download.qemu.org/qemu-${QEMU_VERSION}.tar.xz" | tar xJ + cd "qemu-${QEMU_VERSION}" + ./configure --target-list=arm-softmmu --prefix=/opt/qemu --disable-docs + make -j$(nproc) + sudo make install + cd .. + else + echo "[QEMU] gh release download failed: $dl_err" + exit 1 + fi + + echo "/opt/qemu/bin" >> "$GITHUB_PATH" + /opt/qemu/bin/qemu-system-arm --version + /opt/qemu/bin/qemu-system-arm -M help | awk '{print $1}' | grep -Fx b-l475e-iot01a + + - name: Configure for b-l475e-iot01a with ${{ matrix.name }} run: | - make netduinoplus2_defconfig - # Enable QEMU mode and selected test suite + # Bootstrap Kconfig tools (cloned on demand by make, but we + # need them before the first make invocation here) + make tools/kconfig/kconfiglib.py + cp board/b-l475e-iot01a/defconfig .config + # Enable selected test suite on top of board defaults python3 tools/kconfig/setconfig.py \ - QEMU=y \ - ${{ matrix.config }}=y + ${{ matrix.config }}=y ${{ matrix.config_extra }} python3 tools/kconfig/genconfig.py --header-path include/autoconf.h Kconfig - name: Verify configuration @@ -91,7 +127,7 @@ jobs: - name: Run MPU fault test if: matrix.app == 'tests' run: make run-tests FAULT=mpu - continue-on-error: true # MPU not fully emulated in QEMU + continue-on-error: true # MPU fault test may behave differently under QEMU - name: Run stack canary fault test if: matrix.app == 'tests' diff --git a/.github/workflows/qemu-build.yml b/.github/workflows/qemu-build.yml new file mode 100644 index 00000000..528eebfb --- /dev/null +++ b/.github/workflows/qemu-build.yml @@ -0,0 +1,76 @@ +name: Build QEMU + +# Build a minimal QEMU (arm-softmmu only) and upload as a GitHub release. +# The test jobs in build.yml download this prebuilt binary instead of +# compiling QEMU from source on every run. +# +# Trigger manually or bump QEMU_VERSION to rebuild. + +on: + workflow_dispatch: + inputs: + qemu_version: + description: 'QEMU version to build (e.g. 10.2.2)' + required: true + default: '10.2.2' + +env: + QEMU_VERSION: ${{ inputs.qemu_version || '10.2.2' }} + +permissions: + contents: write # create releases + +jobs: + build: + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v6 + + - name: Validate version format + run: | + if ! echo "${QEMU_VERSION}" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+$'; then + echo "ERROR: Invalid QEMU_VERSION '${QEMU_VERSION}' (expected N.N.N)" + exit 1 + fi + + - name: Install build dependencies + run: | + sudo apt-get update + sudo apt-get install -y ninja-build pkg-config libglib2.0-dev libpixman-1-dev + + - name: Build QEMU ${{ env.QEMU_VERSION }} (arm-softmmu) + run: | + curl -fsSL "https://download.qemu.org/qemu-${QEMU_VERSION}.tar.xz" | tar xJ + cd "qemu-${QEMU_VERSION}" + ./configure \ + --target-list=arm-softmmu \ + --prefix=/opt/qemu \ + --disable-docs + make -j$(nproc) + sudo make install + + - name: Verify + run: | + /opt/qemu/bin/qemu-system-arm --version + /opt/qemu/bin/qemu-system-arm -M help | awk '{print $1}' | grep -Fx b-l475e-iot01a + + - name: Package + run: | + tar -czf "qemu-${QEMU_VERSION}-arm-softmmu-linux-x86_64.tar.gz" -C /opt qemu + + - name: Create release + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + tag="qemu-v${QEMU_VERSION}" + asset="qemu-${QEMU_VERSION}-arm-softmmu-linux-x86_64.tar.gz" + + # Upload to existing release, or create a new one. + # Upload first so the old asset stays available until replaced. + if gh release view "$tag" >/dev/null 2>&1; then + gh release upload "$tag" "$asset" --clobber + else + gh release create "$tag" "$asset" \ + --title "QEMU ${QEMU_VERSION} (arm-softmmu, linux-x86_64)" \ + --notes "Prebuilt QEMU ${QEMU_VERSION} (arm-softmmu only) for CI test jobs." + fi diff --git a/Documentation/quick-start.md b/Documentation/quick-start.md index f2ab5d9c..af446ed1 100644 --- a/Documentation/quick-start.md +++ b/Documentation/quick-start.md @@ -7,8 +7,8 @@ F9 Microkernel supports the following boards: * [STM32F429I-DISC1](https://www.st.com/en/evaluation-tools/32f429idiscovery.html) * [NUCLEO-F429ZI](https://www.st.com/en/evaluation-tools/nucleo-f429zi.html) - All supported boards are based on the ARM Cortex-M4F core. F9 should work on any STM32F40x/STM32F429/STM32F439 microcontroller. -* Netduino Plus 2 (STM32F405RGT6) - - Supported by upstream [QEMU for emulation](https://www.qemu.org/docs/master/system/arm/stm32.html), making it ideal for development and testing without hardware. +* [B-L475E-IOT01A](https://www.st.com/en/evaluation-tools/b-l475e-iot01a.html) + - Supported by upstream QEMU and used as the default emulation target. ## Toolchain Requirements @@ -89,16 +89,18 @@ KDB communicates via USART. The port can be selected during `make config`. ## QEMU Emulation -For Netduino Plus 2 under QEMU, the default configuration uses USART1, which -QEMU routes to the console. Run with: +For B-L475E-IOT01A under QEMU, semihosting carries normal console output and +USART1 is reserved for KDB input. Run with: ```shell -qemu-system-arm -M netduinoplus2 -nographic -serial mon:stdio \ - -kernel build/netduinoplus2/f9.elf +qemu-system-arm -M b-l475e-iot01a -nographic \ + -semihosting -serial mon:stdio \ + -kernel build/b-l475e-iot01a/f9.elf ``` -Note: `-serial mon:stdio` is required for interactive KDB shell. -The `mon:` prefix enables QEMU monitor access via `Ctrl+a` and `c`. Exit with `Ctrl+a` and `x`. +Note: `-serial mon:stdio` is still required for interactive KDB shell. +The `mon:` prefix enables QEMU monitor access via `Ctrl+A` then `c`. Exit with +`Ctrl+A` then `x`. ## Serial Terminal Setup diff --git a/Makefile b/Makefile index 44284629..f4cb807d 100644 --- a/Makefile +++ b/Makefile @@ -16,10 +16,10 @@ endif ifeq "$(CONFIG_BOARD_STM32F429DISCOVERY)" "y" BOARD ?= discoveryf429 -else ifeq "$(CONFIG_BOARD_NETDUINOPLUS2)" "y" -BOARD ?= netduinoplus2 else ifeq "$(CONFIG_BOARD_STM32F429NUCLEO)" "y" BOARD ?= nucleof429 +else ifeq "$(CONFIG_BOARD_B_L475E_IOT01A)" "y" +BOARD ?= b-l475e-iot01a else BOARD ?= discoveryf4 endif @@ -32,8 +32,9 @@ out ?= build/$(BOARD) # output directory for host build targets out_host ?= build/host -# QEMU command for netduinoplus2 emulation -# Usage: qemu-system-arm -M netduinoplus2 -nographic -kernel build/netduinoplus2/f9.elf +# QEMU emulation support (auto-detects board from build path) +# Usage: make run-tests +# Direct: qemu-system-arm -M b-l475e-iot01a -nographic -kernel build/b-l475e-iot01a/f9.elf QEMU ?= qemu-system-arm includes-user = user/include @@ -114,8 +115,12 @@ include mk/generic.mk # Run tests with clean output (filtered debug messages) .PHONY: qemu-clean -qemu-clean: +qemu-clean: $(out)/f9.elf @echo "Running F9 tests (clean output)..." - @python3 scripts/qemu-test.py $(out)/f9.elf -t 75 2>&1 | \ + @$(PYTHON) scripts/qemu-test.py $(out)/f9.elf -t 75 2>&1 | \ grep -vE "^(IPC: |pager_|THREAD_CREATE:)" | \ grep -vE "^\[TEST:(RUN|PASS|FAIL|SKIP|START)\]" || true + +# Note: 'make run-tests' target defined in mk/generic.mk +# Supports fault testing: make run-tests FAULT=mpu +# Auto-detects board and QEMU machine from build path diff --git a/README.md b/README.md index 6aca20c9..3b01a444 100644 --- a/README.md +++ b/README.md @@ -33,10 +33,10 @@ while adding advanced features from industrial RTOSes. - UTCBs: Always-mapped user-level thread control blocks for fast syscall argument access ### Hardware Support -- ARM Cortex-M3/M4/M4F: Optimized for Cortex-M architecture +- ARM Cortex-M4/M4F: Optimized for Cortex-M architecture - NVIC: Nested Vectored Interrupt Controller integration - Bit Banding: Hardware bit manipulation support (where available) -- FPU: Lazy context switching for Cortex-M4F floating-point unit +- FPU: Lazy context switching for Cortex-M4F floating-point unit (VFPv4-D16) ### Development Tools - KDB: In-kernel debugger with thread, memory, and timer inspection @@ -124,13 +124,16 @@ make flash # Flash to STM32F4 board (requires stlink) make qemu ``` -Press `Ctrl+A` and then `X` to exit QEMU. Press `?` in KDB for debug menu (requires `CONFIG_KDB`). +Press `Ctrl+A` then `X` to exit QEMU. Press `?` for KDB debug menu (requires `CONFIG_KDB`). + +QEMU uses the B-L475E-IOT01A machine with ARM semihosting for output and USART1 +for KDB input. Both `-semihosting` and `-serial mon:stdio` are added automatically. ### Supported Hardware - STM32F4DISCOVERY (STM32F407VG) - STM32F429I-DISC1 (STM32F429ZI) - NUCLEO-F429ZI (STM32F429ZI) -- Netduino Plus 2 (STM32F405RG) - QEMU only, used for automated testing +- B-L475E-IOT01A (STM32L475VG) - QEMU target with FPU and MPU emulation For detailed instructions including toolchain setup, serial configuration, and debugging, see [Documentation/quick-start.md](Documentation/quick-start.md). @@ -149,8 +152,9 @@ Run `make config` to configure options via menu. Key options: | `CONFIG_KTIMER_TICKLESS` | Tickless scheduling (power efficiency) | | `CONFIG_MAX_THREADS` | Maximum number of threads | | `CONFIG_MAX_KT_EVENTS` | Maximum kernel timer events | +| `CONFIG_FPU` | FPU support with lazy context switching (Cortex-M4F) | | `CONFIG_PANIC_DUMP_STACK` | Dump stack on kernel panic | -| `CONFIG_QEMU` | QEMU emulation workarounds | +| `CONFIG_QEMU` | QEMU emulation mode (auto-enabled for B-L475E-IOT01A) | For build system details, see [Documentation/build-system.md](Documentation/build-system.md). diff --git a/board/Kconfig b/board/Kconfig index 1c2961f9..dfb380fc 100644 --- a/board/Kconfig +++ b/board/Kconfig @@ -22,32 +22,38 @@ config BOARD_STM32F429DISCOVERY help STM32F429 Discovery board with STM32F429ZIT6 MCU and LCD. -config BOARD_NETDUINOPLUS2 - bool "Netduino Plus 2" - select PLATFORM_STM32F4 - help - Netduino Plus 2 board with STM32F405RGT6 MCU. - This board is supported by upstream QEMU for emulation. - config BOARD_STM32F429NUCLEO bool "STM32F429 Nucleo" select PLATFORM_STM32F429 help STM32F429 Nucleo board with STM32F429ZIT6 MCU. +config BOARD_B_L475E_IOT01A + bool "B-L475E-IOT01A Discovery" + select PLATFORM_STM32L4 + select QEMU + help + STMicroelectronics B-L475E-IOT01A Discovery board with STM32L475VG MCU. + Includes Cortex-M4F with FPU, MPU, and full QEMU support with FPU emulation. + QEMU mode is automatically enabled for this board. + + QEMU command: + qemu-system-arm -M b-l475e-iot01a -nographic -kernel build/b-l475e-iot01a/f9.elf + endchoice config QEMU - bool "QEMU emulation mode" - default y if BOARD_NETDUINOPLUS2 + bool "QEMU emulation mode" if !BOARD_B_L475E_IOT01A help Enable workarounds for QEMU emulation limitations: - - Use synchronous UART output (QEMU TXE interrupt unreliable) - - Place bitmaps in regular SRAM (QEMU lacks CCM RAM emulation) + - Use semihosting for console I/O (reliable in QEMU) + - Use synchronous UART output if UART is selected Enable this when running under QEMU. Disable for real hardware to get better performance. + Note: Automatically enabled and mandatory for B-L475E-IOT01A board. + # Hardware feature availability flags # These control which ARM architecture tests can run based on # platform capabilities and emulation limitations. @@ -65,29 +71,6 @@ config HAS_PRECISE_TIMING Disabled in QEMU because timing is not cycle-accurate. -config MPU_MOCK - bool "Software MPU mock for testing" - depends on QEMU - default y if QEMU - help - Enable minimal MPU register mock for test_arm_mpu_config in QEMU. - - Returns MPU_TYPE = 0x800 (8 regions, unified) to validate that - MPU_TYPE register is readable without QEMU hanging. - - For full MPU validation, test on real hardware with actual MPU. - -config SCB_MOCK - bool "Software SCB mock for testing" - depends on QEMU - default y if QEMU - help - Enable minimal SCB register mock for test_arm_unaligned in QEMU. - - Returns SCB_CCR = 0x200 (STKALIGN enabled, UNALIGN_TRP disabled) - to validate SCB_CCR register readability without QEMU hanging. - - For full SCB validation, test on real hardware with actual SCB. endmenu @@ -97,3 +80,6 @@ config PLATFORM_STM32F4 config PLATFORM_STM32F429 bool + +config PLATFORM_STM32L4 + bool diff --git a/board/netduinoplus2/board.c b/board/b-l475e-iot01a/board.c similarity index 91% rename from board/netduinoplus2/board.c rename to board/b-l475e-iot01a/board.c index 3e2f51d6..e0aa68ba 100644 --- a/board/netduinoplus2/board.c +++ b/board/b-l475e-iot01a/board.c @@ -4,11 +4,11 @@ */ #include "board.h" -#include -#include +#include +#include struct usart_dev console_uart = { - .u_num = 2, + .u_num = 1, .baud = 115200, BOARD_USART_CONFIGS.tx = { diff --git a/board/b-l475e-iot01a/board.h b/board/b-l475e-iot01a/board.h new file mode 100644 index 00000000..1f1825a2 --- /dev/null +++ b/board/b-l475e-iot01a/board.h @@ -0,0 +1,29 @@ +/* Copyright (c) 2013-2014 The F9 Microkernel Project. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef B_L475E_IOT01A_BOARD_H_ +#define B_L475E_IOT01A_BOARD_H_ + +#include +#include +#include +#include +#include + +extern struct usart_dev console_uart; + +/* ST-Link VCP uses USART1: PB6 (TX), PB7 (RX) */ +#define BOARD_UART_DEVICE USART1_IRQn +#define BOARD_UART_HANDLER USART1_HANDLER +#define BOARD_USART_FUNC af_usart1 +#define BOARD_USART_CONFIGS \ + .base = USART1_BASE, .rcc_apbenr = RCC_USART1_APBENR, \ + .rcc_reset = RCC_APB2RSTR_USART1RST, +#define BOARD_USART_TX_IO_PORT GPIOB +#define BOARD_USART_TX_IO_PIN 6 +#define BOARD_USART_RX_IO_PORT GPIOB +#define BOARD_USART_RX_IO_PIN 7 + +#endif /* B_L475E_IOT01A_BOARD_H_ */ diff --git a/board/netduinoplus2/build.mk b/board/b-l475e-iot01a/build.mk similarity index 87% rename from board/netduinoplus2/build.mk rename to board/b-l475e-iot01a/build.mk index cdfe8476..a0a8e4f6 100644 --- a/board/netduinoplus2/build.mk +++ b/board/b-l475e-iot01a/build.mk @@ -2,9 +2,9 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. -CHIP := stm32f4 +CHIP := stm32l4 PLATFORM := stm32 -STM32_VARIANT := f4 +STM32_VARIANT := l4 board-y = board.o loader-board-y = board.loader.o diff --git a/board/b-l475e-iot01a/defconfig b/board/b-l475e-iot01a/defconfig new file mode 100644 index 00000000..37ea55e8 --- /dev/null +++ b/board/b-l475e-iot01a/defconfig @@ -0,0 +1,2 @@ +CONFIG_BOARD_B_L475E_IOT01A=y +CONFIG_FPU=y diff --git a/board/netduinoplus2/board.h b/board/netduinoplus2/board.h deleted file mode 100644 index ab6fb7da..00000000 --- a/board/netduinoplus2/board.h +++ /dev/null @@ -1,62 +0,0 @@ -/* Copyright (c) 2013-2014 The F9 Microkernel Project. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef NETDUINOPLUS2_BOARD_H_ -#define NETDUINOPLUS2_BOARD_H_ - -#include -#include -#include -#include -#include - -extern struct usart_dev console_uart; - -#if defined(CONFIG_DBGPORT_USE_USART1) - -#define BOARD_UART_DEVICE USART1_IRQn -#define BOARD_UART_HANDLER USART1_HANDLER -#define BOARD_USART_FUNC af_usart1 -#define BOARD_USART_CONFIGS \ - .base = USART1_BASE, .rcc_apbenr = RCC_USART1_APBENR, \ - .rcc_reset = RCC_APB2RSTR_USART1RST, -#define BOARD_USART_TX_IO_PORT GPIOA -#define BOARD_USART_TX_IO_PIN 9 -#define BOARD_USART_RX_IO_PORT GPIOA -#define BOARD_USART_RX_IO_PIN 10 - -#elif defined(CONFIG_DBGPORT_USE_USART4) - -#define BOARD_UART_DEVICE UART4_IRQn -#define BOARD_UART_HANDLER UART4_HANDLER -#define BOARD_USART_FUNC af_uart4 -#define BOARD_USART_CONFIGS \ - .base = UART4_BASE, .rcc_apbenr = RCC_UART4_APBENR, \ - .rcc_reset = RCC_APB1RSTR_USART4RST, -#define BOARD_USART_TX_IO_PORT GPIOA -#define BOARD_USART_TX_IO_PIN 0 -#define BOARD_USART_RX_IO_PORT GPIOA -#define BOARD_USART_RX_IO_PIN 1 - -#else /* default: USART2 */ -/* CONFIG_DBGPORT_USE_USART2 - * Note: QEMU routes USART1 to the console by default. - * Use CONFIG_DBGPORT_USE_USART1 for QEMU emulation. - */ - -#define BOARD_UART_DEVICE USART2_IRQn -#define BOARD_UART_HANDLER USART2_HANDLER -#define BOARD_USART_FUNC af_usart2 -#define BOARD_USART_CONFIGS \ - .base = USART2_BASE, .rcc_apbenr = RCC_USART2_APBENR, \ - .rcc_reset = RCC_APB1RSTR_USART2RST, -#define BOARD_USART_TX_IO_PORT GPIOA -#define BOARD_USART_TX_IO_PIN 2 -#define BOARD_USART_RX_IO_PORT GPIOA -#define BOARD_USART_RX_IO_PIN 3 - -#endif - -#endif /* NETDUINOPLUS2_BOARD_H_ */ diff --git a/board/netduinoplus2/defconfig b/board/netduinoplus2/defconfig deleted file mode 100644 index 9f219bd5..00000000 --- a/board/netduinoplus2/defconfig +++ /dev/null @@ -1,166 +0,0 @@ -# -# Automatically generated make config: don't edit -# F9 Microkernel Configurations -# - -# -# Platform -# -# CONFIG_BOARD_STM32F4DISCOVERY is not set -# CONFIG_BOARD_STM32F429DISCOVERY is not set -CONFIG_BOARD_NETDUINOPLUS2=y -# CONFIG_BITMAP_BITBAND is not set -# CONFIG_FPU is not set -# CONFIG_STDIO_NODEV is not set -CONFIG_STDIO_USE_DBGPORT=y -CONFIG_DBGPORT_USE_USART1=y -# CONFIG_DBGPORT_USE_USART2 is not set -# CONFIG_DBGPORT_USE_USART4 is not set - -# -# Limitations -# -CONFIG_MAX_THREADS=32 -CONFIG_MAX_KT_EVENTS=64 -CONFIG_MAX_ASYNC_EVENTS=32 -CONFIG_MAX_ADRESS_SPACES=16 -CONFIG_MAX_FPAGES=256 - -# -# Kernel Timer -# -CONFIG_KTIMER_TICKLESS=y -# CONFIG_KTIMER_TICKLESS_VERIFY is not set -CONFIG_KTIMER_TICKLESS_COMPENSATION=0 -CONFIG_KTIMER_TICKLESS_INT_COMPENSATION=0 -CONFIG_KTIMER_HEARTBEAT=65536 -CONFIG_KTIMER_MINTICKS=128 - -# -# Flexible page tweaks -# -CONFIG_LARGEST_FPAGE_SHIFT=16 -CONFIG_SMALLEST_FPAGE_SHIFT=8 - -# -# Thread tweaks -# -CONFIG_INTR_THREAD_MAX=256 - -# -# KIP tweaks -# -CONFIG_KIP_EXTRA_SIZE=128 - -# -# Kernel hacking -# -CONFIG_DEBUG=y -CONFIG_DEBUG_DEV_UART=y -CONFIG_KDB=y -CONFIG_KPROBES=y -CONFIG_SYMMAP=y -CONFIG_PANIC_DUMP_STACK=y -# CONFIG_LOADER is not set - -# -# User IRQ -# -# CONFIG_WWDG_USER_IRQ is not set -# CONFIG_PVD_USER_IRQ is not set -# CONFIG_TAMP_STAMP_USER_IRQ is not set -# CONFIG_RTC_WKUP_USER_IRQ is not set -# CONFIG_FLASH_USER_IRQ is not set -# CONFIG_RCC_USER_IRQ is not set -# CONFIG_EXTI0_USER_IRQ is not set -# CONFIG_EXTI1_USER_IRQ is not set -# CONFIG_EXTI2_USER_IRQ is not set -# CONFIG_EXTI3_USER_IRQ is not set -# CONFIG_EXTI4_USER_IRQ is not set -# CONFIG_DMA1_Stream0_USER_IRQ is not set -# CONFIG_DMA1_Stream1_USER_IRQ is not set -# CONFIG_DMA1_Stream2_USER_IRQ is not set -# CONFIG_DMA1_Stream3_USER_IRQ is not set -# CONFIG_DMA1_Stream4_USER_IRQ is not set -# CONFIG_DMA1_Stream5_USER_IRQ is not set -# CONFIG_DMA1_Stream6_USER_IRQ is not set -# CONFIG_ADC_USER_IRQ is not set -# CONFIG_CAN1_TX_USER_IRQ is not set -# CONFIG_CAN1_RX_USER_IRQ is not set -# CONFIG_CAN1_RX1_USER_IRQ is not set -# CONFIG_CAN1_SCE_USER_IRQ is not set -# CONFIG_EXTI9_5_USER_IRQ is not set -# CONFIG_TIM1_BRK_TIM9_USER_IRQ is not set -# CONFIG_TIM1_UP_TIM10_USER_IRQ is not set -# CONFIG_TIM1_TRG_COM_TIM11_USER_IRQ is not set -# CONFIG_TIM1_CC_USER_IRQ is not set -# CONFIG_TIM2_USER_IRQ is not set -# CONFIG_TIM3_USER_IRQ is not set -# CONFIG_TIM4_USER_IRQ is not set -# CONFIG_I2C1_EV_USER_IRQ is not set -# CONFIG_I2C1_ER_USER_IRQ is not set -# CONFIG_I2C2_EV_USER_IRQ is not set -# CONFIG_I2C2_ER_USER_IRQ is not set -# CONFIG_SPI1_USER_IRQ is not set -# CONFIG_SPI2_USER_IRQ is not set -# CONFIG_USART1_USER_IRQ is not set -# CONFIG_USART2_USER_IRQ is not set -# CONFIG_USART3_USER_IRQ is not set -# CONFIG_EXTI15_10_USER_IRQ is not set -# CONFIG_RTC_Alarm_USER_IRQ is not set -# CONFIG_OTG_FS_WKUP_USER_IRQ is not set -# CONFIG_TIM8_BRK_TIM12_USER_IRQ is not set -# CONFIG_TIM8_UP_TIM13_USER_IRQ is not set -# CONFIG_TIM8_TRG_COM_TIM14_USER_IRQ is not set -# CONFIG_TIM8_CC_USER_IRQ is not set -# CONFIG_DMA1_Stream7_USER_IRQ is not set -# CONFIG_FSMC_USER_IRQ is not set -# CONFIG_SDIO_USER_IRQ is not set -# CONFIG_TIM5_USER_IRQ is not set -# CONFIG_SPI3_USER_IRQ is not set -# CONFIG_UART4_USER_IRQ is not set -# CONFIG_UART5_USER_IRQ is not set -# CONFIG_TIM6_DAC_USER_IRQ is not set -# CONFIG_TIM7_USER_IRQ is not set -# CONFIG_DMA2_Stream0_USER_IRQ is not set -# CONFIG_DMA2_Stream1_USER_IRQ is not set -# CONFIG_DMA2_Stream2_USER_IRQ is not set -# CONFIG_DMA2_Stream3_USER_IRQ is not set -# CONFIG_DMA2_Stream4_USER_IRQ is not set -# CONFIG_ETH_USER_IRQ is not set -# CONFIG_ETH_WKUP_USER_IRQ is not set -# CONFIG_CAN2_TX_USER_IRQ is not set -# CONFIG_CAN2_RX0_USER_IRQ is not set -# CONFIG_CAN2_RX1_USER_IRQ is not set -# CONFIG_CAN2_SCE_USER_IRQ is not set -# CONFIG_OTG_FS_USER_IRQ is not set -# CONFIG_DMA2_Stream5_USER_IRQ is not set -# CONFIG_DMA2_Stream6_USER_IRQ is not set -# CONFIG_DMA2_Stream7_USER_IRQ is not set -# CONFIG_USART6_USER_IRQ is not set -# CONFIG_I2C3_EV_USER_IRQ is not set -# CONFIG_I2C3_ER_USER_IRQ is not set -# CONFIG_OTG_HS_EP1_OUT_USER_IRQ is not set -# CONFIG_OTG_HS_EP1_IN_USER_IRQ is not set -# CONFIG_OTG_HS_WKUP_USER_IRQ is not set -# CONFIG_OTG_HS_USER_IRQ is not set -# CONFIG_DCMI_USER_IRQ is not set -# CONFIG_CRYP_USER_IRQ is not set -# CONFIG_HASH_RNG_USER_IRQ is not set -# CONFIG_FPU_USER_IRQ is not set - -# -# User Space -# -CONFIG_BUILD_USER_APPS=y - -# -# Apps -# -CONFIG_PINGPONG=y - -# -# Test Cases -# -# CONFIG_EXTI_INTERRUPT_TEST is not set -# CONFIG_LCD_TEST is not set diff --git a/include/platform/cortex_m.h b/include/platform/cortex_m.h index 78d4ef6a..34f09745 100644 --- a/include/platform/cortex_m.h +++ b/include/platform/cortex_m.h @@ -228,6 +228,9 @@ inline void __ISB(void) #define SCB_CCR_STKALIGN \ (uint32_t) (1 << 9) /* Stack 8-byte alignment on exception entry */ +#define SCB_CCR_UNALIGN_TRP \ + (uint32_t) (1 << 3) /* Trap on unaligned accesses \ + */ #define SCB_SHCSR_MEMFAULTENA \ (uint32_t) (1 << 16) /* Enables Memory Management Fault */ diff --git a/include/platform/debug_device.h b/include/platform/debug_device.h index 99aa88a5..678d2015 100644 --- a/include/platform/debug_device.h +++ b/include/platform/debug_device.h @@ -8,8 +8,9 @@ #include #include -#if defined(CONFIG_DEBUG) && \ - (defined(CONFIG_DEBUG_DEV_UART) || defined(CONFIG_DEBUG_DEV_RAM)) +#if defined(CONFIG_DEBUG) && \ + (defined(CONFIG_DEBUG_DEV_UART) || defined(CONFIG_DEBUG_DEV_RAM) || \ + defined(CONFIG_DEBUG_DEV_SEMIHOSTING)) #define DEBUG_DEVICE_EXIST #endif @@ -21,6 +22,9 @@ typedef enum { #ifdef CONFIG_DEBUG_DEV_UART DBG_DEV_UART, #endif +#ifdef CONFIG_DEBUG_DEV_SEMIHOSTING + DBG_DEV_SEMIHOSTING, +#endif #ifdef CONFIG_DEBUG_DEV_RAM DBG_DEV_RAM, #endif diff --git a/include/platform/debug_semihosting.h b/include/platform/debug_semihosting.h new file mode 100644 index 00000000..8f43f124 --- /dev/null +++ b/include/platform/debug_semihosting.h @@ -0,0 +1,13 @@ +/* Copyright (c) 2013 The F9 Microkernel Project. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef PLATFORM_DEBUG_SEMIHOSTING_H_ +#define PLATFORM_DEBUG_SEMIHOSTING_H_ + +#include + +void dbg_semihosting_init(void); + +#endif /* PLATFORM_DEBUG_SEMIHOSTING_H_ */ diff --git a/include/platform/irq.h b/include/platform/irq.h index 5500e2d5..e88377a5 100644 --- a/include/platform/irq.h +++ b/include/platform/irq.h @@ -200,6 +200,56 @@ extern volatile uint32_t __irq_saved_regs[8]; __irq_save(ctx); #endif +#ifdef CONFIG_FPU +/* FPU-aware irq_restore: single asm block to prevent the compiler from + * reordering or clobbering registers between dependent operations. + * + * We pass a single pointer (ctx) and load all fields inside the asm to + * avoid running out of input registers (ARM has only ~6 allocatable GPRs + * after clobbers). The ctx pointer is in r3 throughout. + * + * Sequence: load ret/sp/ctl from ctx → set MSP/PSP → restore d8-d15 + * if fp_flag → ldm {r4-r11} → msr CONTROL → cpsie i. + */ +#define irq_restore(ctx) \ + do { \ + context_t *_ctx = (ctx); \ + __asm__ __volatile__( \ + "mov r3, %[c]\n\t" /* Load ret, sp, ctl from context */ \ + "ldr lr, [r3, %[off_ret]]\n\t" \ + "ldr r0, [r3, %[off_sp]]\n\t" \ + "ldr r2, [r3, %[off_ctl]]\n\t" /* Select MSP or PSP based on \ + EXC_RETURN */ \ + "and r4, lr, #0xf\n\t" \ + "teq r4, #0x9\n\t" \ + "ite eq\n\t" \ + "msreq msp, r0\n\t" \ + "msrne psp, r0\n\t" /* Restore FPU callee-saved regs if fp_flag \ + set */ \ + "ldr r0, [r3, %[off_fpf]]\n\t" \ + "cmp r0, #0\n\t" \ + "beq 1f\n\t" \ + "add r0, r3, %[off_fpr]\n\t" \ + "vldm r0, {d8-d15}\n\t" \ + "1:\n\t" /* Restore R4-R11 (MUST be last - clobbers everything) */ \ + "add r0, r3, %[off_reg]\n\t" \ + "ldm r0, {r4-r11}\n\t" /* Set CONTROL and barrier */ \ + "msr control, r2\n\t" \ + "isb\n\t" \ + "cpsie i" \ + : \ + : \ + [c] "r"(_ctx), [off_ret] "i"(__builtin_offsetof(context_t, ret)), \ + [off_sp] "i"(__builtin_offsetof(context_t, sp)), \ + [off_ctl] "i"(__builtin_offsetof(context_t, ctl)), \ + [off_fpf] "i"(__builtin_offsetof(context_t, fp_flag)), \ + [off_fpr] "i"(__builtin_offsetof(context_t, fp_regs)), \ + [off_reg] "i"(__builtin_offsetof(context_t, regs)) \ + : "r0", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", \ + "r11", "lr", "cc", "memory", "d8", "d9", "d10", "d11", "d12", \ + "d13", "d14", "d15"); \ + } while (0) +#else /* ! CONFIG_FPU */ #define __irq_restore(ctx) \ __asm__ __volatile__("mov lr, %0" : : "r"((ctx)->ret)); \ __asm__ __volatile__("mov r0, %0" : : "r"((ctx)->sp)); \ @@ -213,15 +263,6 @@ extern volatile uint32_t __irq_saved_regs[8]; __asm__ __volatile__("ldm r0, {r4-r11}"); \ __asm__ __volatile__("msr control, r2\n\tisb" ::: "memory"); -#ifdef CONFIG_FPU -#define irq_restore(ctx) \ - __irq_restore(ctx); \ - if ((ctx)->fp_flag) { \ - __asm__ __volatile__("mov r0, %0" : : "r"((ctx)->fp_regs) : "r0"); \ - __asm__ __volatile__("vldm r0, {d8-d15}"); \ - } \ - __asm__ __volatile__("cpsie i"); -#else /* ! CONFIG_FPU */ #define irq_restore(ctx) \ __irq_restore(ctx); \ __asm__ __volatile__("cpsie i"); @@ -254,41 +295,45 @@ extern volatile uint32_t __irq_saved_regs[8]; __asm__ __volatile__("bx lr"); \ } -#define schedule_in_irq() \ - { \ - register tcb_t *sel; \ - sel = schedule_select(); \ - /* Check current thread canary before any return path. \ - * Catches overflow that occurred while thread ran. */ \ - if (!thread_check_canary((tcb_t *) current)) { \ - panic( \ - "Stack overflow (current): tid=%t, " \ - "stack_base=%p, canary=%p\n", \ - current->t_globalid, current->stack_base, \ - current->stack_base ? *((uint32_t *) current->stack_base) \ - : 0); \ - } \ - if (sel != current) { \ - /* Check next thread before switching to it */ \ - if (!thread_check_canary(sel)) { \ - panic( \ - "Stack overflow (next): tid=%t, " \ - "stack_base=%p, canary=%p\n", \ - sel->t_globalid, sel->stack_base, \ - sel->stack_base ? *((uint32_t *) sel->stack_base) : 0); \ - } \ - context_switch(current, sel); \ - } else { \ - /* No context switch - restore saved registers \ - * and return via irq_return path */ \ - extern volatile uint32_t __irq_saved_regs[8]; \ - __asm__ __volatile__( \ - "mov r0, %0\n\t" \ - "ldm r0, {r4-r11}" \ - : \ - : "r"(__irq_saved_regs) \ - : "r0"); \ - } \ +#define schedule_in_irq() \ + { \ + register tcb_t *sel; \ + sel = schedule_select(); \ + /* Check current thread canary before any return path. \ + * Catches overflow that occurred while thread ran. */ \ + if (!thread_check_canary((tcb_t *) current)) { \ + panic( \ + "Stack overflow (current): tid=%t, " \ + "stack_base=%p, canary=%p\n", \ + current->t_globalid, current->stack_base, \ + (current->stack_base && \ + !((uint32_t) current->stack_base & 0x3)) \ + ? *((uint32_t *) current->stack_base) \ + : 0xDEADBEEF); \ + } \ + if (sel != current) { \ + /* Check next thread before switching to it */ \ + if (!thread_check_canary(sel)) { \ + panic( \ + "Stack overflow (next): tid=%t, " \ + "stack_base=%p, canary=%p\n", \ + sel->t_globalid, sel->stack_base, \ + (sel->stack_base && !((uint32_t) sel->stack_base & 0x3)) \ + ? *((uint32_t *) sel->stack_base) \ + : 0xDEADBEEF); \ + } \ + context_switch(current, sel); \ + } else { \ + /* No context switch - restore saved registers \ + * and return via irq_return path */ \ + extern volatile uint32_t __irq_saved_regs[8]; \ + __asm__ __volatile__( \ + "mov r0, %0\n\t" \ + "ldm r0, {r4-r11}" \ + : \ + : "r"(__irq_saved_regs) \ + : "r0"); \ + } \ } #define request_schedule() \ diff --git a/include/platform/stm32f1/gpio.h b/include/platform/stm32f1/gpio.h deleted file mode 100644 index 768e7cdd..00000000 --- a/include/platform/stm32f1/gpio.h +++ /dev/null @@ -1,82 +0,0 @@ -/* Copyright (c) 2014 The F9 Microkernel Project. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef PLATFORM_STM32F1_GPIO_H_ -#define PLATFORM_STM32F1_GPIO_H_ - -#include - -enum { - AF0 = 0, - AF1, - AF2, - AF3, - AF4, - AF5, - AF6, - AF7, - AF8, - AF9, - AF10, - AF11, - AF12, - AF13, - AF14, - AF15, -}; - -struct gpio_cfg { - uint8_t port; - uint8_t pin; - uint8_t mode; - uint8_t ospeed; - uint8_t func; -}; - -/* GPIO Alternative Function */ -#define af_spi1 ((uint32_t) 0x00000001) -#define af_i2c1 ((uint32_t) 0x00000002) -#define af_usart1 ((uint32_t) 0x00000004) -#define af_usart2 ((uint32_t) 0x00000008) -#define af_partial_usart3 ((uint32_t) 0x00140010) -#define af_full_usart3 ((uint32_t) 0x00140030) -#define af_partial_tim1 ((uint32_t) 0x00160040) -#define af_full_tim1 ((uint32_t) 0x001600C0) -#define af_partial_tim2_1 ((uint32_t) 0x00180100) -#define af_partial_tim2_2 ((uint32_t) 0x00180200) -#define af_full_tim2 ((uint32_t) 0x00180300) -#define af_partial_tim3 ((uint32_t) 0x001A0800) -#define af_full_tim3 ((uint32_t) 0x001A0C00) -#define af_tim4 ((uint32_t) 0x00001000) -#define af_can1_1 ((uint32_t) 0x001D4000) -#define af_can1_2 ((uint32_t) 0x001D6000) -#define af_pd01 ((uint32_t) 0x00008000) -#define af_tim5_ch4 ((uint32_t) 0x00200001) -#define af_adc1_ext_inj ((uint32_t) 0x00200002) -#define af_adc1_ext_reg ((uint32_t) 0x00200004) -#define af_adc2_ext_inj ((uint32_t) 0x00200008) -#define af_adc2_ext_reg ((uint32_t) 0x00200010) -#define af_eth ((uint32_t) 0x00200020) -#define af_can2 ((uint32_t) 0x00200040) -#define af_swj_nojtrst ((uint32_t) 0x00300100) -#define af_swj_jtagdisable ((uint32_t) 0x00300200) -#define af_swj_disable ((uint32_t) 0x00300400) -#define af_spi3 ((uint32_t) 0x00201100) -#define af_tim2itr1_ptp_sof ((uint32_t) 0x00202000) -#define af_ptp_pps ((uint32_t) 0x00200400) -#define af_tim1_dma ((uint32_t) 0x80000010) - -void gpio_config(struct gpio_cfg *cfg); -void gpio_config_output(uint8_t port, - uint8_t pin, - uint8_t mode, - uint8_t ospeed); -void gpio_config_input(uint8_t port, uint8_t pin, uint8_t mode); -void gpio_out_high(uint8_t port, uint8_t pin); -void gpio_out_low(uint8_t port, uint8_t pin); -uint8_t gpio_input_bit(uint8_t port, uint8_t pin); -void gpio_writebit(uint8_t port, uint8_t pin, uint8_t bitval); - -#endif /* PLATFORM_STM32F1_GPIO_H_ */ diff --git a/include/platform/stm32f1/nvic_private.h b/include/platform/stm32f1/nvic_private.h deleted file mode 100644 index 49964455..00000000 --- a/include/platform/stm32f1/nvic_private.h +++ /dev/null @@ -1,217 +0,0 @@ -/* This header is only included internally. */ - -/* This header is only included internally. */ -#if !defined(USER_INTERRUPT) || \ - (defined(USER_INTERRUPT) && defined(CONFIG_WWDG_USER_IRQ)) -IRQ_VEC_N_OP(0) -#endif - -#if !defined(USER_INTERRUPT) || \ - (defined(USER_INTERRUPT) && defined(CONFIG_PVD_USER_IRQ)) -IRQ_VEC_N_OP(1) -#endif - -#if !defined(USER_INTERRUPT) || \ - (defined(USER_INTERRUPT) && defined(CONFIG_TAMP_STAMP_USER_IRQ)) -IRQ_VEC_N_OP(2) -#endif - -#if !defined(USER_INTERRUPT) || \ - (defined(USER_INTERRUPT) && defined(CONFIG_RTC_WKUP_USER_IRQ)) -IRQ_VEC_N_OP(3) -#endif - -#if !defined(USER_INTERRUPT) || \ - (defined(USER_INTERRUPT) && defined(CONFIG_FLASH_USER_IRQ)) -IRQ_VEC_N_OP(4) -#endif - -#if !defined(USER_INTERRUPT) || \ - (defined(USER_INTERRUPT) && defined(CONFIG_RCC_USER_IRQ)) -IRQ_VEC_N_OP(5) -#endif - -#if !defined(USER_INTERRUPT) || \ - (defined(USER_INTERRUPT) && defined(CONFIG_EXTI0_USER_IRQ)) -IRQ_VEC_N_OP(6) -#endif - -#if !defined(USER_INTERRUPT) || \ - (defined(USER_INTERRUPT) && defined(CONFIG_EXTI1_USER_IRQ)) -IRQ_VEC_N_OP(7) -#endif - -#if !defined(USER_INTERRUPT) || \ - (defined(USER_INTERRUPT) && defined(CONFIG_EXTI2_USER_IRQ)) -IRQ_VEC_N_OP(8) -#endif - -#if !defined(USER_INTERRUPT) || \ - (defined(USER_INTERRUPT) && defined(CONFIG_EXTI3_USER_IRQ)) -IRQ_VEC_N_OP(9) -#endif - -#if !defined(USER_INTERRUPT) || \ - (defined(USER_INTERRUPT) && defined(CONFIG_EXTI4_USER_IRQ)) -IRQ_VEC_N_OP(10) -#endif - -#if !defined(USER_INTERRUPT) || \ - (defined(USER_INTERRUPT) && defined(CONFIG_DMA_Stream0_USER_IRQ)) -IRQ_VEC_N_OP(11) -#endif - -#if !defined(USER_INTERRUPT) || \ - (defined(USER_INTERRUPT) && defined(CONFIG_DMA_Stream1_USER_IRQ)) -IRQ_VEC_N_OP(12) -#endif - -#if !defined(USER_INTERRUPT) || \ - (defined(USER_INTERRUPT) && defined(CONFIG_DMA_Stream2_USER_IRQ)) -IRQ_VEC_N_OP(13) -#endif - -#if !defined(USER_INTERRUPT) || \ - (defined(USER_INTERRUPT) && defined(CONFIG_DMA_Stream3_USER_IRQ)) -IRQ_VEC_N_OP(14) -#endif - -#if !defined(USER_INTERRUPT) || \ - (defined(USER_INTERRUPT) && defined(CONFIG_DMA_Stream4_USER_IRQ)) -IRQ_VEC_N_OP(15) -#endif - -#if !defined(USER_INTERRUPT) || \ - (defined(USER_INTERRUPT) && defined(CONFIG_DMA_Stream5_USER_IRQ)) -IRQ_VEC_N_OP(16) -#endif - -#if !defined(USER_INTERRUPT) || \ - (defined(USER_INTERRUPT) && defined(CONFIG_DMA_Stream6_USER_IRQ)) -IRQ_VEC_N_OP(17) -#endif - -#if !defined(USER_INTERRUPT) || \ - (defined(USER_INTERRUPT) && defined(CONFIG_ADC_USER_IRQ)) -IRQ_VEC_N_OP(18) -#endif - -#if !defined(USER_INTERRUPT) || \ - (defined(USER_INTERRUPT) && defined(CONFIG_CAN1_TX_USER_IRQ)) -IRQ_VEC_N_OP(19) -#endif - -#if !defined(USER_INTERRUPT) || \ - (defined(USER_INTERRUPT) && defined(CONFIG_CAN1_RX_USER_IRQ)) -IRQ_VEC_N_OP(20) -#endif - -#if !defined(USER_INTERRUPT) || \ - (defined(USER_INTERRUPT) && defined(CONFIG_CAN1_RX1_USER_IRQ)) -IRQ_VEC_N_OP(21) -#endif - -#if !defined(USER_INTERRUPT) || \ - (defined(USER_INTERRUPT) && defined(CONFIG_CAN1_SCE_USER_IRQ)) -IRQ_VEC_N_OP(22) -#endif - -#if !defined(USER_INTERRUPT) || \ - (defined(USER_INTERRUPT) && defined(CONFIG_EXTI9_5_USER_IRQ)) -IRQ_VEC_N_OP(23) -#endif - -#if !defined(USER_INTERRUPT) || \ - (defined(USER_INTERRUPT) && defined(CONFIG_TIM1_BRK_USER_IRQ)) -IRQ_VEC_N_OP(24) -#endif - -#if !defined(USER_INTERRUPT) || \ - (defined(USER_INTERRUPT) && defined(CONFIG_TIM1_UP_USER_IRQ)) -IRQ_VEC_N_OP(25) -#endif - -#if !defined(USER_INTERRUPT) || \ - (defined(USER_INTERRUPT) && defined(CONFIG_TIM1_TRG_COM_USER_IRQ)) -IRQ_VEC_N_OP(26) -#endif - -#if !defined(USER_INTERRUPT) || \ - (defined(USER_INTERRUPT) && defined(CONFIG_TIM1_CC_USER_IRQ)) -IRQ_VEC_N_OP(27) -#endif - -#if !defined(USER_INTERRUPT) || \ - (defined(USER_INTERRUPT) && defined(CONFIG_TIM2_USER_IRQ)) -IRQ_VEC_N_OP(28) -#endif - -#if !defined(USER_INTERRUPT) || \ - (defined(USER_INTERRUPT) && defined(CONFIG_TIM3_USER_IRQ)) -IRQ_VEC_N_OP(29) -#endif - -#if !defined(USER_INTERRUPT) || \ - (defined(USER_INTERRUPT) && defined(CONFIG_TIM4_USER_IRQ)) -IRQ_VEC_N_OP(30) -#endif - -#if !defined(USER_INTERRUPT) || \ - (defined(USER_INTERRUPT) && defined(CONFIG_I2C1_EV_USER_IRQ)) -IRQ_VEC_N_OP(31) -#endif - -#if !defined(USER_INTERRUPT) || \ - (defined(USER_INTERRUPT) && defined(CONFIG_I2C1_ER_USER_IRQ)) -IRQ_VEC_N_OP(32) -#endif - -#if !defined(USER_INTERRUPT) || \ - (defined(USER_INTERRUPT) && defined(CONFIG_I2C2_EV_USER_IRQ)) -IRQ_VEC_N_OP(33) -#endif - -#if !defined(USER_INTERRUPT) || \ - (defined(USER_INTERRUPT) && defined(CONFIG_I2C2_ER_USER_IRQ)) -IRQ_VEC_N_OP(34) -#endif - -#if !defined(USER_INTERRUPT) || \ - (defined(USER_INTERRUPT) && defined(CONFIG_SPI1_USER_IRQ)) -IRQ_VEC_N_OP(35) -#endif - -#if !defined(USER_INTERRUPT) || \ - (defined(USER_INTERRUPT) && defined(CONFIG_SPI2_USER_IRQ)) -IRQ_VEC_N_OP(36) -#endif - -#if !defined(USER_INTERRUPT) || \ - (defined(USER_INTERRUPT) && defined(CONFIG_USART1_USER_IRQ)) -IRQ_VEC_N_OP(37) -#endif - -#if !defined(USER_INTERRUPT) || \ - (defined(USER_INTERRUPT) && defined(CONFIG_USART2_USER_IRQ)) -IRQ_VEC_N_OP(38) -#endif - -#if !defined(USER_INTERRUPT) || \ - (defined(USER_INTERRUPT) && defined(CONFIG_USART3_USER_IRQ)) -IRQ_VEC_N_OP(39) -#endif - -#if !defined(USER_INTERRUPT) || \ - (defined(USER_INTERRUPT) && defined(CONFIG_EXTI15_10_USER_IRQ)) -IRQ_VEC_N_OP(40) -#endif - -#if !defined(USER_INTERRUPT) || \ - (defined(USER_INTERRUPT) && defined(CONFIG_RTC_Alarm_USER_IRQ)) -IRQ_VEC_N_OP(41) -#endif - -#if !defined(USER_INTERRUPT) || \ - (defined(USER_INTERRUPT) && defined(CONFIG_OTG_FS_WKUP_USER_IRQ)) -IRQ_VEC_N_OP(42) -#endif diff --git a/include/platform/stm32f1/registers.h b/include/platform/stm32f1/registers.h deleted file mode 100644 index 13520565..00000000 --- a/include/platform/stm32f1/registers.h +++ /dev/null @@ -1,767 +0,0 @@ -/* STM32F1 Registers and Memory Locations */ - -#ifndef STM32F1_REGISTERS_H_INCLUDED -#define STM32F1_REGISTERS_H_INCLUDED - -#include - -#define STM32F1X - -/* Memory Map */ -#define MEMORY_BASE (uint32_t) (0x00000000) /* Base of memory map */ -#define FLASH_BASE (uint32_t) (0x08000000) /* Flash Memory Base Address */ -#define SRAM_BASE (uint32_t) (0x20000000) /* SRAM Base Address */ - -/* Peripheral Map */ -#define PERIPH_BASE (uint32_t) (0x40000000) /* Peripheral base address */ -#define PRIV_PERIPH_BASE \ - (uint32_t) (0xED000000) /* Private peripheral base address */ -#define APB1PERIPH_BASE (PERIPH_BASE) -#define APB2PERIPH_BASE (PERIPH_BASE + 0x10000) -#define AHBPERIPH_BASE (PERIPH_BASE + 0x20000) - - - -/* APB1 peripherals */ -#define TIM2_BASE (APB1PERIPH_BASE + 0x0000) -#define TIM3_BASE (APB1PERIPH_BASE + 0x0400) -#define TIM4_BASE (APB1PERIPH_BASE + 0x0800) -#define RTC_BASE (APB1PERIPH_BASE + 0x2800) -#define WWDG_BASE (APB1PERIPH_BASE + 0x2C00) -#define IWDG_BASE (APB1PERIPH_BASE + 0x3000) -#define SPI2_BASE (APB1PERIPH_BASE + 0x3800) -#define USART2_BASE (APB1PERIPH_BASE + 0x4400) -#define USART3_BASE (APB1PERIPH_BASE + 0x4800) -#define I2C1_BASE (APB1PERIPH_BASE + 0x5400) -#define I2C2_BASE (APB1PERIPH_BASE + 0x5800) -#define USB_BASE (APB1PERIPH_BASE + 0x5C00) -#define CAN1_BASE (APB1PERIPH_BASE + 0x6400) -#define BKP_BASE (APB1PERIPH_BASE + 0x6C00) -#define PWR_BASE (APB1PERIPH_BASE + 0x7000) - -/* APB2 peripherals */ -#define AFIO_BASE (APB2PERIPH_BASE + 0x0000) -#define EXTI_BASE (APB2PERIPH_BASE + 0x0400) -#define GPIO_BASE(port) \ - (APB2PERIPH_BASE + 0x0800 + (0x400 * port)) /* GPIO Port base address */ -#define ADC1_BASE (APB2PERIPH_BASE + 0x2400) -#define ADC2_BASE (APB2PERIPH_BASE + 0x2800) -#define TIM1_BASE (APB2PERIPH_BASE + 0x2C00) -#define SPI1_BASE (APB2PERIPH_BASE + 0x3000) -#define USART1_BASE (APB2PERIPH_BASE + 0x3800) - -/* AHB */ -#define DMA_BASE (AHBPERIPH_BASE) /* DMA base address */ -#define RCC_BASE \ - (AHBPERIPH_BASE + 0x1000) /* Reset and Clock Control base address */ -#define FLASH_R_BASE \ - (AHBPERIPH_BASE + 0x2000) /* Flash registers base address */ -#define CRC_BASE (AHBPERIPH_BASE + 0x3000) /* CRC base address */ - -/* Timer 1 (TIM1) */ -#define TIM1_CR1 \ - (volatile uint32_t *) (TIM1_BASE + 0x00) /* TIM1 control register 1 */ -#define TIM1_CR2 \ - (volatile uint32_t *) (TIM1_BASE + 0x04) /* TIM1 control register 2 */ -#define TIM1_SMCR \ - (volatile uint32_t *) (TIM1_BASE + \ - 0x08) /* TIM1 slave mode control register */ -#define TIM1_DIER \ - (volatile uint32_t *) (TIM1_BASE + \ - 0x0C) /* TIM1 DMA/Interrupt enable register */ -#define TIM1_SR \ - (volatile uint32_t *) (TIM1_BASE + 0x10) /* TIM1 status register */ -#define TIM1_EGR \ - (volatile uint32_t *) (TIM1_BASE + \ - 0x14) /* TIM1 event generation register */ -#define TIM1_CCMR1 \ - (volatile uint32_t *) (TIM1_BASE + \ - 0x18) /* TIM1 capture/compare mode register 1 */ -#define TIM1_CCMR2 \ - (volatile uint32_t *) (TIM1_BASE + \ - 0x1C) /* TIM1 capture/compare mode register 2 */ -#define TIM1_CCER \ - (volatile uint32_t *) (TIM1_BASE + \ - 0x20) /* TIM1 capture/compare enable register */ -#define TIM1_CNT (volatile uint32_t *) (TIM1_BASE + 0x24) /* TIM1 counter */ -#define TIM1_PSC (volatile uint32_t *) (TIM1_BASE + 0x28) /* TIM1 prescaler */ -#define TIM1_ARR \ - (volatile uint32_t *) (TIM1_BASE + 0x2C) /* TIM1 auto-reload register */ -#define TIM1_CCR1 \ - (volatile uint32_t *) (TIM1_BASE + \ - 0x34) /* TIM1 capture/compare register 1 */ -#define TIM1_CCR2 \ - (volatile uint32_t *) (TIM1_BASE + \ - 0x38) /* TIM1 capture/compare register 2 */ -#define TIM1_CCR3 \ - (volatile uint32_t *) (TIM1_BASE + \ - 0x3C) /* TIM1 capture/compare register 3 */ -#define TIM1_CCR4 \ - (volatile uint32_t *) (TIM1_BASE + \ - 0x40) /* TIM1 capture/compare register 4 */ -#define TIM1_DCR \ - (volatile uint32_t *) (TIM1_BASE + 0x48) /* TIM1 DMA control register */ -#define TIM1_DMAR \ - (volatile uint32_t *) (TIM1_BASE + \ - 0x4C) /* TIM1 DMA address for full transfer */ -#define TIM1_OR \ - (volatile uint32_t *) (TIM1_BASE + 0x50) /* TIM1 option register */ - -#define TIM2_CR1 \ - (volatile uint32_t *) (TIM2_BASE + 0x00) /* TIM2 control register 1 */ -#define TIM2_CR2 \ - (volatile uint32_t *) (TIM2_BASE + 0x04) /* TIM2 control register 2 */ -#define TIM2_SMCR \ - (volatile uint32_t *) (TIM2_BASE + \ - 0x08) /* TIM2 slave mode control register */ -#define TIM2_DIER \ - (volatile uint32_t *) (TIM2_BASE + \ - 0x0C) /* TIM2 DMA/Interrupt enable register */ -#define TIM2_SR \ - (volatile uint32_t *) (TIM2_BASE + 0x10) /* TIM2 status register */ -#define TIM2_EGR \ - (volatile uint32_t *) (TIM2_BASE + \ - 0x14) /* TIM2 event generation register */ -#define TIM2_CCMR1 \ - (volatile uint32_t *) (TIM2_BASE + \ - 0x18) /* TIM2 capture/compare mode register 1 */ -#define TIM2_CCMR2 \ - (volatile uint32_t *) (TIM2_BASE + \ - 0x1C) /* TIM2 capture/compare mode register 2 */ -#define TIM2_CCER \ - (volatile uint32_t *) (TIM2_BASE + \ - 0x20) /* TIM2 capture/compare enable register */ -#define TIM2_CNT (volatile uint32_t *) (TIM2_BASE + 0x24) /* TIM2 counter */ -#define TIM2_PSC (volatile uint32_t *) (TIM2_BASE + 0x28) /* TIM2 prescaler */ -#define TIM2_ARR \ - (volatile uint32_t *) (TIM2_BASE + 0x2C) /* TIM2 auto-reload register */ -#define TIM2_CCR1 \ - (volatile uint32_t *) (TIM2_BASE + \ - 0x34) /* TIM2 capture/compare register 1 */ -#define TIM2_CCR2 \ - (volatile uint32_t *) (TIM2_BASE + \ - 0x38) /* TIM2 capture/compare register 2 */ -#define TIM2_CCR3 \ - (volatile uint32_t *) (TIM2_BASE + \ - 0x3C) /* TIM2 capture/compare register 3 */ -#define TIM2_CCR4 \ - (volatile uint32_t *) (TIM2_BASE + \ - 0x40) /* TIM2 capture/compare register 4 */ -#define TIM2_DCR \ - (volatile uint32_t *) (TIM2_BASE + 0x48) /* TIM2 DMA control register */ -#define TIM2_DMAR \ - (volatile uint32_t *) (TIM2_BASE + \ - 0x4C) /* TIM2 DMA address for full transfer */ -#define TIM2_OR \ - (volatile uint32_t *) (TIM2_BASE + 0x50) /* TIM2 option register */ -/* Power Control (PWR) */ -#define PWR_CR \ - (volatile uint32_t *) (PWR_BASE + 0x00) /* Power Control Register */ -#define PWR_CSR \ - (volatile uint32_t *) (PWR_BASE + 0x04) /* Power Control/Status Register \ - */ - -/* SPI */ -#define SPI_BASE(port) (port) /* Temporary SPI base */ -#define SPI_CR1(port) \ - (volatile uint32_t *) (SPI_BASE(port) + 0x00) /* SPI control register 1 */ -#define SPI_CR2(port) \ - (volatile uint32_t *) (SPI_BASE(port) + 0x04) /* SPI control register 2 */ -#define SPI_SR(port) \ - (volatile uint32_t *) (SPI_BASE(port) + 0x08) /* SPI status register */ -#define SPI_DR(port) \ - (volatile uint32_t *) (SPI_BASE(port) + 0x0c) /* SPI data register */ -#define SPI_CRCPR(port) \ - (volatile uint32_t *) (SPI_BASE(port) + \ - 0x10) /* SPI CRC polynomial register */ -#define SPI_RXCRCR(port) \ - (volatile uint32_t *) (SPI_BASE(port) + 0x14) /* SPI RX CRC register */ -#define SPI_TXCRCR(port) \ - (volatile uint32_t *) (SPI_BASE(port) + 0x18) /* SPI TX CRC register */ -#define SPI_I2SCFGR(port) \ - (volatile uint32_t *) (SPI_BASE(port) + \ - 0x1c) /* SPI I2C configuration register */ -#define SPI_I2SPR(port) \ - (volatile uint32_t *) (SPI_BASE(port) + \ - 0x20) /* SPI I2C prescaler register */ - -/* I2C */ -#define I2C_CR1(port) \ - (volatile uint32_t *) (I2C_BASE(port) + 0x00) /* I2C control register 1 */ -#define I2C_CR2(port) \ - (volatile uint32_t *) (I2C_BASE(port) + 0x04) /* I2C control register 2 */ -#define I2C_OAR1(port) \ - (volatile uint32_t *) (I2C_BASE(port) + \ - 0x08) /* I2C own address register 1 */ -#define I2C_OAR2(port) \ - (volatile uint32_t *) (I2C_BASE(port) + \ - 0x0C) /* I2C own address register 2 */ -#define I2C_DR(port) \ - (volatile uint32_t *) (I2C_BASE(port) + 0x10) /* I2C data register */ -#define I2C_SR1(port) \ - (volatile uint32_t *) (I2C_BASE(port) + 0x14) /* I2C status register 1 */ -#define I2C_SR2(port) \ - (volatile uint32_t *) (I2C_BASE(port) + 0x18) /* I2C status register 2 */ -#define I2C_CCR(port) \ - (volatile uint32_t *) (I2C_BASE(port) + \ - 0x1C) /* I2C clock control register */ -#define I2C_TRISE(port) \ - (volatile uint32_t *) (I2C_BASE(port) + 0x20) /* I2C TRISE register */ - -/* USART 1 */ -#define USART1_SR \ - (volatile uint32_t *) (USART1_BASE + 0x00) /* USART1 status register */ -#define USART1_DR \ - (volatile uint32_t *) (USART1_BASE + 0x04) /* USART1 data register */ -#define USART1_BRR \ - (volatile uint32_t *) (USART1_BASE + 0x08) /* USART1 baud rate register */ -#define USART1_CR1 \ - (volatile uint32_t *) (USART1_BASE + 0x0C) /* USART1 control register 1 */ -#define USART1_CR2 \ - (volatile uint32_t *) (USART1_BASE + 0x10) /* USART1 control register 2 */ -#define USART1_CR3 \ - (volatile uint32_t *) (USART1_BASE + 0x14) /* USART1 control register 3 */ -#define USART1_GTPR \ - (volatile uint32_t *) (USART1_BASE + \ - 0x18) /* USART1 gaurd time and prescale register */ - -/* GPIO Port (GPIO) */ -#define GPIO_CRL(port) \ - (volatile uint32_t *) (GPIO_BASE(port) + \ - 0x00) /* Port configuration low register */ -#define GPIO_CRH(port) \ - (volatile uint32_t *) (GPIO_BASE(port) + \ - 0x04) /* Port configuration high register */ -#define GPIO_IDR(port) \ - (volatile uint32_t *) (GPIO_BASE(port) + \ - 0x08) /* Port input data register */ -#define GPIO_ODR(port) \ - (volatile uint32_t *) (GPIO_BASE(port) + \ - 0x0C) /* Port output data register */ -#define GPIO_BSRR(port) \ - (volatile uint32_t *) (GPIO_BASE(port) + \ - 0x10) /* Port bit set/reset register */ -#define GPIO_BRR(port) \ - (volatile uint32_t *) (GPIO_BASE(port) + 0x14) /* Port bit reset register \ - */ -#define GPIO_LCKR(port) \ - (volatile uint32_t *) (GPIO_BASE(port) + \ - 0x18) /* Port configuration lock register */ - -/* Reset and Clock Control (RCC) */ -#define RCC_CR \ - (volatile uint32_t *) (RCC_BASE + 0x00) /* Clock Control Register */ -#define RCC_CFGR \ - (volatile uint32_t *) (RCC_BASE + 0x04) /* Clock Configuration Register */ -#define RCC_CIR \ - (volatile uint32_t *) (RCC_BASE + 0x08) /* Clock Interrupt Register */ -#define RCC_APB2RSTR \ - (volatile uint32_t *) (RCC_BASE + 0x0C) /* APB2 reset Register */ -#define RCC_APB1RSTR \ - (volatile uint32_t *) (RCC_BASE + 0x10) /* APB1 reset Register */ -#define RCC_AHBENR \ - (volatile uint32_t *) (RCC_BASE + 0x14) /* AHB Enable Register */ -#define RCC_APB2ENR \ - (volatile uint32_t *) (RCC_BASE + \ - 0x18) /* APB2 Peripheral Clock Enable Register */ -#define RCC_APB1ENR \ - (volatile uint32_t *) (RCC_BASE + \ - 0x1C) /* APB1 Peripheral Clock Enable Register */ -#define RCC_BDCR \ - (volatile uint32_t *) (RCC_BASE + \ - 0x20) /* RCC Backup Domain Control Register */ -#define RCC_CSR \ - (volatile uint32_t *) (RCC_BASE + \ - 0x24) /* RCC Clock Control & Status Register */ -#define RCC_AHBRSTR \ - (volatile uint32_t *) (RCC_BASE + 0x28) /* AHB reset Register */ - -/* APB1 RCC ENR */ -#define RCC_TIM2_APBENR RCC_APB1ENR -#define RCC_TIM3_APBENR RCC_APB1ENR -#define RCC_TIM4_APBENR RCC_APB1ENR -#define RCC_RTC_APBENR RCC_APB1ENR -#define RCC_WWDG_APBENR RCC_APB1ENR -#define RCC_IWDG_APBENR RCC_APB1ENR -#define RCC_SPI2_APBENR RCC_APB1ENR -#define RCC_USART2_APBENR RCC_APB1ENR -#define RCC_USART3_APBENR RCC_APB1ENR -#define RCC_I2C1_APBENR RCC_APB1ENR -#define RCC_I2C2_APBENR RCC_APB1ENR -#define RCC_CAN1_APBENR RCC_APB1ENR -#define RCC_BKP_APBENR RCC_APB1ENR -#define RCC_PWR_APBENR RCC_APB1ENR - -/* APB2 RCC ENR */ -#define RCC_AFIO_APBENR RCC_APB2ENR -#define RCC_EXTI_APBENR RCC_APB2ENR -#define RCC_GPIO_APBENR RCC_APB2ENR -#define RCC_ADC1_APBENR RCC_APB2ENR -#define RCC_ADC2_APBENR RCC_APB2ENR -#define RCC_TIM1_APBENR RCC_APB2ENR -#define RCC_SPI1_APBENR RCC_APB2ENR -#define RCC_USART1_APBENR RCC_APB2ENR - -/* Flash Registers (FLASH) */ -#define FLASH_ACR \ - (volatile uint32_t *) (FLASH_R_BASE + \ - 0x00) /* Flash Access Control Register */ - -/* Direct Memory Access (DMA) */ -#define DMA_LISR \ - (volatile uint32_t *) (DMA_BASE + 0x00) /* DMA interrupt status register \ - */ -#define DMA_IFCR \ - (volatile uint32_t *) (DMA_BASE + \ - 0x04) /* DMA interrupt flag clear register */ -/* Channel n */ -#define DMA_CR_C(n) \ - (volatile uint32_t *) (DMA_BASE + 0x08 + \ - (0x14 * \ - n)) /* DMA stream n configuration register */ -#define DMA_NDTR_C(n) \ - (volatile uint32_t *) (DMA_BASE + 0x0C + \ - (0x14 * \ - n)) /* DMA stream n number of data register */ -#define DMA_PAR_C(n) \ - (volatile uint32_t *) (DMA_BASE + 0x10 + \ - (0x14 * \ - n)) /* DMA stream n peripheral address register */ -#define DMA_MAR_C(n) \ - (volatile uint32_t *) (DMA_BASE + 0x14 + \ - (0x14 * \ - n)) /* DMA stream n memory 0 address register */ - -/**********************************************************************************************************************************************/ - -/* Bit Masks - See RM0090 Reference Manual for STM32F4 for details */ - -#define RCC_CR_HSION (uint32_t) (1 << 0) /* HSI clock enable */ -#define RCC_CR_HSIRDY (uint32_t) (1 << 1) /* HSI ready */ -#define RCC_CR_HSITRIM_M (uint32_t) (0xF8 << 0) /* HSI trimming mask */ -#define RCC_CR_HSICAL_M (uint32_t) (0xFF << 8) /* HSI calibration mask */ -#define RCC_CR_HSEON (uint32_t) (1 << 16) /* HSE clock enable */ -#define RCC_CR_HSERDY (uint32_t) (1 << 17) /* HSE ready */ -#define RCC_CR_HSEBYP (uint32_t) (1 << 18) /* HSE bypass */ -#define RCC_CR_CSSON (uint32_t) (1 << 19) /* Clock security system enable */ -#define RCC_CR_PLLON (uint32_t) (1 << 24) /* Main PLL enable */ -#define RCC_CR_PLLRDY (uint32_t) (1 << 25) /* Main PLL clock ready */ - -#define RCC_CFGR_SW_M (uint32_t) (3 << 0) /* System clock switch mask */ -#define RCC_CFGR_SW_HSI \ - (uint32_t) (0 << 0) /* System clock switch - HSI selected as system clock \ - */ -#define RCC_CFGR_SW_HSE \ - (uint32_t) (1 << 0) /* System clock switch - HSE selected as system clock \ - */ -#define RCC_CFGR_SW_PLL \ - (uint32_t) (2 << 0) /* System clock switch - PLL selected as system clock \ - */ -#define RCC_CFGR_SWS_M \ - (uint32_t) (3 << 2) /* System clock switch status mask \ - */ -#define RCC_CFGR_SWS_HSI \ - (uint32_t) (0 << 2) /* System clock switch status - HSI used as system \ - clock */ -#define RCC_CFGR_SWS_HSE \ - (uint32_t) (1 << 2) /* System clock switch status - HSE used as system \ - clock */ -#define RCC_CFGR_SWS_PLL \ - (uint32_t) (2 << 2) /* System clock switch status - PLL used as system \ - clock */ -#define RCC_CFGR_HPRE_M (uint32_t) (0xF << 4) /* AHB prescaler mask */ -#define RCC_CFGR_HPRE_DIV1 \ - (uint32_t) (0x0 << 4) /* AHB prescaler - SYSCLK not divided */ -#define RCC_CFGR_HPRE_DIV2 \ - (uint32_t) (0x8 << 4) /* AHB prescaler - SYSCLK/2 \ - */ -#define RCC_CFGR_HPRE_DIV4 \ - (uint32_t) (0x9 << 4) /* AHB prescaler - SYSCLK/4 \ - */ -#define RCC_CFGR_HPRE_DIV8 \ - (uint32_t) (0xA << 4) /* AHB prescaler - SYSCLK/8 \ - */ -#define RCC_CFGR_HPRE_DIV16 \ - (uint32_t) (0xB << 4) /* AHB prescaler - SYSCLK/16 */ -#define RCC_CFGR_HPRE_DIV64 \ - (uint32_t) (0xC << 4) /* AHB prescaler - SYSCLK/64 */ -#define RCC_CFGR_HPRE_DIV128 \ - (uint32_t) (0xD << 4) /* AHB prescaler - SYSCLK/128 */ -#define RCC_CFGR_HPRE_DIV256 \ - (uint32_t) (0xE << 4) /* AHB prescaler - SYSCLK/256 */ -#define RCC_CFGR_HPRE_DIV512 \ - (uint32_t) (0xF << 4) /* AHB prescaler - SYSCLK/512 */ -#define RCC_CFGR_PPRE1_M \ - (uint32_t) (0x7 << 8) /* APB low speed prescaler mask */ -#define RCC_CFGR_PPRE1_DIV1 \ - (uint32_t) (0x0 << 8) /* APB low speed prescaler - HCLK/1 */ -#define RCC_CFGR_PPRE1_DIV2 \ - (uint32_t) (0x4 << 8) /* APB low speed prescaler - HCLK/2 */ -#define RCC_CFGR_PPRE1_DIV4 \ - (uint32_t) (0x5 << 8) /* APB low speed prescaler - HCLK/4 */ -#define RCC_CFGR_PPRE1_DIV8 \ - (uint32_t) (0x6 << 8) /* APB low speed prescaler - HCLK/8 */ -#define RCC_CFGR_PPRE1_DIV16 \ - (uint32_t) (0x7 << 8) /* APB low speed prescaler - HCLK/16 */ -#define RCC_CFGR_PPRE2_M \ - (uint32_t) (0x38 << 8) /* APB high speec prescaler mask */ -#define RCC_CFGR_PPRE2_DIV1 \ - (uint32_t) (0x0 << 8) /* APB high speed prescaler - HCLK/1 */ -#define RCC_CFGR_PPRE2_DIV2 \ - (uint32_t) (0x20 << 8) /* APB high speed prescaler - HCLK/2 */ -#define RCC_CFGR_PPRE2_DIV4 \ - (uint32_t) (0x28 << 8) /* APB high speed prescaler - HCLK/4 */ -#define RCC_CFGR_PPRE2_DIV8 \ - (uint32_t) (0x30 << 8) /* APB high speed prescaler - HCLK/8 */ -#define RCC_CFGR_PPRE2_DIV16 \ - (uint32_t) (0x38 << 8) /* APB high speed prescaler - HCLK/16 */ -#define RCC_CFGR_RTCPRE_M \ - (uint32_t) (0x1F << 16) /* HSE division factor for RTC clock mask */ -#define RCC_CFGR_RTCPRE(n) \ - (uint32_t) (n << 16) /* HSE division factor for RTC clock */ - -#define RCC_AHBRSTR_ETHMACRST (uint32_t) (1 << 14) /* Ethernet MAC reset */ -#define RCC_AHBRSTR_OTGFSRST (uint32_t) (1 << 12) /* USB OTG FS reset */ - -#define RCC_APB1RSTR_TIM2RST (uint32_t) (1 << 0) /* TIM2 reset */ -#define RCC_APB1RSTR_TIM3RST (uint32_t) (1 << 1) /* TIM3 reset */ -#define RCC_APB1RSTR_TIM4RST (uint32_t) (1 << 2) /* TIM4 reset */ -#define RCC_APB1RSTR_WWDGRST (uint32_t) (1 << 11) /* Window watchdog reset */ -#define RCC_APB1RSTR_SPI2RST (uint32_t) (1 << 14) /* SPI2 reset */ -#define RCC_APB1RSTR_USART2RST (uint32_t) (1 << 17) /* USART2 reset */ -#define RCC_APB1RSTR_USART3RST (uint32_t) (1 << 18) /* USART3 reset */ -#define RCC_APB1RSTR_I2C1RST (uint32_t) (1 << 21) /* I2C1 reset */ -#define RCC_APB1RSTR_I2C2RST (uint32_t) (1 << 22) /* I2C2 reset */ -#define RCC_APB1RSTR_CAN1RST (uint32_t) (1 << 25) /* CAN1 reset */ -#define RCC_APB1RSTR_BKPRST (uint32_t) (1 << 27) /* Backup interface reset */ -#define RCC_APB1RSTR_PWRRST (uint32_t) (1 << 28) /* Power interface reset */ -#define RCC_APB1RSTR_DACRST (uint32_t) (1 << 29) /* DAC reset */ - -#define RCC_APB2RSTR_AFIORST \ - (uint32_t) (1 << 0) /* Alternate Function I/O reset */ -#define RCC_APB2RSTR_IOPARST \ - (uint32_t) (1 << 2) /* Alternate Function I/O port A reset */ -#define RCC_APB2RSTR_IOPBRST \ - (uint32_t) (1 << 3) /* Alternate Function I/O port B reset */ -#define RCC_APB2RSTR_IOPCRST \ - (uint32_t) (1 << 4) /* Alternate Function I/O port C reset */ -#define RCC_APB2RSTR_IOPDRST \ - (uint32_t) (1 << 5) /* Alternate Function I/O port D reset */ -#define RCC_APB2RSTR_IOPERST \ - (uint32_t) (1 << 6) /* Alternate Function I/O port E reset */ -#define RCC_APB2RSTR_ADC1RST (uint32_t) (1 << 9) /* ADC 1 interface reset */ -#define RCC_APB2RSTR_ADC2RST (uint32_t) (1 << 10) /* ADC 2 interface reset */ -#define RCC_APB2RSTR_TIM1RST (uint32_t) (1 << 11) /* TIM1 reset */ -#define RCC_APB2RSTR_SPI1RST (uint32_t) (1 << 12) /* SPI 1 reset */ -#define RCC_APB2RSTR_USART1RST (uint32_t) (1 << 14) /* USART1 reset */ - -#define RCC_AHBENR_DMA1EN (uint16_t) (1 << 0) /* DMA1 clock enable */ -#define RCC_AHBENR_SRAMEN \ - (uint16_t) (1 << 2) /* SRAM interface clock enable \ - */ -#define RCC_AHBENR_FLITFEN (uint16_t) (1 << 4) /* FLITF clock enable */ -#define RCC_AHBENR_CRCEN (uint16_t) (1 << 6) /* CRC clock enable */ - -#define RCC_APB1ENR_TIM2EN (uint32_t) (1 << 0) /* TIM2 clock enable */ -#define RCC_APB1ENR_TIM3EN (uint32_t) (1 << 1) /* TIM3 clock enable */ -#define RCC_APB1ENR_TIM4EN (uint32_t) (1 << 2) /* TIM4 clock enable */ -#define RCC_APB1ENR_WWDGEN \ - (uint32_t) (1 << 11) /* Window watchdog clock enable */ -#define RCC_APB1ENR_SPI2EN (uint32_t) (1 << 14) /* SPI2 clock enable */ -#define RCC_APB1ENR_USART2EN (uint32_t) (1 << 17) /* USART2 clock enable */ -#define RCC_APB1ENR_USART3EN (uint32_t) (1 << 18) /* USART3 clock enable */ -#define RCC_APB1ENR_I2C1EN (uint32_t) (1 << 21) /* I2C1 clock enable */ -#define RCC_APB1ENR_I2C2EN (uint32_t) (1 << 22) /* I2C2 clock enable */ -#define RCC_APB1ENR_CAN1EN (uint32_t) (1 << 25) /* CAN1 clock enable */ -#define RCC_APB1ENR_BKPEN \ - (uint32_t) (1 << 27) /* Backup interface clock enable */ -#define RCC_APB1ENR_PWREN \ - (uint32_t) (1 << 28) /* Power interface clock enable */ - -#define RCC_APB2ENR_AFIOEN \ - (uint32_t) (1 << 0) /* Alternate Function I/O clock enable */ -#define RCC_APB2ENR_IOPAEN \ - (uint32_t) (1 << 2) /* Alternate Function I/O port A clock enable */ -#define RCC_APB2ENR_IOPBEN \ - (uint32_t) (1 << 3) /* Alternate Function I/O port B clock enable */ -#define RCC_APB2ENR_IOPCEN \ - (uint32_t) (1 << 4) /* Alternate Function I/O port C clock enable */ -#define RCC_APB2ENR_IOPDEN \ - (uint32_t) (1 << 5) /* Alternate Function I/O port D clock enable */ -#define RCC_APB2ENR_IOPEEN \ - (uint32_t) (1 << 6) /* Alternate Function I/O port E clock enable */ -#define RCC_APB2ENR_ADC1EN \ - (uint32_t) (1 << 9) /* ADC 1 interface clock enable */ -#define RCC_APB2ENR_ADC2EN \ - (uint32_t) (1 << 10) /* ADC 2 interface clock enable */ -#define RCC_APB2ENR_TIM1EN (uint32_t) (1 << 11) /* TIM1 clock enable */ -#define RCC_APB2ENR_SPI1EN (uint32_t) (1 << 12) /* SPI1 clock enable */ -#define RCC_APB2ENR_USART1EN (uint32_t) (1 << 14) /* USART1 clock enable */ - -#define FLASH_ACR_PRFTEN (uint32_t) (1 << 4) /* Prefetch enable */ -#define FLASH_ACR_LATENCY_M (uint32_t) (3 << 0) /* Latency mask */ -#define FLASH_ACR_LATENCY(n) (uint32_t) (n << 0) /* Latency - n wait states */ - -/* TIMx */ -#define TIMx_CR1_CEN (uint32_t) (1 << 0) /* TIMx counter enable */ -#define TIMx_CR1_UDIS (uint32_t) (1 << 1) /* TIMx update disable */ -#define TIMx_CR1_URS (uint32_t) (1 << 2) /* TIMx update request source */ -#define TIMx_CR1_OPM (uint32_t) (1 << 3) /* TIMx one-pulse mode */ -#define TIMx_CR1_DIR_DOWN (uint32_t) (1 << 4) /* TIMx downcounter */ -#define TIMx_CR1_CMS_EDGE \ - (uint32_t) (0 << 5) /* TIMx center-aligned mode selection - counter up or \ - down depending on DIR bit */ -#define TIMx_CR1_CMS_CM1 \ - (uint32_t) (1 << 5) /* TIMx center-aligned mode selection - up and down, \ - compare flags set down */ -#define TIMx_CR1_CMS_CM2 \ - (uint32_t) (2 << 5) /* TIMx center-aligned mode selection - up and down, \ - compare flags set up */ -#define TIMx_CR1_CMS_CM3 \ - (uint32_t) (3 << 5) /* TIMx center-aligned mode selection - up and down, \ - compare flags set up/down */ -#define TIMx_CR1_ARPE \ - (uint32_t) (1 << 7) /* TIMx auto-reload preload enable \ - */ -#define TIMx_CR1_CKD_1 (uint32_t) (0 << 8) /* TIMx clock division 1 */ -#define TIMx_CR1_CKD_2 (uint32_t) (1 << 8) /* TIMx clock division 2 */ -#define TIMx_CR1_CKD_4 (uint32_t) (2 << 8) /* TIMx clock division 4 */ - -#define TIMx_CR2_CCDS \ - (uint32_t) (1 << 3) /* TIMx capture/compare DMA requests send when update \ - event occurs */ -#define TIMx_CR2_MMS_RST (uint32_t) (0 << 4) /* TIMx master mode - reset */ -#define TIMx_CR2_MMS_EN (uint32_t) (1 << 4) /* TIMx master mode - enable */ -#define TIMx_CR2_MMS_UP (uint32_t) (2 << 4) /* TIMx master mode - update */ -#define TIMx_CR2_MMS_CMP_PUL \ - (uint32_t) (3 << 4) /* TIMx master mode - compare pulse */ -#define TIMx_CR2_MMS_CMP_OC1 \ - (uint32_t) (4 << 4) /* TIMx master mode - compare OC1 */ -#define TIMx_CR2_MMS_CMP_OC2 \ - (uint32_t) (5 << 4) /* TIMx master mode - compare OC2 */ -#define TIMx_CR2_MMS_CMP_OC3 \ - (uint32_t) (6 << 4) /* TIMx master mode - compare OC3 */ -#define TIMx_CR2_MMS_CMP_OC4 \ - (uint32_t) (7 << 4) /* TIMx master mode - compare OC4 */ -#define TIMx_CR2_TI1_123 \ - (uint32_t) (1 << 7) /* TIMx CH1, CH2, CH3 pins connected to TI1 */ - -#define TIMx_DIER_UIE (uint32_t) (1 << 0) /* TIMx update interrupt enable */ -#define TIMx_DIER_CC1IE (uint32_t) (1 << 1) /* TIMx CC1 interrupt enable */ -#define TIMx_DIER_CC2IE (uint32_t) (1 << 2) /* TIMx CC2 interrupt enable */ -#define TIMx_DIER_CC3IE (uint32_t) (1 << 3) /* TIMx CC3 interrupt enable */ -#define TIMx_DIER_CC4IE (uint32_t) (1 << 4) /* TIMx CC4 interrupt enable */ -#define TIMx_DIER_TIE (uint32_t) (1 << 6) /* TIMx trigger interrupt enable */ -#define TIMx_DIER_UDE (uint32_t) (1 << 8) /* TIMx update DMA request enable */ -#define TIMx_DIER_CC1DE (uint32_t) (1 << 9) /* TIMx CC1 DMA request enable */ -#define TIMx_DIER_CC2DE (uint32_t) (1 << 10) /* TIMx CC2 DMA request enable */ -#define TIMx_DIER_CC3DE (uint32_t) (1 << 11) /* TIMx CC3 DMA request enable */ -#define TIMx_DIER_CC4DE (uint32_t) (1 << 12) /* TIMx CC4 DMA request enable */ -#define TIMx_DIER_TDE \ - (uint32_t) (1 << 14) /* TIMx trigger DMA request enable \ - */ - -/* SPI */ -#define SPI_CR1_CPHA (uint32_t) (1 << 0) /* SPI clock phase */ -#define SPI_CR1_CPOL (uint32_t) (1 << 1) /* SPI clock polarity */ -#define SPI_CR1_MSTR (uint32_t) (1 << 2) /* SPI master selection */ -#define SPI_CR1_BR_2 (uint32_t) (0 << 3) /* SPI baud rate = fPCLK/2 */ -#define SPI_CR1_BR_4 (uint32_t) (1 << 3) /* SPI baud rate = fPCLK/4 */ -#define SPI_CR1_BR_8 (uint32_t) (2 << 3) /* SPI baud rate = fPCLK/8 */ -#define SPI_CR1_BR_16 (uint32_t) (3 << 3) /* SPI baud rate = fPCLK/16 */ -#define SPI_CR1_BR_32 (uint32_t) (4 << 3) /* SPI baud rate = fPCLK/32 */ -#define SPI_CR1_BR_64 (uint32_t) (5 << 3) /* SPI baud rate = fPCLK/64 */ -#define SPI_CR1_BR_128 (uint32_t) (6 << 3) /* SPI baud rate = fPCLK/128 */ -#define SPI_CR1_BR_256 (uint32_t) (7 << 3) /* SPI baud rate = fPCLK/256 */ -#define SPI_CR1_SPE (uint32_t) (1 << 6) /* SPI enable */ -#define SPI_CR1_LSBFIRST (uint32_t) (1 << 7) /* SPI LSB transmitted first */ -#define SPI_CR1_SSI (uint32_t) (1 << 8) /* SPI internal slave select */ -#define SPI_CR1_SSM (uint32_t) (1 << 9) /* SPI software slave management */ -#define SPI_CR1_DFF \ - (uint32_t) (1 << 11) /* SPI data frame format (0 = 8bit, 1 = 16bit) */ -#define SPI_SR_RXNE (uint32_t) (1 << 0) /* SPI receive not empty */ -#define SPI_SR_TXNE (uint32_t) (1 << 1) /* SPI transmit not empty */ -#define SPI_SR_CHSIDE (uint32_t) (1 << 2) /* SPI channel side */ -#define SPI_SR_UDR (uint32_t) (1 << 3) /* SPI underrun flag */ -#define SPI_SR_CRCERR (uint32_t) (1 << 4) /* SPI CRC error flag */ -#define SPI_SR_MODF (uint32_t) (1 << 5) /* SPI mode fault */ -#define SPI_SR_OVR (uint32_t) (1 << 6) /* SPI overrun flag */ -#define SPI_SR_BSY (uint32_t) (1 << 7) /* SPI busy flag */ -#define SPI_SR_TIRFE (uint32_t) (1 << 8) /* SPI TI frame format error */ - -/* I2C */ -#define I2C_CR1_PE (uint32_t) (1 << 0) /* I2C peripheral enable */ -#define I2C_CR1_SMBUS (uint32_t) (1 << 1) /* I2C SMBus mode */ -#define I2C_CR1_SMBTYPE \ - (uint32_t) (1 << 3) /* I2C SMBus type (0=Device, 1=Host) */ -#define I2C_CR1_ENARP (uint32_t) (1 << 4) /* I2C enable ARP */ -#define I2C_CR1_ENPEC (uint32_t) (1 << 5) /* I2C enable PEC */ -#define I2C_CR1_ENGC (uint32_t) (1 << 6) /* I2C enable general call */ -#define I2C_CR1_NOSTRETCH \ - (uint32_t) (1 << 7) /* I2C clock stretching disable \ - */ -#define I2C_CR1_START (uint32_t) (1 << 8) /* I2C START generation */ -#define I2C_CR1_STOP (uint32_t) (1 << 9) /* I2C STOP generation */ -#define I2C_CR1_ACK (uint32_t) (1 << 10) /* I2C ACK enable */ -#define I2C_CR1_POS (uint32_t) (1 << 11) /* I2C ACK/PEC position */ -#define I2C_CR1_PEC (uint32_t) (1 << 12) /* I2C packet error checking */ -#define I2C_CR1_ALERT (uint32_t) (1 << 13) /* I2C SMBus alert */ -#define I2C_CR1_SWRST (uint32_t) (1 << 15) /* I2C software reset */ - -#define I2C_CR2_FREQ(n) (uint32_t) (n << 0) /* I2C clock frequency */ -#define I2C_CR2_ITERREN (uint32_t) (1 << 8) /* I2C error interrupt enable */ -#define I2C_CR2_ITEVTEN (uint32_t) (1 << 9) /* I2C event interrupt enable */ -#define I2C_CR2_ITBUFEN (uint32_t) (1 << 10) /* I2C buffer interrupt enable */ -#define I2C_CR2_DMAEN (uint32_t) (1 << 11) /* I2C DMA requests enable */ -#define I2C_CR2_LAST (uint32_t) (1 << 12) /* I2C DMA last transfer */ - -#define I2C_OAR1_ADD10(n) \ - (uint32_t) (n << 0) /* I2C interface address (10-bit) */ -#define I2C_OAR1_ADD7(n) \ - (uint32_t) (n << 1) /* I2C interface address (7-bit) \ - */ -#define I2C_OAR1_ADDMODE \ - (uint32_t) (1 << 15) /* I2C interface address mode (1=10-bit) */ - -#define I2C_OAR2_ENDUAL (uint32_t) (1 << 0) /* I2C dual address mode enable */ -#define I2C_OAR2_ADD2(n) \ - (uint32_t) (n << 1) /* I2C interface address 2 (7-bit) */ - -#define I2C_SR1_SB (uint32_t) (1 << 0) /* I2C start bit generated */ -#define I2C_SR1_ADDR (uint32_t) (1 << 1) /* I2C address sent/matched */ -#define I2C_SR1_BTF (uint32_t) (1 << 2) /* I2C byte transfer finished */ -#define I2C_SR1_ADD10 (uint32_t) (1 << 3) /* I2C 10-bit header sent */ -#define I2C_SR1_STOPF (uint32_t) (1 << 4) /* I2C stop detection */ -#define I2C_SR1_RXNE (uint32_t) (1 << 6) /* I2C DR not empty */ -#define I2C_SR1_TXE (uint32_t) (1 << 7) /* I2C DR empty */ -#define I2C_SR1_BERR (uint32_t) (1 << 8) /* I2C bus error */ -#define I2C_SR1_ARLO (uint32_t) (1 << 9) /* I2C attribution lost */ -#define I2C_SR1_AF (uint32_t) (1 << 10) /* I2C acknowledge failure */ -#define I2C_SR1_OVR (uint32_t) (1 << 11) /* I2C overrun/underrun */ -#define I2C_SR1_PECERR (uint32_t) (1 << 12) /* I2C PEC error in reception */ -#define I2C_SR1_TIMEOUT (uint32_t) (1 << 14) /* I2C timeout or tlow error */ -#define I2C_SR1_SMBALERT (uint32_t) (1 << 15) /* I2C SMBus alert */ - -#define I2C_SR2_MSL (uint32_t) (1 << 0) /* I2C master/slave */ -#define I2C_SR2_BUSY (uint32_t) (1 << 1) /* I2C bus busy */ -#define I2C_SR2_TRA (uint32_t) (1 << 2) /* I2C transmitter/receiver */ -#define I2C_SR2_GENCALL (uint32_t) (1 << 4) /* I2C general call address */ -#define I2C_SR2_SMBDEFAULT \ - (uint32_t) (1 << 5) /* I2C SMBus device default address */ -#define I2C_SR2_SMBHOST (uint32_t) (1 << 6) /* I2C SMBus host header */ -#define I2C_SR2_DUALF (uint32_t) (1 << 7) /* I2C dual flag */ -#define I2C_SR2_PEC(r) \ - (uint32_t) (r >> 8) /* I2C packet error checking register */ - -#define I2C_CCR_CCR(n) \ - (uint32_t) (n & 0x0FFF) /* I2C clock control register \ - */ -#define I2C_CCR_DUTY (uint32_t) (1 << 14) /* I2C fast mode duty cycle */ -#define I2C_CCR_FS (uint32_t) (1 << 15) /* I2C master mode selection */ - -/* USART */ -#define USART_SR_TC (uint32_t) (1 << 6) /* USART Transmission Complete */ -#define USART_SR_RXNE \ - (uint32_t) (1 << 5) /* USART Read data register not empty */ - -/* USART_CR1 */ -#define USART_CR1_OVER8 (uint32_t) (1 << 15) /* Oversampling mode */ -#define USART_CR1_UE (uint32_t) (1 << 13) /* USART Enable */ -#define USART_CR1_M9 \ - (uint32_t) (1 << 12) /* World length 1: 9 bits, 0: 8bits \ - */ -#define USART_CR1_WAKE (uint32_t) (1 << 11) /* Wakeup method */ -#define USART_CR1_PCE (uint32_t) (1 << 10) /* PCE Parity control enable */ -#define USART_CR1_PS (uint32_t) (1 << 9) /* Parity selection */ -#define USART_CR1_PEIE (uint32_t) (1 << 8) /* PE Interrupt enable */ -#define USART_CR1_TXEIE (uint32_t) (1 << 7) /* TXE interrupt enable */ -#define USART_CR1_TCIE \ - (uint32_t) (1 << 6) /* Transmission complete interrupt enable */ -#define USART_CR1_RXNEIE (uint32_t) (1 << 5) /* RXNE Interrupt Enable */ -#define USART_CR1_IDLEIE (uint32_t) (1 << 4) /* IDEL INterrupt Enable */ -#define USART_CR1_TE (uint32_t) (1 << 3) /* USART Transmit Enable */ -#define USART_CR1_RE (uint32_t) (1 << 2) /* USART Receive Enable */ -#define USART_CR1_RWU (uint32_t) (1 << 1) -#define USART_CR1_SBK (uint32_t) (1 << 0) /* Send break characters */ - -#define USART_CR3_DMAR_EN (uint32_t) (1 << 6) /* USART DMA Receive Enable */ -#define USART_CR3_DMAT_EN (uint32_t) (1 << 7) /* USART DMA Transmit Enable */ - -/* GPIO */ -#define GPIOA (uint8_t) (0) /* GPIO Port A */ -#define GPIOB (uint8_t) (1) /* GPIO Port B */ -#define GPIOC (uint8_t) (2) /* GPIO Port C */ -#define GPIOD (uint8_t) (3) /* GPIO Port D */ -#define GPIOE (uint8_t) (4) /* GPIO Port E */ - -#define GPIO_CR_PIN(n) (uint32_t) (4 * n) /* Pin bitshift */ -#define GPIO_CR_M(n) (uint32_t) (0x3 << 4 * n) /* Pin mask */ - -#define GPIO_OSPEED_10M (uint32_t) (0x1) /* Output speed 10MHz */ -#define GPIO_OSPEED_2M (uint32_t) (0x2) /* Output speed 2MHz */ -#define GPIO_OSPEED_50M (uint32_t) (0x3) /* Output speed 50MHz */ - -#define GPIO_MODE_IN_ANALOG (uint32_t) (0x00) /* Input analog mode */ -#define GPIO_MODE_IN_FLOAT (uint32_t) (0x01) /* Input floating point mode */ -#define GPIO_MODE_IN_PD (uint32_t) (0x0A) /* Input push down mode */ -#define GPIO_MODE_IN_PU (uint32_t) (0x12) /* Input pull up mode */ -#define GPIO_MODE_OUT_PP (uint32_t) (0x04) /* Output push-pull mode */ -#define GPIO_MODE_OUT_OD (uint32_t) (0x05) /* Output open-drain mode */ -#define GPIO_MODE_OUT_ALT_PP \ - (uint32_t) (0x06) /* Output alternate function push-pull mode */ -#define GPIO_MODE_OUT_ALT_OD \ - (uint32_t) (0x07) /* Output alternate function open-drain mode */ - -#define GPIO_IDR_PIN(n) (uint32_t) (1 << n) /* Input for pin n */ - -#define GPIO_ODR_PIN(n) (uint32_t) (1 << n) /* Output for pin n */ - -#define GPIO_BSRR_BS(n) (uint32_t) (1 << n) /* Set pin n */ -#define GPIO_BSRR_BR(n) (uint32_t) (1 << (n + 16)) /* Reset pin n */ -#define GPIO_BRR_BR(n) (uint16_t) (1 << n) /* Reset pin n */ -#define GPIO_LCKR_LCK(n) (uint32_t) (1 << n) /* Lock pin n */ - -/* DMA */ -#define DMA_ISR_GIF(n) \ - (uint32_t) (0x1 << ((n - 1) * 4)) /* DMA Channel n Global interrupt flag \ - */ -#define DMA_ISR_TCIF(n) \ - (uint32_t) (0x2 << ((n - 1) * 4)) /* DMA Channel n Transfer Complete flag \ - */ -#define DMA_ISR_HTIF(n) \ - (uint32_t) (0x4 << ((n - 1) * 4)) /* DMA Channel n Half Transfer flag */ -#define DMA_ISR_TEIF(n) \ - (uint32_t) (0x8 << ((n - 1) * 4)) /* DMA Channel n Transfer Error flag */ - -#define DMA_IFCR_CGIF(n) \ - (uint32_t) (0x1 << ((n - 1) * 4)) /* DMA Channel n Global interrupt clear \ - */ -#define DMA_IFCR_CTCIF(n) \ - (uint32_t) (0x2 << ((n - 1) * \ - 4)) /* DMA Channel n Transfer Complete clear */ -#define DMA_IFCR_CHTIF(n) \ - (uint32_t) (0x4 << ((n - 1) * 4)) /* DMA Channel n Half Transfer clear */ -#define DMA_IFCR_CTEIF(n) \ - (uint32_t) (0x8 << ((n - 1) * 4)) /* DMA Channel n Transfer Error clear */ - -#define DMA_CCR_EN (uint16_t) (1 << 0) /* DMA Channel enable */ -#define DMA_CCR_TCIE \ - (uint16_t) (1 << 1) /* DMA Channel transfer complete interrupt enable */ -#define DMA_CCR_HTIE \ - (uint16_t) (1 << 2) /* DMA Channel half transfer interrupt enable */ -#define DMA_CCR_TEIE \ - (uint16_t) (1 << 3) /* DMA Channel transfer error interrupt error enable \ - */ -#define DMA_CCR_DIR \ - (uint16_t) (1 << 4) /* DMA Channel data transfer direction */ -#define DMA_CCR_CIRC (uint16_t) (1 << 5) /* DMA Channel circular mode */ -#define DMA_CCR_PINC \ - (uint16_t) (1 << 6) /* DMA Channel peripheral increment mode */ -#define DMA_CCR_MINC \ - (uint16_t) (1 << 7) /* DMA Channel Memory increment mode \ - */ -#define DMA_CCR_PL (uint16_t) (3 << 12) /* DMA Channel Priority level mask */ -#define DMA_CCR_MEM2MEM \ - (uint16_t) (1 << 14) /* DMA Channel Memory to memory mode */ - -#endif diff --git a/include/platform/stm32f1/syscfg.h b/include/platform/stm32f1/syscfg.h deleted file mode 100644 index fc3c5375..00000000 --- a/include/platform/stm32f1/syscfg.h +++ /dev/null @@ -1,9 +0,0 @@ -/* Copyright (c) 2014 The F9 Microkernel Project. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef PLATFORM_STM32F10_SYSCFG_H_ -#define PLATFORM_STM32F10_SYSCFG_H_ - -#endif /* PLATFORM_STM32F10_SYSCFG_H_ */ diff --git a/include/platform/stm32f1/exti.h b/include/platform/stm32l4/exti.h similarity index 76% rename from include/platform/stm32f1/exti.h rename to include/platform/stm32l4/exti.h index a2ec7536..421274f9 100644 --- a/include/platform/stm32f1/exti.h +++ b/include/platform/stm32l4/exti.h @@ -1,8 +1,8 @@ -#ifndef PLATFORM_STM32F1_EXTI_H_ -#define PLATFORM_STM32F1_EXTI_H_ +#ifndef PLATFORM_STM32L4_EXTI_H_ +#define PLATFORM_STM32L4_EXTI_H_ -#include -#include +#include +#include /* EXTI mode */ #define EXTI_INTERRUPT_MODE 0x0 diff --git a/include/platform/stm32l4/gpio.h b/include/platform/stm32l4/gpio.h new file mode 100644 index 00000000..66d503f1 --- /dev/null +++ b/include/platform/stm32l4/gpio.h @@ -0,0 +1,84 @@ +/* Copyright (c) 2013 The F9 Microkernel Project. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef PLATFORM_STM32L4_GPIO_H_ +#define PLATFORM_STM32L4_GPIO_H_ + +#include + +enum { + AF0 = 0, + AF1, + AF2, + AF3, + AF4, + AF5, + AF6, + AF7, + AF8, + AF9, + AF10, + AF11, + AF12, + AF13, + AF14, + AF15, +}; + +struct gpio_cfg { + uint8_t port; + uint8_t pin; + uint8_t pupd; + uint8_t speed; + uint8_t type; + uint8_t func; + uint8_t o_type; +}; + +/* GPIO Alternative Function */ +#define af_system AF0 +#define af_tim1 AF1 +#define af_tim2 AF1 +#define af_tim3 AF2 +#define af_tim4 AF2 +#define af_tim5 AF2 +#define af_tim8 AF3 +#define af_tim9 AF3 +#define af_tim10 AF3 +#define af_tim11 AF3 +#define af_i2c1 AF4 +#define af_i2c2 AF4 +#define af_i2c3 AF4 +#define af_spi1 AF5 +#define af_spi2 AF5 +#define af_spi3 AF6 +#define af_usart1 AF7 +#define af_usart2 AF7 +#define af_usart3 AF7 +#define af_uart4 AF8 +#define af_uart5 AF8 +#define af_usart6 AF8 +#define af_can1 AF9 +#define af_can2 AF9 +#define af_tim12 AF9 +#define af_tim13 AF9 +#define af_tim14 AF9 +#define af_otg_fs AF10 +#define af_otg_hs AF10 +#define af_eth AF11 +#define af_fsmc AF12 +#define af_sdio AF12 +#define af_dcmi AF13 +#define af_eventout AF15 + +void gpio_config(struct gpio_cfg *cfg); +void gpio_config_output(uint8_t port, uint8_t pin, uint8_t pupd, uint8_t speed); +void gpio_config_input(uint8_t port, uint8_t pin, uint8_t pupd); +void gpio_out_high(uint8_t port, uint8_t pin); +void gpio_out_low(uint8_t port, uint8_t pin); +uint8_t gpio_input_bit(uint8_t port, uint8_t pin); +void gpio_writebit(uint8_t port, uint8_t pin, uint8_t bitval); + +#endif /* PLATFORM_STM32L4_GPIO_H_ */ diff --git a/include/platform/stm32f1/hwtimer.h b/include/platform/stm32l4/hwtimer.h similarity index 52% rename from include/platform/stm32f1/hwtimer.h rename to include/platform/stm32l4/hwtimer.h index bfe542b1..b749d9a0 100644 --- a/include/platform/stm32f1/hwtimer.h +++ b/include/platform/stm32l4/hwtimer.h @@ -1,14 +1,14 @@ -/* Copyright (c) 2014 The F9 Microkernel Project. All rights reserved. +/* Copyright (c) 2013 The F9 Microkernel Project. All rights reserved. * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ -#ifndef PLATFORM_STM32F1_HWTIMER_H_ -#define PLATFORM_STM32F1_HWTIMER_H_ +#ifndef PLATFORM_STM32L4_HWTIMER_H_ +#define PLATFORM_STM32L4_HWTIMER_H_ #include void hwtimer_init(void); uint32_t hwtimer_now(void); -#endif /* PLATFORM_STM32F1_HWTIMER_H_ */ +#endif /* PLATFORM_STM32L4_HWTIMER_H_ */ diff --git a/include/platform/stm32f1/nvic.h b/include/platform/stm32l4/nvic.h similarity index 52% rename from include/platform/stm32f1/nvic.h rename to include/platform/stm32l4/nvic.h index 75812ed3..f9efb29b 100644 --- a/include/platform/stm32f1/nvic.h +++ b/include/platform/stm32l4/nvic.h @@ -1,13 +1,13 @@ -/* Copyright (c) 2014 The F9 Microkernel Project. All rights reserved. +/* Copyright (c) 2013 The F9 Microkernel Project. All rights reserved. * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ -#ifndef __PLATFORM_STM32F1_NVIC_H__ -#define __PLATFORM_STM32F1_NVIC_H__ +#ifndef __PLATFORM_STM32L4_NVIC_H__ +#define __PLATFORM_STM32L4_NVIC_H__ #include -#include +#include #define IRQ_ENABLE 1 #define IRQ_DISABLE 0 @@ -36,38 +36,84 @@ typedef enum IRQn { EXTI2_IRQn = 8, /*!< EXTI Line2 Interrupt */ EXTI3_IRQn = 9, /*!< EXTI Line3 Interrupt */ EXTI4_IRQn = 10, /*!< EXTI Line4 Interrupt */ - DMA_Stream0_IRQn = 11, /*!< DMA1 Stream 0 global Interrupt */ - DMA_Stream1_IRQn = 12, /*!< DMA1 Stream 1 global Interrupt */ - DMA_Stream2_IRQn = 13, /*!< DMA1 Stream 2 global Interrupt */ - DMA_Stream3_IRQn = 14, /*!< DMA1 Stream 3 global Interrupt */ - DMA_Stream4_IRQn = 15, /*!< DMA1 Stream 4 global Interrupt */ - DMA_Stream5_IRQn = 16, /*!< DMA1 Stream 5 global Interrupt */ - DMA_Stream6_IRQn = 17, /*!< DMA1 Stream 6 global Interrupt */ + DMA1_Stream0_IRQn = 11, /*!< DMA1 Stream 0 global Interrupt */ + DMA1_Stream1_IRQn = 12, /*!< DMA1 Stream 1 global Interrupt */ + DMA1_Stream2_IRQn = 13, /*!< DMA1 Stream 2 global Interrupt */ + DMA1_Stream3_IRQn = 14, /*!< DMA1 Stream 3 global Interrupt */ + DMA1_Stream4_IRQn = 15, /*!< DMA1 Stream 4 global Interrupt */ + DMA1_Stream5_IRQn = 16, /*!< DMA1 Stream 5 global Interrupt */ + DMA1_Stream6_IRQn = 17, /*!< DMA1 Stream 6 global Interrupt */ ADC_IRQn = 18, /*!< ADC1, ADC2 and ADC3 global Interrupts */ CAN1_TX_IRQn = 19, /*!< CAN1 TX Interrupt */ CAN1_RX0_IRQn = 20, /*!< CAN1 RX0 Interrupt */ CAN1_RX1_IRQn = 21, /*!< CAN1 RX1 Interrupt */ CAN1_SCE_IRQn = 22, /*!< CAN1 SCE Interrupt */ EXTI9_5_IRQn = 23, /*!< External Line[9:5] Interrupts */ - TIM1_BRK_IRQn = 24, /*!< TIM1 Break interrupt */ - TIM1_UP_IRQn = 25, /*!< TIM1 Update Interrupt */ - TIM1_TRG_COM_IRQn = 26, /*!< TIM1 Trigger and Commutation Interrupt */ - TIM1_CC_IRQn = 27, /*!< TIM1 Capture Compare Interrupt */ - TIM2_IRQn = 28, /*!< TIM2 global Interrupt */ - TIM3_IRQn = 29, /*!< TIM3 global Interrupt */ - TIM4_IRQn = 30, /*!< TIM4 global Interrupt */ - I2C1_EV_IRQn = 31, /*!< I2C1 Event Interrupt */ - I2C1_ER_IRQn = 32, /*!< I2C1 Error Interrupt */ - I2C2_EV_IRQn = 33, /*!< I2C2 Event Interrupt */ - I2C2_ER_IRQn = 34, /*!< I2C2 Error Interrupt */ - SPI1_IRQn = 35, /*!< SPI1 global Interrupt */ - SPI2_IRQn = 36, /*!< SPI2 global Interrupt */ - USART1_IRQn = 37, /*!< USART1 global Interrupt */ - USART2_IRQn = 38, /*!< USART2 global Interrupt */ - USART3_IRQn = 39, /*!< USART3 global Interrupt */ - EXTI15_10_IRQn = 40, /*!< External Line[15:10] Interrupts */ + TIM1_BRK_TIM9_IRQn = + 24, /*!< TIM1 Break interrupt and TIM9 global interrupt */ + TIM1_UP_TIM10_IRQn = + 25, /*!< TIM1 Update Interrupt and TIM10 global interrupt */ + TIM1_TRG_COM_TIM11_IRQn = 26, /*!< TIM1 Trigger and Commutation Interrupt + and TIM11 global interrupt */ + TIM1_CC_IRQn = 27, /*!< TIM1 Capture Compare Interrupt */ + TIM2_IRQn = 28, /*!< TIM2 global Interrupt */ + TIM3_IRQn = 29, /*!< TIM3 global Interrupt */ + TIM4_IRQn = 30, /*!< TIM4 global Interrupt */ + I2C1_EV_IRQn = 31, /*!< I2C1 Event Interrupt */ + I2C1_ER_IRQn = 32, /*!< I2C1 Error Interrupt */ + I2C2_EV_IRQn = 33, /*!< I2C2 Event Interrupt */ + I2C2_ER_IRQn = 34, /*!< I2C2 Error Interrupt */ + SPI1_IRQn = 35, /*!< SPI1 global Interrupt */ + SPI2_IRQn = 36, /*!< SPI2 global Interrupt */ + USART1_IRQn = 37, /*!< USART1 global Interrupt */ + USART2_IRQn = 38, /*!< USART2 global Interrupt */ + USART3_IRQn = 39, /*!< USART3 global Interrupt */ + EXTI15_10_IRQn = 40, /*!< External Line[15:10] Interrupts */ RTC_Alarm_IRQn = 41, /*!< RTC Alarm (A and B) through EXTI Line Interrupt */ OTG_FS_WKUP_IRQn = 42, /*!< USB OTG FS Wakeup through EXTI line interrupt */ + TIM8_BRK_TIM12_IRQn = + 43, /*!< TIM8 Break Interrupt and TIM12 global interrupt */ + TIM8_UP_TIM13_IRQn = + 44, /*!< TIM8 Update Interrupt and TIM13 global interrupt */ + TIM8_TRG_COM_TIM14_IRQn = 45, /*!< TIM8 Trigger and Commutation Interrupt + and TIM14 global interrupt */ + TIM8_CC_IRQn = 46, /*!< TIM8 Capture Compare Interrupt */ + DMA1_Stream7_IRQn = 47, /*!< DMA1 Stream7 Interrupt */ + FSMC_IRQn = 48, /*!< FSMC global Interrupt */ + SDIO_IRQn = 49, /*!< SDIO global Interrupt */ + TIM5_IRQn = 50, /*!< TIM5 global Interrupt */ + SPI3_IRQn = 51, /*!< SPI3 global Interrupt */ + UART4_IRQn = 52, /*!< UART4 global Interrupt */ + UART5_IRQn = 53, /*!< UART5 global Interrupt */ + TIM6_DAC_IRQn = 54, /*!< TIM6 global and DAC1&2 underrun error interrupts */ + TIM7_IRQn = 55, /*!< TIM7 global interrupt */ + DMA2_Stream0_IRQn = 56, /*!< DMA2 Stream 0 global Interrupt */ + DMA2_Stream1_IRQn = 57, /*!< DMA2 Stream 1 global Interrupt */ + DMA2_Stream2_IRQn = 58, /*!< DMA2 Stream 2 global Interrupt */ + DMA2_Stream3_IRQn = 59, /*!< DMA2 Stream 3 global Interrupt */ + DMA2_Stream4_IRQn = 60, /*!< DMA2 Stream 4 global Interrupt */ + ETH_IRQn = 61, /*!< Ethernet global Interrupt */ + ETH_WKUP_IRQn = 62, /*!< Ethernet Wakeup through EXTI line Interrupt */ + CAN2_TX_IRQn = 63, /*!< CAN2 TX Interrupt */ + CAN2_RX0_IRQn = 64, /*!< CAN2 RX0 Interrupt */ + CAN2_RX1_IRQn = 65, /*!< CAN2 RX1 Interrupt */ + CAN2_SCE_IRQn = 66, /*!< CAN2 SCE Interrupt */ + OTG_FS_IRQn = 67, /*!< USB OTG FS global Interrupt */ + DMA2_Stream5_IRQn = 68, /*!< DMA2 Stream 5 global interrupt */ + DMA2_Stream6_IRQn = 69, /*!< DMA2 Stream 6 global interrupt */ + DMA2_Stream7_IRQn = 70, /*!< DMA2 Stream 7 global interrupt */ + USART6_IRQn = 71, /*!< USART6 global interrupt */ + I2C3_EV_IRQn = 72, /*!< I2C3 event interrupt */ + I2C3_ER_IRQn = 73, /*!< I2C3 error interrupt */ + OTG_HS_EP1_OUT_IRQn = + 74, /*!< USB OTG HS End Point 1 Out global interrupt */ + OTG_HS_EP1_IN_IRQn = 75, /*!< USB OTG HS End Point 1 In global interrupt */ + OTG_HS_WKUP_IRQn = 76, /*!< USB OTG HS Wakeup through EXTI interrupt */ + OTG_HS_IRQn = 77, /*!< USB OTG HS global interrupt */ + DCMI_IRQn = 78, /*!< DCMI global interrupt */ + CRYP_IRQn = 79, /*!< CRYP crypto global interrupt */ + HASH_RNG_IRQn = 80, /*!< Hash and Rng global interrupt */ + FPU_IRQn = 81, /*!< FPU global interrupt */ IRQn_NUM, } IRQn_Type; @@ -98,9 +144,9 @@ typedef enum IRQn { #define CAN1_RX1_HANDLER nvic_handler21 #define CAN1_SCE_HANDLER nvic_handler22 #define EXTI9_5_HANDLER nvic_handler23 -#define TIM1_BRK_HANDLER nvic_handler24 -#define TIM1_UP_HANDLER nvic_handler25 -#define TIM1_TRG_COM_HANDLER nvic_handler26 +#define TIM1_BRK_TIM9_HANDLER nvic_handler24 +#define TIM1_UP_TIM10_HANDLER nvic_handler25 +#define TIM1_TRG_COM_TIM11_HANDLER nvic_handler26 #define TIM1_CC_HANDLER nvic_handler27 #define TIM2_HANDLER nvic_handler28 #define TIM3_HANDLER nvic_handler29 @@ -118,11 +164,51 @@ typedef enum IRQn { #define EXTI15_10_HANDLER nvic_handler40 #define RTC_Alarm_HANDLER nvic_handler41 #define OTG_FS_WKUP_HANDLER nvic_handler42 +#define TIM8_BRK_TIM12_HANDLER nvic_handler43 +#define TIM8_UP_TIM13_HANDLER nvic_handler44 +#define TIM8_TRG_COM_TIM14_HANDLER nvic_handler45 +#define TIM8_CC_HANDLER nvic_handler46 +#define DMA1_Stream7_HANDLER nvic_handler47 +#define FSMC_HANDLER nvic_handler48 +#define SDIO_HANDLER nvic_handler49 +#define TIM5_HANDLER nvic_handler50 +#define SPI3_HANDLER nvic_handler51 +#define UART4_HANDLER nvic_handler52 +#define UART5_HANDLER nvic_handler53 +#define TIM6_DAC_HANDLER nvic_handler54 +#define TIM7_HANDLER nvic_handler55 +#define DMA2_Stream0_HANDLER nvic_handler56 +#define DMA2_Stream1_HANDLER nvic_handler57 +#define DMA2_Stream2_HANDLER nvic_handler58 +#define DMA2_Stream3_HANDLER nvic_handler59 +#define DMA2_Stream4_HANDLER nvic_handler60 +#define ETH_HANDLER nvic_handler61 +#define ETH_WKUP_HANDLER nvic_handler62 +#define CAN2_TX_HANDLER nvic_handler63 +#define CAN2_RX0_HANDLER nvic_handler64 +#define CAN2_RX1_HANDLER nvic_handler65 +#define CAN2_SCE_HANDLER nvic_handler66 +#define OTG_FS_HANDLER nvic_handler67 +#define DMA2_Stream5_HANDLER nvic_handler68 +#define DMA2_Stream6_HANDLER nvic_handler69 +#define DMA2_Stream7_HANDLER nvic_handler70 +#define USART6_HANDLER nvic_handler71 +#define I2C3_EV_HANDLER nvic_handler72 +#define I2C3_ER_HANDLER nvic_handler73 +#define OTG_HS_EP1_OUT_HANDLER nvic_handler74 +#define OTG_HS_EP1_IN_HANDLER nvic_handler75 +#define OTG_HS_WKUP_HANDLER nvic_handler76 +#define OTG_HS_HANDLER nvic_handler77 +#define DCMI_HANDLER nvic_handler78 +#define CRYP_HANDLER nvic_handler79 +#define HASH_RNG_HANDLER nvic_handler80 +#define FPU_HANDLER nvic_handler81 + #define IRQ_VEC_N_HANDLER_DECLARE(n) void nvic_handler##n(void); #define IRQ_VEC_N_OP IRQ_VEC_N_HANDLER_DECLARE -#include "platform/stm32f1/nvic_private.h" +#include "platform/stm32l4/nvic_private.h" #undef IRQ_VEC_N_OP typedef struct { @@ -208,4 +294,4 @@ inline static uint32_t NVIC_GetActive(IRQn_Type IRQn) } int nvic_is_setup(int irq); -#endif /* __PLATFORM_STM32F1_NVIC_H__ */ +#endif /* __PLATFORM_STM32F4_NVIC_H__ */ diff --git a/include/platform/stm32l4/nvic_private.h b/include/platform/stm32l4/nvic_private.h new file mode 100644 index 00000000..d459ba41 --- /dev/null +++ b/include/platform/stm32l4/nvic_private.h @@ -0,0 +1,410 @@ +/* This header is only included internally. */ +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_WWDG_USER_IRQ)) +IRQ_VEC_N_OP(0) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_PVD_USER_IRQ)) +IRQ_VEC_N_OP(1) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_TAMP_STAMP_USER_IRQ)) +IRQ_VEC_N_OP(2) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_RTC_WKUP_USER_IRQ)) +IRQ_VEC_N_OP(3) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_FLASH_USER_IRQ)) +IRQ_VEC_N_OP(4) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_RCC_USER_IRQ)) +IRQ_VEC_N_OP(5) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_EXTI0_USER_IRQ)) +IRQ_VEC_N_OP(6) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_EXTI1_USER_IRQ)) +IRQ_VEC_N_OP(7) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_EXTI2_USER_IRQ)) +IRQ_VEC_N_OP(8) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_EXTI3_USER_IRQ)) +IRQ_VEC_N_OP(9) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_EXTI4_USER_IRQ)) +IRQ_VEC_N_OP(10) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_DMA1_Stream0_USER_IRQ)) +IRQ_VEC_N_OP(11) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_DMA1_Stream1_USER_IRQ)) +IRQ_VEC_N_OP(12) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_DMA1_Stream2_USER_IRQ)) +IRQ_VEC_N_OP(13) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_DMA1_Stream3_USER_IRQ)) +IRQ_VEC_N_OP(14) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_DMA1_Stream4_USER_IRQ)) +IRQ_VEC_N_OP(15) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_DMA1_Stream5_USER_IRQ)) +IRQ_VEC_N_OP(16) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_DMA1_Stream6_USER_IRQ)) +IRQ_VEC_N_OP(17) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_ADC_USER_IRQ)) +IRQ_VEC_N_OP(18) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_CAN1_TX_USER_IRQ)) +IRQ_VEC_N_OP(19) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_CAN1_RX_USER_IRQ)) +IRQ_VEC_N_OP(20) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_CAN1_RX1_USER_IRQ)) +IRQ_VEC_N_OP(21) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_CAN1_SCE_USER_IRQ)) +IRQ_VEC_N_OP(22) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_EXTI9_5_USER_IRQ)) +IRQ_VEC_N_OP(23) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_TIM1_BRK_TIM9_USER_IRQ)) +IRQ_VEC_N_OP(24) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_TIM1_UP_TIM10_USER_IRQ)) +IRQ_VEC_N_OP(25) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_TIM1_TRG_COM_TIM11_USER_IRQ)) +IRQ_VEC_N_OP(26) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_TIM1_CC_USER_IRQ)) +IRQ_VEC_N_OP(27) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_TIM2_USER_IRQ)) +IRQ_VEC_N_OP(28) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_TIM3_USER_IRQ)) +IRQ_VEC_N_OP(29) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_TIM4_USER_IRQ)) +IRQ_VEC_N_OP(30) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_I2C1_EV_USER_IRQ)) +IRQ_VEC_N_OP(31) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_I2C1_ER_USER_IRQ)) +IRQ_VEC_N_OP(32) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_I2C2_EV_USER_IRQ)) +IRQ_VEC_N_OP(33) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_I2C2_ER_USER_IRQ)) +IRQ_VEC_N_OP(34) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_SPI1_USER_IRQ)) +IRQ_VEC_N_OP(35) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_SPI2_USER_IRQ)) +IRQ_VEC_N_OP(36) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_USART1_USER_IRQ)) +IRQ_VEC_N_OP(37) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_USART2_USER_IRQ)) +IRQ_VEC_N_OP(38) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_USART3_USER_IRQ)) +IRQ_VEC_N_OP(39) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_EXTI15_10_USER_IRQ)) +IRQ_VEC_N_OP(40) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_RTC_Alarm_USER_IRQ)) +IRQ_VEC_N_OP(41) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_OTG_FS_WKUP_USER_IRQ)) +IRQ_VEC_N_OP(42) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_TIM8_BRK_TIM12_USER_IRQ)) +IRQ_VEC_N_OP(43) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_TIM8_UP_TIM13_USER_IRQ)) +IRQ_VEC_N_OP(44) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_TIM8_TRG_COM_TIM14_USER_IRQ)) +IRQ_VEC_N_OP(45) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_TIM8_CC_USER_IRQ)) +IRQ_VEC_N_OP(46) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_DMA1_Stream7_USER_IRQ)) +IRQ_VEC_N_OP(47) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_FSMC_USER_IRQ)) +IRQ_VEC_N_OP(48) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_SDIO_USER_IRQ)) +IRQ_VEC_N_OP(49) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_TIM5_USER_IRQ)) +IRQ_VEC_N_OP(50) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_SPI3_USER_IRQ)) +IRQ_VEC_N_OP(51) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_UART4_USER_IRQ)) +IRQ_VEC_N_OP(52) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_UART5_USER_IRQ)) +IRQ_VEC_N_OP(53) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_TIM6_DAC_USER_IRQ)) +IRQ_VEC_N_OP(54) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_TIM7_USER_IRQ)) +IRQ_VEC_N_OP(55) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_DMA2_Stream0_USER_IRQ)) +IRQ_VEC_N_OP(56) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_DMA2_Stream1_USER_IRQ)) +IRQ_VEC_N_OP(57) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_DMA2_Stream2_USER_IRQ)) +IRQ_VEC_N_OP(58) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_DMA2_Stream3_USER_IRQ)) +IRQ_VEC_N_OP(59) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_DMA2_Stream4_USER_IRQ)) +IRQ_VEC_N_OP(60) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_ETH_USER_IRQ)) +IRQ_VEC_N_OP(61) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_ETH_WKUP_USER_IRQ)) +IRQ_VEC_N_OP(62) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_CAN2_TX_USER_IRQ)) +IRQ_VEC_N_OP(63) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_CAN2_RX0_USER_IRQ)) +IRQ_VEC_N_OP(64) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_CAN2_RX1_USER_IRQ)) +IRQ_VEC_N_OP(65) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_CAN2_SCE_USER_IRQ)) +IRQ_VEC_N_OP(66) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_OTG_FS_USER_IRQ)) +IRQ_VEC_N_OP(67) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_DMA2_Stream5_USER_IRQ)) +IRQ_VEC_N_OP(68) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_DMA2_Stream6_USER_IRQ)) +IRQ_VEC_N_OP(69) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_DMA2_Stream7_USER_IRQ)) +IRQ_VEC_N_OP(70) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_USART6_USER_IRQ)) +IRQ_VEC_N_OP(71) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_I2C3_EV_USER_IRQ)) +IRQ_VEC_N_OP(72) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_I2C3_ER_USER_IRQ)) +IRQ_VEC_N_OP(73) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_OTG_HS_EP1_OUT_USER_IRQ)) +IRQ_VEC_N_OP(74) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_OTG_HS_EP1_IN_USER_IRQ)) +IRQ_VEC_N_OP(75) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_OTG_HS_WKUP_USER_IRQ)) +IRQ_VEC_N_OP(76) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_OTG_HS_USER_IRQ)) +IRQ_VEC_N_OP(77) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_DCMI_USER_IRQ)) +IRQ_VEC_N_OP(78) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_CRYP_USER_IRQ)) +IRQ_VEC_N_OP(79) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_HASH_RNG_USER_IRQ)) +IRQ_VEC_N_OP(80) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_FPU_USER_IRQ)) +IRQ_VEC_N_OP(81) +#endif diff --git a/include/platform/stm32f1/nvic_table.h b/include/platform/stm32l4/nvic_table.h similarity index 77% rename from include/platform/stm32f1/nvic_table.h rename to include/platform/stm32l4/nvic_table.h index dd315201..b5757202 100644 --- a/include/platform/stm32f1/nvic_table.h +++ b/include/platform/stm32l4/nvic_table.h @@ -3,5 +3,5 @@ #define IRQ_HANDLER_FUNC(n) nvic_handler##n, #define IRQ_VEC_N_OP IRQ_HANDLER_FUNC -#include "platform/stm32f1/nvic_private.h" +#include "platform/stm32l4/nvic_private.h" #undef IRQ_VEC_N_OP diff --git a/include/platform/stm32f1/rcc.h b/include/platform/stm32l4/rcc.h similarity index 64% rename from include/platform/stm32f1/rcc.h rename to include/platform/stm32l4/rcc.h index 93c83de5..95fd0607 100644 --- a/include/platform/stm32f1/rcc.h +++ b/include/platform/stm32l4/rcc.h @@ -1,7 +1,7 @@ -#ifndef PLATFORM_STM32F1_RCC_H__ -#define PLATFORM_STM32F1_RCC_H__ +#ifndef PLATFORM_STM32L4_RCC_H__ +#define PLATFORM_STM32L4_RCC_H__ -#include +#include struct rcc_clocks { uint32_t sysclk_freq; uint32_t hclk_freq; @@ -10,11 +10,17 @@ struct rcc_clocks { }; /* RCC_FLAG definition */ +#define RCC_FLAG_MSIRDY \ + ((uint8_t) 0x01) /* MSI oscillator ready (new in L4) \ + */ #define RCC_FLAG_HSIRDY ((uint8_t) 0x21) #define RCC_FLAG_HSERDY ((uint8_t) 0x31) #define RCC_FLAG_PLLRDY ((uint8_t) 0x39) +#define RCC_FLAG_PLLSAI1RDY ((uint8_t) 0x3B) /* PLLSAI1 in L4 */ +#define RCC_FLAG_PLLSAI2RDY ((uint8_t) 0x3D) /* PLLSAI2 in L4 */ #define RCC_FLAG_LSERDY ((uint8_t) 0x41) #define RCC_FLAG_LSIRDY ((uint8_t) 0x61) +#define RCC_FLAG_BORRST ((uint8_t) 0x79) #define RCC_FLAG_PINRST ((uint8_t) 0x7A) #define RCC_FLAG_PORRST ((uint8_t) 0x7B) #define RCC_FLAG_SFTRST ((uint8_t) 0x7C) @@ -23,8 +29,8 @@ struct rcc_clocks { #define RCC_FLAG_LPWRRST ((uint8_t) 0x7F) void sys_clock_init(void); -void RCC_AHBPeriphClockCmd(uint32_t rcc_AHB, uint8_t enable); -void RCC_AHBPeriphResetCmd(uint32_t rcc_AHB, uint8_t enable); +void RCC_AHB1PeriphClockCmd(uint32_t rcc_AHB1, uint8_t enable); +void RCC_AHB1PeriphResetCmd(uint32_t rcc_AHB1, uint8_t enable); void RCC_APB1PeriphClockCmd(uint32_t rcc_APB1, uint8_t enable); void RCC_APB1PeriphResetCmd(uint32_t rcc_APB1, uint8_t enable); void RCC_APB2PeriphClockCmd(uint32_t rcc_APB2, uint8_t enable); diff --git a/include/platform/stm32l4/registers.h b/include/platform/stm32l4/registers.h new file mode 100644 index 00000000..7993f35f --- /dev/null +++ b/include/platform/stm32l4/registers.h @@ -0,0 +1,1744 @@ +/* STM32L4 Registers and Memory Locations */ + +#ifndef STM32L4_REGISTERS_H_INCLUDED +#define STM32L4_REGISTERS_H_INCLUDED + +#include + +#define STM32L4X + +/* Memory Map */ +#define MEMORY_BASE (uint32_t) (0x00000000) /* Base of memory map */ +#define FLASH_BASE (uint32_t) (0x08000000) /* Flash Memory Base Address */ +#define RAM_BASE (uint32_t) (0x20000000) /* RAM Base Address */ +#define ETHRAM_BASE (uint32_t) (0x2001C000) /* ETHRAM Base Address */ +#define CCMRAM_BASE \ + (uint32_t) (0x10000000) /* CCMRAM Base Address - Accessible only to CPU */ + +/* Peripheral Map */ +#define PERIPH_BASE (uint32_t) (0x40000000) /* Peripheral base address */ +#define PRIV_PERIPH_BASE \ + (uint32_t) (0xED000000) /* Private peripheral base address */ +#define APB1PERIPH_BASE (PERIPH_BASE) +#define APB2PERIPH_BASE (PERIPH_BASE + 0x00010000) +#define AHB1PERIPH_BASE (PERIPH_BASE + 0x00020000) +#define AHB2PERIPH_BASE (PERIPH_BASE + 0x10000000) + + + +/* APB1 peripherals */ +#define TIM2_BASE (APB1PERIPH_BASE + 0x0000) +#define TIM3_BASE (APB1PERIPH_BASE + 0x0400) +#define TIM4_BASE (APB1PERIPH_BASE + 0x0800) +#define TIM5_BASE (APB1PERIPH_BASE + 0x0C00) +#define TIM6_BASE (APB1PERIPH_BASE + 0x1000) +#define TIM7_BASE (APB1PERIPH_BASE + 0x1400) +#define TIM12_BASE (APB1PERIPH_BASE + 0x1800) +#define TIM13_BASE (APB1PERIPH_BASE + 0x1C00) +#define TIM14_BASE (APB1PERIPH_BASE + 0x2000) +#define RTC_BASE (APB1PERIPH_BASE + 0x2800) +#define WWDG_BASE (APB1PERIPH_BASE + 0x2C00) +#define IWDG_BASE (APB1PERIPH_BASE + 0x3000) +#define I2S2ext_BASE (APB1PERIPH_BASE + 0x3400) +#define SPI2_BASE (APB1PERIPH_BASE + 0x3800) +#define SPI3_BASE (APB1PERIPH_BASE + 0x3C00) +#define I2S3ext_BASE (APB1PERIPH_BASE + 0x4000) +#define USART2_BASE (APB1PERIPH_BASE + 0x4400) +#define USART3_BASE (APB1PERIPH_BASE + 0x4800) +#define UART4_BASE (APB1PERIPH_BASE + 0x4C00) +#define UART5_BASE (APB1PERIPH_BASE + 0x5000) +#define I2C1_BASE (APB1PERIPH_BASE + 0x5400) +#define I2C2_BASE (APB1PERIPH_BASE + 0x5800) +#define I2C3_BASE (APB1PERIPH_BASE + 0x5C00) +#define CAN1_BASE (APB1PERIPH_BASE + 0x6400) +#define CAN2_BASE (APB1PERIPH_BASE + 0x6800) +#define PWR_BASE (APB1PERIPH_BASE + 0x7000) +#define DAC_BASE (APB1PERIPH_BASE + 0x7400) + +/* APB2 peripherals - STM32L4 offsets (different from F4) */ +#define TIM1_BASE (APB2PERIPH_BASE + 0x2C00) +#define TIM8_BASE (APB2PERIPH_BASE + 0x3400) +#define USART1_BASE (APB2PERIPH_BASE + 0x3800) +/* No USART6 on STM32L475 */ +#define ADC1_BASE (APB2PERIPH_BASE + 0x2000) +#define ADC2_BASE (APB2PERIPH_BASE + 0x2100) +#define ADC3_BASE (APB2PERIPH_BASE + 0x2200) +#define ADC_BASE (APB2PERIPH_BASE + 0x2300) +#define SDIO_BASE (APB2PERIPH_BASE + 0x2C00) +#define SPI1_BASE (APB2PERIPH_BASE + 0x3000) +#define SYSCFG_BASE (APB2PERIPH_BASE + 0x0000) +#define EXTI_BASE (APB2PERIPH_BASE + 0x3C00) +#define TIM9_BASE (APB2PERIPH_BASE + 0x4000) +#define TIM10_BASE (APB2PERIPH_BASE + 0x4400) +#define TIM11_BASE (APB2PERIPH_BASE + 0x4800) + +/* AHB */ +#define GPIO_BASE(port) \ + (0x48000000 + (0x400 * port)) /* GPIO Port base address */ +#define RCC_BASE \ + (AHB1PERIPH_BASE + \ + 0x1000) /* Reset and Clock Control base address (L4: 0x40021000) */ +#define FLASH_R_BASE \ + (AHB1PERIPH_BASE + \ + 0x2000) /* Flash registers base address (L4: 0x40022000) */ +#define DMA1_BASE (AHB1PERIPH_BASE + 0x6000) /* DMA1 base address */ +#define DMA2_BASE (AHB1PERIPH_BASE + 0x6400) /* DMA2 base address */ +#define USB_FS_BASE (AHB2PERIPH_BASE + 0x0000) /* USB OTG FS base address */ + + +/* Timer 1 (TIM1) */ +#define TIM1_CR1 \ + (volatile uint32_t *) (TIM1_BASE + 0x00) /* TIM1 control register 1 */ +#define TIM1_CR2 \ + (volatile uint32_t *) (TIM1_BASE + 0x04) /* TIM1 control register 2 */ +#define TIM1_SMCR \ + (volatile uint32_t *) (TIM1_BASE + \ + 0x08) /* TIM1 slave mode control register */ +#define TIM1_DIER \ + (volatile uint32_t *) (TIM1_BASE + \ + 0x0C) /* TIM1 DMA/Interrupt enable register */ +#define TIM1_SR \ + (volatile uint32_t *) (TIM1_BASE + 0x10) /* TIM1 status register */ +#define TIM1_EGR \ + (volatile uint32_t *) (TIM1_BASE + \ + 0x14) /* TIM1 event generation register */ +#define TIM1_CCMR1 \ + (volatile uint32_t *) (TIM1_BASE + \ + 0x18) /* TIM1 capture/compare mode register 1 */ +#define TIM1_CCMR2 \ + (volatile uint32_t *) (TIM1_BASE + \ + 0x1C) /* TIM1 capture/compare mode register 2 */ +#define TIM1_CCER \ + (volatile uint32_t *) (TIM1_BASE + \ + 0x20) /* TIM1 capture/compare enable register */ +#define TIM1_CNT (volatile uint32_t *) (TIM1_BASE + 0x24) /* TIM1 counter */ +#define TIM1_PSC (volatile uint32_t *) (TIM1_BASE + 0x28) /* TIM1 prescaler */ +#define TIM1_ARR \ + (volatile uint32_t *) (TIM1_BASE + 0x2C) /* TIM1 auto-reload register */ +#define TIM1_CCR1 \ + (volatile uint32_t *) (TIM1_BASE + \ + 0x34) /* TIM1 capture/compare register 1 */ +#define TIM1_CCR2 \ + (volatile uint32_t *) (TIM1_BASE + \ + 0x38) /* TIM1 capture/compare register 2 */ +#define TIM1_CCR3 \ + (volatile uint32_t *) (TIM1_BASE + \ + 0x3C) /* TIM1 capture/compare register 3 */ +#define TIM1_CCR4 \ + (volatile uint32_t *) (TIM1_BASE + \ + 0x40) /* TIM1 capture/compare register 4 */ +#define TIM1_DCR \ + (volatile uint32_t *) (TIM1_BASE + 0x48) /* TIM1 DMA control register */ +#define TIM1_DMAR \ + (volatile uint32_t *) (TIM1_BASE + \ + 0x4C) /* TIM1 DMA address for full transfer */ +#define TIM1_OR \ + (volatile uint32_t *) (TIM1_BASE + 0x50) /* TIM1 option register */ + +#define TIM2_CR1 \ + (volatile uint32_t *) (TIM2_BASE + 0x00) /* TIM2 control register 1 */ +#define TIM2_CR2 \ + (volatile uint32_t *) (TIM2_BASE + 0x04) /* TIM2 control register 2 */ +#define TIM2_SMCR \ + (volatile uint32_t *) (TIM2_BASE + \ + 0x08) /* TIM2 slave mode control register */ +#define TIM2_DIER \ + (volatile uint32_t *) (TIM2_BASE + \ + 0x0C) /* TIM2 DMA/Interrupt enable register */ +#define TIM2_SR \ + (volatile uint32_t *) (TIM2_BASE + 0x10) /* TIM2 status register */ +#define TIM2_EGR \ + (volatile uint32_t *) (TIM2_BASE + \ + 0x14) /* TIM2 event generation register */ +#define TIM2_CCMR1 \ + (volatile uint32_t *) (TIM2_BASE + \ + 0x18) /* TIM2 capture/compare mode register 1 */ +#define TIM2_CCMR2 \ + (volatile uint32_t *) (TIM2_BASE + \ + 0x1C) /* TIM2 capture/compare mode register 2 */ +#define TIM2_CCER \ + (volatile uint32_t *) (TIM2_BASE + \ + 0x20) /* TIM2 capture/compare enable register */ +#define TIM2_CNT (volatile uint32_t *) (TIM2_BASE + 0x24) /* TIM2 counter */ +#define TIM2_PSC (volatile uint32_t *) (TIM2_BASE + 0x28) /* TIM2 prescaler */ +#define TIM2_ARR \ + (volatile uint32_t *) (TIM2_BASE + 0x2C) /* TIM2 auto-reload register */ +#define TIM2_CCR1 \ + (volatile uint32_t *) (TIM2_BASE + \ + 0x34) /* TIM2 capture/compare register 1 */ +#define TIM2_CCR2 \ + (volatile uint32_t *) (TIM2_BASE + \ + 0x38) /* TIM2 capture/compare register 2 */ +#define TIM2_CCR3 \ + (volatile uint32_t *) (TIM2_BASE + \ + 0x3C) /* TIM2 capture/compare register 3 */ +#define TIM2_CCR4 \ + (volatile uint32_t *) (TIM2_BASE + \ + 0x40) /* TIM2 capture/compare register 4 */ +#define TIM2_DCR \ + (volatile uint32_t *) (TIM2_BASE + 0x48) /* TIM2 DMA control register */ +#define TIM2_DMAR \ + (volatile uint32_t *) (TIM2_BASE + \ + 0x4C) /* TIM2 DMA address for full transfer */ +#define TIM2_OR \ + (volatile uint32_t *) (TIM2_BASE + 0x50) /* TIM2 option register */ +/* Power Control (PWR) */ +#define PWR_CR \ + (volatile uint32_t *) (PWR_BASE + 0x00) /* Power Control Register */ +#define PWR_CSR \ + (volatile uint32_t *) (PWR_BASE + 0x04) /* Power Control/Status Register \ + */ + +/* SPI */ +#define SPI_CR1(port) \ + (volatile uint32_t *) (SPI_BASE(port) + 0x00) /* SPI control register 1 */ +#define SPI_CR2(port) \ + (volatile uint32_t *) (SPI_BASE(port) + 0x04) /* SPI control register 2 */ +#define SPI_SR(port) \ + (volatile uint32_t *) (SPI_BASE(port) + 0x08) /* SPI status register */ +#define SPI_DR(port) \ + (volatile uint32_t *) (SPI_BASE(port) + 0x0c) /* SPI data register */ +#define SPI_CRCPR(port) \ + (volatile uint32_t *) (SPI_BASE(port) + \ + 0x10) /* SPI CRC polynomial register */ +#define SPI_RXCRCR(port) \ + (volatile uint32_t *) (SPI_BASE(port) + 0x14) /* SPI RX CRC register */ +#define SPI_TXCRCR(port) \ + (volatile uint32_t *) (SPI_BASE(port) + 0x18) /* SPI TX CRC register */ +#define SPI_I2SCFGR(port) \ + (volatile uint32_t *) (SPI_BASE(port) + \ + 0x1c) /* SPI I2C configuration register */ +#define SPI_I2SPR(port) \ + (volatile uint32_t *) (SPI_BASE(port) + \ + 0x20) /* SPI I2C prescaler register */ + +/* I2C */ +#define I2C_CR1(port) \ + (volatile uint32_t *) (I2C_BASE(port) + 0x00) /* I2C control register 1 */ +#define I2C_CR2(port) \ + (volatile uint32_t *) (I2C_BASE(port) + 0x04) /* I2C control register 2 */ +#define I2C_OAR1(port) \ + (volatile uint32_t *) (I2C_BASE(port) + \ + 0x08) /* I2C own address register 1 */ +#define I2C_OAR2(port) \ + (volatile uint32_t *) (I2C_BASE(port) + \ + 0x0C) /* I2C own address register 2 */ +#define I2C_DR(port) \ + (volatile uint32_t *) (I2C_BASE(port) + 0x10) /* I2C data register */ +#define I2C_SR1(port) \ + (volatile uint32_t *) (I2C_BASE(port) + 0x14) /* I2C status register 1 */ +#define I2C_SR2(port) \ + (volatile uint32_t *) (I2C_BASE(port) + 0x18) /* I2C status register 2 */ +#define I2C_CCR(port) \ + (volatile uint32_t *) (I2C_BASE(port) + \ + 0x1C) /* I2C clock control register */ +#define I2C_TRISE(port) \ + (volatile uint32_t *) (I2C_BASE(port) + 0x20) /* I2C TRISE register */ + +/* USART 1 */ +#define USART1_SR \ + (volatile uint32_t *) (USART1_BASE + 0x00) /* USART1 status register */ +#define USART1_DR \ + (volatile uint32_t *) (USART1_BASE + 0x04) /* USART1 data register */ +#define USART1_BRR \ + (volatile uint32_t *) (USART1_BASE + 0x08) /* USART1 baud rate register */ +#define USART1_CR1 \ + (volatile uint32_t *) (USART1_BASE + 0x0C) /* USART1 control register 1 */ +#define USART1_CR2 \ + (volatile uint32_t *) (USART1_BASE + 0x10) /* USART1 control register 2 */ +#define USART1_CR3 \ + (volatile uint32_t *) (USART1_BASE + 0x14) /* USART1 control register 3 */ +#define USART1_GTPR \ + (volatile uint32_t *) (USART1_BASE + \ + 0x18) /* USART1 gaurd time and prescale register */ + +/* GPIO Port (GPIO) */ +#define GPIO_MODER(port) \ + (volatile uint32_t *) (GPIO_BASE(port) + 0x00) /* Port mode register */ +#define GPIO_OTYPER(port) \ + (volatile uint32_t *) (GPIO_BASE(port) + \ + 0x04) /* Port output type register */ +#define GPIO_OSPEEDR(port) \ + (volatile uint32_t *) (GPIO_BASE(port) + \ + 0x08) /* Port output speed register */ +#define GPIO_PUPDR(port) \ + (volatile uint32_t *) (GPIO_BASE(port) + \ + 0x0C) /* Port pull up/down register */ +#define GPIO_IDR(port) \ + (volatile uint32_t *) (GPIO_BASE(port) + \ + 0x10) /* Port input data register */ +#define GPIO_ODR(port) \ + (volatile uint32_t *) (GPIO_BASE(port) + \ + 0x14) /* Port output data register */ +#define GPIO_BSRR(port) \ + (volatile uint32_t *) (GPIO_BASE(port) + \ + 0x18) /* Port bit set/reset register */ +#define GPIO_LCKR(port) \ + (volatile uint32_t *) (GPIO_BASE(port) + \ + 0x1C) /* Port configuration lock register */ +#define GPIO_AFRL(port) \ + (volatile uint32_t *) (GPIO_BASE(port) + \ + 0x20) /* Port alternate function low register */ +#define GPIO_AFRH(port) \ + (volatile uint32_t *) (GPIO_BASE(port) + \ + 0x24) /* Port alternate function high register */ + +/* Reset and Clock Control (RCC) */ +#define RCC_CR \ + (volatile uint32_t *) (RCC_BASE + 0x00) /* Clock Control Register */ +#define RCC_PLLCFGR \ + (volatile uint32_t *) (RCC_BASE + 0x04) /* PLL Configuration Register */ +#define RCC_CFGR \ + (volatile uint32_t *) (RCC_BASE + 0x08) /* Clock Configuration Register */ +#define RCC_CIR \ + (volatile uint32_t *) (RCC_BASE + 0x0C) /* Clock Interrupt Register */ +#define RCC_AHB1RSTR \ + (volatile uint32_t *) (RCC_BASE + 0x10) /* AHB1 reset Register */ +#define RCC_APB1RSTR \ + (volatile uint32_t *) (RCC_BASE + 0x20) /* APB1 reset Register */ +#define RCC_APB2RSTR \ + (volatile uint32_t *) (RCC_BASE + 0x24) /* APB2 reset Register */ +/* STM32L4 RCC enable registers (different offsets from F4) */ +#define RCC_AHB1ENR \ + (volatile uint32_t *) (RCC_BASE + 0x48) /* AHB1 Enable Register */ +#define RCC_AHB2ENR \ + (volatile uint32_t *) (RCC_BASE + 0x4C) /* AHB2 Enable Register */ +#define RCC_APB1ENR \ + (volatile uint32_t *) (RCC_BASE + \ + 0x58) /* APB1 Peripheral Clock Enable Register 1 */ +#define RCC_APB2ENR \ + (volatile uint32_t *) (RCC_BASE + \ + 0x60) /* APB2 Peripheral Clock Enable Register */ +#define RCC_BDCR \ + (volatile uint32_t *) (RCC_BASE + \ + 0x70) /* RCC Backup Domain Control Register */ +#define RCC_CSR \ + (volatile uint32_t *) (RCC_BASE + \ + 0x74) /* RCC Clock Control & Status Register */ +#define RCC_PLLSAICFGR \ + (volatile uint32_t *) (RCC_BASE + \ + 0x88) /* RCC PLLSAI Configuration register */ +#define RCC_DCKCFGR \ + (volatile uint32_t *) (RCC_BASE + 0x8C) /* RCC Dedicated Clocks \ + Configuration register */ + +/* SYSCFG */ +#define SYSCFG_MEMRMP \ + (volatile uint32_t *) (SYSCFG_BASE + 0x0) /* Memory remap register */ +#define SYSCFG_PMC \ + (volatile uint32_t *) (SYSCFG_BASE + \ + 0x4) /* Peripheral mode config register */ +#define SYSCFG_EXTICR1 \ + (volatile uint32_t *) (SYSCFG_BASE + \ + 0x8) /* External INT config register1 */ +#define SYSCFG_EXTICR2 \ + (volatile uint32_t *) (SYSCFG_BASE + \ + 0xc) /* External INT config register2 */ +#define SYSCFG_EXTICR3 \ + (volatile uint32_t *) (SYSCFG_BASE + \ + 0x10) /* External INT config register3 */ +#define SYSCFG_EXTICR4 \ + (volatile uint32_t *) (SYSCFG_BASE + \ + 0x14) /* External INT config register4 */ +#define SYSCFG_CMPCR \ + (volatile uint32_t *) (SYSCFG_BASE + \ + 0x20) /* Compensation cell control register*/ + + + +/* APB1 RCC ENR */ +#define RCC_TIM2_APBENR RCC_APB1ENR +#define RCC_TIM3_APBENR RCC_APB1ENR +#define RCC_TIM4_APBENR RCC_APB1ENR +#define RCC_TIM5_APBENR RCC_APB1ENR +#define RCC_TIM6_APBENR RCC_APB1ENR +#define RCC_TIM7_APBENR RCC_APB1ENR +#define RCC_TIM12_APBENR RCC_APB1ENR +#define RCC_TIM13_APBENR RCC_APB1ENR +#define RCC_TIM14_APBENR RCC_APB1ENR +#define RCC_WWDG_APBENR RCC_APB1ENR +#define RCC_SPI2_APBENR RCC_APB1ENR +#define RCC_SPI3_APBENR RCC_APB1ENR +#define RCC_USART2_APBENR RCC_APB1ENR +#define RCC_USART3_APBENR RCC_APB1ENR +#define RCC_UART4_APBENR RCC_APB1ENR +#define RCC_UART5_APBENR RCC_APB1ENR +#define RCC_I2C1_APBENR RCC_APB1ENR +#define RCC_I2C2_APBENR RCC_APB1ENR +#define RCC_I2C3_APBENR RCC_APB1ENR +#define RCC_CAN1_APBENR RCC_APB1ENR +#define RCC_CAN2_APBENR RCC_APB1ENR +#define RCC_PWR_APBENR RCC_APB1ENR +#define RCC_DAC_APBENR RCC_APB1ENR + +/* APB2 RCC ENR */ +#define RCC_TIM1_APBENR RCC_APB2ENR +#define RCC_TIM8_APBENR RCC_APB2ENR +#define RCC_USART1_APBENR RCC_APB2ENR +#define RCC_USART6_APBENR RCC_APB2ENR +#define RCC_ADC1_APBENR RCC_APB2ENR +#define RCC_ADC2_APBENR RCC_APB2ENR +#define RCC_ADC3_APBENR RCC_APB2ENR +#define RCC_SDIO_APBENR RCC_APB2ENR +#define RCC_SPI1_APBENR RCC_APB2ENR +#define RCC_SYSCFG_APBENR RCC_APB2ENR +#define RCC_TIM9_APBENR RCC_APB2ENR +#define RCC_TIM10_APBENR RCC_APB2ENR +#define RCC_TIM11_APBENR RCC_APB2ENR + +/* Flash Registers (FLASH) */ +#define FLASH_ACR \ + (volatile uint32_t *) (FLASH_R_BASE + \ + 0x00) /* Flash Access Control Register */ + +/* Direct Memory Access 1 (DMA) */ +#define DMA1_LISR \ + (volatile uint32_t *) (DMA1_BASE + \ + 0x00) /* DMA1 low interrupt status register */ +#define DMA1_HISR \ + (volatile uint32_t *) (DMA1_BASE + \ + 0x04) /* DMA1 high interrupt status register */ +#define DMA1_LIFCR \ + (volatile uint32_t *) (DMA1_BASE + \ + 0x08) /* DMA1 low interrupt flag clear register */ +#define DMA1_HIFCR \ + (volatile uint32_t *) (DMA1_BASE + \ + 0x0C) /* DMA1 high interrupt flag clear register */ +/* Stream n */ +#define DMA1_CR_S(n) \ + (volatile uint32_t *) (DMA1_BASE + 0x10 + \ + (0x18 * \ + n)) /* DMA1 stream n configuration register */ +#define DMA1_NDTR_S(n) \ + (volatile uint32_t *) (DMA1_BASE + 0x14 + \ + (0x18 * \ + n)) /* DMA1 stream n number of data register */ +#define DMA1_PAR_S(n) \ + (volatile uint32_t \ + *) (DMA1_BASE + 0x18 + \ + (0x18 * n)) /* DMA1 stream n peripheral address register */ +#define DMA1_M0AR_S(n) \ + (volatile uint32_t *) (DMA1_BASE + 0x1C + \ + (0x18 * \ + n)) /* DMA1 stream n memory 0 address register */ +#define DMA1_M1AR_S(n) \ + (volatile uint32_t *) (DMA1_BASE + 0x20 + \ + (0x18 * \ + n)) /* DMA1 stream n memory 1 address register */ +#define DMA1_FCR_S(n) \ + (volatile uint32_t *) (DMA1_BASE + 0x24 + \ + (0x18 * \ + n)) /* DMA1 stream n FIFO control register */ + +/* Direct Memory Access 2 (DMA) */ +#define DMA2_LISR \ + (volatile uint32_t *) (DMA2_BASE + \ + 0x00) /* DMA2 low interrupt status register */ +#define DMA2_HISR \ + (volatile uint32_t *) (DMA2_BASE + \ + 0x04) /* DMA2 high interrupt status register */ +#define DMA2_LIFCR \ + (volatile uint32_t *) (DMA2_BASE + \ + 0x08) /* DMA2 low interrupt flag clear register */ +#define DMA2_HIFCR \ + (volatile uint32_t *) (DMA2_BASE + \ + 0x0C) /* DMA2 high interrupt flag clear register */ +/* Stream n */ +#define DMA2_CR_S(n) \ + (volatile uint32_t *) (DMA2_BASE + 0x10 + \ + (0x18 * \ + n)) /* DMA2 stream n configuration register */ +#define DMA2_NDTR_S(n) \ + (volatile uint32_t *) (DMA2_BASE + 0x14 + \ + (0x18 * \ + n)) /* DMA2 stream n number of data register */ +#define DMA2_PAR_S(n) \ + (volatile uint32_t \ + *) (DMA2_BASE + 0x18 + \ + (0x18 * n)) /* DMA2 stream n peripheral address register */ +#define DMA2_M0AR_S(n) \ + (volatile uint32_t *) (DMA2_BASE + 0x1C + \ + (0x18 * \ + n)) /* DMA2 stream n memory 0 address register */ +#define DMA2_M1AR_S(n) \ + (volatile uint32_t *) (DMA2_BASE + 0x20 + \ + (0x18 * \ + n)) /* DMA2 stream n memory 1 address register */ +#define DMA2_FCR_S(n) \ + (volatile uint32_t *) (DMA2_BASE + 0x24 + \ + (0x18 * \ + n)) /* DMA2 stream n FIFO control register */ + +/* USB OTG Full-Speed */ +/* Global Control and Status Registers */ +#define USB_FS_GOTGCTL \ + (volatile uint32_t *) (USB_FS_BASE + \ + 0x0000) /* USB control and status register */ +#define USB_FS_GOTGINT \ + (volatile uint32_t *) (USB_FS_BASE + 0x0004) /* USB interrupt register */ +#define USB_FS_GAHBCFG \ + (volatile uint32_t *) (USB_FS_BASE + \ + 0x0008) /* USB AHB configuration register */ +#define USB_FS_GUSBCFG \ + (volatile uint32_t *) (USB_FS_BASE + \ + 0x000C) /* USB USB configuration register */ +#define USB_FS_GRSTCTL \ + (volatile uint32_t *) (USB_FS_BASE + \ + 0x0010) /* USB reset control register */ +#define USB_FS_GINTSTS \ + (volatile uint32_t *) (USB_FS_BASE + \ + 0x0014) /* USB core interrupt register */ +#define USB_FS_GINTMSK \ + (volatile uint32_t *) (USB_FS_BASE + \ + 0x0018) /* USB interrupt mask register */ +#define USB_FS_GRXSTSR \ + (volatile uint32_t *) (USB_FS_BASE + 0x001C) /* USB receive status debug \ + read register */ +#define USB_FS_GRXSTSP \ + (volatile uint32_t *) (USB_FS_BASE + 0x0020) /* USB receive status debug \ + read and pop register */ +#define USB_FS_GRXFSIZ \ + (volatile uint32_t *) (USB_FS_BASE + \ + 0x0024) /* USB receive FIFO size register */ +#define USB_FS_DIEPTXF0 \ + (volatile uint32_t *) (USB_FS_BASE + 0x0028) /* USB endpoint 0 transmit \ + FIFO size register */ +#define USB_FS_HNPTXFSIZ \ + (volatile uint32_t \ + *) (USB_FS_BASE + \ + 0x0028) /* USB host non-periodic transmit FIFO size register */ +#define USB_FS_HNPTXSTS \ + (volatile uint32_t *) (USB_FS_BASE + \ + 0x002C) /* USB host non-periodic transmit \ + FIFO/queue status register */ +#define USB_FS_GCCFG \ + (volatile uint32_t *) (USB_FS_BASE + 0x0038) /* USB general core \ + configuration register */ +#define USB_FS_CID \ + (volatile uint32_t *) (USB_FS_BASE + 0x003C) /* USB core ID register */ +#define USB_FS_HPTXFSIZ \ + (volatile uint32_t *) (USB_FS_BASE + 0x0100) /* USB host periodic transmit \ + FIFO size register */ +#define USB_FS_DIEPTXF1 \ + (volatile uint32_t *) (USB_FS_BASE + \ + 0x0104) /* USB device IN endpoint transmit FIFO \ + size register 1 */ +#define USB_FS_DIEPTXF2 \ + (volatile uint32_t *) (USB_FS_BASE + \ + 0x0108) /* USB device IN endpoint transmit FIFO \ + size register 2 */ +#define USB_FS_DIEPTXF3 \ + (volatile uint32_t *) (USB_FS_BASE + \ + 0x010C) /* USB device IN endpoint transmit FIFO \ + size register 3 */ + +/* Host-mode Registers */ +/* ... */ + +/* Device-mode Registers */ +#define USB_FS_DCFG \ + (volatile uint32_t *) (USB_FS_BASE + \ + 0x0800) /* USB device configuration register */ +#define USB_FS_DCTL \ + (volatile uint32_t *) (USB_FS_BASE + \ + 0x0804) /* USB device control register */ +#define USB_FS_DSTS \ + (volatile uint32_t *) (USB_FS_BASE + \ + 0x0808) /* USB device status register */ +#define USB_FS_DSTS \ + (volatile uint32_t *) (USB_FS_BASE + \ + 0x0808) /* USB device status register */ +#define USB_FS_DIEPMSK \ + (volatile uint32_t *) (USB_FS_BASE + \ + 0x0810) /* USB device IN endpoint common interrupt \ + mask register */ +#define USB_FS_DOEPMSK \ + (volatile uint32_t *) (USB_FS_BASE + \ + 0x0814) /* USB device OUT endpoint common interrupt \ + mask register */ +#define USB_FS_DAINT \ + (volatile uint32_t *) (USB_FS_BASE + 0x0818) /* USB device all endpoints \ + interrupt register */ +#define USB_FS_DAINTMSK \ + (volatile uint32_t *) (USB_FS_BASE + 0x081C) /* USB device all endpoints \ + interrupt mask register */ +#define USB_FS_DVBUSDIS \ + (volatile uint32_t *) (USB_FS_BASE + 0x0828) /* USB device VBUS discharge \ + time register */ +#define USB_FS_DVBUSPULSE \ + (volatile uint32_t *) (USB_FS_BASE + \ + 0x082C) /* USB device VBUS pulse time register */ +#define USB_FS_DIEPEMPMSK \ + (volatile uint32_t *) (USB_FS_BASE + \ + 0x0834) /* USB device IN endpoint FIFO empty \ + interrupt mask register */ +#define USB_FS_DIEPCTL0 \ + (volatile uint32_t *) (USB_FS_BASE + 0x0900) /* USB device IN endpoint 0 \ + control register */ +#define USB_FS_DIEPCTL(n) \ + (volatile uint32_t \ + *) (USB_FS_BASE + 0x0900 + \ + n * 0x20) /* USB device endpoint n control register */ +#define USB_FS_DIEPINT(n) \ + (volatile uint32_t \ + *) (USB_FS_BASE + 0x0908 + \ + n * 0x20) /* USB device endpoint n interrupt register */ +#define USB_FS_DIEPTSIZ0 \ + (volatile uint32_t *) (USB_FS_BASE + 0x0910) /* USB device IN endpoint 0 \ + transfer size register */ +#define USB_FS_DIEPTSIZ(n) \ + (volatile uint32_t \ + *) (USB_FS_BASE + 0x0910 + \ + n * 0x20) /* USB device OUT endpoint n transfer size register */ +#define USB_FS_DTXFSTS(n) \ + (volatile uint32_t \ + *) (USB_FS_BASE + 0x0918 + \ + n * 0x20) /* USB device IN endpoint n FIFO status register */ +#define USB_FS_DOEPCTL0 \ + (volatile uint32_t *) (USB_FS_BASE + 0x0B00) /* USB device OUT endpoint 0 \ + control register */ +#define USB_FS_DOEPCTL(n) \ + (volatile uint32_t \ + *) (USB_FS_BASE + 0x0B00 + \ + n * 0x20) /* USB device endpoint n control register */ +#define USB_FS_DOEPINT(n) \ + (volatile uint32_t \ + *) (USB_FS_BASE + 0x0B08 + \ + n * 0x20) /* USB device endpoint 1 interrupt register */ +#define USB_FS_DOEPTSIZ0 \ + (volatile uint32_t *) (USB_FS_BASE + 0x0B10) /* USB device OUT endpoint 0 \ + transfer size register */ +#define USB_FS_DOEPTSIZ(n) \ + (volatile uint32_t \ + *) (USB_FS_BASE + 0x0B10 + \ + n * 0x20) /* USB device OUT endpoint n transfer size register */ + +/* Data FIFO Registers */ +#define USB_FS_DFIFO_EP(n) \ + (volatile uint32_t \ + *) (USB_FS_BASE + 0x1000 + \ + n * 0x1000) /* USB endpoint n data FIFO base address */ + +/* Power and Clock Gating Registers */ +#define USB_FS_PCGCR \ + (volatile uint32_t *) (USB_FS_BASE + 0x0E00) /* USB power and clock gating \ + control register */ + + +/**********************************************************************************************************************************************/ + +/* Bit Masks - See RM0090 Reference Manual for STM32F4 for details */ +#define PWR_CR_VOS \ + (uint16_t) (1 << 9) /* Regulator voltage scaling output selection - L4: \ + VOS[1:0] bits 10:9, use 01b for Range 1 (80MHz) */ + +#define MSI_VALUE (uint32_t) (4000000) /* MSI default value in Hz (Range 6) */ +#define HSI_VALUE (uint32_t) (16000000) /* HSI value in Hz */ +#define HSE_VALUE (uint32_t) (1 << 27) /* HSE value in Hz */ + +#define RCC_CR_HSION (uint32_t) (1 << 0) /* HSI clock enable */ +#define RCC_CR_HSIRDY (uint32_t) (1 << 1) /* HSI ready */ +#define RCC_CR_HSITRIM_M (uint32_t) (0x1F << 3) /* HSI trimming mask */ +#define RCC_CR_HSITRIM(n) (uint32_t) (n << 3) /* HSI trimming */ +#define RCC_CR_HSICAL_M (uint32_t) (0xFF << 8) /* HSI calibration mask */ +#define RCC_CR_HSEON (uint32_t) (1 << 16) /* HSE clock enable */ +#define RCC_CR_HSERDY (uint32_t) (1 << 17) /* HSE ready */ +#define RCC_CR_HSEBYP (uint32_t) (1 << 18) /* HSE bypass */ +#define RCC_CR_CSSON (uint32_t) (1 << 19) /* Clock security system enable */ +#define RCC_CR_PLLON (uint32_t) (1 << 24) /* Main PLL enable */ +#define RCC_CR_PLLRDY (uint32_t) (1 << 25) /* Main PLL clock ready */ +#define RCC_CR_PLLI2SON (uint32_t) (1 << 26) /* PLLI2S enable */ +#define RCC_CR_PLLI2SRDY (uint32_t) (1 << 27) /* PLLI2S clock ready */ + +#define RCC_PLLCFGR_RESET \ + (uint32_t) (0x24003010) /* PLLCFGR register reset value */ +/* STM32L4 PLLSRC is bits [1:0]: 01=MSI, 10=HSI16, 11=HSE */ +#define RCC_PLLCFGR_PLLSRC_MSI (uint32_t) (1) /* MSI selected as PLL input */ +#define RCC_PLLCFGR_PLLSRC_HSI \ + (uint32_t) (2) /* HSI16 selected as PLL input \ + */ +#define RCC_PLLCFGR_PLLSRC_HSE (uint32_t) (3) /* HSE selected as PLL input */ +#define RCC_PLLCFGR_PLLM (uint32_t) (0x003F) +#define RCC_PLLCFGR_PLLN (uint32_t) (0x7FC0) +#define RCC_PLLCFGR_PLLP (uint32_t) (0x00030000) +#define RCC_PLLCFGR_PLLR (uint32_t) (0x06000000) /* L4: PLLR bits [26:25] */ + +#define RCC_CFGR_SW_M (uint32_t) (3 << 0) /* System clock switch mask */ +#define RCC_CFGR_SW_HSI \ + (uint32_t) (0 << 0) /* System clock switch - HSI selected as system clock \ + */ +#define RCC_CFGR_SW_HSE \ + (uint32_t) (1 << 0) /* System clock switch - HSE selected as system clock \ + */ +#define RCC_CFGR_SW_PLL \ + (uint32_t) (2 << 0) /* System clock switch - PLL selected as system clock \ + */ +#define RCC_CFGR_SWS_M \ + (uint32_t) (3 << 2) /* System clock switch status mask \ + */ +#define RCC_CFGR_SWS_HSI \ + (uint32_t) (0 << 2) /* System clock switch status - HSI used as system \ + clock */ +#define RCC_CFGR_SWS_HSE \ + (uint32_t) (1 << 2) /* System clock switch status - HSE used as system \ + clock */ +#define RCC_CFGR_SWS_PLL \ + (uint32_t) (2 << 2) /* System clock switch status - PLL used as system \ + clock */ +#define RCC_CFGR_HPRE_M (uint32_t) (0xF << 4) /* AHB prescaler mask */ +#define RCC_CFGR_HPRE_DIV1 \ + (uint32_t) (0x0 << 4) /* AHB prescaler - SYSCLK not divided */ +#define RCC_CFGR_HPRE_DIV2 \ + (uint32_t) (0x8 << 4) /* AHB prescaler - SYSCLK/2 \ + */ +#define RCC_CFGR_HPRE_DIV4 \ + (uint32_t) (0x9 << 4) /* AHB prescaler - SYSCLK/4 \ + */ +#define RCC_CFGR_HPRE_DIV8 \ + (uint32_t) (0xA << 4) /* AHB prescaler - SYSCLK/8 \ + */ +#define RCC_CFGR_HPRE_DIV16 \ + (uint32_t) (0xB << 4) /* AHB prescaler - SYSCLK/16 */ +#define RCC_CFGR_HPRE_DIV64 \ + (uint32_t) (0xC << 4) /* AHB prescaler - SYSCLK/64 */ +#define RCC_CFGR_HPRE_DIV128 \ + (uint32_t) (0xD << 4) /* AHB prescaler - SYSCLK/128 */ +#define RCC_CFGR_HPRE_DIV256 \ + (uint32_t) (0xE << 4) /* AHB prescaler - SYSCLK/256 */ +#define RCC_CFGR_HPRE_DIV512 \ + (uint32_t) (0xF << 4) /* AHB prescaler - SYSCLK/512 */ +#define RCC_CFGR_PPRE1_M \ + (uint32_t) (7 << 10) /* APB low speed prescaler mask \ + */ +#define RCC_CFGR_PPRE1_DIV1 \ + (uint32_t) (0 << 10) /* APB low speed prescaler - HCLK/1 */ +#define RCC_CFGR_PPRE1_DIV2 \ + (uint32_t) (4 << 10) /* APB low speed prescaler - HCLK/2 */ +#define RCC_CFGR_PPRE1_DIV4 \ + (uint32_t) (5 << 10) /* APB low speed prescaler - HCLK/4 */ +#define RCC_CFGR_PPRE1_DIV8 \ + (uint32_t) (6 << 10) /* APB low speed prescaler - HCLK/8 */ +#define RCC_CFGR_PPRE1_DIV16 \ + (uint32_t) (7 << 10) /* APB low speed prescaler - HCLK/16 */ +#define RCC_CFGR_PPRE2_M \ + (uint32_t) (7 << 13) /* APB high speec prescaler mask */ +#define RCC_CFGR_PPRE2_DIV1 \ + (uint32_t) (0 << 13) /* APB high speed prescaler - HCLK/1 */ +#define RCC_CFGR_PPRE2_DIV2 \ + (uint32_t) (4 << 13) /* APB high speed prescaler - HCLK/2 */ +#define RCC_CFGR_PPRE2_DIV4 \ + (uint32_t) (5 << 13) /* APB high speed prescaler - HCLK/4 */ +#define RCC_CFGR_PPRE2_DIV8 \ + (uint32_t) (6 << 13) /* APB high speed prescaler - HCLK/8 */ +#define RCC_CFGR_PPRE2_DIV16 \ + (uint32_t) (7 << 13) /* APB high speed prescaler - HCLK/16 */ +#define RCC_CFGR_RTCPRE_M \ + (uint32_t) (0x1F << 16) /* HSE division factor for RTC clock mask */ +#define RCC_CFGR_RTCPRE(n) \ + (uint32_t) (n << 16) /* HSE division factor for RTC clock */ + +#define RCC_AHB1RSTR_GPIOARST (uint32_t) (1 << 0) /* GPIOA reset */ +#define RCC_AHB1RSTR_GPIOBRST (uint32_t) (1 << 1) /* GPIOB reset */ +#define RCC_AHB1RSTR_GPIOCRST (uint32_t) (1 << 2) /* GPIOC reset */ +#define RCC_AHB1RSTR_GPIODRST (uint32_t) (1 << 3) /* GPIOD reset */ +#define RCC_AHB1RSTR_GPIOERST (uint32_t) (1 << 4) /* GPIOE reset */ +#define RCC_AHB1RSTR_GPIOFRST (uint32_t) (1 << 5) /* GPIOF reset */ +#define RCC_AHB1RSTR_GPIOGRST (uint32_t) (1 << 6) /* GPIOG reset */ +#define RCC_AHB1RSTR_GPIOHRST (uint32_t) (1 << 7) /* GPIOH reset */ +#define RCC_AHB1RSTR_GPIOIRST (uint32_t) (1 << 8) /* GPIOI reset */ +#define RCC_AHB1RSTR_CRCRST (uint32_t) (1 << 12) /* CRC reset */ +#define RCC_AHB1RSTR_DMA1RST (uint32_t) (1 << 21) /* DMA1 reset */ +#define RCC_AHB1RSTR_DMA2RST (uint32_t) (1 << 22) /* DMA2 reset */ +#define RCC_AHB1RSTR_ETHMACRST (uint32_t) (1 << 25) /* Ethernet MAC reset */ +#define RCC_AHB1RSTR_OTGHSRST (uint32_t) (1 << 29) /* USB OTG HS reset */ + +#define RCC_AHB2RSTR_DCMIRST (uint32_t) (1 << 0) /* Camera interface reset */ +#define RCC_AHB2RSTR_CRYPRST (uint32_t) (1 << 4) /* Cyrpto modules reset */ +#define RCC_AHB2RSTR_HASHRST (uint32_t) (1 << 5) /* Hash modules reset */ +#define RCC_AHB2RSTR_RNGRST \ + (uint32_t) (1 << 6) /* Random number generator reset */ +#define RCC_AHB2RSTR_OTGFSRST (uint32_t) (1 << 7) /* USB OTG FS reset */ + +#define RCC_AHB3RSTR_FSMCRST \ + (uint32_t) (1 << 0) /* Flexible static memeory controller reset */ + +#define RCC_APB1RSTR_TIM2RST (uint32_t) (1 << 0) /* TIM2 reset */ +#define RCC_APB1RSTR_TIM3RST (uint32_t) (1 << 1) /* TIM3 reset */ +#define RCC_APB1RSTR_TIM4RST (uint32_t) (1 << 2) /* TIM4 reset */ +#define RCC_APB1RSTR_TIM5RST (uint32_t) (1 << 3) /* TIM5 reset */ +#define RCC_APB1RSTR_TIM6RST (uint32_t) (1 << 4) /* TIM6 reset */ +#define RCC_APB1RSTR_TIM7RST (uint32_t) (1 << 5) /* TIM7 reset */ +#define RCC_APB1RSTR_TIM12RST (uint32_t) (1 << 6) /* TIM12 reset */ +#define RCC_APB1RSTR_TIM13RST (uint32_t) (1 << 7) /* TIM13 reset */ +#define RCC_APB1RSTR_TIM14RST (uint32_t) (1 << 8) /* TIM14 reset */ +#define RCC_APB1RSTR_WWDGRST (uint32_t) (1 << 11) /* Window watchdog reset */ +#define RCC_APB1RSTR_SPI2RST (uint32_t) (1 << 14) /* SPI2 reset */ +#define RCC_APB1RSTR_SPI3RST (uint32_t) (1 << 15) /* SPI3 reset */ +#define RCC_APB1RSTR_USART2RST (uint32_t) (1 << 17) /* USART2 reset */ +#define RCC_APB1RSTR_USART3RST (uint32_t) (1 << 18) /* USART3 reset */ +#define RCC_APB1RSTR_USART4RST (uint32_t) (1 << 19) /* USART4 reset */ +#define RCC_APB1RSTR_USART5RST (uint32_t) (1 << 20) /* USART5 reset */ +#define RCC_APB1RSTR_I2C1RST (uint32_t) (1 << 21) /* I2C1 reset */ +#define RCC_APB1RSTR_I2C2RST (uint32_t) (1 << 22) /* I2C2 reset */ +#define RCC_APB1RSTR_I2C3RST (uint32_t) (1 << 23) /* I2C3 reset */ +#define RCC_APB1RSTR_CAN1RST (uint32_t) (1 << 25) /* CAN1 reset */ +#define RCC_APB1RSTR_CAN2RST (uint32_t) (1 << 26) /* CAN2 reset */ +#define RCC_APB1RSTR_PWRRST (uint32_t) (1 << 28) /* Power interface reset */ +#define RCC_APB1RSTR_DACRST (uint32_t) (1 << 29) /* DAC reset */ + +#define RCC_APB2RSTR_TIM1RST (uint32_t) (1 << 0) /* TIM1 reset */ +#define RCC_APB2RSTR_TIM8RST (uint32_t) (1 << 1) /* TIM8 reset */ +#define RCC_APB2RSTR_USART1RST (uint32_t) (1 << 14) /* USART1 reset */ +#define RCC_APB2RSTR_USART6RST (uint32_t) (1 << 5) /* USART6 reset */ +#define RCC_APB2RSTR_ADCRST (uint32_t) (1 << 8) /* ADC1 reset */ +#define RCC_APB2RSTR_SDIORST (uint32_t) (1 << 11) /* SDIO reset */ +#define RCC_APB2RSTR_SPI1RST (uint32_t) (1 << 12) /* SPI1 reset */ +#define RCC_APB2RSTR_SYSCFGRST \ + (uint32_t) (1 << 14) /* System configuration controller reset */ +#define RCC_APB2RSTR_TIM9RST (uint32_t) (1 << 16) /* TIM9 reset */ +#define RCC_APB2RSTR_TIM10RST (uint32_t) (1 << 17) /* TIM10 reset */ +#define RCC_APB2RSTR_TIM11RST (uint32_t) (1 << 18) /* TIM11 reset */ + +#define RCC_AHB1ENR_GPIOAEN (uint32_t) (1 << 0) /* GPIOA clock enable */ +#define RCC_AHB1ENR_GPIOBEN (uint32_t) (1 << 1) /* GPIOB clock enable */ +#define RCC_AHB1ENR_GPIOCEN (uint32_t) (1 << 2) /* GPIOC clock enable */ +#define RCC_AHB1ENR_GPIODEN (uint32_t) (1 << 3) /* GPIOD clock enable */ +#define RCC_AHB1ENR_GPIOEEN (uint32_t) (1 << 4) /* GPIOE clock enable */ +#define RCC_AHB1ENR_GPIOFEN (uint32_t) (1 << 5) /* GPIOF clock enable */ +#define RCC_AHB1ENR_GPIOGEN (uint32_t) (1 << 6) /* GPIOG clock enable */ +#define RCC_AHB1ENR_GPIOHEN (uint32_t) (1 << 7) /* GPIOH clock enable */ +#define RCC_AHB1ENR_GPIOIEN (uint32_t) (1 << 8) /* GPIOI clock enable */ +#define RCC_AHB1ENR_CRCEN (uint32_t) (1 << 12) /* CRC clock enable */ +#define RCC_AHB1ENR_BKPSRAMEN \ + (uint32_t) (1 << 18) /* Backup SRAM clock enable */ +#define RCC_AHB1ENR_CCMDATARAMEN \ + (uint32_t) (1 << 20) /* CCM data RAM clock enable */ +#define RCC_AHB1ENR_DMA1EN (uint32_t) (1 << 21) /* DMA1 clock enable */ +#define RCC_AHB1ENR_DMA2EN (uint32_t) (1 << 22) /* DMA2 clock enable */ +#define RCC_AHB1ENR_ETHMACEN \ + (uint32_t) (1 << 25) /* Ethernet MAC clock enable */ +#define RCC_AHB1ENR_ETHMACTXEN \ + (uint32_t) (1 << 26) /* Ethernet MAC TX clock enable */ +#define RCC_AHB1ENR_ETHMACRXEN \ + (uint32_t) (1 << 27) /* Ethernet MAC RX clock enable */ +#define RCC_AHB1ENR_ETHMACPTPEN \ + (uint32_t) (1 << 28) /* Ethernet MAC PTP clock enable */ +#define RCC_AHB1ENR_OTGHSEN (uint32_t) (1 << 29) /* USB OTG HS clock enable */ +#define RCC_AHB1ENR_OTGHSULPIEN \ + (uint32_t) (1 << 30) /* USB OTG HSULPI clock enable */ + +#define RCC_AHB2ENR_DCMIEN \ + (uint32_t) (1 << 0) /* Camera interface clock enable */ +#define RCC_AHB2ENR_CRYPEN \ + (uint32_t) (1 << 4) /* Cyrpto modules clock enable \ + */ +#define RCC_AHB2ENR_HASHEN (uint32_t) (1 << 5) /* Hash modules clock enable */ +#define RCC_AHB2ENR_RNGEN \ + (uint32_t) (1 << 6) /* Random number generator clock enable */ +#define RCC_AHB2ENR_OTGFSEN (uint32_t) (1 << 7) /* USB OTG FS clock enable */ + +#define RCC_AHB3ENR_FSMCEN \ + (uint32_t) (1 << 0) /* Flexible static memeory controller clock enable */ + +#define RCC_APB1ENR_TIM2EN (uint32_t) (1 << 0) /* TIM2 clock enable */ +#define RCC_APB1ENR_TIM3EN (uint32_t) (1 << 1) /* TIM3 clock enable */ +#define RCC_APB1ENR_TIM4EN (uint32_t) (1 << 2) /* TIM4 clock enable */ +#define RCC_APB1ENR_TIM5EN (uint32_t) (1 << 3) /* TIM5 clock enable */ +#define RCC_APB1ENR_TIM6EN (uint32_t) (1 << 4) /* TIM6 clock enable */ +#define RCC_APB1ENR_TIM7EN (uint32_t) (1 << 5) /* TIM7 clock enable */ +#define RCC_APB1ENR_TIM12EN (uint32_t) (1 << 6) /* TIM12 clock enable */ +#define RCC_APB1ENR_TIM13EN (uint32_t) (1 << 7) /* TIM13 clock enable */ +#define RCC_APB1ENR_TIM14EN (uint32_t) (1 << 8) /* TIM14 clock enable */ +#define RCC_APB1ENR_WWDGEN \ + (uint32_t) (1 << 11) /* Window watchdog clock enable */ +#define RCC_APB1ENR_SPI2EN (uint32_t) (1 << 14) /* SPI2 clock enable */ +#define RCC_APB1ENR_SPI3EN (uint32_t) (1 << 15) /* SPI3 clock enable */ +#define RCC_APB1ENR_USART2EN (uint32_t) (1 << 17) /* USART2 clock enable */ +#define RCC_APB1ENR_USART3EN (uint32_t) (1 << 18) /* USART3 clock enable */ +#define RCC_APB1ENR_USART4EN (uint32_t) (1 << 19) /* USART4 clock enable */ +#define RCC_APB1ENR_USART5EN (uint32_t) (1 << 20) /* USART5 clock enable */ +#define RCC_APB1ENR_I2C1EN (uint32_t) (1 << 21) /* I2C1 clock enable */ +#define RCC_APB1ENR_I2C2EN (uint32_t) (1 << 22) /* I2C2 clock enable */ +#define RCC_APB1ENR_I2C3EN (uint32_t) (1 << 23) /* I2C3 clock enable */ +#define RCC_APB1ENR_CAN1EN (uint32_t) (1 << 25) /* CAN1 clock enable */ +#define RCC_APB1ENR_CAN2EN (uint32_t) (1 << 26) /* CAN2 clock enable */ +#define RCC_APB1ENR_PWREN \ + (uint32_t) (1 << 28) /* Power interface clock enable */ +#define RCC_APB1ENR_DACEN (uint32_t) (1 << 29) /* DAC clock enable */ + +#define RCC_APB2ENR_TIM1EN (uint32_t) (1 << 0) /* TIM1 clock enable */ +#define RCC_APB2ENR_TIM8EN (uint32_t) (1 << 1) /* TIM8 clock enable */ +#define RCC_APB2ENR_USART1EN (uint32_t) (1 << 14) /* USART1 clock enable */ +#define RCC_APB2ENR_USART2EN (uint32_t) (1 << 5) /* USART2 clock enable */ +#define RCC_APB2ENR_ADC1EN (uint32_t) (1 << 8) /* ADC1 clock enable */ +#define RCC_APB2ENR_ADC2EN (uint32_t) (1 << 9) /* ADC2 clock enable */ +#define RCC_APB2ENR_ADC3EN (uint32_t) (1 << 10) /* ADC3 clock enable */ +#define RCC_APB2ENR_SDIOEN (uint32_t) (1 << 11) /* SDIO clock enable */ +#define RCC_APB2ENR_SPI1EN (uint32_t) (1 << 12) /* SPI1 clock enable */ +#define RCC_APB2ENR_SYSCFGEN \ + (uint32_t) (1 << 14) /* System configuration controller clock enable */ +#define RCC_APB2ENR_TIM9EN (uint32_t) (1 << 16) /* TIM9 clock enable */ +#define RCC_APB2ENR_TIM10EN (uint32_t) (1 << 17) /* TIM10 clock enable */ +#define RCC_APB2ENR_TIM11EN (uint32_t) (1 << 18) /* TIM11 clock enable */ + +#define FLASH_ACR_PRFTEN (uint32_t) (1 << 8) /* Prefetch enable */ +#define FLASH_ACR_ICEN (uint32_t) (1 << 9) /* Instruction cache enable */ +#define FLASH_ACR_DCEN (uint32_t) (1 << 10) /* Data cache enable */ +#define FLASH_ACR_ICRST (uint32_t) (1 << 11) /* Instruction cache reset */ +#define FLASH_ACR_CCRST (uint32_t) (1 << 12) /* Data cache reset */ +#define FLASH_ACR_LATENCY_M (uint32_t) (7 << 0) /* Latency mask */ +#define FLASH_ACR_LATENCY(n) (uint32_t) (n << 0) /* Latency - n wait states */ + +/* TIMx */ +#define TIMx_CR1_CEN (uint32_t) (1 << 0) /* TIMx counter enable */ +#define TIMx_CR1_UDIS (uint32_t) (1 << 1) /* TIMx update disable */ +#define TIMx_CR1_URS (uint32_t) (1 << 2) /* TIMx update request source */ +#define TIMx_CR1_OPM (uint32_t) (1 << 3) /* TIMx one-pulse mode */ +#define TIMx_CR1_DIR_DOWN (uint32_t) (1 << 4) /* TIMx downcounter */ +#define TIMx_CR1_CMS_EDGE \ + (uint32_t) (0 << 5) /* TIMx center-aligned mode selection - counter up or \ + down depending on DIR bit */ +#define TIMx_CR1_CMS_CM1 \ + (uint32_t) (1 << 5) /* TIMx center-aligned mode selection - up and down, \ + compare flags set down */ +#define TIMx_CR1_CMS_CM2 \ + (uint32_t) (2 << 5) /* TIMx center-aligned mode selection - up and down, \ + compare flags set up */ +#define TIMx_CR1_CMS_CM3 \ + (uint32_t) (3 << 5) /* TIMx center-aligned mode selection - up and down, \ + compare flags set up/down */ +#define TIMx_CR1_ARPE \ + (uint32_t) (1 << 7) /* TIMx auto-reload preload enable \ + */ +#define TIMx_CR1_CKD_1 (uint32_t) (0 << 8) /* TIMx clock division 1 */ +#define TIMx_CR1_CKD_2 (uint32_t) (1 << 8) /* TIMx clock division 2 */ +#define TIMx_CR1_CKD_4 (uint32_t) (2 << 8) /* TIMx clock division 4 */ + +#define TIMx_CR2_CCDS \ + (uint32_t) (1 << 3) /* TIMx capture/compare DMA requests send when update \ + event occurs */ +#define TIMx_CR2_MMS_RST (uint32_t) (0 << 4) /* TIMx master mode - reset */ +#define TIMx_CR2_MMS_EN (uint32_t) (1 << 4) /* TIMx master mode - enable */ +#define TIMx_CR2_MMS_UP (uint32_t) (2 << 4) /* TIMx master mode - update */ +#define TIMx_CR2_MMS_CMP_PUL \ + (uint32_t) (3 << 4) /* TIMx master mode - compare pulse */ +#define TIMx_CR2_MMS_CMP_OC1 \ + (uint32_t) (4 << 4) /* TIMx master mode - compare OC1 */ +#define TIMx_CR2_MMS_CMP_OC2 \ + (uint32_t) (5 << 4) /* TIMx master mode - compare OC2 */ +#define TIMx_CR2_MMS_CMP_OC3 \ + (uint32_t) (6 << 4) /* TIMx master mode - compare OC3 */ +#define TIMx_CR2_MMS_CMP_OC4 \ + (uint32_t) (7 << 4) /* TIMx master mode - compare OC4 */ +#define TIMx_CR2_TI1_123 \ + (uint32_t) (1 << 7) /* TIMx CH1, CH2, CH3 pins connected to TI1 */ + +#define TIMx_DIER_UIE (uint32_t) (1 << 0) /* TIMx update interrupt enable */ +#define TIMx_DIER_CC1IE (uint32_t) (1 << 1) /* TIMx CC1 interrupt enable */ +#define TIMx_DIER_CC2IE (uint32_t) (1 << 2) /* TIMx CC2 interrupt enable */ +#define TIMx_DIER_CC3IE (uint32_t) (1 << 3) /* TIMx CC3 interrupt enable */ +#define TIMx_DIER_CC4IE (uint32_t) (1 << 4) /* TIMx CC4 interrupt enable */ +#define TIMx_DIER_TIE (uint32_t) (1 << 6) /* TIMx trigger interrupt enable */ +#define TIMx_DIER_UDE (uint32_t) (1 << 8) /* TIMx update DMA request enable */ +#define TIMx_DIER_CC1DE (uint32_t) (1 << 9) /* TIMx CC1 DMA request enable */ +#define TIMx_DIER_CC2DE (uint32_t) (1 << 10) /* TIMx CC2 DMA request enable */ +#define TIMx_DIER_CC3DE (uint32_t) (1 << 11) /* TIMx CC3 DMA request enable */ +#define TIMx_DIER_CC4DE (uint32_t) (1 << 12) /* TIMx CC4 DMA request enable */ +#define TIMx_DIER_TDE \ + (uint32_t) (1 << 14) /* TIMx trigger DMA request enable \ + */ + +/* SPI */ +#define SPI_CR1_CPHA (uint32_t) (1 << 0) /* SPI clock phase */ +#define SPI_CR1_CPOL (uint32_t) (1 << 1) /* SPI clock polarity */ +#define SPI_CR1_MSTR (uint32_t) (1 << 2) /* SPI master selection */ +#define SPI_CR1_BR_2 (uint32_t) (0 << 3) /* SPI baud rate = fPCLK/2 */ +#define SPI_CR1_BR_4 (uint32_t) (1 << 3) /* SPI baud rate = fPCLK/4 */ +#define SPI_CR1_BR_8 (uint32_t) (2 << 3) /* SPI baud rate = fPCLK/8 */ +#define SPI_CR1_BR_16 (uint32_t) (3 << 3) /* SPI baud rate = fPCLK/16 */ +#define SPI_CR1_BR_32 (uint32_t) (4 << 3) /* SPI baud rate = fPCLK/32 */ +#define SPI_CR1_BR_64 (uint32_t) (5 << 3) /* SPI baud rate = fPCLK/64 */ +#define SPI_CR1_BR_128 (uint32_t) (6 << 3) /* SPI baud rate = fPCLK/128 */ +#define SPI_CR1_BR_256 (uint32_t) (7 << 3) /* SPI baud rate = fPCLK/256 */ +#define SPI_CR1_SPE (uint32_t) (1 << 6) /* SPI enable */ +#define SPI_CR1_LSBFIRST (uint32_t) (1 << 7) /* SPI LSB transmitted first */ +#define SPI_CR1_SSI (uint32_t) (1 << 8) /* SPI internal slave select */ +#define SPI_CR1_SSM (uint32_t) (1 << 9) /* SPI software slave management */ +#define SPI_CR1_DFF \ + (uint32_t) (1 << 11) /* SPI data frame format (0 = 8bit, 1 = 16bit) */ +#define SPI_SR_RXNE (uint32_t) (1 << 0) /* SPI receive not empty */ +#define SPI_SR_TXNE (uint32_t) (1 << 1) /* SPI transmit not empty */ +#define SPI_SR_CHSIDE (uint32_t) (1 << 2) /* SPI channel side */ +#define SPI_SR_UDR (uint32_t) (1 << 3) /* SPI underrun flag */ +#define SPI_SR_CRCERR (uint32_t) (1 << 4) /* SPI CRC error flag */ +#define SPI_SR_MODF (uint32_t) (1 << 5) /* SPI mode fault */ +#define SPI_SR_OVR (uint32_t) (1 << 6) /* SPI overrun flag */ +#define SPI_SR_BSY (uint32_t) (1 << 7) /* SPI busy flag */ +#define SPI_SR_TIRFE (uint32_t) (1 << 8) /* SPI TI frame format error */ + +/* I2C */ +#define I2C_CR1_PE (uint32_t) (1 << 0) /* I2C peripheral enable */ +#define I2C_CR1_SMBUS (uint32_t) (1 << 1) /* I2C SMBus mode */ +#define I2C_CR1_SMBTYPE \ + (uint32_t) (1 << 3) /* I2C SMBus type (0=Device, 1=Host) */ +#define I2C_CR1_ENARP (uint32_t) (1 << 4) /* I2C enable ARP */ +#define I2C_CR1_ENPEC (uint32_t) (1 << 5) /* I2C enable PEC */ +#define I2C_CR1_ENGC (uint32_t) (1 << 6) /* I2C enable general call */ +#define I2C_CR1_NOSTRETCH \ + (uint32_t) (1 << 7) /* I2C clock stretching disable \ + */ +#define I2C_CR1_START (uint32_t) (1 << 8) /* I2C START generation */ +#define I2C_CR1_STOP (uint32_t) (1 << 9) /* I2C STOP generation */ +#define I2C_CR1_ACK (uint32_t) (1 << 10) /* I2C ACK enable */ +#define I2C_CR1_POS (uint32_t) (1 << 11) /* I2C ACK/PEC position */ +#define I2C_CR1_PEC (uint32_t) (1 << 12) /* I2C packet error checking */ +#define I2C_CR1_ALERT (uint32_t) (1 << 13) /* I2C SMBus alert */ +#define I2C_CR1_SWRST (uint32_t) (1 << 15) /* I2C software reset */ + +#define I2C_CR2_FREQ(n) (uint32_t) (n << 0) /* I2C clock frequency */ +#define I2C_CR2_ITERREN (uint32_t) (1 << 8) /* I2C error interrupt enable */ +#define I2C_CR2_ITEVTEN (uint32_t) (1 << 9) /* I2C event interrupt enable */ +#define I2C_CR2_ITBUFEN (uint32_t) (1 << 10) /* I2C buffer interrupt enable */ +#define I2C_CR2_DMAEN (uint32_t) (1 << 11) /* I2C DMA requests enable */ +#define I2C_CR2_LAST (uint32_t) (1 << 12) /* I2C DMA last transfer */ + +#define I2C_OAR1_ADD10(n) \ + (uint32_t) (n << 0) /* I2C interface address (10-bit) */ +#define I2C_OAR1_ADD7(n) \ + (uint32_t) (n << 1) /* I2C interface address (7-bit) \ + */ +#define I2C_OAR1_ADDMODE \ + (uint32_t) (1 << 15) /* I2C interface address mode (1=10-bit) */ + +#define I2C_OAR2_ENDUAL (uint32_t) (1 << 0) /* I2C dual address mode enable */ +#define I2C_OAR2_ADD2(n) \ + (uint32_t) (n << 1) /* I2C interface address 2 (7-bit) */ + +#define I2C_SR1_SB (uint32_t) (1 << 0) /* I2C start bit generated */ +#define I2C_SR1_ADDR (uint32_t) (1 << 1) /* I2C address sent/matched */ +#define I2C_SR1_BTF (uint32_t) (1 << 2) /* I2C byte transfer finished */ +#define I2C_SR1_ADD10 (uint32_t) (1 << 3) /* I2C 10-bit header sent */ +#define I2C_SR1_STOPF (uint32_t) (1 << 4) /* I2C stop detection */ +#define I2C_SR1_RXNE (uint32_t) (1 << 6) /* I2C DR not empty */ +#define I2C_SR1_TXE (uint32_t) (1 << 7) /* I2C DR empty */ +#define I2C_SR1_BERR (uint32_t) (1 << 8) /* I2C bus error */ +#define I2C_SR1_ARLO (uint32_t) (1 << 9) /* I2C attribution lost */ +#define I2C_SR1_AF (uint32_t) (1 << 10) /* I2C acknowledge failure */ +#define I2C_SR1_OVR (uint32_t) (1 << 11) /* I2C overrun/underrun */ +#define I2C_SR1_PECERR (uint32_t) (1 << 12) /* I2C PEC error in reception */ +#define I2C_SR1_TIMEOUT (uint32_t) (1 << 14) /* I2C timeout or tlow error */ +#define I2C_SR1_SMBALERT (uint32_t) (1 << 15) /* I2C SMBus alert */ + +#define I2C_SR2_MSL (uint32_t) (1 << 0) /* I2C master/slave */ +#define I2C_SR2_BUSY (uint32_t) (1 << 1) /* I2C bus busy */ +#define I2C_SR2_TRA (uint32_t) (1 << 2) /* I2C transmitter/receiver */ +#define I2C_SR2_GENCALL (uint32_t) (1 << 4) /* I2C general call address */ +#define I2C_SR2_SMBDEFAULT \ + (uint32_t) (1 << 5) /* I2C SMBus device default address */ +#define I2C_SR2_SMBHOST (uint32_t) (1 << 6) /* I2C SMBus host header */ +#define I2C_SR2_DUALF (uint32_t) (1 << 7) /* I2C dual flag */ +#define I2C_SR2_PEC(r) \ + (uint32_t) (r >> 8) /* I2C packet error checking register */ + +#define I2C_CCR_CCR(n) \ + (uint32_t) (n & 0x0FFF) /* I2C clock control register \ + */ +#define I2C_CCR_DUTY (uint32_t) (1 << 14) /* I2C fast mode duty cycle */ +#define I2C_CCR_FS (uint32_t) (1 << 15) /* I2C master mode selection */ + +/* USART */ +#define USART_SR_TC (uint32_t) (1 << 6) /* USART Transmission Complete */ +#define USART_SR_RXNE \ + (uint32_t) (1 << 5) /* USART Read data register not empty */ + +/* USART_CR1 */ +#define USART_CR1_OVER8 (uint32_t) (1 << 15) /* Oversampling mode */ +#define USART_CR1_UE (uint32_t) (1 << 13) /* USART Enable */ +#define USART_CR1_M9 \ + (uint32_t) (1 << 12) /* World length 1: 9 bits, 0: 8bits \ + */ +#define USART_CR1_WAKE (uint32_t) (1 << 11) /* Wakeup method */ +#define USART_CR1_PCE (uint32_t) (1 << 10) /* PCE Parity control enable */ +#define USART_CR1_PS (uint32_t) (1 << 9) /* Parity selection */ +#define USART_CR1_PEIE (uint32_t) (1 << 8) /* PE Interrupt enable */ +#define USART_CR1_TXEIE (uint32_t) (1 << 7) /* TXE interrupt enable */ +#define USART_CR1_TCIE \ + (uint32_t) (1 << 6) /* Transmission complete interrupt enable */ +#define USART_CR1_RXNEIE (uint32_t) (1 << 5) /* RXNE Interrupt Enable */ +#define USART_CR1_IDLEIE (uint32_t) (1 << 4) /* IDEL INterrupt Enable */ +#define USART_CR1_TE (uint32_t) (1 << 3) /* USART Transmit Enable */ +#define USART_CR1_RE (uint32_t) (1 << 2) /* USART Receive Enable */ +#define USART_CR1_RWU (uint32_t) (1 << 1) +#define USART_CR1_SBK (uint32_t) (1 << 0) /* Send break characters */ + +#define USART_CR3_DMAR_EN (uint32_t) (1 << 6) /* USART DMA Receive Enable */ +#define USART_CR3_DMAT_EN (uint32_t) (1 << 7) /* USART DMA Transmit Enable */ + +/* GPIO */ +#define GPIOA (uint8_t) (0) /* GPIO Port A */ +#define GPIOB (uint8_t) (1) /* GPIO Port B */ +#define GPIOC (uint8_t) (2) /* GPIO Port C */ +#define GPIOD (uint8_t) (3) /* GPIO Port D */ +#define GPIOE (uint8_t) (4) /* GPIO Port E */ +#define GPIOF (uint8_t) (5) /* GPIO Port F */ +#define GPIOG (uint8_t) (6) /* GPIO Port G */ +#define GPIOH (uint8_t) (7) /* GPIO Port H */ +#define GPIOI (uint8_t) (8) /* GPIO Port I */ + +#define GPIO_MODER_PIN(n) (uint32_t) (2 * n) /* Pin bitshift */ +#define GPIO_MODER_M(n) (uint32_t) (0x3 << 2 * n) /* Pin mask */ +#define GPIO_MODER_IN (uint32_t) (0x0) /* Input mode */ +#define GPIO_MODER_OUT (uint32_t) (0x1) /* Output mode */ +#define GPIO_MODER_ALT (uint32_t) (0x2) /* Alternative function mode */ +#define GPIO_MODER_ANA (uint32_t) (0x3) /* Analog mode */ + +#define GPIO_OTYPER_PIN(n) (uint32_t) (n) /* Pin bitshift */ +#define GPIO_OTYPER_M(n) (uint32_t) (1 << n) /* Pin mask */ +#define GPIO_OTYPER_PP (uint32_t) (0x0) /* Output push-pull */ +#define GPIO_OTYPER_OD (uint32_t) (0x1) /* Output open drain */ + +#define GPIO_OSPEEDR_PIN(n) (uint32_t) (2 * n) /* Pin bitshift */ +#define GPIO_OSPEEDR_M(n) (uint32_t) (0x3 << (2 * n)) /* Pin mask */ +#define GPIO_OSPEEDR_2M (uint32_t) (0x0) /* Output speed 2MHz */ +#define GPIO_OSPEEDR_25M (uint32_t) (0x1) /* Output speed 25MHz */ +#define GPIO_OSPEEDR_50M (uint32_t) (0x2) /* Output speed 50MHz */ +#define GPIO_OSPEEDR_100M (uint32_t) (0x3) /* Output speed 100MHz */ + +#define GPIO_PUPDR_PIN(n) (uint32_t) (2 * n) /* Pin bitshift */ +#define GPIO_PUPDR_M(n) (uint32_t) (0x3 << (2 * n)) /* Pin mask */ +#define GPIO_PUPDR_NONE (uint32_t) (0x0) /* Port no pull-up, pull-down */ +#define GPIO_PUPDR_UP (uint32_t) (0x1) /* Port pull-up */ +#define GPIO_PUPDR_DOWN (uint32_t) (0x2) /* Port pull-down */ + +#define GPIO_IDR_PIN(n) (uint32_t) (1 << n) /* Input for pin n */ + +#define GPIO_ODR_PIN(n) (uint32_t) (1 << n) /* Output for pin n */ + +#define GPIO_BSRR_BS(n) (uint32_t) (1 << n) /* Set pin n */ +#define GPIO_BSRR_BR(n) (uint32_t) (1 << (n + 16)) /* Reset pin n */ + +#define GPIO_AFRL_PIN(n) (uint32_t) (4 * n) /* Pin bitshift */ +#define GPIO_AFRL_M(n) (uint32_t) (0xF << (4 * n)) /* Pin mask */ +#define GPIO_AFRH_PIN(n) (uint32_t) (4 * (n - 8)) /* Pin bitshift */ +#define GPIO_AFRH_M(n) (uint32_t) (0xF << (4 * (n - 8))) /* Pin mask */ + +/* DMA */ +#define DMA_LISR_TCIF2 \ + (uint32_t) (1 << 21) /* DMA stream 2 transfer complete flag */ +#define DMA_HISR_TCIF7 \ + (uint32_t) (1 << 27) /* DMA stream 7 transfer complete flag */ +#define DMA_LIFCR_CTCIF2 \ + (uint32_t) (1 << 21) /* DMA clear stream 2 transfer complete flag */ +#define DMA_HIFCR_CTCIF7 \ + (uint32_t) (1 << 27) /* DMA clear stream 7 transfer complete flag */ + +#define DMA_SxCR_EN (uint32_t) (1 << 0) /* DMA stream enable */ +#define DMA_SxCR_DMEIE \ + (uint32_t) (1 << 1) /* DMA stream direct mode error interrupt enable */ +#define DMA_SxCR_TEIE \ + (uint32_t) (1 << 2) /* DMA stream transmit error interrupt enable */ +#define DMA_SxCR_HTIE \ + (uint32_t) (1 << 3) /* DMA stream half transfer interrupt enable */ +#define DMA_SxCR_TCIE \ + (uint32_t) (1 << 4) /* DMA stream transfer complete interrupt enable */ +#define DMA_SxCR_PFCTRL \ + (uint32_t) (1 << 5) /* DMA stream peripheral flow control */ +#define DMA_SxCR_DIR_PM \ + (uint32_t) (0 << 6) /* DMA stream peripheral-to-memory data transfer */ +#define DMA_SxCR_DIR_MP \ + (uint32_t) (1 << 6) /* DMA stream memory-to-peripheral data transfer */ +#define DMA_SxCR_DIR_MM \ + (uint32_t) (2 << 6) /* DMA stream memory-to-memory data transfer */ +#define DMA_SxCR_CIRC \ + (uint32_t) (1 << 8) /* DMA stream circular mode enable \ + */ +#define DMA_SxCR_PINC \ + (uint32_t) (1 << 9) /* DMA stream peripheral increment mode enable */ +#define DMA_SxCR_MINC \ + (uint32_t) (1 << 10) /* DMA stream memory increment mode enable */ +#define DMA_SxCR_PSIZE_BYTE \ + (uint32_t) (0 << 11) /* DMA stream peripheral data size - Byte */ +#define DMA_SxCR_PSIZE_HW \ + (uint32_t) (1 << 11) /* DMA stream peripheral data size - Half-word */ +#define DMA_SxCR_PSIZE_WORD \ + (uint32_t) (2 << 11) /* DMA stream peripheral data size - Word */ +#define DMA_SxCR_MSIZE_BYTE \ + (uint32_t) (0 << 13) /* DMA stream memory data size - Byte */ +#define DMA_SxCR_MSIZE_HW \ + (uint32_t) (1 << 13) /* DMA stream memory data size - Half-word */ +#define DMA_SxCR_MSIZE_WORD \ + (uint32_t) (2 << 13) /* DMA stream memory data size - Word */ +#define DMA_SxCR_PINCOS_LINKED \ + (uint32_t) (0 << 15) /* DMA stream peripheral increment offset size linked \ + to PSIZE */ +#define DMA_SxCR_PINCOS_FIXED \ + (uint32_t) (1 << 15) /* DMA stream peripheral increment offset size fixed \ + */ +#define DMA_SxCR_PL_LOW \ + (uint32_t) (0 << 16) /* DMA stream priority level low \ + */ +#define DMA_SxCR_PL_MED \ + (uint32_t) (1 << 16) /* DMA stream priority level medium */ +#define DMA_SxCR_PL_HIGH \ + (uint32_t) (2 << 16) /* DMA stream priority level high */ +#define DMA_SxCR_PL_VHIGH \ + (uint32_t) (3 << 16) /* DMA stream priority level very high */ +#define DMA_SxCR_DBM (uint32_t) (1 << 18) /* DMA stream double buffer mode */ +#define DMA_SxCR_CT \ + (uint32_t) (1 << 19) /* DMA stream current target (M0 or M1) */ +#define DMA_SxCR_PBURST_NO \ + (uint32_t) (0 << 21) /* DMA stream peripheral burst disable */ +#define DMA_SxCR_PBURST_4 \ + (uint32_t) (1 << 21) /* DMA stream peripheral burst of 4 beats */ +#define DMA_SxCR_PBURST_8 \ + (uint32_t) (2 << 21) /* DMA stream peripheral burst of 8 beats */ +#define DMA_SxCR_PBURST_16 \ + (uint32_t) (3 << 21) /* DMA stream peripheral burst of 16 beats */ +#define DMA_SxCR_MBURST_NO \ + (uint32_t) (0 << 23) /* DMA stream memory burst disable */ +#define DMA_SxCR_MBURST_4 \ + (uint32_t) (1 << 23) /* DMA stream memory burst of 4 beats */ +#define DMA_SxCR_MBURST_8 \ + (uint32_t) (2 << 23) /* DMA stream memory burst of 8 beats */ +#define DMA_SxCR_MBURST_16 \ + (uint32_t) (3 << 23) /* DMA stream memory burst of 16 beats */ +#define DMA_SxCR_CHSEL(x) (uint32_t) (x << 25) /* DMA stream channel select */ + +#define DMA_SxFCR_FTH_1 \ + (uint32_t) (0 << 0) /* DMA stream FIFO threshold 1/4 \ + */ +#define DMA_SxFCR_FTH_2 \ + (uint32_t) (1 << 0) /* DMA stream FIFO threshold 1/2 \ + */ +#define DMA_SxFCR_FTH_3 \ + (uint32_t) (2 << 0) /* DMA stream FIFO threshold 3/4 \ + */ +#define DMA_SxFCR_FTH_4 \ + (uint32_t) (3 << 0) /* DMA stream FIFO threshold \ + full*/ +#define DMA_SxFCR_DMDIS \ + (uint32_t) (1 << 2) /* DMA stream direct mode disable \ + */ +#define DMA_SxFCR_FS (uint32_t) (7 << 3) /* DMA stream FIFO status */ +#define DMA_SxFCR_FEIE \ + (uint32_t) (1 << 7) /* DMA stream FIFO error interrupt enable */ + +/* USB FS */ +/* Global Registers */ +#define USB_FS_GOTGCTL_SRQSCS \ + (uint32_t) (1 << 0) /* USB session request success */ +#define USB_FS_GOTGCTL_SRQ (uint32_t) (1 << 1) /* USB session request */ +#define USB_FS_GOTGCTL_HNGSCS \ + (uint32_t) (1 << 8) /* USB host negotiation success */ +#define USB_FS_GOTGCTL_HNP (uint32_t) (1 << 9) /* USB HNP request */ +#define USB_FS_GOTGCTL_HSHNPEN \ + (uint32_t) (1 << 10) /* USB host set HPN enable */ +#define USB_FS_GOTGCTL_DHNPEN \ + (uint32_t) (1 << 11) /* USB device HPN enabled \ + */ +#define USB_FS_GOTGCTL_CIDSTS \ + (uint32_t) (1 << 16) /* USB connector ID status \ + */ +#define USB_FS_GOTGCTL_DBCT (uint32_t) (1 << 17) /* USB debounce time */ +#define USB_FS_GOTGCTL_ASVLD (uint32_t) (1 << 18) /* USB A session valid */ +#define USB_FS_GOTGCTL_BSVLD (uint32_t) (1 << 19) /* USB B session valid */ + +#define USB_FS_GOTGINT_SEDET \ + (uint32_t) (1 << 2) /* USB session end detected \ + */ +#define USB_FS_GOTGINT_SRSSCHG \ + (uint32_t) (1 << 8) /* USB session request success status change */ +#define USB_FS_GOTGINT_HNSSCHG \ + (uint32_t) (1 << 9) /* USB host negotiation success status change */ +#define USB_FS_GOTGINT_HNGDET \ + (uint32_t) (1 << 17) /* USB host negotiation detected */ +#define USB_FS_GOTGINT_ADTOCHG \ + (uint32_t) (1 << 18) /* USB A-device timeout change */ +#define USB_FS_GOTGINT_DBCDNE (uint32_t) (1 << 19) /* USB debounce done */ + +#define USB_FS_GAHBCFG_GINTMSK \ + (uint32_t) (1 << 0) /* USB global interrupt mask */ +#define USB_FS_GAHBCFG_TXFELVL \ + (uint32_t) (1 << 7) /* USB TX FIFO empty level \ + */ +#define USB_FS_GAHBCFG_PTXFELVL \ + (uint32_t) (1 << 8) /* USB Periodic TX FIFO empty level */ + +#define USB_FS_GUSBCFG_TOCAL(n) \ + (uint32_t) (n << 0) /* USB FS timeout calibration */ +#define USB_FS_GUSBCFG_PHYSEL \ + (uint32_t) (1 << 7) /* USB FS serial transceiver select */ +#define USB_FS_GUSBCFG_SRPCAP (uint32_t) (1 << 8) /* USB SRP capable */ +#define USB_FS_GUSBCFG_HNPCAP (uint32_t) (1 << 9) /* USB HNP capable */ +#define USB_FS_GUSBCFG_TRDT(n) \ + (uint32_t) (n << 10) /* USB turnaround time (4 bits) */ +#define USB_FS_GUSBCFG_FHMOD (uint32_t) (1 << 29) /* USB force host mode */ +#define USB_FS_GUSBCFG_FDMOD (uint32_t) (1 << 30) /* USB force device mode */ +#define USB_FS_GUSBCFG_CTXPKT (uint32_t) (1 << 31) /* USB corrupt packet */ + +#define USB_FS_GRSTCTL_CSRST (uint32_t) (1 << 0) /* USB core soft reset */ +#define USB_FS_GRSTCTL_HSRST (uint32_t) (1 << 1) /* USB HCLK soft reset */ +#define USB_FS_GRSTCTL_FCRST \ + (uint32_t) (1 << 2) /* USB host frame counter reset */ +#define USB_FS_GRSTCTL_RXFFLSH (uint32_t) (1 << 4) /* USB RX FIFO flush */ +#define USB_FS_GRSTCTL_TXFFLSH (uint32_t) (1 << 5) /* USB TX FIFO flush */ +#define USB_FS_GRSTCTL_TXFNUM(n) (uint32_t) (n << 6) /* USB TX FIFO number */ +#define USB_FS_GRSTCTL_AHBIDL (uint32_t) (1 << 31) /* USB AHB master idle */ + +#define USB_FS_GINTSTS_CMOD \ + (uint32_t) (1 << 0) /* USB current mode of operation */ +#define USB_FS_GINTSTS_MMIS \ + (uint32_t) (1 << 1) /* USB mode mismatch interrupt */ +#define USB_FS_GINTSTS_OTGINT (uint32_t) (1 << 2) /* USB OTG interrupt */ +#define USB_FS_GINTSTS_SOF (uint32_t) (1 << 3) /* USB start of frame */ +#define USB_FS_GINTSTS_RXFLVL (uint32_t) (1 << 4) /* USB RX FIFO non-empty */ +#define USB_FS_GINTSTS_NPTXFE \ + (uint32_t) (1 << 5) /* USB non-periodic TX FIFO empty */ +#define USB_FS_GINTSTS_GINAKEFF \ + (uint32_t) (1 << 6) /* USB global IN non-periodic NAK effective */ +#define USB_FS_GINTSTS_GONAKEFF \ + (uint32_t) (1 << 7) /* USB global OUT NAK effective */ +#define USB_FS_GINTSTS_ESUSP (uint32_t) (1 << 10) /* USB early suspend */ +#define USB_FS_GINTSTS_USBSUSP (uint32_t) (1 << 11) /* USB suspend */ +#define USB_FS_GINTSTS_USBRST (uint32_t) (1 << 12) /* USB reset */ +#define USB_FS_GINTSTS_ENUMDNE (uint32_t) (1 << 13) /* USB enumeration done */ +#define USB_FS_GINTSTS_ISOODRP \ + (uint32_t) (1 << 14) /* USB isochronous OUT packet dropped interrupt */ +#define USB_FS_GINTSTS_EOPF \ + (uint32_t) (1 << 15) /* USB end of packet frame interrupt */ +#define USB_FS_GINTSTS_IEPINT \ + (uint32_t) (1 << 18) /* USB IN endpoint interrupt */ +#define USB_FS_GINTSTS_OEPINT \ + (uint32_t) (1 << 19) /* USB OUT endpoint interrupt */ +#define USB_FS_GINTSTS_IISOIXFR \ + (uint32_t) (1 << 20) /* USB incomplete isochronous IN transfer */ +#define USB_FS_GINTSTS_IISOOXFR \ + (uint32_t) (1 << 21) /* USB incomplete isochronous OUT transfer */ +#define USB_FS_GINTSTS_IPXFR \ + (uint32_t) (1 << 21) /* USB incomplete periodic transfer */ +#define USB_FS_GINTSTS_HPRTINT \ + (uint32_t) (1 << 24) /* USB host port interrupt */ +#define USB_FS_GINTSTS_HCINT \ + (uint32_t) (1 << 25) /* USB host channels interrupt */ +#define USB_FS_GINTSTS_PTXFE \ + (uint32_t) (1 << 26) /* USB periodic TX FIFO empty */ +#define USB_FS_GINTSTS_CIDSCHG \ + (uint32_t) (1 << 28) /* USB connector ID status change */ +#define USB_FS_GINTSTS_DISCINT \ + (uint32_t) (1 << 29) /* USB disconnect detected interrupt */ +#define USB_FS_GINTSTS_SRQINT \ + (uint32_t) (1 << 30) /* USB session request/new session detected interrupt \ + */ +#define USB_FS_GINTSTS_WKUPINT \ + (uint32_t) (1 << 31) /* USB resume/remote wakeup detected interrupt */ + +#define USB_FS_GINTMSK_MMISM \ + (uint32_t) (1 << 1) /* USB mode mismatch interrupt mask */ +#define USB_FS_GINTMSK_OTGINT (uint32_t) (1 << 2) /* USB OTG interrupt mask */ +#define USB_FS_GINTMSK_SOFM (uint32_t) (1 << 3) /* USB start of frame mask */ +#define USB_FS_GINTMSK_RXFLVLM \ + (uint32_t) (1 << 4) /* USB RX FIFO non-empty mask */ +#define USB_FS_GINTMSK_NPTXFEM \ + (uint32_t) (1 << 5) /* USB non-periodic TX FIFO empty mask */ +#define USB_FS_GINTMSK_GINAKEFFM \ + (uint32_t) (1 << 6) /* USB global IN non-periodic NAK effective mask */ +#define USB_FS_GINTMSK_GONAKEFFM \ + (uint32_t) (1 << 7) /* USB global OUT NAK effective mask */ +#define USB_FS_GINTMSK_ESUSPM \ + (uint32_t) (1 << 10) /* USB early suspend mask \ + */ +#define USB_FS_GINTMSK_USBSUSPM (uint32_t) (1 << 11) /* USB suspend mask */ +#define USB_FS_GINTMSK_USBRSTM (uint32_t) (1 << 12) /* USB reset mask */ +#define USB_FS_GINTMSK_ENUMDNEM \ + (uint32_t) (1 << 13) /* USB enumeration done mask */ +#define USB_FS_GINTMSK_ISOODRPM \ + (uint32_t) (1 << 14) /* USB isochronous OUT packet dropped interrupt mask \ + */ +#define USB_FS_GINTMSK_EOPFM \ + (uint32_t) (1 << 15) /* USB end of packet frame interrupt mask */ +#define USB_FS_GINTMSK_EPMISM \ + (uint32_t) (1 << 17) /* USB endpoint mismatch interrupt mask */ +#define USB_FS_GINTMSK_IEPINT \ + (uint32_t) (1 << 18) /* USB IN endpoint interrupt mask */ +#define USB_FS_GINTMSK_OEPINT \ + (uint32_t) (1 << 19) /* USB OUT endpoint interrupt mask */ +#define USB_FS_GINTMSK_IISOIXFRM \ + (uint32_t) (1 << 20) /* USB incomplete isochronous IN transfer mask */ +#define USB_FS_GINTMSK_IISOOXFRM \ + (uint32_t) (1 << 21) /* USB incomplete isochronous OUT transfer mask */ +#define USB_FS_GINTMSK_IPXFRM \ + (uint32_t) (1 << 21) /* USB incomplete periodic transfer mask */ +#define USB_FS_GINTMSK_HPRTINT \ + (uint32_t) (1 << 24) /* USB host port interrupt mask */ +#define USB_FS_GINTMSK_HCINT \ + (uint32_t) (1 << 25) /* USB host channels interrupt mask */ +#define USB_FS_GINTMSK_PTXFEM \ + (uint32_t) (1 << 26) /* USB periodic TX FIFO empty mask */ +#define USB_FS_GINTMSK_CIDSCHGM \ + (uint32_t) (1 << 28) /* USB connector ID status change mask */ +#define USB_FS_GINTMSK_DISCINT \ + (uint32_t) (1 << 29) /* USB disconnect detected interrupt mask */ +#define USB_FS_GINTMSK_SRQINT \ + (uint32_t) (1 << 30) /* USB session request/new session detected interrupt \ + mask */ +#define USB_FS_GINTMSK_WKUPINT \ + (uint32_t) (1 << 31) /* USB resume/remote wakeup detected interrupt mask \ + */ + +#define USB_FS_GRXSTS_EPNUM(r) \ + (uint32_t) (r & 0xF) /* USB RX FIFO endpoint number */ +#define USB_FS_GRXSTS_BCNT(r) \ + (uint32_t) ((r & 0x7FF0) >> 4) /* USB RX FIFO byte count */ +#define USB_FS_GRXSTS_DPID(r) \ + (uint32_t) ((r & 0x18000) >> 15) /* USB RX FIFO data PID */ +#define USB_FS_GRXSTS_PKTSTS(r) \ + (uint32_t) ((r & 0x1E0000) >> 17) /* USB RX FIFO packet status */ +#define USB_FS_GRXSTS_FRMNUM(r) \ + (uint32_t) ((r & 0x1E00000) >> 21) /* USB RX FIFO frame number */ +#define USB_FS_GRXSTS_PKTSTS_NAK \ + (uint8_t) (1) /* USB RX FIFO packet status = global OUT NAK */ +#define USB_FS_GRXSTS_PKTSTS_ORX \ + (uint8_t) (2) /* USB RX FIFO packet status = OUT data packet received */ +#define USB_FS_GRXSTS_PKTSTS_OCP \ + (uint8_t) (3) /* USB RX FIFO packet status = OUT transfer completed */ +#define USB_FS_GRXSTS_PKTSTS_STUPCP \ + (uint8_t) (4) /* USB RX FIFO packet status = SETUP transaction completed \ + */ +#define USB_FS_GRXSTS_PKTSTS_STUPRX \ + (uint8_t) (6) /* USB RX FIFO packet status = SETUP data packet received */ + +#define USB_FS_DIEPTXF0_TX0FSA(n) \ + (uint32_t) (n << 0) /* USB endpoint 0 transmit RAM start address */ +#define USB_FS_DIEPTXF0_TX0FD(n) \ + (uint32_t) (n << 16) /* USB endpoint 0 TX FIFO depth */ + +#define USB_FS_GCCFG_PWRDWN (uint32_t) (1 << 16) /* USB power down */ +#define USB_FS_GCCFG_VBUSASEN \ + (uint32_t) (1 << 18) /* USB VBUS "A" sensing enable */ +#define USB_FS_GCCFG_VBUSBSEN \ + (uint32_t) (1 << 19) /* USB VBUS "B" sensing enable */ +#define USB_FS_GCCFG_SOFOUTEN (uint32_t) (1 << 20) /* USB SOF output enable */ +#define USB_FS_GCCFG_NOVBUSSSENS \ + (uint32_t) (1 << 21) /* USB VBUS sensing disable */ + +#define USB_FS_DIEPTXF_INEPTXSA(n) \ + (uint32_t) (n << 0) /* USB IN endpoint FIFOx transmit RAM start address */ +#define USB_FS_DIEPTXF_INEPTXFD(n) \ + (uint32_t) (n << 16) /* USB IN endpoint TX FIFOx depth */ + +/* Device-mode Registers */ +#define USB_FS_DCFG_DSPD_FS \ + (uint32_t) (1 << 1 | 1 << 0) /* USB device speed: full speed (USB 1.1) */ +#define USB_FS_DCFG_NZLSOHSK \ + (uint32_t) (1 << 2) /* USB device non-zero-length status OUT handshake */ +#define USB_FS_DCFG_DAD(x) (uint32_t) (x << 4) /* USB device address */ +#define USB_FS_DCFG_PFIVL_80 \ + (uint32_t) (0 << 11) /* USB device periodic frame interval: 80% */ +#define USB_FS_DCFG_PFIVL_85 \ + (uint32_t) (1 << 11) /* USB device periodic frame interval: 85% */ +#define USB_FS_DCFG_PFIVL_90 \ + (uint32_t) (2 << 11) /* USB device periodic frame interval: 90% */ +#define USB_FS_DCFG_PFIVL_95 \ + (uint32_t) (3 << 11) /* USB device periodic frame interval: 95% */ + +#define USB_FS_DCTL_RWUSIG \ + (uint32_t) (1 << 0) /* USB device remote wakeup signaling */ +#define USB_FS_DCTL_SDIS (uint32_t) (1 << 1) /* USB device soft disconnect */ +#define USB_FS_DCTL_GINSTS \ + (uint32_t) (1 << 2) /* USB device global IN NAK status */ +#define USB_FS_DCTL_GONSTS \ + (uint32_t) (1 << 3) /* USB device global OUT NAK status */ +#define USB_FS_DCTL_TCTL_J (uint32_t) (1 << 4) /* USB device Test_J mode */ +#define USB_FS_DCTL_TCTL_K (uint32_t) (2 << 4) /* USB device Test_K mode */ +#define USB_FS_DCTL_TCTL_SE0_NAK \ + (uint32_t) (3 << 4) /* USB device Test_SE0_NAK mode */ +#define USB_FS_DCTL_TCTL_PKT \ + (uint32_t) (4 << 4) /* USB device Test_Packet mode */ +#define USB_FS_DCTL_TCTL_FEN \ + (uint32_t) (5 << 4) /* USB device Test_Force_Enable mode */ +#define USB_FS_DCTL_SGINAK \ + (uint32_t) (1 << 7) /* USB device set global IN NAK */ +#define USB_FS_DCTL_CGINAK \ + (uint32_t) (1 << 8) /* USB device clear global IN NAK */ +#define USB_FS_DCTL_SGONAK \ + (uint32_t) (1 << 9) /* USB device set global OUT NAK */ +#define USB_FS_DCTL_CGONAK \ + (uint32_t) (1 << 10) /* USB device clear global OUT NAK */ +#define USB_FS_DCTL_POPRGDNE \ + (uint32_t) (1 << 11) /* USB device power-no programming done */ + +#define USB_FS_DSTS_SUSPSTS \ + (uint32_t) (1 << 0) /* USB device suspend status \ + */ +#define USB_FS_DSTS_ENUMSPD \ + (uint32_t) (3 << 1) /* USB device enumerated speed (Must == 3) */ +#define USB_FS_DSTS_ENUMSPD_FS \ + (uint32_t) (3 << 1) /* USB device enumerated speed (Must == 3) */ +#define USB_FS_DSTS_EERR (uint32_t) (1 << 3) /* USB device erratic error */ +#define USB_FS_DSTS_FNSOF \ + (uint32_t) (0x3FFF00) /* USB device frame number of received SOF (bits \ + 21:8) */ + +#define USB_FS_DIEPMSK_XFRCM \ + (uint32_t) (1 << 0) /* USB device transfer completed interrupt mask */ +#define USB_FS_DIEPMSK_EPDM \ + (uint32_t) (1 << 1) /* USB device endpoint disabled interrupt mask */ +#define USB_FS_DIEPMSK_TOM \ + (uint32_t) (1 << 3) /* USB device timout condition mask */ +#define USB_FS_DIEPMSK_ITTXFEMSK \ + (uint32_t) (1 << 4) /* USB device IN token received when TX FIFO empty \ + mask */ +#define USB_FS_DIEPMSK_INEPNMM \ + (uint32_t) (1 << 5) /* USB device IN token received with EP mismatch mask \ + */ +#define USB_FS_DIEPMSK_INEPNEM \ + (uint32_t) (1 << 6) /* USB device IN endpoint NAK effective mask */ + +#define USB_FS_DOEPMSK_XFRCM \ + (uint32_t) (1 << 0) /* USB device transfer completed interrupt mask */ +#define USB_FS_DOEPMSK_EPDM \ + (uint32_t) (1 << 1) /* USB device endpoint disabled interrupt mask */ +#define USB_FS_DOEPMSK_STUPM \ + (uint32_t) (1 << 3) /* USB device SETUP phase done mask */ +#define USB_FS_DOEPMSK_OTEPDM \ + (uint32_t) (1 << 4) /* USB device OUT token received when endpoint \ + disabled mask */ + +#define USB_FS_DAINT_IEPINT(n) \ + (uint32_t) (1 << n) /* USB device IN endpoint interrupt bits */ +#define USB_FS_DAINT_OEPINT(n) \ + (uint32_t) (1 << (n + 16)) /* USB device OUT endpoint interrupt bits */ + +#define USB_FS_DAINT_IEPM(n) \ + (uint32_t) (1 << n) /* USB device IN endpoint interrupt mask bits */ +#define USB_FS_DAINT_OEPM(n) \ + (uint32_t) (1 << (n + 16)) /* USB device OUT endpoint interrupt mask bits \ + */ + +#define USB_FS_DIEPEMPMSK_INEPTXFEM(n) \ + (uint32_t) (1 << n) /* USB device IN EP TX FIFO empty interrupt mask bits \ + */ + +#define USB_FS_DIEPCTL0_MPSIZE \ + (uint32_t) (3 << 0) /* USB device endpoint 0 IN maximum packet size */ +#define USB_FS_DIEPCTL0_MPSIZE_64 \ + (uint32_t) (0 << 0) /* USB device endpoint 0 IN maximum packet size 64 \ + bytes */ +#define USB_FS_DIEPCTL0_MPSIZE_32 \ + (uint32_t) (1 << 0) /* USB device endpoint 0 IN maximum packet size 32 \ + bytes */ +#define USB_FS_DIEPCTL0_MPSIZE_16 \ + (uint32_t) (2 << 0) /* USB device endpoint 0 IN maximum packet size 16 \ + bytes */ +#define USB_FS_DIEPCTL0_MPSIZE_8 \ + (uint32_t) (3 << 0) /* USB device endpoint 0 IN maximum packet size 8 \ + bytes */ +#define USB_FS_DIEPCTL0_USBAEP \ + (uint32_t) (1 << 15) /* USB device endpoint 0 IN USB active endpoint \ + (always 1) */ +#define USB_FS_DIEPCTL0_NAKSTS \ + (uint32_t) (1 << 17) /* USB device endpoint 0 IN NAK status */ +#define USB_FS_DIEPCTL0_STALL \ + (uint32_t) (1 << 21) /* USB device endpoint 0 IN STALL handshake */ +#define USB_FS_DIEPCTL0_TXFNUM(n) \ + (uint32_t) (n << 22) /* USB device endpoint 0 IN TX FIFO number */ +#define USB_FS_DIEPCTL0_CNAK \ + (uint32_t) (1 << 26) /* USB device endpoint 0 IN clear NAK */ +#define USB_FS_DIEPCTL0_SNAK \ + (uint32_t) (1 << 27) /* USB device endpoint 0 IN set NAK */ +#define USB_FS_DIEPCTL0_EPDIS \ + (uint32_t) (1 << 30) /* USB device endpoint 0 IN endpoint disable */ +#define USB_FS_DIEPCTL0_EPENA \ + (uint32_t) (1 << 31) /* USB device endpoint 0 IN endpoint enable */ + +#define USB_FS_DIEPCTLx_MPSIZE(n) \ + (uint32_t) (n << 0) /* USB device endpoint x IN maximum packet size in \ + bytes (11 bits) */ +#define USB_FS_DIEPCTLx_USBAEP \ + (uint32_t) (1 << 15) /* USB device endpoint x IN USB active endpoint */ +#define USB_FS_DIEPCTLx_EONUM_EVEN \ + (uint32_t) (0 << 16) /* USB device endpoint x IN Odd frame */ +#define USB_FS_DIEPCTLx_EONUM_ODD \ + (uint32_t) (1 << 16) /* USB device endpoint x IN Odd frame */ +#define USB_FS_DIEPCTLx_DPID_0 \ + (uint32_t) (0 << 16) /* USB device endpoint x IN data PID 0 */ +#define USB_FS_DIEPCTLx_DPID_1 \ + (uint32_t) (1 << 16) /* USB device endpoint x IN data PID 1 */ +#define USB_FS_DIEPCTLx_NAKSTS \ + (uint32_t) (1 << 17) /* USB device endpoint x IN NAK status */ +#define USB_FS_DIEPCTLx_EPTYP_CTL \ + (uint32_t) (0 << 18) /* USB device endpoint x IN type: control */ +#define USB_FS_DIEPCTLx_EPTYP_ISO \ + (uint32_t) (1 << 18) /* USB device endpoint x IN type: isochronous */ +#define USB_FS_DIEPCTLx_EPTYP_BLK \ + (uint32_t) (2 << 18) /* USB device endpoint x IN type: bulk */ +#define USB_FS_DIEPCTLx_EPTYP_INT \ + (uint32_t) (3 << 18) /* USB device endpoint x IN type: interrupt */ +#define USB_FS_DIEPCTLx_STALL \ + (uint32_t) (1 << 21) /* USB device endpoint x IN STALL handshake */ +#define USB_FS_DIEPCTLx_TXFNUM(n) \ + (uint32_t) (n << 22) /* USB device endpoint x IN TX FIFO number (4 bits) \ + */ +#define USB_FS_DIEPCTLx_CNAK \ + (uint32_t) (1 << 26) /* USB device endpoint x IN clear NAK */ +#define USB_FS_DIEPCTLx_SNAK \ + (uint32_t) (1 << 27) /* USB device endpoint x IN set NAK */ +#define USB_FS_DIEPCTLx_SD0PID \ + (uint32_t) (1 << 28) /* USB device endpoint x IN set DATA0 PID */ +#define USB_FS_DIEPCTLx_SEVNFRM \ + (uint32_t) (1 << 28) /* USB device endpoint x IN set even frame */ +#define USB_FS_DIEPCTLx_SODDFRM \ + (uint32_t) (1 << 29) /* USB device endpoint x IN set odd frame */ +#define USB_FS_DIEPCTLx_EPDIS \ + (uint32_t) (1 << 30) /* USB device endpoint x IN endpoint disable */ +#define USB_FS_DIEPCTLx_EPENA \ + (uint32_t) (1 << 31) /* USB device endpoint x IN endpoint enable */ + +#define USB_FS_DOEPCTL0_MPSIZE \ + (uint32_t) (3 << 0) /* USB device endpoint 0 OUT maximum packet size */ +#define USB_FS_DOEPCTL0_MPSIZE_64 \ + (uint32_t) (0 << 0) /* USB device endpoint 0 OUT maximum packet size 64 \ + bytes */ +#define USB_FS_DOEPCTL0_MPSIZE_32 \ + (uint32_t) (1 << 0) /* USB device endpoint 0 OUT maximum packet size 32 \ + bytes */ +#define USB_FS_DOEPCTL0_MPSIZE_16 \ + (uint32_t) (2 << 0) /* USB device endpoint 0 OUT maximum packet size 16 \ + bytes */ +#define USB_FS_DOEPCTL0_MPSIZE_8 \ + (uint32_t) (3 << 0) /* USB device endpoint 0 OUT maximum packet size 8 \ + bytes */ +#define USB_FS_DOEPCTL0_USBAEP \ + (uint32_t) (1 << 15) /* USB device endpoint 0 OUT USB active endpoint \ + (always 1) */ +#define USB_FS_DOEPCTL0_NAKSTS \ + (uint32_t) (1 << 17) /* USB device endpoint 0 OUT NAK status */ +#define USB_FS_DOEPCTL0_SNPM \ + (uint32_t) (1 << 20) /* USB device endpoint 0 OUT snoop mode */ +#define USB_FS_DOEPCTL0_STALL \ + (uint32_t) (1 << 21) /* USB device endpoint 0 OUT STALL handshake */ +#define USB_FS_DOEPCTL0_CNAK \ + (uint32_t) (1 << 26) /* USB device endpoint 0 OUT clear NAK */ +#define USB_FS_DOEPCTL0_SNAK \ + (uint32_t) (1 << 27) /* USB device endpoint 0 OUT set NAK */ +#define USB_FS_DOEPCTL0_EPDIS \ + (uint32_t) (1 << 30) /* USB device endpoint 0 OUT endpoint disable */ +#define USB_FS_DOEPCTL0_EPENA \ + (uint32_t) (1 << 31) /* USB device endpoint 0 OUT endpoint enable */ + +#define USB_FS_DOEPCTLx_MPSIZE(n) \ + (uint32_t) (n << 0) /* USB device endpoint x OUT maximum packet size in \ + bytes (11 bits) */ +#define USB_FS_DOEPCTLx_USBAEP \ + (uint32_t) (1 << 15) /* USB device endpoint x OUT USB active endpoint */ +#define USB_FS_DOEPCTLx_EONUM_EVEN \ + (uint32_t) (0 << 16) /* USB device endpoint x OUT Odd frame */ +#define USB_FS_DOEPCTLx_EONUM_ODD \ + (uint32_t) (1 << 16) /* USB device endpoint x OUT Odd frame */ +#define USB_FS_DOEPCTLx_DPID_0 \ + (uint32_t) (0 << 16) /* USB device endpoint x OUT data PID 0 */ +#define USB_FS_DOEPCTLx_DPID_1 \ + (uint32_t) (1 << 16) /* USB device endpoint x OUT data PID 1 */ +#define USB_FS_DOEPCTLx_NAKSTS \ + (uint32_t) (1 << 17) /* USB device endpoint x OUT NAK status */ +#define USB_FS_DOEPCTLx_EPTYP_CTL \ + (uint32_t) (0 << 18) /* USB device endpoint x OUT type: control */ +#define USB_FS_DOEPCTLx_EPTYP_ISO \ + (uint32_t) (1 << 18) /* USB device endpoint x OUT type: isochronous */ +#define USB_FS_DOEPCTLx_EPTYP_BLK \ + (uint32_t) (2 << 18) /* USB device endpoint x OUT type: bulk */ +#define USB_FS_DOEPCTLx_EPTYP_INT \ + (uint32_t) (3 << 18) /* USB device endpoint x OUT type: interrupt */ +#define USB_FS_DOEPCTLx_SNPMN \ + (uint32_t) (1 << 20) /* USB device endpoint x OUT snoop mode */ +#define USB_FS_DOEPCTLx_STALL \ + (uint32_t) (1 << 21) /* USB device endpoint x OUT STALL handshake */ +#define USB_FS_DOEPCTLx_CNAK \ + (uint32_t) (1 << 26) /* USB device endpoint x OUT clear NAK */ +#define USB_FS_DOEPCTLx_SNAK \ + (uint32_t) (1 << 27) /* USB device endpoint x OUT set NAK */ +#define USB_FS_DOEPCTLx_SD0PID \ + (uint32_t) (1 << 28) /* USB device endpoint x OUT set DATA0 PID */ +#define USB_FS_DOEPCTLx_SEVNFRM \ + (uint32_t) (1 << 28) /* USB device endpoint x OUT set even frame */ +#define USB_FS_DOEPCTLx_SODDFRM \ + (uint32_t) (1 << 29) /* USB device endpoint x OUT set odd frame */ +#define USB_FS_DOEPCTLx_EPDIS \ + (uint32_t) (1 << 30) /* USB device endpoint x OUT endpoint disable */ +#define USB_FS_DOEPCTLx_EPENA \ + (uint32_t) (1 << 31) /* USB device endpoint x OUT endpoint enable */ + +#define USB_FS_DIEPINTx_XFRC \ + (uint32_t) (1 << 0) /* USB device endpoint x IN transfer complete \ + interrupt */ +#define USB_FS_DIEPINTx_EPDISD \ + (uint32_t) (1 << 1) /* USB device endpoint x IN endpoint disabled \ + interrupt */ +#define USB_FS_DIEPINTx_TOC \ + (uint32_t) (1 << 3) /* USB device endpoint x IN timeout condition */ +#define USB_FS_DIEPINTx_ITTXFE \ + (uint32_t) (1 << 4) /* USB device endpoint x IN token received when TX \ + FIFO is empty */ +#define USB_FS_DIEPINTx_INEPNE \ + (uint32_t) (1 << 6) /* USB device endpoint x IN endpoint NAK effective */ +#define USB_FS_DIEPINTx_TXFE \ + (uint32_t) (1 << 7) /* USB device endpoint x IN TX FIFO empty */ + +#define USB_FS_DOEPINTx_XFRC \ + (uint32_t) (1 << 0) /* USB device endpoint x OUT transfer complete \ + interrupt */ +#define USB_FS_DOEPINTx_EPDISD \ + (uint32_t) (1 << 1) /* USB device endpoint x OUT endpoint disabled \ + interrupt */ +#define USB_FS_DOEPINTx_STUP \ + (uint32_t) (1 << 3) /* USB device endpoint x OUT SETUP phase complete */ +#define USB_FS_DOEPINTx_OTEPDIS \ + (uint32_t) (1 << 4) /* USB device endpoint x OUT token receieved when \ + endpoint disabled */ +#define USB_FS_DOEPINTx_B2BSTUP \ + (uint32_t) (1 << 6) /* USB device endpoint x OUT back-to-back SETUP \ + packets received */ + +#define USB_FS_DIEPTSIZ0_XFRSIZ(n) \ + (uint32_t) (n << 0) /* USB device endpoint 0 IN transfer size (7 bits) */ +#define USB_FS_DIEPTSIZ0_PKTCNT(n) \ + (uint32_t) (n << 19) /* USB device endpoint 0 IN packet count */ + +#define USB_FS_DIEPTSIZx_XFRSIZ(n) \ + (uint32_t) (n << 0) /* USB device endpoint x IN transfer size (19 bits) */ +#define USB_FS_DIEPTSIZx_PKTCNT(n) \ + (uint32_t) (n << 19) /* USB device endpoint x IN packet count (10 bits) */ +#define USB_FS_DIEPTSIZx_MCNT_1 \ + (uint32_t) (1 << 29) /* USB device endpoint x IN multi count 1 */ +#define USB_FS_DIEPTSIZx_MCNT_2 \ + (uint32_t) (2 << 29) /* USB device endpoint x IN multi count 1 */ +#define USB_FS_DIEPTSIZx_MCNT_3 \ + (uint32_t) (3 << 29) /* USB device endpoint x IN multi count 1 */ + +#define USB_FS_DOEPTSIZ0_XFRSIZ(n) \ + (uint32_t) (n << 0) /* USB device endpoint 0 OUT transfer size (7 bits) */ +#define USB_FS_DOEPTSIZ0_PKTCNT(n) \ + (uint32_t) (n << 19) /* USB device endpoint 0 OUT packet count */ +#define USB_FS_DOEPTSIZ0_STUPCNT(n) \ + (uint32_t) (n << 29) /* USB device endpoint 0 OUT back-to-back SETUP \ + packets allowed */ + +#define USB_FS_DOEPTSIZx_XFRSIZ(n) \ + (uint32_t) (n << 0) /* USB device endpoint x OUT transfer size (19 bits) \ + */ +#define USB_FS_DOEPTSIZx_PKTCNT(n) \ + (uint32_t) (n << 19) /* USB device endpoint x OUT packet count (10 bits) \ + */ +#define USB_FS_DOEPTSIZx_STUPCNT(n) \ + (uint32_t) (n << 29) /* USB device endpoint x OUT back-to-back SETUP \ + packets allowed */ +#define USB_FS_DOEPTSIZx_RXDPID \ + (uint32_t) (1 << 29 | \ + 1 << 30) /* USB device endpoint x OUT received data PID */ + +/* Powe and Clock Gating Control Register */ +#define USB_FS_PCGCCTL_STPPCLK (uint32_t) (1 << 0) /* USB stop PHY clock */ +#define USB_FS_PCGCCTL_GATEHCLK (uint32_t) (1 << 1) /* USB gate HCLK */ +#define USB_FS_PCGCCTL_PHYSUSP (uint32_t) (1 << 4) /* USB PHY suspended */ + +#endif diff --git a/include/platform/stm32l4/syscfg.h b/include/platform/stm32l4/syscfg.h new file mode 100644 index 00000000..cd15c2c4 --- /dev/null +++ b/include/platform/stm32l4/syscfg.h @@ -0,0 +1,27 @@ +/* Copyright (c) 2013 The F9 Microkernel Project. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef PLATFORM_STM32L4_SYSCFG_H_ +#define PLATFORM_STM32L4_SYSCFG_H_ + +#include + +static inline void memory_remap_flash(void) +{ + *SYSCFG_MEMRMP = 0x0; +} + +static inline void memory_remap_sysflash(void) +{ + *SYSCFG_MEMRMP = 0x1; +} + + +static inline void memory_remap_sram(void) +{ + *SYSCFG_MEMRMP = 0x3; +} + +#endif diff --git a/include/platform/stm32f1/systick.h b/include/platform/stm32l4/systick.h similarity index 52% rename from include/platform/stm32f1/systick.h rename to include/platform/stm32l4/systick.h index f1f15f2c..c13de767 100644 --- a/include/platform/stm32f1/systick.h +++ b/include/platform/stm32l4/systick.h @@ -1,9 +1,9 @@ -#ifndef PLATFORM_STM32F1_SYSTICK_H_ -#define PLATFORM_STM32F1_SYSTICK_H_ +#ifndef PLATFORM_STM32L4_SYSTICK_H_ +#define PLATFORM_STM32L4_SYSTICK_H_ -#include +#include -#define CORE_CLOCK (0x044aa200) /* 72MHz */ +#define CORE_CLOCK (0x0a037a00) /* 168 MHz - QEMU SysTick runs at this rate */ #define SYSTICK_MAXRELOAD (0x00ffffff) void init_systick(uint32_t tick_reload, uint32_t tick_next_reload); diff --git a/include/platform/stm32f1/usart.h b/include/platform/stm32l4/usart.h similarity index 79% rename from include/platform/stm32f1/usart.h rename to include/platform/stm32l4/usart.h index e5e5dbfd..9648d9ea 100644 --- a/include/platform/stm32f1/usart.h +++ b/include/platform/stm32l4/usart.h @@ -1,13 +1,13 @@ -/* Copyright (c) 2014 The F9 Microkernel Project. All rights reserved. +/* Copyright (c) 2013 The F9 Microkernel Project. All rights reserved. * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ -#ifndef PLATFORM_STM32F1_USART_H_ -#define PLATFORM_STM32F1_USART_H_ +#ifndef PLATFORM_STM32F4_USART_H_ +#define PLATFORM_STM32F4_USART_H_ -#include -#include +#include +#include struct usart_dev { uint32_t u_num; @@ -19,7 +19,7 @@ struct usart_dev { struct gpio_cfg rx; }; -#define USART_NUM 3 +#define USART_NUM 6 /* status bit */ #define USART_CTS ((uint16_t) (0x1 << 9)) @@ -34,9 +34,10 @@ struct usart_dev { #define USART_PE ((uint16_t) (0x1 << 0)) -#define USART_IT_CR1 (0xc << 8) -#define USART_IT_CR2 (0x10 << 8) -#define USART_IT_CR3 (0x14 << 8) +/* L4 USART CR register offsets from base (different from F4) */ +#define USART_IT_CR1 (0x00 << 8) +#define USART_IT_CR2 (0x04 << 8) +#define USART_IT_CR3 (0x08 << 8) #define USART_IT_PE ((uint16_t) USART_IT_CR1 | 0x8) #define USART_IT_TXE ((uint16_t) USART_IT_CR1 | 0x7) @@ -59,4 +60,4 @@ void usart_config_interrupt(struct usart_dev *usart, uint16_t it, uint8_t state); -#endif /* PLATFORM_STM32F1_USART_H_ */ +#endif /* PLATFORM_STM32F4_USART_H_ */ diff --git a/include/thread.h b/include/thread.h index 60ffce45..5f094e24 100644 --- a/include/thread.h +++ b/include/thread.h @@ -100,10 +100,11 @@ struct tcb { l4_thread_t t_globalid; /* 4 bytes (16-19) */ l4_thread_t t_localid; /* 4 bytes (20-23) */ + l4_thread_t t_pager; /* 4 bytes (24-27) */ - memptr_t stack_base; /* 4 bytes (24-27) */ - size_t stack_size; /* 4 bytes (28-31) */ - /* End of Cache Line 0 (32 bytes) */ + memptr_t stack_base; /* 4 bytes (28-31) */ + size_t stack_size; /* 4 bytes (32-35) */ + /* End of hot fields */ context_t ctx; @@ -171,6 +172,8 @@ struct tcb { * Allows IPC path to skip notification checks with single word read. */ uint8_t notify_pending; + uint8_t utcb_needs_sync; + uint8_t stack_canary_needs_init; uint8_t _notify_pad[1]; /* Alignment padding */ @@ -204,8 +207,11 @@ static inline void thread_init_canary(tcb_t *thr) /* Check stack canary. Returns 1 if valid, 0 if corrupted. */ static inline int thread_check_canary(tcb_t *thr) { - if (!thr->stack_base) - return 1; /* No stack tracking, skip check */ + /* Skip check if stack_base is NULL or unaligned (prevents UsageFault). + * User threads may have uninitialized/corrupted stack_base. + */ + if (!thr->stack_base || ((uint32_t) thr->stack_base & 0x3)) + return 1; return *((uint32_t *) thr->stack_base) == STACK_CANARY; } @@ -218,6 +224,7 @@ tcb_t *thread_create(l4_thread_t globalid, utcb_t *utcb); void thread_destroy(tcb_t *thr); void thread_space(tcb_t *thr, l4_thread_t spaceid, utcb_t *utcb); void thread_init_ctx(void *sp, void *pc, void *rx, tcb_t *thr); +void thread_init_prebuilt_ctx(void *sp, tcb_t *thr); void thread_init_kernel_ctx(void *sp, tcb_t *thr); void thread_switch(tcb_t *thr); diff --git a/kernel/Kconfig b/kernel/Kconfig index 4f8baa9b..9f3c2ac7 100644 --- a/kernel/Kconfig +++ b/kernel/Kconfig @@ -137,7 +137,6 @@ config KDB bool "Kdb: kernel debugger" default y select DEBUG - select DEBUG_DEV_UART config KPROBES bool "KProbes: dynamic instrumentation system" diff --git a/kernel/init.c b/kernel/init.c index 8d8e6af7..e4df5492 100644 --- a/kernel/init.c +++ b/kernel/init.c @@ -35,6 +35,41 @@ void hard_fault_handler(void) * preemption, then processor escalates the exception priority to * HardFault. */ + volatile uint32_t *cfsr = + (uint32_t *) 0xE000ED28; /* Configurable Fault Status */ + volatile uint32_t *hfsr = (uint32_t *) 0xE000ED2C; /* HardFault Status */ + volatile uint32_t *mmfar = + (uint32_t *) 0xE000ED34; /* MemManage Fault Address */ + volatile uint32_t *bfar = (uint32_t *) 0xE000ED38; /* BusFault Address */ + + /* Get faulting context from exception stack frame. + * EXC_RETURN bit 2 determines which stack pointer was active: + * bit 2 = 0: MSP (handler mode fault) + * bit 2 = 1: PSP (thread mode fault) + */ + uint32_t exc_lr; + __asm__ __volatile__("mov %0, lr" : "=r"(exc_lr)); + + uint32_t sp_val; + if (exc_lr & 0x4) { + __asm__ __volatile__("mrs %0, psp" : "=r"(sp_val)); + } else { + __asm__ __volatile__("mrs %0, msp" : "=r"(sp_val)); + } + uint32_t *frame = (uint32_t *) sp_val; + uint32_t fault_pc = frame[6]; + uint32_t fault_lr = frame[5]; + uint32_t fault_r12 = frame[4]; + uint16_t *inst = (uint16_t *) (fault_pc & ~1); + + dbg_printf(DL_KDB, "HARD FAULT: CFSR=%p HFSR=%p MMFAR=%p BFAR=%p\n", *cfsr, + *hfsr, *mmfar, *bfar); + dbg_printf(DL_KDB, "FAULT frame on %s: PC=%p LR=%p R12=%p inst=%04x\n", + (exc_lr & 0x4) ? "PSP" : "MSP", fault_pc, fault_lr, fault_r12, + inst[0]); + dbg_printf(DL_KDB, "FAULT R0=%p R1=%p R2=%p R3=%p\n", frame[0], frame[1], + frame[2], frame[3]); + panic("Kernel panic: Hard fault. Restarting\n"); } diff --git a/kernel/ipc.c b/kernel/ipc.c index 2cedec94..01c9a493 100644 --- a/kernel/ipc.c +++ b/kernel/ipc.c @@ -99,7 +99,6 @@ static inline void do_ipc_error(tcb_t *from, to->state = to_state; } - static void do_ipc(tcb_t *from, tcb_t *to) { ipc_typed_item typed_item; @@ -202,17 +201,6 @@ static void do_ipc(tcb_t *from, tcb_t *to) return; } - to->utcb->sender = from->t_globalid; - - /* Conditionally boost receiver priority for IPC fast path. - * Only boost if receiver was waiting for ANY message (ipc_from == - * ANYTHREAD). If waiting for a specific reply, skip boost - thread was just - * processing an IPC and will return to user code immediately after - * receiving reply. - * - * This prevents priority inversion where reply receivers accumulate - * priority 3 and starve lower-priority threads indefinitely. - */ /* Write receiver's R0 (sender ID) and UTCB sender BEFORE making runnable. * If enqueue happens first and scheduler runs preemptively, * receiver could see stale R0 value. @@ -326,7 +314,7 @@ uint32_t ipc_timeout(void *data) ktimer_event_t *event = (ktimer_event_t *) data; tcb_t *thr = (tcb_t *) event->data; - dbg_printf(DL_KDB, "IPC: timeout tid=%t st=%d\n", thr->t_globalid, + dbg_printf(DL_IPC, "IPC: timeout tid=%t st=%d\n", thr->t_globalid, thr->state); if (thr->timeout_event == (uint32_t) data) { @@ -354,7 +342,7 @@ static void sys_ipc_timeout(uint32_t timeout) kevent = ktimer_event_create(ticks, ipc_timeout, caller); - dbg_printf(DL_KDB, "IPC: sched timeout ticks=%d ev=%p\n", ticks, kevent); + dbg_printf(DL_IPC, "IPC: sched timeout ticks=%d ev=%p\n", ticks, kevent); caller->timeout_event = (uint32_t) kevent; } @@ -366,11 +354,11 @@ void sys_ipc(uint32_t *param1) l4_thread_t to_tid = param1[REG_R0], from_tid = param1[REG_R1]; uint32_t timeout = param1[REG_R2]; - dbg_printf(DL_KDB, "IPC: %t->%t from=%t timeout=%p\n", caller->t_globalid, + dbg_printf(DL_IPC, "IPC: %t->%t from=%t timeout=%p\n", caller->t_globalid, to_tid, from_tid, timeout); if (to_tid == L4_NILTHREAD && from_tid == L4_NILTHREAD) { - dbg_printf(DL_KDB, "IPC: sleep tid=%t timeout=%p\n", caller->t_globalid, + dbg_printf(DL_IPC, "IPC: sleep tid=%t timeout=%p\n", caller->t_globalid, timeout); caller->state = T_INACTIVE; if (timeout) @@ -395,18 +383,16 @@ void sys_ipc(uint32_t *param1) do_ipc(caller, to_thr); return; } else if (to_thr && to_thr->state == T_INACTIVE && to_thr->utcb && - GLOBALID_TO_TID(to_thr->utcb->t_pager) == + GLOBALID_TO_TID(to_thr->t_pager) == GLOBALID_TO_TID(caller->t_globalid)) { - dbg_printf(DL_KDB, - "IPC: INACTIVE thread %t accepted (pager match)\n", - to_tid); - uint32_t tag = ipc_read_mr(caller, 0); - dbg_printf(DL_KDB, "IPC: startup tag=%p\n", tag); - if (tag == 0x00000005) { - /* Thread start protocol from pager: - * mr1: thread_container (wrapper), mr2: sp, - * mr3: stack size, mr4: entry point, mr5: entry arg */ - + /* Read tag - should be 0x00000005 (u=5, t=0) for thread start */ + ipc_msg_tag_t tag_struct; + tag_struct.raw = ipc_read_mr(caller, 0); + + /* Thread start protocol: Tag must be 0x05 (u=5, t=0) + * MR1=container, MR2=sp, MR3=stack_size, MR4=entry, MR5=arg + * Other tags (like 0x80 for maps) go to the else branch below */ + if (tag_struct.s.n_untyped == 5 && tag_struct.s.n_typed == 0) { uint32_t mr1_container = ipc_read_mr(caller, 1); memptr_t sp = ipc_read_mr(caller, 2); size_t stack_size = ipc_read_mr(caller, 3); @@ -414,21 +400,10 @@ void sys_ipc(uint32_t *param1) uint32_t entry_arg = ipc_read_mr(caller, 5); uint32_t regs[4]; /* r0, r1, r2, r3 */ - dbg_printf(DL_KDB, - "IPC: start sp=%p size=%p entry=%p container=%p\n", - sp, stack_size, entry_point, mr1_container); - /* Security check: Ensure stack is in user-writable memory */ int pid = mempool_search(sp - stack_size, stack_size); mempool_t *mp = mempool_getbyid(pid); - - dbg_printf(DL_KDB, "IPC: mempool pid=%d mp=%p\n", pid, mp); - if (!mp || !(mp->flags & MP_UW)) { - dbg_printf( - DL_KDB, - "IPC: REJECT invalid stack for %t: %p (pool %s)\n", - to_tid, sp - stack_size, mp ? mp->name : "N/A"); user_ipc_error(caller, UE_IPC_ABORTED | UE_IPC_PHASE_SEND); thread_make_runnable(caller); return; @@ -436,32 +411,30 @@ void sys_ipc(uint32_t *param1) to_thr->stack_base = sp - stack_size; to_thr->stack_size = stack_size; - thread_init_canary(to_thr); - - dbg_printf(DL_KDB, "IPC: %t stack_base:%p stack_size:%p\n", - to_tid, to_thr->stack_base, to_thr->stack_size); + if (!caller || thread_ispriviliged(caller)) { + thread_init_canary(to_thr); + } else { + to_thr->stack_canary_needs_init = 1; + } regs[REG_R0] = (uint32_t) &kip; regs[REG_R1] = (uint32_t) to_thr->utcb; regs[REG_R2] = entry_point; /* Actual entry passed to container */ regs[REG_R3] = entry_arg; - - dbg_printf(DL_KDB, "IPC: calling thread_init_ctx\n"); - thread_init_ctx((void *) sp, (void *) mr1_container, regs, - to_thr); - dbg_printf(DL_KDB, "IPC: thread_init_ctx done\n"); - - dbg_printf(DL_KDB, "IPC: making caller %t runnable\n", - caller->t_globalid); + if (!caller || thread_ispriviliged(caller)) { + if (caller->as) + mpu_select_lru(caller->as, sp - RESERVED_STACK); + *((uint32_t *) (sp - RESERVED_STACK)) = 0; + thread_init_ctx((void *) sp, (void *) mr1_container, regs, + to_thr); + } else { + thread_init_prebuilt_ctx((void *) sp, to_thr); + } thread_make_runnable(caller); /* Start thread */ - dbg_printf(DL_KDB, "IPC: making to_thr %t runnable\n", - to_thr->t_globalid); thread_make_runnable(to_thr); - - dbg_printf(DL_KDB, "IPC: startup complete for %t\n", to_tid); return; } else { /* Non-start IPC to INACTIVE thread: process @@ -484,9 +457,6 @@ void sys_ipc(uint32_t *param1) return; } - dbg_printf(DL_IPC, "IPC: %t to INACTIVE %t (non-start)\n", - caller->t_globalid, to_thr->t_globalid); - /* Process typed items (MapItems only) */ for (int typed_idx = untyped_last; typed_idx < typed_last; ++typed_idx) { @@ -498,29 +468,18 @@ void sys_ipc(uint32_t *param1) } else if (typed_item.s.header & IPC_TI_MAP_GRANT) { memptr_t map_base = typed_item.raw & 0xFFFFFFC0; memptr_t map_size = mr_data & 0xFFFFFFC0; - int ret; /* S1 fix: reject unaligned addresses */ if (!addr_is_fpage_aligned(map_base)) { - dbg_printf( - DL_IPC, - "IPC: REJECT unaligned map to INACTIVE %p\n", - map_base); thread_make_runnable(caller); return; } - ret = map_area( + map_area( caller->as, to_thr->as, map_base, map_size, (typed_item.s.header & IPC_TI_GRANT) ? GRANT : MAP, thread_ispriviliged(caller)); typed_item_idx = -1; - - if (ret < 0) { - dbg_printf(DL_IPC, - "IPC: map to INACTIVE failed: %d\n", - ret); - } } } @@ -544,17 +503,9 @@ void sys_ipc(uint32_t *param1) if (to_thr->state == T_INACTIVE && !timeout) { /* T_INACTIVE thread with no timeout - would block forever */ - dbg_printf(DL_IPC, "IPC: %t send to INACTIVE %t (no timeout)\n", - caller->t_globalid, to_tid); - if (to_thr->utcb) { - dbg_printf( - DL_IPC, - "IPC: INACTIVE reject: caller=%t pager=%t utcb=%p\n", - caller->t_globalid, to_thr->utcb->t_pager, - to_thr->utcb); - } else { - dbg_printf(DL_IPC, "IPC: INACTIVE reject: utcb=NULL\n"); - } + dbg_printf(DL_IPC, + "IPC: %t send to INACTIVE %t rejected (utcb=%p)\n", + caller->t_globalid, to_tid, to_thr->utcb); user_ipc_error(caller, UE_IPC_ABORTED | UE_IPC_PHASE_SEND); thread_make_runnable(caller); return; diff --git a/kernel/memory.c b/kernel/memory.c index 544b8373..6b9d1800 100644 --- a/kernel/memory.c +++ b/kernel/memory.c @@ -57,7 +57,11 @@ static mempool_t memmap[] = { MPT_USER_TEXT), DECLARE_MEMPOOL_2("KIP", kip, - MP_KR | MP_KW | MP_UR | MP_SRAM, + /* Root UTCB lives in the KIP section and must remain + * writable from user mode even though the KIP payload + * itself is logically read-mostly. + */ + MP_KR | MP_KW | MP_UR | MP_UW | MP_SRAM, MPT_KERNEL_DATA), DECLARE_MEMPOOL("KDATA", &kip_end, @@ -78,7 +82,7 @@ static mempool_t memmap[] = { MPT_USER_DATA), DECLARE_MEMPOOL("MEM0", &mem0_start, - 0x2001c000, + 0x20018000, /* SRAM1 end: 96KB */ MP_UR | MP_UW | MP_SRAM, MPT_AVAILABLE), #ifdef CONFIG_BITMAP_BITBAND @@ -262,14 +266,7 @@ void memory_init() int j = 0; uint32_t *shcsr = (uint32_t *) 0xE000ED24; - /* Verify and set STKALIGN for 8-byte stack alignment on exceptions. - * This is critical for Cortex-M: misaligned stacks cause HardFault. - * STKALIGN (bit 9 of CCR) ensures automatic 8-byte alignment. - */ - if (!(*SCB_CCR & SCB_CCR_STKALIGN)) { - *SCB_CCR |= SCB_CCR_STKALIGN; - __ISB(); - } + /* CCR already configured in start.c main() */ fpages_init(); @@ -385,7 +382,7 @@ void as_setup_mpu(as_t *as, } /* Prevent link to stack pages */ - for (fp = as->mpu_first; i < 8 && fp; fp = fp->mpu_next) { + for (fp = as->mpu_first; i < 7 && fp; fp = fp->mpu_next) { for (j = 0; j < mpu_first_i; j++) { if (fp == mpu[j]) { break; @@ -421,6 +418,10 @@ void as_setup_mpu(as_t *as, for (; j < 8; ++j) { mpu_setup_region(j, NULL); } + + /* Memory barriers required after MPU configuration changes */ + __asm__ __volatile__("dsb" ::: "memory"); + __asm__ __volatile__("isb" ::: "memory"); } void as_map_user(as_t *as) diff --git a/kernel/start.c b/kernel/start.c index 5fdad2a5..e2cd3f75 100644 --- a/kernel/start.c +++ b/kernel/start.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -50,6 +51,17 @@ int main(void) *SCB_CPACR |= (SCB_CPACR_CP10_FULL | SCB_CPACR_CP11_FULL); #endif + /* Configure CCR early to prevent UsageFaults: + * - Enable 8-byte stack alignment (STKALIGN) + * - Disable unaligned access traps (clear UNALIGN_TRP for Cortex-M4) + */ + uint32_t ccr = *SCB_CCR; + ccr |= SCB_CCR_STKALIGN; /* Enable stack alignment */ + ccr &= ~SCB_CCR_UNALIGN_TRP; /* Allow unaligned access */ + *SCB_CCR = ccr; + __DSB(); + __ISB(); + run_init_hook(INIT_LEVEL_PLATFORM); __l4_printf("%s", banner); diff --git a/kernel/syscall.c b/kernel/syscall.c index b7dd45cc..237ceabd 100644 --- a/kernel/syscall.c +++ b/kernel/syscall.c @@ -241,7 +241,12 @@ static void sys_thread_control(uint32_t *param1, uint32_t *param2) return; } thread_space(thr, space, utcb); - thr->utcb->t_pager = pager; + thr->t_pager = pager; + if (!caller || thread_ispriviliged(caller)) { + thr->utcb->t_pager = pager; + } else { + thr->utcb_needs_sync = 1; + } param1[REG_R0] = 1; } else { /* Removal of thread */ @@ -551,7 +556,6 @@ void syscall_handler() sched_enqueue(caller); } else if (svc_num == SYS_IPC) { sys_ipc(svc_param1); - dbg_printf(DL_KDB, "SYSCALL: sys_ipc returned\n"); } else { dbg_printf(DL_SYSCALL, "SVC: %d called [%d, %d, %d, %d]\n", svc_num, svc_param1[REG_R0], svc_param1[REG_R1], svc_param1[REG_R2], diff --git a/kernel/systhread.c b/kernel/systhread.c index 6a556a49..0a803665 100644 --- a/kernel/systhread.c +++ b/kernel/systhread.c @@ -5,6 +5,7 @@ #include #include +#include #include #include #include @@ -19,6 +20,11 @@ tcb_t *idle; tcb_t *kernel; tcb_t *root; +#ifdef CONFIG_KDB +/* KDB notification bit - bit 30 reserved for KDB activation */ +#define KDB_NOTIFY_BIT (1UL << 30) +#endif + extern void root_thread(void); utcb_t root_utcb __KIP; @@ -114,6 +120,22 @@ void set_kernel_state(thread_state_t state) static void kernel_thread(void) { while (1) { +#ifdef CONFIG_KDB + /* Check for KDB activation notification from user space. + * KDB monitor thread posts KDB_NOTIFY_BIT via SYS_NOTIFY_POST + * when '?' key is pressed. Schedule KDB_SOFTIRQ to activate + * debugger. + */ + if (kernel->notify_bits & KDB_NOTIFY_BIT) { + /* Clear notification bit atomically */ + notification_clear(kernel, KDB_NOTIFY_BIT); + + /* Schedule KDB softirq to activate debugger */ + softirq_schedule(KDB_SOFTIRQ); + + dbg_printf(DL_KDB, "KDB: Activation requested via notification\n"); + } +#endif /* If all softirqs processed, call SVC to * switch context immediately */ diff --git a/kernel/thread.c b/kernel/thread.c index 8fe3a524..c6c09f1a 100644 --- a/kernel/thread.c +++ b/kernel/thread.c @@ -56,6 +56,7 @@ void *current_utcb __USER_DATA; /* KIP declarations */ static fpage_t *kip_fpage, *kip_extra_fpage; +static fpage_t *utext_fpage, *udata_fpage, *ubss_fpage; extern kip_t kip; extern char *kip_extra; @@ -87,6 +88,43 @@ void thread_init_subsys() "THREAD: Failed to create KIP extra fpage (addr=%p sz=%d ret=%d)\n", kip_extra, CONFIG_KIP_EXTRA_SIZE, ret); } + + /* Create fpages for shared user sections - needed by all user threads. + * These sections contain code and data common to all user programs. + */ + extern uint32_t user_text_start, user_text_end; + extern uint32_t user_data_start, user_data_end; + extern uint32_t user_bss_start, user_bss_end; + + struct { + memptr_t start; + memptr_t end; + fpage_t **fp; + const char *name; + } user_sections[] = { + {(memptr_t) &user_text_start, (memptr_t) &user_text_end, &utext_fpage, + "UTEXT"}, + {(memptr_t) &user_data_start, (memptr_t) &user_data_end, &udata_fpage, + "UDATA"}, + {(memptr_t) &user_bss_start, (memptr_t) &user_bss_end, &ubss_fpage, + "UBSS"}, + }; + + for (int s = 0; s < 3; ++s) { + size_t sz = user_sections[s].end - user_sections[s].start; + *user_sections[s].fp = NULL; + if (sz == 0) + continue; + last = NULL; + ret = assign_fpages_ext(-1, NULL, user_sections[s].start, sz, + user_sections[s].fp, &last); + if (ret < 0 || !*user_sections[s].fp) { + dbg_printf(DL_KDB, + "THREAD: Failed to create %s fpage (addr=%p sz=%d)\n", + user_sections[s].name, user_sections[s].start, sz); + *user_sections[s].fp = NULL; + } + } } INIT_HOOK(thread_init_subsys, INIT_LEVEL_KERNEL); @@ -94,32 +132,25 @@ INIT_HOOK(thread_init_subsys, INIT_LEVEL_KERNEL); extern tcb_t *caller; /* - * Return upper_bound using binary search + * Return the insertion point for @globalid in the sorted thread_map array. + * The @count argument is the current number of valid entries, so the search + * range is [0, count). */ -static int thread_map_search(l4_thread_t globalid, int from, int to) +static int thread_map_search(l4_thread_t globalid, int count) { int tid = GLOBALID_TO_TID(globalid); + int from = 0; + int to = count; - /* Upper bound if beginning of array */ - if (to == from || GLOBALID_TO_TID(thread_map[from]->t_globalid) >= tid) - return from; - - while (from <= to) { - if ((to - from) <= 1) - return to; - + while (from < to) { int mid = from + (to - from) / 2; - if (GLOBALID_TO_TID(thread_map[mid]->t_globalid) > tid) + if (GLOBALID_TO_TID(thread_map[mid]->t_globalid) >= tid) to = mid; - else if (GLOBALID_TO_TID(thread_map[mid]->t_globalid) < tid) - from = mid; else - return mid; + from = mid + 1; } - - /* not reached */ - return -1; + return from; } /* @@ -130,7 +161,7 @@ static void thread_map_insert(l4_thread_t globalid, tcb_t *thr) if (thread_count == 0) { thread_map[thread_count++] = thr; } else { - int i = thread_map_search(globalid, 0, thread_count); + int i = thread_map_search(globalid, thread_count); int j = thread_count; /* Move forward @@ -151,7 +182,7 @@ static void thread_map_delete(l4_thread_t globalid) if (thread_count == 1) { thread_count = 0; } else { - int i = thread_map_search(globalid, 0, thread_count); + int i = thread_map_search(globalid, thread_count); --thread_count; for (; i < thread_count; i++) thread_map[i] = thread_map[i + 1]; @@ -169,17 +200,21 @@ tcb_t *thread_init(l4_thread_t globalid, utcb_t *utcb) set_caller_error(UE_OUT_OF_MEM); return NULL; } - thread_map_insert(globalid, thr); thr->t_localid = 0x0; thr->t_child = NULL; thr->t_parent = NULL; thr->t_sibling = NULL; - thr->t_globalid = globalid; - if (utcb) + thr->t_pager = 0; + thr->stack_canary_needs_init = 0; + thr->utcb_needs_sync = 0; + if (utcb && (!caller || thread_ispriviliged(caller))) { utcb->t_globalid = globalid; + } else { + thr->utcb_needs_sync = utcb ? 1 : 0; + } thr->as = NULL; thr->utcb = utcb; @@ -217,12 +252,8 @@ tcb_t *thread_create(l4_thread_t globalid, utcb_t *utcb) assert((intptr_t) caller); - dbg_printf(DL_KDB, "THREAD_CREATE: gid=%p tid=%d utcb=%p\n", globalid, id, - utcb); - if (id < THREAD_SYS || globalid == L4_ANYTHREAD || globalid == L4_ANYLOCALTHREAD) { - dbg_printf(DL_KDB, "THREAD_CREATE: rejected (id=%d)\n", id); set_caller_error(UE_TC_NOT_AVAILABLE); return NULL; } @@ -233,9 +264,16 @@ tcb_t *thread_create(l4_thread_t globalid, utcb_t *utcb) /* Place under */ if (caller->t_child) { tcb_t *t = caller->t_child; + int guard = CONFIG_MAX_THREADS; - while (t->t_sibling != 0) + while (t->t_sibling != 0 && --guard > 0) t = t->t_sibling; + if (guard <= 0) { + dbg_printf(DL_KDB, + "THREAD_CREATE: child chain cycle caller=%t child=%p\n", + caller->t_globalid, caller->t_child); + return thr; + } t->t_sibling = thr; thr->t_localid = t->t_localid + (1 << 6); @@ -326,6 +364,13 @@ void thread_space(tcb_t *thr, l4_thread_t spaceid, utcb_t *utcb) thr->t_globalid); } + /* Shared user sections (UTEXT/UDATA/UBSS) are mapped by the root + * thread via map_user_sections() -> L4_Map IPC after ThreadControl. + * Do NOT map them here: map_fpage() only covers the first fpage of + * each chain, and the duplicate partial mappings waste MPU entries + * on the 8-region Cortex-M MPU. + */ + dbg_printf(DL_THREAD, "\tNew space: as: %p, utcb: %p \n", thr->as, utcb); } else { @@ -406,6 +451,25 @@ void thread_init_ctx(void *sp, void *pc, void *regs, tcb_t *thr) ((uint32_t *) sp)[REG_xPSR] = 0x1000000; /* Thumb bit on */ } +void thread_init_prebuilt_ctx(void *sp, tcb_t *thr) +{ + int i; + + sp -= RESERVED_STACK; + thr->ctx.sp = (uint32_t) sp; + + if (GLOBALID_TO_TID(thr->t_globalid) >= THREAD_ROOT) { + thr->ctx.ret = 0xFFFFFFFD; + thr->ctx.ctl = 0x3; + } else { + thr->ctx.ret = 0xFFFFFFF9; + thr->ctx.ctl = 0x0; + } + + for (i = 0; i < 8; i++) + thr->ctx.regs[i] = 0; +} + /* Kernel has no fake context, instead of that we rewind * stack and reuse it for kernel thread * @@ -435,10 +499,10 @@ void thread_init_kernel_ctx(void *sp, tcb_t *thr) */ tcb_t *thread_by_globalid(l4_thread_t globalid) { - int idx = thread_map_search(globalid, 0, thread_count); + int idx = thread_map_search(globalid, thread_count); - if (GLOBALID_TO_TID(thread_map[idx]->t_globalid) != - GLOBALID_TO_TID(globalid)) + if (idx >= thread_count || GLOBALID_TO_TID(thread_map[idx]->t_globalid) != + GLOBALID_TO_TID(globalid)) return NULL; return thread_map[idx]; } @@ -477,7 +541,12 @@ void thread_switch(tcb_t *thr) /* Check stack canary before switching to this thread. * If canary is corrupted, the thread's stack has overflowed. */ - if (!thread_check_canary(thr)) { + if (thr->stack_canary_needs_init) { + if (thr->as) + mpu_select_lru(thr->as, (uint32_t) thr->stack_base); + thread_init_canary(thr); + thr->stack_canary_needs_init = 0; + } else if (!thread_check_canary(thr)) { panic("Stack overflow: tid=%t, stack_base=%p, canary=%p\n", thr->t_globalid, thr->stack_base, thr->stack_base ? *((uint32_t *) thr->stack_base) : 0); @@ -489,6 +558,13 @@ void thread_switch(tcb_t *thr) as_setup_mpu(current->as, current->ctx.sp, ((uint32_t *) current->ctx.sp)[REG_PC], current->stack_base, current->stack_size); + if (current->utcb && current->utcb_needs_sync) { + if (current->as) + mpu_select_lru(current->as, (uint32_t) current->utcb); + current->utcb->t_globalid = current->t_globalid; + current->utcb->t_pager = current->t_pager; + current->utcb_needs_sync = 0; + } } /** diff --git a/mk/generic.mk b/mk/generic.mk index 1db3520f..f59ddb37 100644 --- a/mk/generic.mk +++ b/mk/generic.mk @@ -28,7 +28,7 @@ cmd_strip = $(STRIP) $< -o $@ cmd_elf_relink = $(LD) $(LDFLAGS) $(objs) $(symmap_obj-list) -o $@ \ -L platform -T $(CHIP)/$(F9_LD_FILE) $(LIBGCC) \ -Map $(out)/$*.map -cmd_c_to_o = $(CC) $(CFLAGS) -MMD -MF $@.d -c $< -o $@ +cmd_c_to_o = $(CC) $(CFLAGS) $(CFLAGS_KERNEL) -MMD -MF $@.d -c $< -o $@ cmd_c_to_o_user = $(CC) $(CFLAGS_INCLUDE_USER) $(CFLAGS) $(CFLAGS_USER) -MMD -MF $@.d -c $< -o $@ cmd_c_to_build = $(BUILDCC) $(BUILD_CFLAGS) $(BUILD_LDFLAGS) \ -MMD -MF $@.d $< -o $@ @@ -108,13 +108,19 @@ distclean: clean -rm -rf $(out_host) $(KCONFIG_DIR) -rm -f $(CONFIG) $(CONFIG).old include/autoconf.h -# QEMU emulation for netduinoplus2 +# QEMU emulation (auto-detects machine from BOARD) .PHONY: qemu qemu: $(out)/$(PROJECT).bin -killall -q qemu-system-arm - $(QEMU) -M netduinoplus2 -nographic -kernel $(out)/$(PROJECT).elf -serial mon:stdio +ifeq ($(BOARD),b-l475e-iot01a) + $(QEMU) -M b-l475e-iot01a -nographic -semihosting -serial mon:stdio -kernel $(out)/$(PROJECT).elf +else + @echo "Error: QEMU machine not defined for board '$(BOARD)'" + @echo "Supported boards: b-l475e-iot01a" + @exit 1 +endif -# QEMU with GDB debugging +# QEMU with GDB debugging (auto-detects machine from BOARD) # Terminal 1: make qemu-gdb # Terminal 2: make gdb-attach .PHONY: qemu-gdb @@ -123,7 +129,12 @@ qemu-gdb: $(out)/$(PROJECT).bin @echo "In another terminal, run: make gdb-attach" @echo "Press Ctrl+C to exit" -killall -q qemu-system-arm - $(QEMU) -M netduinoplus2 -nographic -kernel $(out)/$(PROJECT).elf -s -S +ifeq ($(BOARD),b-l475e-iot01a) + $(QEMU) -M b-l475e-iot01a -nographic -semihosting -serial mon:stdio -kernel $(out)/$(PROJECT).elf -s -S +else + @echo "Error: QEMU machine not defined for board '$(BOARD)'" + @exit 1 +endif .PHONY: gdb-attach gdb-attach: $(out)/$(PROJECT).elf diff --git a/mk/toolchain.mk b/mk/toolchain.mk index 7fd2231f..70ca5eb7 100644 --- a/mk/toolchain.mk +++ b/mk/toolchain.mk @@ -64,4 +64,4 @@ CFLAGS = \ LDFLAGS = \ --gc-sections -LIBGCC = $(shell $(CC) -print-libgcc-file-name) +LIBGCC = $(shell $(CC) $(CFLAGS_CPU) -print-libgcc-file-name) diff --git a/platform/Kconfig b/platform/Kconfig index 70f26035..938d6077 100644 --- a/platform/Kconfig +++ b/platform/Kconfig @@ -11,15 +11,10 @@ config BITMAP_BITBAND config FPU bool "Floating point support" default n - depends on !PLATFORM_STM32F1 - -config SEMIHOST - bool "Semihosting enable" - default n - depends on PLATFORM_STM32F1 choice prompt "Standard I/O device" + default STDIO_SEMIHOSTING if QEMU default STDIO_USE_DBGPORT help Select input/output device for stdio @@ -31,6 +26,16 @@ config STDIO_USE_DBGPORT bool "Debug serial IO" select DEBUG +config STDIO_SEMIHOSTING + bool "ARM Semihosting (QEMU/Debugger)" + help + Use ARM semihosting for console I/O via debugger interface. + + QEMU: Requires -semihosting flag (fast, reliable) + Real hardware: Requires active debugger (OpenOCD/J-Link/pyOCD) + VERY SLOW - only for debugging + Will CRASH if no debugger attached! + endchoice choice @@ -55,8 +60,8 @@ endif if PLATFORM_STM32F429 source "platform/stm32f429/Kconfig" endif -if PLATFORM_STM32F1 -source "platform/stm32f1/Kconfig" +if PLATFORM_STM32L4 +source "platform/stm32l4/Kconfig" endif endmenu diff --git a/platform/Kconfig.debug b/platform/Kconfig.debug index f48df1fb..45df2f00 100644 --- a/platform/Kconfig.debug +++ b/platform/Kconfig.debug @@ -3,18 +3,49 @@ # found in the LICENSE file. if DEBUG + +choice + prompt "Debug device" + default DEBUG_DEV_SEMIHOSTING if STDIO_SEMIHOSTING + default DEBUG_DEV_UART + help + Select debug output device for KDB and panic messages + config DEBUG_DEV_UART bool "UART based implementation" - default y + depends on STDIO_USE_DBGPORT help - At present, it is the only device for KDB use. + Use UART for debug output (KDB, panic messages). + Requires STDIO_USE_DBGPORT to be enabled. + +config DEBUG_DEV_SEMIHOSTING + bool "ARM Semihosting" + depends on STDIO_SEMIHOSTING + help + Use ARM semihosting for debug output (KDB, panic messages). + Only works with QEMU or active debugger connection. -if !KDB config DEBUG_DEV_RAM bool "RAM based virtual device" - default n + depends on !KDB help - A simple implementation of RAM base virtual debug device -endif + A simple implementation of RAM based virtual debug device. + Not compatible with KDB. + +endchoice + +config KDB_UART_INPUT + bool "UART input for KDB (QEMU semihosting mode)" + depends on KDB && DEBUG_DEV_SEMIHOSTING && QEMU + default y if KDB && DEBUG_DEV_SEMIHOSTING && QEMU + help + Enable USART1 receive interrupt for KDB interactive input while + using semihosting for debug output. Pressing '?' activates KDB. + + This is QEMU-specific: it hard-codes BRR for the 4 MHz MSI + fallback clock and skips normal GPIO/USART board init. + Do NOT enable on real hardware. + + Requires QEMU: -serial mon:stdio -semihosting endif diff --git a/platform/build.mk b/platform/build.mk index b2fdc77b..2146c192 100644 --- a/platform/build.mk +++ b/platform/build.mk @@ -6,16 +6,22 @@ CFLAGS_FPU-$(CONFIG_FPU) = -mfpu=fpv4-sp-d16 -mfloat-abi=hard # CPU specific compilation flags -ifeq (STM32_VARIANT,f1) -CFLAGS_CPU = -mlittle-endian -mcpu=cortex-m3 -else +# All supported boards use Cortex-M4 (STM32F4, STM32F429, STM32L4) CFLAGS_CPU = -mlittle-endian -mcpu=cortex-m4 -endif CFLAGS_CPU += -mthumb -mthumb-interwork -Xassembler -mimplicit-it=thumb CFLAGS_CPU += -mno-sched-prolog -mno-unaligned-access CFLAGS_CPU += -Wdouble-promotion -fsingle-precision-constant CFLAGS_CPU += $(CFLAGS_FPU-y) +# Prevent compiler from emitting FPU instructions in kernel code. +# GCC with -mfloat-abi=hard may use VFP for non-FP ops (e.g., vldr/vstr +# to zero a long long). This sets CONTROL.FPCA in handler mode, changing +# exception frames from 8 to 26 words and corrupting context switches. +# -mgeneral-regs-only does NOT change the ABI -- it only restricts which +# registers the compiler uses for code generation. Links fine with hard-float. +CFLAGS_KERNEL-$(CONFIG_FPU) = -mgeneral-regs-only +CFLAGS_KERNEL = $(CFLAGS_KERNEL-y) + platform-y = \ bitops.o \ debug_device.o \ @@ -25,7 +31,10 @@ platform-y = \ irq-latency.o platform-$(CONFIG_DEBUG_DEV_UART) += debug_uart.o +platform-$(CONFIG_DEBUG_DEV_SEMIHOSTING) += debug_semihosting.o +platform-$(CONFIG_KDB_UART_INPUT) += kdb_uart.o platform-$(CONFIG_DEBUG_DEV_RAM) += debug_ram.o +platform-$(CONFIG_STDIO_SEMIHOSTING) += semihosting.o platform-KPROBES-$(CONFIG_KPROBES) = \ kprobes-arch.o \ diff --git a/platform/debug_device.c b/platform/debug_device.c index 73e05902..681d0a51 100644 --- a/platform/debug_device.c +++ b/platform/debug_device.c @@ -12,13 +12,16 @@ #ifdef CONFIG_DEBUG_DEV_UART #include #endif +#ifdef CONFIG_DEBUG_DEV_SEMIHOSTING +#include +#endif #ifdef CONFIG_DEBUG_DEV_RAM #include #endif #ifdef DEBUG_DEVICE_EXIST static dbg_dev_t dbg_dev[DBG_DEV_MAX]; -static dbg_dev_t *cur_dev = &dbg_dev[0]; +dbg_dev_t *cur_dev = &dbg_dev[0]; static uint8_t default_getchar(void) { @@ -27,11 +30,14 @@ static uint8_t default_getchar(void) static void default_putchar(uint8_t chr) { - chr = 0; + (void) chr; } static void default_start_panic(void) {} +/* Debug output state: async (buffered) or panic (synchronous) */ +enum { DBG_ASYNC, DBG_PANIC } dbg_state = DBG_ASYNC; + /* * Receive a character from debug port */ @@ -45,7 +51,13 @@ uint8_t dbg_getchar(void) */ void dbg_putchar(uint8_t chr) { +#ifdef CONFIG_DEBUG_DEV_SEMIHOSTING + /* Semihosting: call directly to avoid device layer complexity */ + extern void semihosting_putc(uint8_t c); + semihosting_putc(chr); +#else (*cur_dev->putchar)(chr); +#endif } /* @@ -78,6 +90,16 @@ static void dbg_device_init(void) dbg_uart_init(); #endif +#ifdef CONFIG_DEBUG_DEV_SEMIHOSTING + dbg_semihosting_init(); +#endif + +#ifdef CONFIG_KDB_UART_INPUT + /* UART RX for KDB input alongside semihosting output */ + extern void kdb_uart_input_init(void); + kdb_uart_input_init(); +#endif + #ifdef CONFIG_DEBUG_DEV_RAM dbg_ram_init(); #endif @@ -124,7 +146,7 @@ uint8_t dbg_getchar(void) void dbg_putchar(uint8_t chr) { - chr = 0; + (void) chr; } void dbg_start_panic(void) {} diff --git a/platform/debug_semihosting.c b/platform/debug_semihosting.c new file mode 100644 index 00000000..c8ffdd0f --- /dev/null +++ b/platform/debug_semihosting.c @@ -0,0 +1,53 @@ +/* Copyright (c) 2013 The F9 Microkernel Project. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include +#include +#include + +/* ARM Semihosting operation numbers */ +#define SYS_WRITEC 0x03 +#define SYS_WRITE0 0x04 +#define SYS_READC 0x07 + +/* Debug state: async (buffered) or panic (synchronous) */ +extern enum { DBG_ASYNC, DBG_PANIC } dbg_state; + +static inline long semihosting_call(int reason, void *arg) +{ + register long r0 asm("r0") = reason; + register void *r1 asm("r1") = arg; + asm volatile("bkpt #0xAB" : "=r"(r0) : "0"(r0), "r"(r1) : "memory"); + return r0; +} + +static uint8_t dbg_semihosting_getchar(void) +{ + /* Blocking read via semihosting */ + return (uint8_t) semihosting_call(SYS_READC, NULL); +} + +static void dbg_semihosting_putchar(uint8_t c) +{ + semihosting_call(SYS_WRITEC, &c); +} + +static void dbg_semihosting_start_panic(void) +{ + /* Set panic state to prevent interactive prompts in KDB */ + dbg_state = DBG_PANIC; +} + +void dbg_semihosting_init(void) +{ + dbg_dev_t device = { + .dev_id = DBG_DEV_SEMIHOSTING, + .getchar = dbg_semihosting_getchar, + .putchar = dbg_semihosting_putchar, + .start_panic = dbg_semihosting_start_panic, + }; + + dbg_register_device(&device); +} diff --git a/platform/debug_uart.c b/platform/debug_uart.c index c4184049..e40f45cf 100644 --- a/platform/debug_uart.c +++ b/platform/debug_uart.c @@ -19,7 +19,7 @@ static struct dbg_uart_t dbg_uart; static uint8_t dbg_uart_tx_buffer[SEND_BUFSIZE]; static uint8_t dbg_uart_rx_buffer[RECV_BUFSIZE]; -enum { DBG_ASYNC, DBG_PANIC } dbg_state; +extern enum { DBG_ASYNC, DBG_PANIC } dbg_state; static void dbg_uart_recv(void); static void dbg_uart_send(int avail); diff --git a/platform/kdb_uart.c b/platform/kdb_uart.c new file mode 100644 index 00000000..f9ab482f --- /dev/null +++ b/platform/kdb_uart.c @@ -0,0 +1,88 @@ +/* KDB UART input driver for semihosting configurations. + * + * Enables USART1 RX interrupt for KDB interactive input while semihosting + * handles debug output. Pressing '?' activates KDB under QEMU. + * + * Uses QEMU's USART1 emulation directly -- minimal init (no GPIO/RCC + * needed since QEMU pre-initializes the USART hardware model). + * Requires: qemu-system-arm -serial mon:stdio -semihosting + */ + +#ifdef CONFIG_KDB_UART_INPUT + +#include +#include +#include +#include + +#include "board.h" +#include INC_PLAT(registers.h) + +/* STM32L4 USART1 register access using platform USART1_BASE. + * Register layout: L4 uses CR1(+0x00)/BRR(+0x0C)/ISR(+0x1C)/RDR(+0x24) + */ +#define KDB_USART1_CR1 (*(volatile uint32_t *) (USART1_BASE + 0x00)) +#define KDB_USART1_BRR (*(volatile uint32_t *) (USART1_BASE + 0x0C)) +#define KDB_USART1_ISR (*(volatile uint32_t *) (USART1_BASE + 0x1C)) +#define KDB_USART1_RDR (*(volatile uint32_t *) (USART1_BASE + 0x24)) + +#define KDB_USART_ISR_RXNE (1 << 5) +#define KDB_USART_CR1_UE (1 << 0) +#define KDB_USART_CR1_RE (1 << 2) +#define KDB_USART_CR1_RXNEIE (1 << 5) + +/* Simple circular buffer for received characters */ +#define KDB_RX_BUFSIZE 16 +static volatile uint8_t kdb_rx_buf[KDB_RX_BUFSIZE]; +static volatile uint8_t kdb_rx_head, kdb_rx_tail; + +void __kdb_uart_irq_handler(void) +{ + if (KDB_USART1_ISR & KDB_USART_ISR_RXNE) { + uint8_t chr = (uint8_t) KDB_USART1_RDR; + uint8_t next = (kdb_rx_head + 1) % KDB_RX_BUFSIZE; + if (next != kdb_rx_tail) { + kdb_rx_buf[kdb_rx_head] = chr; + kdb_rx_head = next; + } + softirq_schedule(KDB_SOFTIRQ); + } +} + +IRQ_HANDLER(BOARD_UART_HANDLER, __kdb_uart_irq_handler); + +static uint8_t kdb_uart_getchar(void) +{ + if (kdb_rx_head == kdb_rx_tail) + return 0; + uint8_t chr = kdb_rx_buf[kdb_rx_tail]; + kdb_rx_tail = (kdb_rx_tail + 1) % KDB_RX_BUFSIZE; + return chr; +} + +void kdb_uart_input_init(void) +{ + kdb_rx_head = 0; + kdb_rx_tail = 0; + + /* Enable USART1 peripheral clock on APB2 before touching registers. + * sys_clock_init() resets APB enables, so we must re-enable here. + */ + *(volatile uint32_t *) RCC_APB2ENR |= RCC_APB2ENR_USART1EN; + + /* Minimal USART1 init: baud rate, receiver, RX interrupt */ + KDB_USART1_BRR = 35; /* ~115200 baud at 4MHz MSI (4000000/115200) */ + KDB_USART1_CR1 = KDB_USART_CR1_UE | KDB_USART_CR1_RE | KDB_USART_CR1_RXNEIE; + + NVIC_SetPriority(BOARD_UART_DEVICE, 0xe, 0); + NVIC_ClearPendingIRQ(BOARD_UART_DEVICE); + NVIC_EnableIRQ(BOARD_UART_DEVICE); + + /* Override semihosting getchar with UART RX reader. + * Output (putchar) remains on semihosting. + */ + extern dbg_dev_t *cur_dev; + cur_dev->getchar = kdb_uart_getchar; +} + +#endif /* CONFIG_KDB_UART_INPUT */ diff --git a/platform/semihosting.c b/platform/semihosting.c new file mode 100644 index 00000000..fc78e5b6 --- /dev/null +++ b/platform/semihosting.c @@ -0,0 +1,72 @@ +/* Copyright (c) 2013 The F9 Microkernel Project. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +/* ARM Semihosting support for QEMU console I/O */ + +#include +#include + +/* ARM Semihosting operation numbers */ +#define SYS_WRITEC 0x03 /* Write one character to debug channel */ +#define SYS_WRITE0 0x04 /* Write null-terminated string */ +#define SYS_READ 0x06 /* Read from file/console */ +#define SYS_READC 0x07 /* Read one character from debug channel */ +#define SYS_ISTTY 0x09 /* Check if file descriptor is a TTY */ + +/* File handles for semihosting */ +#define STDIN_FILENO 0 + +/* + * Perform ARM semihosting call + * For Cortex-M: Uses BKPT #0xAB instruction + */ +static inline long semihosting_call(int reason, void *arg) +{ + register long r0 asm("r0") = reason; + register void *r1 asm("r1") = arg; + + asm volatile("bkpt #0xAB" : "=r"(r0) : "0"(r0), "r"(r1) : "memory"); + + return r0; +} + +/* + * Write one character via semihosting + */ +void semihosting_putc(uint8_t c) +{ + semihosting_call(SYS_WRITEC, &c); +} + +/* + * Read one character via semihosting (blocking) + */ +uint8_t semihosting_getc(void) +{ + return (uint8_t) semihosting_call(SYS_READC, NULL); +} + +/* + * Write null-terminated string via semihosting + */ +void semihosting_puts(const char *str) +{ + semihosting_call(SYS_WRITE0, (void *) str); +} + +#ifdef CONFIG_STDIO_SEMIHOSTING +/* Kernel-space __l4_putchar/__l4_getchar for kernel printf. + * User-space printf() uses IPC to THREAD_LOG, not __l4_putchar. + */ +void __l4_putchar(uint8_t chr) +{ + semihosting_putc(chr); +} + +uint8_t __l4_getchar(void) +{ + return semihosting_getc(); +} +#endif /* CONFIG_STDIO_SEMIHOSTING */ diff --git a/platform/stm32-common/build.mk b/platform/stm32-common/build.mk index 6ff39a4d..2eb842cb 100644 --- a/platform/stm32-common/build.mk +++ b/platform/stm32-common/build.mk @@ -8,5 +8,6 @@ platform-common-y = \ mpu.o \ nvic.o \ systick.o \ - hwtimer.o \ - usart.o + hwtimer.o + +platform-common-$(CONFIG_DEBUG_DEV_UART) += usart.o diff --git a/platform/stm32-common/gpio-f1.c b/platform/stm32-common/gpio-f1.c deleted file mode 100644 index d2962602..00000000 --- a/platform/stm32-common/gpio-f1.c +++ /dev/null @@ -1,106 +0,0 @@ -/* Copyright (c) 2014 The F9 Microkernel Project. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include INC_PLAT(gpio.h) -#include - -#include INC_PLAT(gpio.c) - -inline static void gpio_cr(uint8_t port, - uint8_t pin, - uint8_t mode, - uint8_t ospeed) -{ - uint32_t reg; - if (pin < 8) { - reg = *GPIO_CRL(port); - reg &= ~(GPIO_CR_M(pin)); - reg |= (((mode << 2) | ospeed) << GPIO_CR_PIN(pin)); - *GPIO_CRL(port) = reg; - } else { - reg = *GPIO_CRH(port); - reg &= ~(GPIO_CR_M(pin)); - reg |= (((mode << 2) | ospeed) << GPIO_CR_PIN((pin - 8))); - *GPIO_CRH(port) = reg; - } -} - -void __USER_TEXT gpio_config(struct gpio_cfg *cfg) -{ - uint8_t port, pin, cfg_data; - - port = cfg->port; - pin = cfg->pin; - - *RCC_APB2ENR |= (1 << (port + 2)); - - /* Mode and speed */ - gpio_cr(port, pin, cfg->mode, cfg->ospeed); - - cfg_data = cfg->mode; - /* Input Push up or push down */ - if ((((uint32_t) cfg_data) & ((uint32_t) 0x10)) != 0x00) { - if (cfg_data == GPIO_MODE_IN_PD) - *GPIO_BRR(port) = GPIO_BRR_BR(pin); - else if (cfg_data == GPIO_MODE_IN_PU) - *GPIO_BSRR(port) = GPIO_BSRR_BS(pin); - return; - } -} - -void __USER_TEXT gpio_config_output(uint8_t port, - uint8_t pin, - uint8_t mode, - uint8_t ospeed) -{ - struct gpio_cfg cfg = { - .port = port, - .pin = pin, - .mode = mode, - .ospeed = ospeed, - .func = 0, - }; - - gpio_config(&cfg); -} - -void __USER_TEXT gpio_config_input(uint8_t port, uint8_t pin, uint8_t mode) -{ - struct gpio_cfg cfg = { - .port = port, - .pin = pin, - .mode = mode, - .ospeed = 0, - .func = 0, - }; - - gpio_config(&cfg); -} - -void __USER_TEXT gpio_out_high(uint8_t port, uint8_t pin) -{ - *GPIO_ODR(port) |= GPIO_ODR_PIN(pin); -} - -void __USER_TEXT gpio_out_low(uint8_t port, uint8_t pin) -{ - *GPIO_ODR(port) &= ~GPIO_ODR_PIN(pin); -} - -uint8_t __USER_TEXT gpio_input_bit(uint8_t port, uint8_t pin) -{ - if (*GPIO_IDR(port) & GPIO_IDR_PIN(pin)) - return 1; - - return 0; -} - -void __USER_TEXT gpio_writebit(uint8_t port, uint8_t pin, uint8_t bitval) -{ - if (bitval != 0) - *GPIO_BSRR(port) = GPIO_BSRR_BS(pin); - else - *GPIO_BSRR(port) = GPIO_BSRR_BR(pin); -} diff --git a/platform/stm32-common/gpio-l4.c b/platform/stm32-common/gpio-l4.c new file mode 100644 index 00000000..83e7bf17 --- /dev/null +++ b/platform/stm32-common/gpio-l4.c @@ -0,0 +1,167 @@ +/* Copyright (c) 2014 The F9 Microkernel Project. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include INC_PLAT(gpio.h) +#include + +#include INC_PLAT(gpio.c) + +inline static void gpio_moder(uint8_t port, uint8_t pin, uint8_t type) +{ + uint32_t reg = *GPIO_MODER(port); + + reg &= ~(GPIO_MODER_M(pin)); + reg |= (type << GPIO_MODER_PIN(pin)); + + *GPIO_MODER(port) = reg; +} + +inline static void gpio_otyper(uint8_t port, uint8_t pin, uint8_t type) +{ + uint32_t reg = *GPIO_OTYPER(port); + + reg &= ~(GPIO_OTYPER_M(pin)); + reg |= (type << GPIO_OTYPER_PIN(pin)); + + *GPIO_OTYPER(port) = reg; +} + +inline static void gpio_ospeedr(uint8_t port, uint8_t pin, uint8_t speed) +{ + uint32_t reg = *GPIO_OSPEEDR(port); + + reg &= ~(GPIO_OSPEEDR_M(pin)); + reg |= (speed << GPIO_OSPEEDR_PIN(pin)); + + *GPIO_OSPEEDR(port) = reg; +} + +inline static void gpio_pupdr(uint8_t port, uint8_t pin, uint8_t mode) +{ + uint32_t reg = *GPIO_PUPDR(port); + + reg &= ~(GPIO_PUPDR_M(pin)); + reg |= (mode << GPIO_PUPDR_PIN(pin)); + + *GPIO_PUPDR(port) = reg; +} + +inline static void gpio_afr(uint8_t port, uint8_t pin, uint8_t func) +{ + uint32_t reg; + + if (pin < 8) { + reg = *GPIO_AFRL(port); + reg &= ~(GPIO_AFRL_M(pin)); + reg |= (func << GPIO_AFRL_PIN(pin)); + *GPIO_AFRL(port) = reg; + } else { + reg = *GPIO_AFRH(port); + reg &= ~(GPIO_AFRH_M(pin)); + reg |= (func << GPIO_AFRH_PIN(pin)); + *GPIO_AFRH(port) = reg; + } +} + +void __USER_TEXT gpio_config(struct gpio_cfg *cfg) +{ + uint8_t port, pin, cfg_data; + + port = cfg->port; + pin = cfg->pin; + + /* STM32L4: GPIO clocks are on AHB2, not AHB1 */ + *RCC_AHB2ENR |= (1 << port); + + /* pupd */ + cfg_data = cfg->pupd; + gpio_pupdr(port, pin, cfg_data); + + /* mode type */ + cfg_data = cfg->type; + gpio_moder(port, pin, cfg_data); + + if (cfg_data == GPIO_MODER_IN) + return; + + /* Alternative function */ + if (cfg_data == GPIO_MODER_ALT) { + uint8_t func = cfg->func; + gpio_afr(port, pin, func); + } + + /* Sets pin output type */ + cfg_data = cfg->o_type; + gpio_otyper(port, pin, cfg_data); + + /* Speed */ + cfg_data = cfg->speed; + gpio_ospeedr(port, pin, cfg_data); +} + +void __USER_TEXT gpio_config_output(uint8_t port, + uint8_t pin, + uint8_t pupd, + uint8_t speed) +{ + struct gpio_cfg cfg = { + .port = port, + .pin = pin, + .pupd = pupd, + .type = GPIO_MODER_OUT, + .func = 0, + .o_type = GPIO_OTYPER_PP, + .pupd = pupd, + .speed = speed, + }; + + /* STM32L4: GPIO clocks are on AHB2, not AHB1 */ + *RCC_AHB2ENR |= (1 << port); + gpio_config(&cfg); +} + +void __USER_TEXT gpio_config_input(uint8_t port, uint8_t pin, uint8_t pupd) +{ + struct gpio_cfg cfg = { + .port = port, + .pin = pin, + .pupd = pupd, + .type = GPIO_MODER_IN, + .func = 0, + .o_type = 0, + .pupd = pupd, + .speed = 0, + }; + + /* STM32L4: GPIO clocks are on AHB2, not AHB1 */ + *RCC_AHB2ENR |= (1 << port); + gpio_config(&cfg); +} + +void __USER_TEXT gpio_out_high(uint8_t port, uint8_t pin) +{ + *GPIO_BSRR(port) = (1 << pin); +} + +void __USER_TEXT gpio_out_low(uint8_t port, uint8_t pin) +{ + *GPIO_BSRR(port) = (1 << (pin + 16)); +} + +uint8_t __USER_TEXT gpio_input_bit(uint8_t port, uint8_t pin) +{ + if (*GPIO_IDR(port) & (1 << pin)) + return 1; + + return 0; +} + +void __USER_TEXT gpio_writebit(uint8_t port, uint8_t pin, uint8_t bitval) +{ + if (bitval != 0) + *GPIO_BSRR(port) = GPIO_BSRR_BS(pin); + else + *GPIO_BSRR(port) = GPIO_BSRR_BR(pin); +} diff --git a/platform/stm32-common/mpu.c b/platform/stm32-common/mpu.c index 7d808c65..b2ca153b 100644 --- a/platform/stm32-common/mpu.c +++ b/platform/stm32-common/mpu.c @@ -13,18 +13,38 @@ #include INC_PLAT(mpu.c) +static uint32_t mpu_access_bits(const mempool_t *mp) +{ + uint32_t user_rw = mp->flags & (MP_UR | MP_UW); + + switch (user_rw) { + case MP_UR | MP_UW: + return MPU_RASR_AP_PRIV_RW_UN_RW; + case MP_UR: + return MPU_RASR_AP_PRIV_RW_UN_RO; + case 0: + return MPU_RASR_AP_PRIV_RW_UN_NO; + default: + /* Write-only is not representable on Cortex-M MPU. Keep it privileged + * only rather than accidentally granting user writes. + */ + return MPU_RASR_AP_PRIV_RW_UN_NO; + } +} + void mpu_setup_region(int n, fpage_t *fp) { static uint32_t *mpu_base = (uint32_t *) MPU_BASE_ADDR; static uint32_t *mpu_attr = (uint32_t *) MPU_ATTR_ADDR; if (fp) { + mempool_t *mp = mempool_getbyid(fp->fpage.mpid); + uint32_t xn_bit = (mp->flags & MP_UX) ? 0 : (1 << 28); + uint32_t ap_bits = mpu_access_bits(mp); + *mpu_base = (FPAGE_BASE(fp) & MPU_REGION_MASK) | 0x10 | (n & 0xF); - *mpu_attr = ((mempool_getbyid(fp->fpage.mpid)->flags & MP_UX) - ? 0 - : (1 << 28)) | /* XN bit */ - (0x3 << 24) /* Full access */ - | ((fp->fpage.shift - 1) << 1) /* Region size*/ | + *mpu_attr = xn_bit | ap_bits | + ((fp->fpage.shift - 1) << 1) /* Region size*/ | 1 /* Enable */; } else { /* Clean MPU region */ @@ -97,7 +117,6 @@ int mpu_select_lru(as_t *as, uint32_t addr) ++i; sfp = sfp->mpu_next; } - /* Update MPU */ mpu_setup_region(i++, fp); diff --git a/platform/stm32-common/rcc.c b/platform/stm32-common/rcc.c index c0f8038f..fa9f9dea 100644 --- a/platform/stm32-common/rcc.c +++ b/platform/stm32-common/rcc.c @@ -16,6 +16,16 @@ #define PLL_P 2 /*!< SYSCLK = PLL_VCO / PLL_P */ #define PLL_Q 7 /*!< USB OTG FS, SDIO and RNG Clock = PLL_VCO / PLLQ */ +static __USER_DATA uint8_t APBAHBPrescTable[16] = {0, 0, 0, 0, 1, 2, 3, 4, + 1, 2, 3, 4, 6, 7, 8, 9}; +#elif defined(STM32L4X) +/* L4 uses different PLL architecture: MSI-based clock tree */ +#define PLL_M 1 /*!< Input divider (MSI 4MHz / 1 = 4MHz) */ +#define PLL_N 40 /*!< Multiplier (4MHz * 40 = 160MHz VCO) */ +#define PLL_P 7 /*!< SAI clock divider */ +#define PLL_Q 2 /*!< USB/RNG/SDMMC clock */ +#define PLL_R 2 /*!< System clock divider (160MHz / 2 = 80MHz SYSCLK) */ + static __USER_DATA uint8_t APBAHBPrescTable[16] = {0, 0, 0, 0, 1, 2, 3, 4, 1, 2, 3, 4, 6, 7, 8, 9}; #elif defined(STM32F1X) @@ -30,7 +40,7 @@ void sys_clock_init(void) { volatile uint32_t startup_count, HSE_status; -#if defined(STM32F4X) && defined(CONFIG_FPU) +#if (defined(STM32F4X) || defined(STM32L4X)) && defined(CONFIG_FPU) /* Enable the FPU */ *SCB_CPACR |= (0xf << 20); /* Enable floating point state preservation */ @@ -52,6 +62,10 @@ void sys_clock_init(void) #if defined(STM32F4X) /* Reset PLLCFGR register */ *RCC_PLLCFGR = 0x24003010; +#elif defined(STM32L4X) + /* Reset PLLCFGR register (L4 default value) */ + *RCC_PLLCFGR = 0x00001000; + *RCC_CFGR &= (uint32_t) 0xFF80FFFF; #elif defined(STM32F1X) *RCC_CFGR &= (uint32_t) 0xFF80FFFF; #endif @@ -59,8 +73,9 @@ void sys_clock_init(void) *RCC_CR &= (uint32_t) 0xFFFBFFFF; /* Disable all interrupts */ -#if defined(STM32F4X) +#if defined(STM32F4X) || defined(STM32L4X) *RCC_CIR = 0x00000000; + *RCC_CIR = 0x009F0000; #elif defined(STM32F1X) *RCC_CIR = 0x009F0000; #endif @@ -90,6 +105,9 @@ void sys_clock_init(void) *RCC_APB1ENR |= RCC_APB1ENR_PWREN; #if defined(STM32F4X) *PWR_CR |= PWR_CR_VOS; +#elif defined(STM32L4X) + /* L4: Voltage scaling range 1 for 80MHz operation */ + *PWR_CR |= PWR_CR_VOS; #endif /* HCLK = SYSCLK / 1 */ *RCC_CFGR |= RCC_CFGR_HPRE_DIV1; @@ -105,15 +123,30 @@ void sys_clock_init(void) /* PLL Options - See RM0090 Reference Manual pg. 95 */ *RCC_PLLCFGR = PLL_M | (PLL_N << 6) | (((PLL_P >> 1) - 1) << 16) | (RCC_PLLCFGR_PLLSRC_HSE) | (PLL_Q << 24); +#elif defined(STM32L4X) + /* L4 PLL: MSI (4MHz) * N/M/R = 4*40/1/2 = 80MHz + * PLLSRC=MSI matches the PLL_M/N/R constants defined above. + */ + *RCC_PLLCFGR = ((PLL_M - 1) << 4) | (PLL_N << 8) | + (RCC_PLLCFGR_PLLSRC_MSI) | (((PLL_R >> 1) - 1) << 25) | + (1 << 24); /* Enable PLLR output for system clock */ #elif defined(STM32F1X) *RCC_CFGR |= PLL_MUL << 18; #endif /* Enable the main PLL */ *RCC_CR |= RCC_CR_PLLON; - /* Wait till the main PLL is ready */ - while ((*RCC_CR & RCC_CR_PLLRDY) == 0) - /* wait */; + /* Wait till the main PLL is ready (with timeout) */ + volatile uint32_t pll_timeout = 0x100000; + while (((*RCC_CR & RCC_CR_PLLRDY) == 0) && (pll_timeout > 0)) { + pll_timeout--; + } + + /* If PLL failed to lock, fall back to HSI/MSI */ + if (pll_timeout == 0) { + *RCC_CR &= ~RCC_CR_PLLON; + goto fallback_clock; + } /* Configure Flash prefetch, Instruction cache, * Data cache and wait state @@ -124,6 +157,9 @@ void sys_clock_init(void) #endif #if defined(STM32F4X) *FLASH_ACR = FLASH_ACR_LATENCY(5); +#elif defined(STM32L4X) + /* L4: 4 wait states for 80MHz at 1.8V (per RM0351) */ + *FLASH_ACR = FLASH_ACR_LATENCY(4); #elif defined(STM32F1X) *FLASH_ACR = FLASH_ACR_LATENCY(1); #endif @@ -132,12 +168,16 @@ void sys_clock_init(void) *RCC_CFGR |= RCC_CFGR_SW_PLL; /* Wait till the main PLL is used as system clock source */ - while ((*RCC_CFGR & (uint32_t) RCC_CFGR_SWS_M) != RCC_CFGR_SWS_PLL) - /* wait */; + volatile uint32_t switch_timeout = 0x10000; + while (((*RCC_CFGR & (uint32_t) RCC_CFGR_SWS_M) != RCC_CFGR_SWS_PLL) && + (switch_timeout > 0)) { + switch_timeout--; + } } else { - /* HSE failed to start - fall back to HSI. + fallback_clock: + /* HSE failed to start - fall back to HSI/MSI. * This is expected when running under QEMU emulation. - * Use HSI (16MHz) as system clock directly without PLL. + * Use HSI (16MHz) or MSI (4MHz) as system clock directly without PLL. */ #if defined(STM32F4X) /* Configure Flash latency for 16MHz (HSI) */ @@ -149,6 +189,11 @@ void sys_clock_init(void) /* Wait till HSI is used as system clock source */ while ((*RCC_CFGR & (uint32_t) RCC_CFGR_SWS_M) != 0) /* wait */; +#elif defined(STM32L4X) + /* Configure Flash latency for 4MHz (MSI default) */ + *FLASH_ACR = FLASH_ACR_LATENCY(0); + + /* MSI is already selected as system clock by default (SW = 00) */ #endif } #if defined(STM32F4X) @@ -160,56 +205,44 @@ void sys_clock_init(void) *SCB_SHCSR |= SCB_SHCSR_USEFAULTENA; } -#if defined(STM32F4X) +#if defined(STM32F4X) || defined(STM32L4X) void __USER_TEXT RCC_AHB1PeriphClockCmd(uint32_t rcc_AHB1, uint8_t enable) { - /* TODO: assertion */ - if (enable != 0) *RCC_AHB1ENR |= rcc_AHB1; else *RCC_AHB1ENR &= ~rcc_AHB1; - +} #elif defined(STM32F1X) void __USER_TEXT RCC_AHBPeriphClockCmd(uint32_t rcc_AHB, uint8_t enable) { - /* TODO: assertion */ - if (enable != 0) *RCC_AHBENR |= rcc_AHB; else *RCC_AHBENR &= ~rcc_AHB; - -#endif } +#endif -#if defined(STM32F4X) +#if defined(STM32F4X) || defined(STM32L4X) void __USER_TEXT RCC_AHB1PeriphResetCmd(uint32_t rcc_AHB1, uint8_t enable) { - /* TODO: assertion */ - if (enable != 0) *RCC_AHB1RSTR |= rcc_AHB1; else *RCC_AHB1RSTR &= ~rcc_AHB1; - +} #elif defined(STM32F1X) void __USER_TEXT RCC_AHBPeriphResetCmd(uint32_t rcc_AHB, uint8_t enable) { - /* TODO: assertion */ - if (enable != 0) *RCC_AHBRSTR |= rcc_AHB; else *RCC_AHBRSTR &= ~rcc_AHB; - -#endif } +#endif void __USER_TEXT RCC_APB1PeriphClockCmd(uint32_t rcc_APB1, uint8_t enable) { - /* TODO: assertion */ - if (enable != 0) *RCC_APB1ENR |= rcc_APB1; else @@ -218,8 +251,6 @@ void __USER_TEXT RCC_APB1PeriphClockCmd(uint32_t rcc_APB1, uint8_t enable) void __USER_TEXT RCC_APB1PeriphResetCmd(uint32_t rcc_APB1, uint8_t enable) { - /* TODO: assertion */ - if (enable != 0) *RCC_APB1RSTR |= rcc_APB1; else @@ -228,8 +259,6 @@ void __USER_TEXT RCC_APB1PeriphResetCmd(uint32_t rcc_APB1, uint8_t enable) void __USER_TEXT RCC_APB2PeriphClockCmd(uint32_t rcc_APB2, uint8_t enable) { - /* TODO: assertion */ - if (enable != 0) *RCC_APB2ENR |= rcc_APB2; else @@ -238,8 +267,6 @@ void __USER_TEXT RCC_APB2PeriphClockCmd(uint32_t rcc_APB2, uint8_t enable) void __USER_TEXT RCC_APB2PeriphResetCmd(uint32_t rcc_APB2, uint8_t enable) { - /* TODO: assertion */ - if (enable != 0) *RCC_APB2RSTR |= rcc_APB2; else @@ -252,8 +279,6 @@ uint8_t __USER_TEXT RCC_GetFlagStatus(uint8_t flag) uint32_t statusreg = 0; uint8_t bitstatus = 0; - /* TODO: assertion */ - tmp = flag >> 5; if (tmp == 1) statusreg = *RCC_CR; @@ -273,21 +298,29 @@ uint8_t __USER_TEXT RCC_GetFlagStatus(uint8_t flag) void __USER_TEXT RCC_GetClocksFreq(struct rcc_clocks *clock) { -#if defined(STM32F4X) - uint32_t tmp = 0, presc = 0, pllvco = 0, pllp = 2, pllsource = 0, pllm = 2; +#if defined(STM32F4X) || defined(STM32L4X) + uint32_t tmp = 0, presc = 0, pllvco = 0, pllsource = 0, pllm = 2; tmp = *RCC_CFGR & RCC_CFGR_SWS_M; switch (tmp) { case 0x00: +#if defined(STM32L4X) + /* L4 default clock is MSI (4MHz), not HSI */ + clock->sysclk_freq = MSI_VALUE; +#else clock->sysclk_freq = HSI_VALUE; +#endif break; case 0x04: clock->sysclk_freq = HSE_VALUE; break; case 0x08: +#if defined(STM32F4X) pllsource = (*RCC_PLLCFGR & RCC_PLLCFGR_PLLSRC_HSE) >> 22; pllm = *RCC_PLLCFGR & RCC_PLLCFGR_PLLM; + if (pllm == 0) + pllm = 2; if (pllsource != 0) pllvco = @@ -296,11 +329,32 @@ void __USER_TEXT RCC_GetClocksFreq(struct rcc_clocks *clock) pllvco = (HSI_VALUE / pllm) * ((*RCC_PLLCFGR & RCC_PLLCFGR_PLLN) >> 6); - pllp = (((*RCC_PLLCFGR & RCC_PLLCFGR_PLLP) >> 16) + 1) * 2; + uint32_t pllp = (((*RCC_PLLCFGR & RCC_PLLCFGR_PLLP) >> 16) + 1) * 2; clock->sysclk_freq = pllvco / pllp; +#elif defined(STM32L4X) + /* L4: PLLSRC bits [1:0]: 01=MSI, 10=HSI16, 11=HSE */ + pllsource = *RCC_PLLCFGR & 0x3; + pllm = ((*RCC_PLLCFGR >> 4) & 0x7) + 1; + + uint32_t pll_input; + if (pllsource == 3) + pll_input = HSE_VALUE; + else if (pllsource == 2) + pll_input = HSI_VALUE; + else + pll_input = MSI_VALUE; + + pllvco = (pll_input / pllm) * ((*RCC_PLLCFGR >> 8) & 0x7F); + uint32_t pllr = (((*RCC_PLLCFGR >> 25) & 0x3) + 1) * 2; + clock->sysclk_freq = pllvco / pllr; +#endif break; default: +#if defined(STM32L4X) + clock->sysclk_freq = MSI_VALUE; +#else clock->sysclk_freq = HSI_VALUE; +#endif break; } diff --git a/platform/stm32-common/usart.c b/platform/stm32-common/usart.c index d2a1ca74..0938c35a 100644 --- a/platform/stm32-common/usart.c +++ b/platform/stm32-common/usart.c @@ -8,6 +8,7 @@ #include INC_PLAT(usart.c) +#ifndef USART_OPS_DEFINED struct usart_regs { volatile uint16_t SR; uint16_t reserved0; @@ -27,6 +28,7 @@ struct usart_regs { /* Calculates the value for the USART_BRR */ /* TODO: Need more precise algorithm */ +#ifndef USART_BAUD_DEFINED static int16_t usart_baud(uint32_t base, uint32_t baud) { uint16_t mantissa; @@ -55,7 +57,14 @@ static int16_t usart_baud(uint32_t base, uint32_t baud) return (mantissa << 4) | fraction; } +#endif /* USART_BAUD_DEFINED */ +#endif /* USART_OPS_DEFINED */ +/* Interrupt helpers are register-layout agnostic: they use base + offset + * computed from the USART_IT_* encoding. Kept in common code for all + * platforms since the CR1/CR2/CR3 bit positions are compatible. + */ +#ifndef USART_IT_OPS_DEFINED void usart_config_interrupt(struct usart_dev *usart, uint16_t it, uint8_t state) { uint32_t it_reg, it_bit; @@ -84,7 +93,9 @@ int usart_interrupt_status(struct usart_dev *usart, uint16_t it) return (*(volatile uint32_t *) it_reg & it_bit); } +#endif /* USART_IT_OPS_DEFINED */ +#ifndef USART_OPS_DEFINED int usart_status(struct usart_dev *usart, uint16_t st) { struct usart_regs *uregs; @@ -134,3 +145,4 @@ void usart_init(struct usart_dev *usart) /* Enable reciever and transmitter */ uregs->CR1 |= (USART_CR1_RE | USART_CR1_TE); } +#endif /* USART_OPS_DEFINED */ diff --git a/platform/stm32f1/Kconfig b/platform/stm32f1/Kconfig deleted file mode 100644 index c709e383..00000000 --- a/platform/stm32f1/Kconfig +++ /dev/null @@ -1,175 +0,0 @@ -menu "User Interrupt Config" - -config WWDG_USER_IRQ - bool "User WWDG IRQ" - default n - -config PVD_USER_IRQ - bool "User PVD IRQ" - default n - -config TAMP_STAMP_USER_IRQ - bool "User TAMP_STAMP IRQ" - default n - -config RTC_WKUP_USER_IRQ - bool "User RTC_WKUP IRQ" - default n - -config FLASH_USER_IRQ - bool "User FLASH_USER IRQ" - default n - -config RCC_USER_IRQ - bool "User RCC IRQ" - default n - -config EXTI0_USER_IRQ - bool "User EXTI0 IRQ" - default n - -config EXTI1_USER_IRQ - bool "User EXIT1 IRQ" - default n - -config EXTI2_USER_IRQ - bool "User EXIT2 IRQ" - default n - -config EXTI3_USER_IRQ - bool "User EXIT3 IRQ" - default n - -config EXTI4_USER_IRQ - bool "User EXIT4 IRQ" - default n - -config DMA_Stream0_USER_IRQ - bool "User DMA_Stream0 IRQ" - default n - -config DMA_Stream1_USER_IRQ - bool "User DMA_Stream1 IRQ" - default n - -config DMA_Stream2_USER_IRQ - bool "User DMA_Stream2 IRQ" - default n - -config DMA_Stream3_USER_IRQ - bool "User DMA_Stream3 IRQ" - default n - -config DMA_Stream4_USER_IRQ - bool "User DMA_Stream4 IRQ" - default n - -config DMA_Stream5_USER_IRQ - bool "User DMA_Stream5 IRQ" - default n - -config DMA_Stream6_USER_IRQ - bool "User DMA_Stream6 IRQ" - default n - -config ADC_USER_IRQ - bool "User ADC IRQ" - default n - -config CAN1_TX_USER_IRQ - bool "CAN1 TX User IRQ" - default n - -config CAN1_RX_USER_IRQ - bool "CAN1 RX User IRQ" - default n - -config CAN1_RX1_USER_IRQ - bool "CAN1 RX1 User IRQ" - default n - -config CAN1_SCE_USER_IRQ - bool "CAN1 SEC User IRQ" - default n - -config EXTI9_5_USER_IRQ - bool "EXTI9_5 User IRQ" - default n - -config TIM1_BRK_USER_IRQ - bool "TIM1_BRK User IRQ" - default n - -config TIM1_UP_USER_IRQ - bool "TIM1_UP User IRQ" - default n - -config TIM1_TRG_COM_USER_IRQ - bool "TIM1_TRG_COM User IRQ" - default n - -config TIM1_CC_USER_IRQ - bool "TIM1_CC User IRQ" - default n - -config TIM2_USER_IRQ - bool "TIM2 User IRQ" - default n - -config TIM3_USER_IRQ - bool "TIM3 User IRQ" - default n - -config TIM4_USER_IRQ - bool "TIM4 User IRQ" - default n - -config I2C1_EV_USER_IRQ - bool "I2C1_EV User IRQ" - default n - -config I2C1_ER_USER_IRQ - bool "I2C1_ER User IRQ" - default n - -config I2C2_EV_USER_IRQ - bool "I2C2_EV User IRQ" - default n - -config I2C2_ER_USER_IRQ - bool "I2C2_ER User IRQ" - default n - -config SPI1_USER_IRQ - bool "SPI1 User IRQ" - default n - -config SPI2_USER_IRQ - bool "SPI2 User IRQ" - default n - -config USART1_USER_IRQ - bool "USART1 User IRQ" - default n - -config USART2_USER_IRQ - bool "USART2 User IRQ" - default n - -config USART3_USER_IRQ - bool "USART3 User IRQ" - default n - -config EXTI15_10_USER_IRQ - bool "EXTI15_10 User IRQ" - default n - -config RTC_Alarm_USER_IRQ - bool "RTC Alarm User IRQ" - default n - -config OTG_FS_WKUP_USER_IRQ - bool "OTG_FS_WKUP User IRQ" - default n - -endmenu diff --git a/platform/stm32f1/usart.c b/platform/stm32f1/usart.c deleted file mode 100644 index bc89a86d..00000000 --- a/platform/stm32f1/usart.c +++ /dev/null @@ -1 +0,0 @@ -/* no additional platform specific implementation */ diff --git a/platform/stm32l4/Kconfig b/platform/stm32l4/Kconfig new file mode 100644 index 00000000..c784be47 --- /dev/null +++ b/platform/stm32l4/Kconfig @@ -0,0 +1,330 @@ +menu "User Interrupt Config" + +config WWDG_USER_IRQ + bool "User WWDG IRQ" + default n + +config PVD_USER_IRQ + bool "User PVD IRQ" + default n + +config TAMP_STAMP_USER_IRQ + bool "User TAMP_STAMP IRQ" + default n + +config RTC_WKUP_USER_IRQ + bool "User RTC_WKUP IRQ" + default n + +config FLASH_USER_IRQ + bool "User FLASH_USER IRQ" + default n + +config RCC_USER_IRQ + bool "User RCC IRQ" + default n + +config EXTI0_USER_IRQ + bool "User EXTI0 IRQ" + default n + +config EXTI1_USER_IRQ + bool "User EXTI1 IRQ" + default n + +config EXTI2_USER_IRQ + bool "User EXIT2 IRQ" + default n + +config EXTI3_USER_IRQ + bool "User EXIT3 IRQ" + default n + +config EXTI4_USER_IRQ + bool "User EXIT4 IRQ" + default n + +config DMA1_Stream0_USER_IRQ + bool "User DMA1_Stream0 IRQ" + default n + +config DMA1_Stream1_USER_IRQ + bool "User DMA1_Stream1 IRQ" + default n + +config DMA1_Stream2_USER_IRQ + bool "User DMA1_Stream2 IRQ" + default n + +config DMA1_Stream3_USER_IRQ + bool "User DMA1_Stream3 IRQ" + default n + +config DMA1_Stream4_USER_IRQ + bool "User DMA1_Stream4 IRQ" + default n + +config DMA1_Stream5_USER_IRQ + bool "User DMA1_Stream5 IRQ" + default n + +config DMA1_Stream6_USER_IRQ + bool "User DMA1_Stream6 IRQ" + default n + +config ADC_USER_IRQ + bool "User ADC IRQ" + default n + +config CAN1_TX_USER_IRQ + bool "CAN1 TX User IRQ" + default n + +config CAN1_RX_USER_IRQ + bool "CAN1 RX User IRQ" + default n + +config CAN1_RX1_USER_IRQ + bool "CAN1 RX1 User IRQ" + default n + +config CAN1_SCE_USER_IRQ + bool "CAN1 SEC User IRQ" + default n + +config EXTI9_5_USER_IRQ + bool "EXTI9_5 User IRQ" + default n + +config TIM1_BRK_TIM9_USER_IRQ + bool "TIM1_BRK_TIM9 User IRQ" + default n + +config TIM1_UP_TIM10_USER_IRQ + bool "TIM1_UP_TIM10 User IRQ" + default n + +config TIM1_TRG_COM_TIM11_USER_IRQ + bool "TIM1_TRG_COM_TIM11 User IRQ" + default n + +config TIM1_CC_USER_IRQ + bool "TIM1_CC User IRQ" + default n + +config TIM2_USER_IRQ + bool "TIM2 User IRQ" + default n + +config TIM3_USER_IRQ + bool "TIM3 User IRQ" + default n + +config TIM4_USER_IRQ + bool "TIM4 User IRQ" + default n + +config I2C1_EV_USER_IRQ + bool "I2C1_EV User IRQ" + default n + +config I2C1_ER_USER_IRQ + bool "I2C1_ER User IRQ" + default n + +config I2C2_EV_USER_IRQ + bool "I2C2_EV User IRQ" + default n + +config I2C2_ER_USER_IRQ + bool "I2C2_ER User IRQ" + default n + +config SPI1_USER_IRQ + bool "SPI1 User IRQ" + default n + +config SPI2_USER_IRQ + bool "SPI2 User IRQ" + default n + +config USART1_USER_IRQ + bool "USART1 User IRQ" + default n + +config USART2_USER_IRQ + bool "USART2 User IRQ" + default n + +config USART3_USER_IRQ + bool "USART3 User IRQ" + default n + +config EXTI15_10_USER_IRQ + bool "EXTI15_10 User IRQ" + default n + +config RTC_Alarm_USER_IRQ + bool "RTC Alarm User IRQ" + default n + +config OTG_FS_WKUP_USER_IRQ + bool "OTG_FS_WKUP User IRQ" + default n + +config TIM8_BRK_TIM12_USER_IRQ + bool "TIM8_BRK_TIM12 User IRQ" + default n + +config TIM8_UP_TIM13_USER_IRQ + bool "TIM8_UP_TIM13 User IRQ" + default n + +config TIM8_TRG_COM_TIM14_USER_IRQ + bool "TIM8_TRG_COM_TIM14 User IRQ" + default n + +config TIM8_CC_USER_IRQ + bool "TIM8_CC User IRQ" + default n + +config DMA1_Stream7_USER_IRQ + bool "DMA1_Stream7 User IRQ" + default n + +config FSMC_USER_IRQ + bool "FSMC User IRQ" + default n + +config SDIO_USER_IRQ + bool "SDIO User IRQ" + default n + +config TIM5_USER_IRQ + bool "TIM5 User IRQ" + default n + +config SPI3_USER_IRQ + bool "SPI3 User IRQ" + default n + +config UART4_USER_IRQ + bool "UART4 User IRQ" + default n + +config UART5_USER_IRQ + bool "UART5 User IRQ" + default n + +config TIM6_DAC_USER_IRQ + bool "TIM6_DAC User IRQ" + default n + +config TIM7_USER_IRQ + bool "TIM7 User IRQ" + default n + +config DMA2_Stream0_USER_IRQ + bool "DMA2 Stream0 User IRQ" + default n + +config DMA2_Stream1_USER_IRQ + bool "DMA2 Stream1 User IRQ" + default n + +config DMA2_Stream2_USER_IRQ + bool "DMA2 Stream2 User IRQ" + default n + +config DMA2_Stream3_USER_IRQ + bool "DMA2 Stream3 User IRQ" + default n + +config DMA2_Stream4_USER_IRQ + bool "DMA2_Stream4 User IRQ" + default n + +config ETH_USER_IRQ + bool "ETH User IRQ" + default n + +config ETH_WKUP_USER_IRQ + bool "ETH WKUP User IRQ" + default n + +config CAN2_TX_USER_IRQ + bool "CAN2 TX User IRQ" + default n + +config CAN2_RX0_USER_IRQ + bool "CAN2 RX0 User IRQ" + default n + +config CAN2_RX1_USER_IRQ + bool "CAN2 RX1 User IRQ" + default n + +config CAN2_SCE_USER_IRQ + bool "CAN2 SCE User IRQ" + default n + +config OTG_FS_USER_IRQ + bool "OTG FS User IRQ" + default n + +config DMA2_Stream5_USER_IRQ + bool "DMA2 Stream5 User IRQ" + default n + +config DMA2_Stream6_USER_IRQ + bool "DMA2 Stream6 User IRQ" + default n + +config DMA2_Stream7_USER_IRQ + bool "DMA2 Stream7 User IRQ" + default n + +config USART6_USER_IRQ + bool "USART6 User IRQ" + default n + +config I2C3_EV_USER_IRQ + bool "I2C3 EV User IRQ" + default n + +config I2C3_ER_USER_IRQ + bool "I2C3 ER User IRQ" + default n + +config OTG_HS_EP1_OUT_USER_IRQ + bool "OTG_HS_EP1_OUT User IRQ" + default n + +config OTG_HS_EP1_IN_USER_IRQ + bool "OTG_HS_EP1_IN User IRQ" + default n + +config OTG_HS_WKUP_USER_IRQ + bool "OTG_HS_WKUP User IRQ" + default n + +config OTG_HS_USER_IRQ + bool "OTG_HS User IRQ" + default n + +config DCMI_USER_IRQ + bool "DCMI User IRQ" + default n + +config CRYP_USER_IRQ + bool "CRYP User IRQ" + default n + +config HASH_RNG_USER_IRQ + bool "HASH_RNG User IRQ" + default n + +config FPU_USER_IRQ + bool "FPU User IRQ" + default n +endmenu diff --git a/platform/stm32f1/build.mk b/platform/stm32l4/build.mk similarity index 84% rename from platform/stm32f1/build.mk rename to platform/stm32l4/build.mk index e93c0b42..a583bf48 100644 --- a/platform/stm32f1/build.mk +++ b/platform/stm32l4/build.mk @@ -2,7 +2,7 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. -chip-y = +chip-y = loader-chip-y = \ gpio.loader.o \ @@ -13,9 +13,9 @@ loader-chip-y = \ # FIXME: move to toplevel definitions platform-flash-command = \ - st-flash write $(1) 0x8000000 || \ + st-flash --connect-under-reset write $(1) 0x8000000 || \ openocd -f interface/stlink-v2.cfg \ - -f target/stm32f4x_stlink.cfg \ + -f target/stm32l4x_stlink.cfg \ -c "init" \ -c "reset init" \ -c "flash probe 0" \ diff --git a/platform/stm32f1/f9.ld b/platform/stm32l4/f9.ld similarity index 84% rename from platform/stm32f1/f9.ld rename to platform/stm32l4/f9.ld index 7613a0ce..572cb3a4 100644 --- a/platform/stm32f1/f9.ld +++ b/platform/stm32l4/f9.ld @@ -2,7 +2,7 @@ * memory area definitions */ -INCLUDE "f9_mem.ld" +INCLUDE "stm32l4/f9_mem.ld" ENTRY (__l4_start) @@ -17,6 +17,11 @@ ENTRY (__l4_start) * | text / data | 30k * ~~~~~~~~~~~~~~~~~~~~~ * + * +-------------------+ 0x1000 0000 + * + Bitmap / + + * + kernel AHB + + * +-------------------+ + * * +-------------------+ 0x2000 0000 * + stack + 1k * +-------------------+ 0x2000 0400 (+KERNEL_STACK) @@ -24,9 +29,6 @@ ENTRY (__l4_start) * +-------------------+ * +..userspace........+ * +-------------------+ - * + Bitmap / + - * + kernel AHB + - * +-------------------+ * * +-------------------+ 0x4000 0000 * + APB mem + @@ -110,6 +112,14 @@ SECTIONS { bitmap_bitband_start = .; *(.bitmap_bitband*) bitmap_bitband_end = .; + /* Place bitmaps in RamLoc for QEMU compatibility. + * QEMU's netduinoplus2 doesn't emulate CCM RAM at 0x10000000. + * This also works on real hardware with minimal performance impact + * since bitmaps are small and accessed infrequently. + */ + bitmap_start = .; + *(.bitmap*) + bitmap_end = .; bss_end = .; } > RamLoc @@ -136,16 +146,18 @@ SECTIONS { *(.user_bss*) . = ALIGN (256); user_bss_end = .; + mem0_start = .; } > RamLoc + /* STM32L4 has no CCM RAM at 0x10000000. + * Define mem1 symbols as fixed addresses so MEM1 pool is zero-size. + */ + mem1_start = 0x10000000; + mem1_end = 0x10000000; .data_AHB (NOLOAD) : { kernel_ahb_start = .; - bitmap_start = .; - *(.bitmap*) - bitmap_end = .; kernel_ahb_end = .; - mem0_start = .; } > RamLoc } diff --git a/platform/stm32f1/f9_flash.ld b/platform/stm32l4/f9_flash.ld similarity index 82% rename from platform/stm32f1/f9_flash.ld rename to platform/stm32l4/f9_flash.ld index 9b1b0136..18ea194e 100644 --- a/platform/stm32f1/f9_flash.ld +++ b/platform/stm32l4/f9_flash.ld @@ -2,7 +2,7 @@ * memory area definitions */ -INCLUDE "stm32f1/f9_mem.ld" +INCLUDE "stm32l4/f9_mem.ld" ENTRY (__l4_start) @@ -17,6 +17,11 @@ ENTRY (__l4_start) * | text / data | 30k * ~~~~~~~~~~~~~~~~~~~~~ * + * +-------------------+ 0x1000 0000 + * + Bitmap / + + * + kernel AHB + + * +-------------------+ + * * +-------------------+ 0x2000 0000 * + stack + 1k * +-------------------+ 0x2000 0400 (+KERNEL_STACK) @@ -24,9 +29,6 @@ ENTRY (__l4_start) * +-------------------+ * +..userspace........+ * +-------------------+ - * + Bitmap / + - * + kernel AHB + - * +-------------------+ * * +-------------------+ 0x4000 0000 * + APB mem + @@ -41,7 +43,7 @@ USERSPACE_BASE = 0x0000C000; IDLE_STACK_SIZE = 0x00000100; KERNEL_STACK_SIZE = 0x00000300; -ROOT_THREAD_STACK_SIZE = 0x00000200; +ROOT_THREAD_STACK_SIZE = 0x00001000; /* Increased to 0x1000 (4KB) for fpage loop + semihosting printf */ SECTIONS { .text 0x08000000: @@ -95,6 +97,14 @@ SECTIONS { bitmap_bitband_start = .; *(.bitmap_bitband*) bitmap_bitband_end = .; + /* Place bitmaps in RamLoc for QEMU compatibility. + * QEMU's netduinoplus2 doesn't emulate CCM RAM at 0x10000000. + * This also works on real hardware with minimal performance impact + * since bitmaps are small and accessed infrequently. + */ + bitmap_start = .; + *(.bitmap*) + bitmap_end = .; bss_end = .; } > RamLoc @@ -134,16 +144,18 @@ SECTIONS { *(.user_bss*) . = ALIGN (256); user_bss_end = .; + mem0_start = .; } > RamLoc + /* STM32L4 has no CCM RAM at 0x10000000. + * Define mem1 symbols as fixed addresses so MEM1 pool is zero-size. + */ + mem1_start = 0x10000000; + mem1_end = 0x10000000; .data_AHB (NOLOAD) : { kernel_ahb_start = .; - bitmap_start = .; - *(.bitmap*) - bitmap_end = .; kernel_ahb_end = .; - mem0_start = .; } > RamLoc .sym_tab ( 0x800c000 + SIZEOF(.user_text) + SIZEOF(.user_data) ) : diff --git a/platform/stm32f1/f9_mem.ld b/platform/stm32l4/f9_mem.ld similarity index 64% rename from platform/stm32f1/f9_mem.ld rename to platform/stm32l4/f9_mem.ld index eb91ef17..694324ab 100644 --- a/platform/stm32f1/f9_mem.ld +++ b/platform/stm32l4/f9_mem.ld @@ -5,5 +5,5 @@ MEMORY { MFlash (rx) : ORIGIN = 0x08000000, LENGTH = 1024K - RamLoc (rwx) : ORIGIN = 0x20000000, LENGTH = 112K + RamLoc (rwx) : ORIGIN = 0x20000000, LENGTH = 96K } diff --git a/platform/stm32f1/f9_sram.ld b/platform/stm32l4/f9_sram.ld similarity index 84% rename from platform/stm32f1/f9_sram.ld rename to platform/stm32l4/f9_sram.ld index 82afd55b..c8eafa71 100644 --- a/platform/stm32f1/f9_sram.ld +++ b/platform/stm32l4/f9_sram.ld @@ -2,7 +2,7 @@ * memory area definitions */ -INCLUDE "stm32f1/f9_mem.ld" +INCLUDE "stm32l4/f9_mem.ld" ENTRY (__l4_start) @@ -17,6 +17,11 @@ ENTRY (__l4_start) * | text / data | 30k * ~~~~~~~~~~~~~~~~~~~~~ * + * +-------------------+ 0x1000 0000 + * + Bitmap / + + * + kernel AHB + + * +-------------------+ + * * +-------------------+ 0x2000 0000 * + stack + 1k * +-------------------+ 0x2000 0400 (+KERNEL_STACK) @@ -24,9 +29,6 @@ ENTRY (__l4_start) * +-------------------+ * +..userspace........+ * +-------------------+ - * + Bitmap / + - * + kernel AHB + - * +-------------------+ * * +-------------------+ 0x4000 0000 * + APB mem + @@ -111,6 +113,14 @@ SECTIONS { bitmap_bitband_start = .; *(.bitmap_bitband*) bitmap_bitband_end = .; + /* Place bitmaps in RamLoc for QEMU compatibility. + * QEMU's netduinoplus2 doesn't emulate CCM RAM at 0x10000000. + * This also works on real hardware with minimal performance impact + * since bitmaps are small and accessed infrequently. + */ + bitmap_start = .; + *(.bitmap*) + bitmap_end = .; bss_end = .; } > RamLoc @@ -137,16 +147,18 @@ SECTIONS { *(.user_bss*) . = ALIGN (256); user_bss_end = .; + mem0_start = .; } > RamLoc + /* STM32L4 has no CCM RAM at 0x10000000. + * Define mem1 symbols as fixed addresses so MEM1 pool is zero-size. + */ + mem1_start = 0x10000000; + mem1_end = 0x10000000; .data_AHB (NOLOAD) : { kernel_ahb_start = .; - bitmap_start = .; - *(.bitmap*) - bitmap_end = .; kernel_ahb_end = .; - mem0_start = .; } > RamLoc } diff --git a/platform/stm32f1/gpio.c b/platform/stm32l4/gpio.c similarity index 100% rename from platform/stm32f1/gpio.c rename to platform/stm32l4/gpio.c diff --git a/platform/stm32f1/hwtimer.c b/platform/stm32l4/hwtimer.c similarity index 100% rename from platform/stm32f1/hwtimer.c rename to platform/stm32l4/hwtimer.c diff --git a/platform/stm32f1/mpu.c b/platform/stm32l4/mpu.c similarity index 100% rename from platform/stm32f1/mpu.c rename to platform/stm32l4/mpu.c diff --git a/platform/stm32f1/nvic.c b/platform/stm32l4/nvic.c similarity index 100% rename from platform/stm32f1/nvic.c rename to platform/stm32l4/nvic.c diff --git a/platform/stm32f1/rcc.c b/platform/stm32l4/rcc.c similarity index 100% rename from platform/stm32f1/rcc.c rename to platform/stm32l4/rcc.c diff --git a/platform/stm32f1/systick.c b/platform/stm32l4/systick.c similarity index 100% rename from platform/stm32f1/systick.c rename to platform/stm32l4/systick.c diff --git a/platform/stm32l4/usart.c b/platform/stm32l4/usart.c new file mode 100644 index 00000000..8e435605 --- /dev/null +++ b/platform/stm32l4/usart.c @@ -0,0 +1,102 @@ +/* STM32L4 USART implementation. + * + * The L4 USART has a different register layout from the F4: + * F4: SR(+0x00), DR(+0x04), BRR(+0x08), CR1(+0x0C), CR2(+0x10), CR3(+0x14) + * L4: CR1(+0x00), CR2(+0x04), CR3(+0x08), BRR(+0x0C), ISR(+0x1C), RDR(+0x24), + * TDR(+0x28) + * + * This file defines USART_OPS_DEFINED and USART_BAUD_DEFINED to override + * the F4 fallbacks in platform/stm32-common/usart.c. + */ + +#include INC_PLAT(registers.h) +#include INC_PLAT(gpio.h) + +#define USART_OPS_DEFINED +#define USART_BAUD_DEFINED + +/* STM32L4 USART register map */ +struct usart_regs { + volatile uint32_t CR1; /* +0x00 */ + volatile uint32_t CR2; /* +0x04 */ + volatile uint32_t CR3; /* +0x08 */ + volatile uint32_t BRR; /* +0x0C */ + volatile uint32_t GTPR; /* +0x10 */ + volatile uint32_t RTOR; /* +0x14 */ + volatile uint32_t RQR; /* +0x18 */ + volatile uint32_t ISR; /* +0x1C (replaces F4 SR) */ + volatile uint32_t ICR; /* +0x20 */ + volatile uint32_t RDR; /* +0x24 (replaces F4 DR for read) */ + volatile uint32_t TDR; /* +0x28 (replaces F4 DR for write) */ +}; + +/* L4 ISR bits (compatible positions with F4 SR for common flags) */ +#define L4_USART_ISR_RXNE (1 << 5) +#define L4_USART_ISR_TC (1 << 6) +#define L4_USART_ISR_TXE (1 << 7) + +static int16_t usart_baud(uint32_t base, uint32_t baud) +{ + uint32_t apb_clock; + uint32_t sws = *RCC_CFGR & RCC_CFGR_SWS_M; + + if (sws == RCC_CFGR_SWS_PLL) { + if (base == USART1_BASE) + apb_clock = 80000000; /* APB2 */ + else + apb_clock = 40000000; /* APB1 */ + } else { + apb_clock = 4000000; /* MSI fallback */ + } + + /* L4 BRR is a simple 16-bit divider (no mantissa/fraction split + * when OVER8=0, which is the default) */ + return (uint16_t) (apb_clock / baud); +} + +int usart_status(struct usart_dev *usart, uint16_t st) +{ + struct usart_regs *uregs = (struct usart_regs *) usart->base; + return (uregs->ISR & st); +} + +uint8_t usart_getc(struct usart_dev *usart) +{ + struct usart_regs *uregs = (struct usart_regs *) usart->base; + return (uregs->RDR & 0xff); +} + +void usart_putc(struct usart_dev *usart, uint8_t c) +{ + struct usart_regs *uregs = (struct usart_regs *) usart->base; + uregs->TDR = c; +} + +void usart_init(struct usart_dev *usart) +{ + struct usart_regs *uregs; + + /* Enable peripheral clock */ + *(usart->rcc_apbenr) |= usart->rcc_reset; + + /* Configure GPIO pins */ + gpio_config(&usart->tx); + gpio_config(&usart->rx); + + uregs = (struct usart_regs *) usart->base; + + /* Disable USART during configuration */ + uregs->CR1 &= ~USART_CR1_UE; + + /* 8-bit word length (M[1:0] = 00) */ + uregs->CR1 &= ~(USART_CR1_M9); + + /* 1 stop bit (STOP[1:0] = 00) */ + uregs->CR2 &= ~(3 << 12); + + /* Set baud rate */ + uregs->BRR = usart_baud(usart->base, usart->baud); + + /* Enable USART, receiver, and transmitter */ + uregs->CR1 |= (USART_CR1_UE | USART_CR1_RE | USART_CR1_TE); +} diff --git a/scripts/qemu-kdb-auto.py b/scripts/qemu-kdb-auto.py new file mode 100755 index 00000000..d43ccf70 --- /dev/null +++ b/scripts/qemu-kdb-auto.py @@ -0,0 +1,159 @@ +#!/usr/bin/env python3 +# QEMU wrapper that auto-triggers KDB after boot for semihosting +# Copyright (c) 2026 The F9 Microkernel Project + +""" +Runs F9 under QEMU and automatically sends '?' to activate KDB +after detecting boot completion. + +Usage: + python3 scripts/qemu-kdb-auto.py [ELF_FILE] [--delay SECONDS] + +This script solves the ARM semihosting limitation: +- Semihosting uses blocking I/O (no hardware interrupts) +- Cannot poll for '?' without freezing the system +- Solution: Automatically send '?' after boot detection +""" + +import argparse +import os +import select +import subprocess +import sys +import time + + +def main(): + parser = argparse.ArgumentParser(description="Run F9 with auto-KDB trigger") + parser.add_argument( + "elf_file", + nargs="?", + default="build/b-l475e-iot01a/f9.elf", + help="ELF file to run (default: build/b-l475e-iot01a/f9.elf)", + ) + parser.add_argument( + "--delay", + type=float, + default=2.0, + help="Delay in seconds after boot before sending ? (default: 2.0)", + ) + parser.add_argument( + "--no-trigger", + action="store_true", + help="Do not auto-trigger KDB (manual mode)", + ) + + args = parser.parse_args() + + if not os.path.exists(args.elf_file): + print(f"Error: ELF file not found: {args.elf_file}", file=sys.stderr) + return 1 + + print("=" * 60) + print("F9 Microkernel - QEMU with KDB Auto-Trigger") + print("=" * 60) + print(f"ELF: {args.elf_file}") + if not args.no_trigger: + print(f"KDB trigger: {args.delay}s after boot") + print() + print("Press Ctrl+C to exit") + print("=" * 60) + print() + + qemu = os.environ.get("QEMU", "qemu-system-arm") + cmd = [ + qemu, + "-M", + "b-l475e-iot01a", + "-nographic", + "-chardev", + "stdio,id=console,mux=on,signal=off", + "-serial", + "chardev:console", + "-mon", + "chardev=console,mode=readline", + "-semihosting-config", + "enable=on,target=native,chardev=console", + "-kernel", + args.elf_file, + ] + + try: + proc = subprocess.Popen( + cmd, + stdin=None if args.no_trigger else subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + text=True, + bufsize=1, + ) + except FileNotFoundError: + print("Error: qemu-system-arm not found", file=sys.stderr) + return 127 + + boot_detected = False + start_time = time.time() + kdb_triggered = args.no_trigger # Skip trigger if --no-trigger + line_buffer = "" + + try: + while True: + # Check if process exited + if proc.poll() is not None: + break + + # Read output with timeout + ready, _, _ = select.select([proc.stdout], [], [], 0.1) + if ready: + try: + chunk = proc.stdout.read(1024) + if not chunk: + break + + # Print output + sys.stdout.write(chunk) + sys.stdout.flush() + + line_buffer += chunk + + # Detect boot completion + if ( + not boot_detected + and "Press '?' to print KDB menu" in line_buffer + ): + line_buffer = "" # Free buffer after marker found + boot_detected = True + start_time = time.time() + if not kdb_triggered: + print( + f"\n[AUTO] Boot detected, waiting {args.delay}s before triggering KDB..." + ) + + except (IOError, OSError): + pass + + # Auto-trigger KDB after delay + if boot_detected and not kdb_triggered: + elapsed = time.time() - start_time + if elapsed >= args.delay: + print("[AUTO] Sending '?' to activate KDB...") + proc.stdin.write("?") + proc.stdin.flush() + kdb_triggered = True + + except KeyboardInterrupt: + print("\n[QEMU] Interrupted by user") + + finally: + if proc.poll() is None: + proc.terminate() + try: + proc.wait(timeout=2) + except subprocess.TimeoutExpired: + proc.kill() + + return proc.returncode or 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/scripts/qemu-kdb.sh b/scripts/qemu-kdb.sh new file mode 100755 index 00000000..25c8575b --- /dev/null +++ b/scripts/qemu-kdb.sh @@ -0,0 +1,77 @@ +#!/bin/bash +# QEMU wrapper script that enables KDB activation for semihosting +# Copyright (c) 2026 The F9 Microkernel Project + +# Usage: ./scripts/qemu-kdb.sh [ELF_FILE] +# +# Press Ctrl+A then 'k' to trigger KDB +# Press Ctrl+A then 'x' to exit QEMU + +ELF_FILE="${1:-build/b-l475e-iot01a/f9.elf}" + +if [ ! -f "$ELF_FILE" ]; then + echo "Error: ELF file not found: $ELF_FILE" + exit 1 +fi + +# Create a named pipe for input +PIPE="/tmp/qemu-kdb-$$" +mkfifo "$PIPE" || exit 1 + +# Cleanup on exit +trap "exec 3>&- 2>/dev/null; rm -f $PIPE" EXIT + +echo "===================================================" +echo "F9 Microkernel - QEMU with KDB Support" +echo "===================================================" +echo "ELF: $ELF_FILE" +echo "" +echo "Keyboard shortcuts:" +echo " Ctrl+A k - Trigger KDB (send '?')" +echo " Ctrl+A x - Exit QEMU" +echo " Ctrl+C - Stop this script" +echo "===================================================" +echo "" + +# Hold the FIFO open for writing so QEMU's read side doesn't block on open. +exec 3>"$PIPE" + +# Start QEMU with stdin from pipe +qemu-system-arm \ + -M b-l475e-iot01a \ + -nographic \ + -semihosting \ + -serial mon:stdio \ + -kernel "$ELF_FILE" <"$PIPE" & + +QEMU_PID=$! + +# Function to send character to QEMU +send_kdb() { + echo "?" >&3 + echo "[KDB] Sent '?' to activate debugger" +} + +# Handle Ctrl+C +trap "kill $QEMU_PID 2>/dev/null; exit 0" INT + +# Wait for QEMU and handle keyboard shortcuts +while kill -0 $QEMU_PID 2>/dev/null; do + # Read a single character with timeout + read -t 0.1 -n 1 -s key + + if [ "$key" = $'\x01' ]; then # Ctrl+A + read -t 0.5 -n 1 -s key2 + case "$key2" in + k) send_kdb ;; + x) + echo "[QEMU] Exiting..." + kill $QEMU_PID + break + ;; + esac + fi +done + +wait $QEMU_PID 2>/dev/null +exit $? diff --git a/scripts/qemu-test.py b/scripts/qemu-test.py index 3d972e75..f60ff0b6 100755 --- a/scripts/qemu-test.py +++ b/scripts/qemu-test.py @@ -6,15 +6,21 @@ """ QEMU Test Runner for F9 Microkernel -Runs test suite or fault tests under QEMU and parses UART output. +Runs test suite or fault tests under QEMU and parses test output. Exits with 0 on success, non-zero on failure. +Automatically detects board from ELF path and uses the correct QEMU machine. + Usage: # Test suite - python3 scripts/qemu-test.py build/netduinoplus2/f9.elf [-t TIMEOUT] + python3 scripts/qemu-test.py build/b-l475e-iot01a/f9.elf [-t TIMEOUT] # Fault tests (expect kernel panic) - python3 scripts/qemu-test.py build/netduinoplus2/f9.elf --fault [-t TIMEOUT] + python3 scripts/qemu-test.py build/b-l475e-iot01a/f9.elf --fault [-t TIMEOUT] + +Supported boards: + - b-l475e-iot01a: QEMU machine 'b-l475e-iot01a' (Cortex-M4F with FPU) + - netduinoplus2: QEMU machine 'netduinoplus2' (legacy, no FPU) """ import argparse @@ -22,6 +28,8 @@ import os import re import select +import shutil +import shlex import subprocess import sys import time @@ -128,6 +136,116 @@ def set_nonblocking(fd): fcntl.fcntl(fd, fcntl.F_SETFL, flags | os.O_NONBLOCK) +def detect_qemu_machine(elf_path: str) -> str: + """ + Detect QEMU machine type from ELF path. + + ELF paths contain the board name: build//f9.elf + + Args: + elf_path: Path to the ELF file + + Returns: + QEMU machine name + """ + # Board name to QEMU machine mapping + BOARD_TO_QEMU_MACHINE = { + "b-l475e-iot01a": "b-l475e-iot01a", + "netduinoplus2": "netduinoplus2", + # discoveryf4 and discoveryf429 not supported in QEMU + } + + # Try to extract board from path: .../build//... or ...//... + # Works with default build/ and custom out= directories. + for board, machine in BOARD_TO_QEMU_MACHINE.items(): + if board in elf_path: + return machine + + # No known board found in path + print(f"[ERROR] Cannot detect QEMU machine from path: {elf_path}") + print( + f"[ERROR] Path must contain a supported board name: " + f"{', '.join(BOARD_TO_QEMU_MACHINE.keys())}" + ) + sys.exit(1) + + +def validate_qemu_machine(qemu: str, machine: str) -> None: + """Check that the QEMU binary supports the requested machine. + + Exits with a clear error if the machine is not available, which + typically means the QEMU version is too old (b-l475e-iot01a + requires QEMU >= 9.0). + """ + try: + result = subprocess.run( + [qemu, "-M", "help"], + capture_output=True, + text=True, + timeout=5, + ) + except FileNotFoundError: + print(f"[ERROR] QEMU not found: {qemu}") + sys.exit(127) + except (PermissionError, subprocess.TimeoutExpired) as e: + print(f"[ERROR] Cannot execute QEMU: {e}") + sys.exit(1) + + if result.returncode != 0: + print(f"[ERROR] QEMU -M help failed (exit {result.returncode})") + if result.stderr: + print(f"[ERROR] {result.stderr.strip()}") + sys.exit(1) + + # Match exact machine name (first column of -M help output) + machines = {line.split()[0] for line in result.stdout.splitlines() if line.strip()} + if machine not in machines: + ver = subprocess.run( + [qemu, "--version"], + capture_output=True, + text=True, + timeout=5, + ) + version_line = ver.stdout.split("\n")[0] if ver.stdout else "unknown" + print(f"[ERROR] QEMU does not support machine '{machine}'") + print(f"[ERROR] {version_line}") + if machine == "b-l475e-iot01a": + print("[ERROR] b-l475e-iot01a requires QEMU >= 9.0") + sys.exit(1) + + +def build_qemu_cmd(elf_path: str, machine: str) -> list[str]: + """Build a QEMU command line for the selected machine. + + For semihosting boards, wraps QEMU in script(1) to provide a PTY. + Without a PTY, semihosting output blocks after a few KB because + QEMU's internal write buffer fills when stdout is a pipe. + """ + qemu = os.environ.get("QEMU", "qemu-system-arm") + validate_qemu_machine(qemu, machine) + qemu_cmd = [qemu, "-M", machine, "-nographic", "-serial", "mon:stdio"] + + if machine == "b-l475e-iot01a": + qemu_cmd.append("-semihosting") + + qemu_cmd += ["-kernel", elf_path] + + # Wrap in script(1) for PTY so semihosting doesn't block on pipe + if machine == "b-l475e-iot01a" and shutil.which("script"): + if sys.platform == "darwin": + return ["script", "-q", "/dev/null"] + qemu_cmd + else: + return [ + "script", + "-qe", + "-c", + " ".join(shlex.quote(a) for a in qemu_cmd), + "/dev/null", + ] + + return qemu_cmd + + def run_qemu(elf_path: str, timeout: int) -> TestResults: """ Run QEMU and parse test output. @@ -141,19 +259,9 @@ def run_qemu(elf_path: str, timeout: int) -> TestResults: """ results = TestResults() - # Find QEMU binary - qemu = os.environ.get("QEMU", "qemu-system-arm") - - cmd = [ - qemu, - "-M", - "netduinoplus2", - "-nographic", - "-serial", - "mon:stdio", - "-kernel", - elf_path, - ] + # Detect QEMU machine from ELF path + machine = detect_qemu_machine(elf_path) + cmd = build_qemu_cmd(elf_path, machine) print(f"[QEMU] Starting: {' '.join(cmd)}") print(f"[QEMU] Timeout: {timeout}s") @@ -167,11 +275,11 @@ def run_qemu(elf_path: str, timeout: int) -> TestResults: stdin=subprocess.PIPE, text=True, encoding="utf-8", - errors="replace", # Replace invalid UTF-8 with replacement character + errors="replace", bufsize=1, ) except FileNotFoundError: - print(f"[ERROR] QEMU not found: {qemu}") + print(f"[ERROR] QEMU not found: {cmd[0]}") print("[ERROR] Install QEMU or set QEMU environment variable") results.exit_code = 127 return results @@ -199,18 +307,14 @@ def run_qemu(elf_path: str, timeout: int) -> TestResults: eof_reached = True except (IOError, OSError): pass # No data available yet (non-blocking) - except UnicodeDecodeError as e: - # Handle invalid UTF-8 (should be rare with errors='replace') - print(f"[WARNING] Unicode decode error: {e}", file=sys.stderr) - pass # Process complete lines (even after EOF to drain buffer) while "\n" in line_buffer: line, line_buffer = line_buffer.split("\n", 1) - stripped = line.rstrip() + stripped = re.sub(r"[\x00-\x08\x0b-\x1f\x7f]", "", line.rstrip("\r")) # Parse test markers (before display filtering) - exit_requested = parse_test_line(line, results) + exit_requested = parse_test_line(stripped, results) # Check for test suite start marker (various formats) if "[TEST:START]" in stripped or ( @@ -258,7 +362,12 @@ def run_qemu(elf_path: str, timeout: int) -> TestResults: if eof_reached: # Process any remaining incomplete line if line_buffer.strip(): - parse_test_line(line_buffer, results) + parse_test_line( + re.sub( + r"[\x00-\x08\x0b-\x1f\x7f]", "", line_buffer.rstrip("\r") + ), + results, + ) break # Check timeout AFTER processing available data (use monotonic clock) @@ -278,7 +387,14 @@ def run_qemu(elf_path: str, timeout: int) -> TestResults: # Process remaining complete lines for line in line_buffer.split("\n"): if line.strip(): - parse_test_line(line, results) + parse_test_line( + re.sub( + r"[\x00-\x08\x0b-\x1f\x7f]", + "", + line.rstrip("\r"), + ), + results, + ) except (IOError, OSError): pass if not exit_found: @@ -329,19 +445,8 @@ def run_qemu_fault(elf_path: str, timeout: int) -> FaultTestResults: """ results = FaultTestResults() - # Find QEMU binary - qemu = os.environ.get("QEMU", "qemu-system-arm") - - cmd = [ - qemu, - "-M", - "netduinoplus2", - "-nographic", - "-serial", - "mon:stdio", - "-kernel", - elf_path, - ] + machine = detect_qemu_machine(elf_path) + cmd = build_qemu_cmd(elf_path, machine) print(f"[QEMU] Starting fault test: {' '.join(cmd)}") print(f"[QEMU] Timeout: {timeout}s") @@ -355,11 +460,11 @@ def run_qemu_fault(elf_path: str, timeout: int) -> FaultTestResults: stdin=subprocess.PIPE, text=True, encoding="utf-8", - errors="replace", # Replace invalid UTF-8 with replacement character + errors="replace", bufsize=1, ) except FileNotFoundError: - print(f"[ERROR] QEMU not found: {qemu}") + print(f"[ERROR] QEMU not found: {cmd[0]}") results.exit_code = 127 return results @@ -383,15 +488,11 @@ def run_qemu_fault(elf_path: str, timeout: int) -> FaultTestResults: eof_reached = True except (IOError, OSError): pass - except UnicodeDecodeError as e: - # Handle invalid UTF-8 (should be rare with errors='replace') - print(f"[WARNING] Unicode decode error: {e}", file=sys.stderr) - pass # Process complete lines while "\n" in line_buffer: line, line_buffer = line_buffer.split("\n", 1) - stripped = line.rstrip() + stripped = re.sub(r"[\x00-\x08\x0b-\x1f\x7f]", "", line.rstrip("\r")) if stripped: # Store all output diff --git a/user/apps/tests/main.c b/user/apps/tests/main.c index 1189357b..5d8b754d 100644 --- a/user/apps/tests/main.c +++ b/user/apps/tests/main.c @@ -165,15 +165,15 @@ static void *test_main(void *user) * HEAP_FPAGE: 512 bytes for thread pool metadata * * For canary fault test: - * Smaller stack to make overflow easier to trigger + * Reserve enough space for pager bootstrap + at least one worker thread. + * The worker stack used by the test is still 512 bytes in pager.c. */ #if defined(FAULT_TYPE) && (FAULT_TYPE == FAULT_CANARY) -/* Smaller stack for canary test (must match STACK_SIZE_WORDS in test-fault.c) - */ +/* Minimum RES_FPAGE for pager bootstrap + one child thread. */ DECLARE_USER(257, tests, test_main, - DECLARE_FPAGE(0x0, 2048) DECLARE_FPAGE(0x0, 512)); + DECLARE_FPAGE(0x0, 4096) DECLARE_FPAGE(0x0, 512)); #else /* Normal stack for test suite and MPU fault test */ DECLARE_USER(257, @@ -181,3 +181,9 @@ DECLARE_USER(257, test_main, DECLARE_FPAGE(0x0, 8192) DECLARE_FPAGE(0x0, 512)); #endif + +/* Note: KDB interactive input requires UART (CONFIG_DEBUG_DEV_UART). + * Semihosting SYS_READC blocks the CPU, preventing other threads from + * running. For QEMU automated testing, KDB is activated via the test + * harness (scripts/qemu-test.py), not interactive input. + */ diff --git a/user/apps/tests/test-arm.c b/user/apps/tests/test-arm.c index 94ebd747..4be149f7 100644 --- a/user/apps/tests/test-arm.c +++ b/user/apps/tests/test-arm.c @@ -33,7 +33,7 @@ void test_arm_lazy_fpu(void) { TEST_RUN("arm_lazy_fpu"); -#ifdef CONFIG_HAS_FPU +#ifdef CONFIG_FPU volatile float a = 1.5f; volatile float b = 2.5f; volatile float c = a + b; diff --git a/user/apps/tests/test-fault.c b/user/apps/tests/test-fault.c index 84474698..e1320af4 100644 --- a/user/apps/tests/test-fault.c +++ b/user/apps/tests/test-fault.c @@ -132,9 +132,9 @@ __attribute__((noinline)) static void stack_consumer(void) /* * Directly corrupt the canary. * Search the entire stack region for the canary value. - * Stack size is 2048 bytes (defined in main.c DECLARE_USER). + * Pager-created worker threads use a 512-byte stack. */ -#define STACK_SIZE_WORDS (2048 / sizeof(uint32_t)) +#define STACK_SIZE_WORDS (512 / sizeof(uint32_t)) __USER_TEXT static void corrupt_canary_directly(void) diff --git a/user/include/l4/pager.h b/user/include/l4/pager.h index 8c8cdc51..6d9e8b41 100644 --- a/user/include/l4/pager.h +++ b/user/include/l4/pager.h @@ -11,6 +11,7 @@ #define THREAD_MAX_NUM 32 +#define PAGER_BOOTSTRAP_STACK_SIZE 0x800 /* msg tag label */ #define PAGER_REQUEST_LABEL 0xf000 diff --git a/user/include/platform/safe_mmio.h b/user/include/platform/safe_mmio.h deleted file mode 100644 index 39d3c2f7..00000000 --- a/user/include/platform/safe_mmio.h +++ /dev/null @@ -1,227 +0,0 @@ -/* Copyright (c) 2026 The F9 Microkernel Project. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef __PLATFORM_SAFE_MMIO_H__ -#define __PLATFORM_SAFE_MMIO_H__ - -/* - * Safe MMIO Access Macros - * - * Purpose: Explicit handling of Memory-Mapped I/O (MMIO) accesses that may - * hang or fail in emulation environments like QEMU. - * - * Background: - * - QEMU's netduinoplus2 machine does not emulate all ARM System Control Space - * (SCS) registers (0xE000E000 - 0xE000FFFF) - * - Direct MMIO access via LDR/STR instructions to these addresses hangs QEMU - * - CPU instructions (MRS/MSR) and software variables are safe - * - * Pattern discovered: - * ✅ Safe: CPU instructions (MRS, MSR), software variables - * ❌ Unsafe: MMIO to SCS/PPB region (0xE000Exxx) on QEMU netduinoplus2 - * - * Usage: - * Instead of: uint32_t val = *(volatile uint32_t *)0xE000ED90; // May hang - * Use: uint32_t val = SAFE_MMIO_READ32(0xE000ED90, 0); // Explicit - * - * See also: - * - board/Kconfig: CONFIG_HAS_* flags for feature availability - * - claudedocs/qemu_test_skips.md: MMIO pattern documentation - */ - -#include - -/* MPU register address range (for CONFIG_MPU_MOCK routing) */ -#define MPU_TYPE_ADDR 0xE000ED90 -#define MPU_CTRL_ADDR 0xE000ED94 -#define MPU_RNR_ADDR 0xE000ED98 -#define MPU_RBAR_ADDR 0xE000ED9C -#define MPU_RASR_ADDR 0xE000EDA0 - -/* SCB register addresses (for CONFIG_SCB_MOCK routing) */ -#define SCB_CCR_ADDR 0xE000ED14 - -#ifdef CONFIG_MPU_MOCK -/* Forward declarations for MPU mock functions (defined in mpu_mock.c) */ -uint32_t mpu_mock_read32(uintptr_t addr); -void mpu_mock_write32(uintptr_t addr, uint32_t value); -#endif - -#ifdef CONFIG_SCB_MOCK -/* Forward declarations for SCB mock functions (defined in scb_mock.c) */ -uint32_t scb_mock_read32(uintptr_t addr); -void scb_mock_write32(uintptr_t addr, uint32_t value); -#endif - -/* - * SAFE_MMIO_READ32 - Read 32-bit value from MMIO address - * - * @addr: Physical address of MMIO register - * @fallback: Value to return when MMIO not available (QEMU builds) - * - * Returns: Register value on hardware, fallback value on QEMU - * - * Priority (highest to lowest): - * 1. CONFIG_MPU_MOCK: Software mock for MPU registers (QEMU testing) - * 2. CONFIG_SCB_MOCK: Software mock for SCB registers (QEMU testing) - * 3. CONFIG_HAS_MPU: Real MPU hardware access - * 4. CONFIG_HAS_SCB_ACCESS: Real SCB hardware access - * 5. Fallback: Return default value (QEMU without mock) - * - * Example: - * uint32_t mpu_type = SAFE_MMIO_READ32(0xE000ED90, 0); - * uint32_t scb_ccr = SAFE_MMIO_READ32(0xE000ED14, 0); - * if (mpu_type == 0) { - * // QEMU or MPU not present - * } - */ -#if defined(CONFIG_MPU_MOCK) && defined(CONFIG_SCB_MOCK) -/* Both MPU and SCB mocks: Route to appropriate mock based on address */ -#define SAFE_MMIO_READ32(addr, fallback) \ - (((addr) >= MPU_TYPE_ADDR && (addr) <= MPU_RASR_ADDR) \ - ? mpu_mock_read32(addr) \ - : ((addr) == SCB_CCR_ADDR) ? scb_mock_read32(addr) \ - : (fallback)) -#elif defined(CONFIG_MPU_MOCK) -/* MPU mock only: Route MPU register access to software mock */ -#define SAFE_MMIO_READ32(addr, fallback) \ - (((addr) >= MPU_TYPE_ADDR && (addr) <= MPU_RASR_ADDR) \ - ? mpu_mock_read32(addr) \ - : (fallback)) -#elif defined(CONFIG_SCB_MOCK) -/* SCB mock only: Route SCB register access to software mock */ -#define SAFE_MMIO_READ32(addr, fallback) \ - (((addr) == SCB_CCR_ADDR) ? scb_mock_read32(addr) : (fallback)) -#elif defined(CONFIG_HAS_MPU) -/* MPU registers accessible - direct MMIO read */ -#define SAFE_MMIO_READ32(addr, fallback) (*(volatile uint32_t *) (addr)) -#elif defined(CONFIG_HAS_SCB_ACCESS) -/* SCB registers accessible - direct MMIO read */ -#define SAFE_MMIO_READ32(addr, fallback) (*(volatile uint32_t *) (addr)) -#else -/* MMIO not available (QEMU) - return fallback value */ -#define SAFE_MMIO_READ32(addr, fallback) (fallback) -#endif - -/* - * SAFE_MMIO_WRITE32 - Write 32-bit value to MMIO address - * - * @addr: Physical address of MMIO register - * @value: Value to write - * - * Priority (highest to lowest): - * 1. CONFIG_MPU_MOCK: Software mock for MPU registers (QEMU testing) - * 2. CONFIG_SCB_MOCK: Software mock for SCB registers (QEMU testing) - * 3. CONFIG_HAS_MPU: Real MPU hardware access - * 4. CONFIG_HAS_SCB_ACCESS: Real SCB hardware access - * 5. No-op: QEMU without mock - * - * Example: - * SAFE_MMIO_WRITE32(0xE000ED90, 0x12345678); - */ -#if defined(CONFIG_MPU_MOCK) && defined(CONFIG_SCB_MOCK) -/* Both MPU and SCB mocks: Route to appropriate mock based on address */ -#define SAFE_MMIO_WRITE32(addr, value) \ - do { \ - if ((addr) >= MPU_TYPE_ADDR && (addr) <= MPU_RASR_ADDR) { \ - mpu_mock_write32(addr, value); \ - } else if ((addr) == SCB_CCR_ADDR) { \ - scb_mock_write32(addr, value); \ - } \ - } while (0) -#elif defined(CONFIG_MPU_MOCK) -/* MPU mock only: Route MPU register writes to software mock */ -#define SAFE_MMIO_WRITE32(addr, value) \ - do { \ - if ((addr) >= MPU_TYPE_ADDR && (addr) <= MPU_RASR_ADDR) { \ - mpu_mock_write32(addr, value); \ - } \ - } while (0) -#elif defined(CONFIG_SCB_MOCK) -/* SCB mock only: Route SCB register writes to software mock */ -#define SAFE_MMIO_WRITE32(addr, value) \ - do { \ - if ((addr) == SCB_CCR_ADDR) { \ - scb_mock_write32(addr, value); \ - } \ - } while (0) -#elif defined(CONFIG_HAS_MPU) -#define SAFE_MMIO_WRITE32(addr, value) \ - do { \ - *(volatile uint32_t *) (addr) = (value); \ - } while (0) -#elif defined(CONFIG_HAS_SCB_ACCESS) -#define SAFE_MMIO_WRITE32(addr, value) \ - do { \ - *(volatile uint32_t *) (addr) = (value); \ - } while (0) -#else -/* MMIO not available (QEMU) - write is no-op */ -#define SAFE_MMIO_WRITE32(addr, value) \ - do { \ - (void) (value); \ - } while (0) -#endif - -/* - * SAFE_MMIO_MODIFY32 - Read-modify-write 32-bit MMIO register - * - * @addr: Physical address of MMIO register - * @mask: Bits to clear (set bits will be cleared) - * @value: Bits to set (set bits will be set) - * - * Example: - * // Set bit 3, clear bit 5 - * SAFE_MMIO_MODIFY32(0xE000ED14, (1 << 5), (1 << 3)); - */ -#if defined(CONFIG_HAS_MPU) || defined(CONFIG_HAS_SCB_ACCESS) -#define SAFE_MMIO_MODIFY32(addr, mask, value) \ - do { \ - uint32_t reg = *(volatile uint32_t *) (addr); \ - reg = (reg & ~(mask)) | (value); \ - *(volatile uint32_t *) (addr) = reg; \ - } while (0) -#else -/* MMIO not available (QEMU) - modify is no-op */ -#define SAFE_MMIO_MODIFY32(addr, mask, value) \ - do { \ - (void) (mask); \ - (void) (value); \ - } while (0) -#endif - -/* - * MMIO_IS_AVAILABLE - Check if MMIO access is available - * - * Returns: 1 if MMIO is available, 0 if running on QEMU or MMIO disabled - * - * Example: - * if (!MMIO_IS_AVAILABLE()) { - * printf("Skipping MMIO test - not available\n"); - * return; - * } - */ -#if defined(CONFIG_MPU_MOCK) || defined(CONFIG_SCB_MOCK) || \ - defined(CONFIG_HAS_MPU) || defined(CONFIG_HAS_SCB_ACCESS) -#define MMIO_IS_AVAILABLE() 1 -#else -#define MMIO_IS_AVAILABLE() 0 -#endif - -/* - * Common SCS/PPB Register Addresses (for reference) - * - * These are the registers that hang QEMU netduinoplus2: - * - MPU_TYPE: 0xE000ED90 (hangs - use CONFIG_HAS_MPU guard) - * - SCB_CCR: 0xE000ED14 (hangs - use CONFIG_HAS_SCB_ACCESS guard) - * - SCB_CPACR: 0xE000ED88 (hangs - use CONFIG_HAS_DWT guard for FPU tests) - * - SYSTICK_*: 0xE000E010-0xE000E01C (hangs - use CONFIG_HAS_SYSTICK_TIMING) - * - * Safe alternatives: - * - PSP: Use MRS instruction (read_psp() in test-arm.c) - * - UTCB: Read software variable (__L4_TCR_MyLocalId()) - */ - -#endif /* __PLATFORM_SAFE_MMIO_H__ */ diff --git a/user/lib/build.mk b/user/lib/build.mk index f5f8851d..1cd502b8 100644 --- a/user/lib/build.mk +++ b/user/lib/build.mk @@ -7,6 +7,3 @@ user-lib-dirs = \ io \ posix \ -# MPU and SCB mocks (conditional, for QEMU testing) -user-lib-$(CONFIG_MPU_MOCK) += mpu_mock.o -user-lib-$(CONFIG_SCB_MOCK) += scb_mock.o diff --git a/user/lib/io/semihost-io.c b/user/lib/io/semihost-io.c index 316380e3..1b23a7ea 100644 --- a/user/lib/io/semihost-io.c +++ b/user/lib/io/semihost-io.c @@ -3,6 +3,7 @@ * found in the LICENSE file. */ #include +#include #include "lib/string.h" enum SEMIHOST_SYSCALL { @@ -80,3 +81,15 @@ int __USER_TEXT semihost_puts(char *log) semihost_close(handle); return 0; } + +/* Semihosting character input for KDB monitor. + * Blocks until character available (ARM semihosting limitation). + */ +uint8_t __USER_TEXT semihosting_getc(void) +{ + return (uint8_t) semihost_call(SYS_READC, NULL); +} + +/* Note: kernel-space __l4_putchar is in platform/semihosting.c. + * User-space printf() uses IPC to THREAD_LOG, not __l4_putchar. + */ diff --git a/user/lib/l4/pager.c b/user/lib/l4/pager.c index 99e0c389..40e4f768 100644 --- a/user/lib/l4/pager.c +++ b/user/lib/l4/pager.c @@ -8,12 +8,21 @@ #include #include #include +#include +#include /* POSIX error codes for pager join protocol */ #define ESRCH 3 /* No such process/thread */ #define EAGAIN 11 /* Resource temporarily unavailable */ +/* Pager-managed child threads are sized from RES_FPAGE. Keep this compact so + * the default 8 KiB pool can still create worker threads. + */ #define STACK_SIZE 0x200 +#define STACK_CANARY_VALUE 0xDEADBEEF +#define PAGER_BOOT_RESERVED \ + (((UTCB_SIZE + PAGER_BOOTSTRAP_STACK_SIZE) + NODE_ALIGN - 1) & \ + ~(NODE_ALIGN - 1)) /* Kernel requires 256-byte alignment for UTCB addresses */ #define NODE_ALIGN 256 @@ -50,6 +59,12 @@ struct thread_pool { L4_ThreadId_t pager_tid; }; +/* Keep pager metadata in user BSS so bootstrap does not depend on an extra + * demand-mapped heap fpage before the pager can start serving faults itself. + */ +static struct thread_pool pager_pool_storage __USER_BSS; +static struct thread_node pager_node_storage[THREAD_MAX_NUM] __USER_BSS; + /* Wait queue for blocking synchronization (PSE51 compliance) */ #define MAX_WAITERS 16 #define MAX_SYNC_OBJECTS 8 @@ -165,7 +180,8 @@ static inline L4_Word_t user_fpage_number(user_fpage_t *fpages) } __USER_TEXT -static struct thread_pool *init_thread_pool(L4_Word_t res_base, +static struct thread_pool *init_thread_pool(L4_Word_t pager_tid_raw, + L4_Word_t res_base, L4_Word_t res_size, L4_Word_t heap_base, L4_Word_t heap_size) @@ -175,19 +191,25 @@ static struct thread_pool *init_thread_pool(L4_Word_t res_base, struct thread_pool *pool; struct thread_node *nodes; - num1 = - (heap_size - sizeof(struct thread_pool)) / sizeof(struct thread_node); - num2 = (res_size) / NODE_SIZE_ALIGNED; + (void) heap_base; + (void) heap_size; + + if (res_size <= PAGER_BOOT_RESERVED) + return NULL; + + res_base += PAGER_BOOT_RESERVED; + res_size -= PAGER_BOOT_RESERVED; + num1 = THREAD_MAX_NUM; + num2 = (res_size) / NODE_SIZE_ALIGNED; node_num = (num1 < num2) ? num1 : num2; - node_num = (node_num > THREAD_MAX_NUM) ? THREAD_MAX_NUM : node_num; - pool = (struct thread_pool *) heap_base; - nodes = (struct thread_node *) (heap_base + sizeof(struct thread_pool)); + pool = &pager_pool_storage; + nodes = pager_node_storage; pool->node_num = node_num; pool->all_nodes = nodes; - pool->pager_tid = L4_MyGlobalId(); + pool->pager_tid.raw = pager_tid_raw; if (res_base & 0x1) { printf("unalign res base\n"); @@ -304,6 +326,23 @@ static void start_thread(L4_ThreadId_t t, L4_Word_t stack_size) { L4_Msg_t msg; + volatile L4_Word_t *frame = (volatile L4_Word_t *) (sp - RESERVED_STACK); + volatile L4_Word_t *stack_base = (volatile L4_Word_t *) (sp - stack_size); + L4_Word_t *utcb = (L4_Word_t *) (sp - STACK_SIZE - UTCB_SIZE); + L4_Word_t kip = (L4_Word_t) L4_KernelInterface(NULL, NULL, NULL); + + /* Pager-managed children share our RES_FPAGE, so prepare the initial + * exception frame in user space and let the kernel only bind ctx.sp. + */ + *stack_base = STACK_CANARY_VALUE; + frame[REG_R0] = kip; + frame[REG_R1] = (L4_Word_t) utcb; + frame[REG_R2] = entry; + frame[REG_R3] = entry_arg; + frame[REG_R12] = 0; + frame[REG_LR] = 0xFFFFFFFF; + frame[REG_PC] = (L4_Word_t) thread_container; + frame[REG_xPSR] = 0x1000000; /* CRITICAL: Do NOT call functions after L4_MsgLoad! * Any function call (including printf) will clobber R4-R11 (MR0-MR7)! @@ -341,7 +380,7 @@ static L4_ThreadId_t __thread_create(struct thread_pool *pool) node->detached = 0; use_thread_node(node); - myself = L4_MyGlobalId(); + myself = pool->pager_tid; free_mem = (L4_Word_t) THREAD_NODE_BASE(node); /* Create thread with shared address space (spaceid=myself). @@ -538,9 +577,15 @@ void pager_thread(user_struct *user, void *(*entry_main)(void *) ) return; } - pool = init_thread_pool( - user->fpages[RES_FPAGE].base, user->fpages[RES_FPAGE].size, - user->fpages[HEAP_FPAGE].base, user->fpages[HEAP_FPAGE].size); + pool = init_thread_pool(user->thread_num, user->fpages[RES_FPAGE].base, + user->fpages[RES_FPAGE].size, + user->fpages[HEAP_FPAGE].base, + user->fpages[HEAP_FPAGE].size); + + if (!pool) { + printf("pager: init_thread_pool failed\n"); + return; + } /* Create main entry thread */ main_tid = __thread_create(pool); diff --git a/user/lib/l4/platform/syscalls.c b/user/lib/l4/platform/syscalls.c index 433cfa1a..f5268a52 100644 --- a/user/lib/l4/platform/syscalls.c +++ b/user/lib/l4/platform/syscalls.c @@ -125,67 +125,70 @@ L4_Word_t L4_TimerNotify(L4_Word_t ticks, } __USER_TEXT -L4_MsgTag_t L4_Ipc(L4_ThreadId_t to, - L4_ThreadId_t FromSpecifier, - L4_Word_t Timeouts, - L4_ThreadId_t *from) +__attribute__((naked)) L4_MsgTag_t L4_Ipc(L4_ThreadId_t to, + L4_ThreadId_t FromSpecifier, + L4_Word_t Timeouts, + L4_ThreadId_t *from) { - L4_MsgTag_t result; - extern void *current_utcb; - utcb_t *utcb = (utcb_t *) current_utcb; - L4_Word_t *mr_ptr = &utcb->mr_low[0]; - - register L4_Word_t r0 __asm__("r0") = to.raw; - register L4_Word_t r1 __asm__("r1") = FromSpecifier.raw; - register L4_Word_t r2 __asm__("r2") = Timeouts; - - /* B8 Fix: MRs stored in UTCB->mr_low[], marshaled to R4-R11 for SVC - * - * The ARM ABI says R4-R11 are callee-saved, so any function call - * between L4_LoadMR() and L4_Ipc() could corrupt them. We now store - * MRs in UTCB memory (mr_low[]) and marshal here. + /* Naked function - we manage the stack ourselves to prevent the compiler + * from storing locals that would be overwritten by the SVC exception frame. * - * P1 Fix: Use r12 as base register for ldmia/stmia. ARM reference: - * "If is in the register list, behavior is UNPREDICTABLE." - * By explicitly using r12 (outside r4-r11), we avoid this hazard. - * We save mr_ptr to stack because SVC may clobber r0-r3 where the - * compiler might have placed it. + * Parameters in registers (ARM AAPCS): + * R0 = to.raw + * R1 = FromSpecifier.raw + * R2 = Timeouts + * R3 = from (pointer) * - * Register usage during SVC: - * - R0-R3: IPC parameters (to, from, timeout) - * - R4-R11: Message registers (loaded from UTCB before SVC) - * - R12: Scratch register for ldmia/stmia base + * Return value in R0 = MsgTag.raw * - * NOTE: The SVC handler saves R4-R11 to __irq_saved_regs on entry - * and restores them on exit. For blocking IPC, received MRs are - * delivered via context switch (ctx.regs[]). For non-blocking, - * sender gets original MRs back (no reply expected). + * CRITICAL: Must preserve callee-saved registers R4-R11 per AAPCS. */ __asm__ __volatile__( - /* Save mr_ptr to stack (SVC may clobber the input register) */ - "mov r12, %[mr_ptr]\n" - "push {r4-r11}\n" - "sub sp, sp, #8\n" - "str r12, [sp, #4]\n" + /* Save callee-saved registers R4-R11 and R3 (from pointer), LR */ + "push {r3-r11, lr}\n" + /* Load MR0-MR7 from UTCB into R4-R11 */ + "ldr r12, =current_utcb\n" + "ldr r12, [r12]\n" /* r12 = utcb */ + "add r12, r12, #48\n" /* r12 = &utcb->mr_low[0] */ "ldmia r12, {r4-r11}\n" - /* SVC call with MRs in r4-r11 */ - "svc %[syscall_num]\n" - /* Restore mr_ptr and store received MRs back to UTCB */ - "ldr r12, [sp, #4]\n" - "stmia r12, {r4-r11}\n" - "add sp, sp, #8\n" - "pop {r4-r11}\n" - : "+r"(r0) - : "r"(r1), "r"(r2), [mr_ptr] "r"(mr_ptr), [syscall_num] "i"(SYS_IPC) - : "r12", "memory"); - result.raw = utcb->mr_low[0]; /* MR0 = tag */ + /* SVC syscall - exception frame saves R0-R3, R12, LR, PC, xPSR */ + /* Kernel preserves R4-R11 across syscall */ + "svc %[syscall_num]\n" - if (from) - from->raw = r0; + /* Reload UTCB MR pointer and store received MRs. + * LR was restored to caller's return address by the exception + * frame -- it no longer holds the UTCB pointer. + */ + "ldr r12, =current_utcb\n" + "ldr r12, [r12]\n" + "add r12, r12, #48\n" /* r12 = &utcb->mr_low[0] */ + "stmia r12, {r4-r11}\n" - return result; + /* Restore callee-saved registers (including original R3 with 'from' + pointer) */ + "pop {r3-r11, lr}\n" + + /* Load return value: MR0 = tag (utcb->mr_low[0]) */ + "ldr r12, =current_utcb\n" + "ldr r12, [r12]\n" + "ldr r1, [r12, #48]\n" + + /* Store 'from' result if pointer is non-NULL AND aligned */ + "cmp r3, #0\n" + "beq 1f\n" /* Skip if NULL */ + "tst r3, #3\n" /* Check 4-byte alignment */ + "bne 1f\n" /* Skip if misaligned */ + "str r0, [r3]\n" /* *from = R0 (from kernel) */ + "1:\n" + + /* Return tag in R0 */ + "mov r0, r1\n" + "bx lr\n" + : + : [syscall_num] "i"(SYS_IPC) + : "memory"); } diff --git a/user/lib/mpu_mock.c b/user/lib/mpu_mock.c deleted file mode 100644 index c9c2473f..00000000 --- a/user/lib/mpu_mock.c +++ /dev/null @@ -1,61 +0,0 @@ -/* Copyright (c) 2026 The F9 Microkernel Project. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -/** - * @file mpu_mock.c - * @brief Minimal MPU mock for test_arm_mpu_config in QEMU - * - * Provides minimal MPU register simulation to enable test_arm_mpu_config. - * Returns MPU_TYPE = 0x800 (8 regions, unified). - * - * Simplified from 307-line stateful implementation after analysis revealed - * only single-register read was actually tested. - */ - -#include -#include -#include - -#ifdef CONFIG_MPU_MOCK - -/* MPU register addresses */ -#define MPU_TYPE_ADDR 0xE000ED90 - -/** - * @brief Read MPU register (minimal mock) - * - * Returns MPU_TYPE = 0x800 (8 regions, unified) for test_arm_mpu_config. - * All other addresses return 0. - */ -__USER_TEXT -uint32_t mpu_mock_read32(uintptr_t addr) -{ - return (addr == MPU_TYPE_ADDR) ? 0x00000800 : 0; -} - -/** - * @brief Write MPU register (no-op) - * - * Not used by current tests. No-op for interface compatibility. - */ -__USER_TEXT -void mpu_mock_write32(uintptr_t addr, uint32_t value) -{ - (void) addr; - (void) value; -} - -/** - * @brief Initialize MPU mock (no-op) - * - * No state to initialize. Exists for interface compatibility. - */ -__USER_TEXT -void mpu_mock_init(void) -{ - /* No state to initialize */ -} - -#endif /* CONFIG_MPU_MOCK */ diff --git a/user/lib/scb_mock.c b/user/lib/scb_mock.c deleted file mode 100644 index c50d5249..00000000 --- a/user/lib/scb_mock.c +++ /dev/null @@ -1,66 +0,0 @@ -/* Copyright (c) 2026 The F9 Microkernel Project. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -/** - * @file scb_mock.c - * @brief Minimal SCB mock for test_arm_unaligned in QEMU - * - * Provides minimal SCB register simulation to enable test_arm_unaligned. - * Returns SCB_CCR = 0x200 (STKALIGN=1, UNALIGN_TRP=0). - * - * This follows the same pattern as mpu_mock.c, providing just enough - * functionality for the test to validate register accessibility. - */ - -#include -#include - -#ifdef CONFIG_SCB_MOCK - -/* SCB register addresses */ -#define SCB_CCR_ADDR 0xE000ED14 - -/** - * @brief Read SCB register (minimal mock) - * - * Returns SCB_CCR = 0x200 for test_arm_unaligned: - * - Bit 9 (STKALIGN): 1 = 8-byte stack alignment on exception entry - * - Bit 3 (UNALIGN_TRP): 0 = unaligned access does not trap - * - * This matches typical Cortex-M4 configuration with stack alignment enabled - * and unaligned trapping disabled. - * - * All other addresses return 0. - */ -__USER_TEXT -uint32_t scb_mock_read32(uintptr_t addr) -{ - return (addr == SCB_CCR_ADDR) ? 0x00000200 : 0; -} - -/** - * @brief Write SCB register (no-op) - * - * Not used by current tests. No-op for interface compatibility. - */ -__USER_TEXT -void scb_mock_write32(uintptr_t addr, uint32_t value) -{ - (void) addr; - (void) value; -} - -/** - * @brief Initialize SCB mock (no-op) - * - * No state to initialize. Exists for interface compatibility. - */ -__USER_TEXT -void scb_mock_init(void) -{ - /* No state to initialize */ -} - -#endif /* CONFIG_SCB_MOCK */ diff --git a/user/root_thread.c b/user/root_thread.c index 3572d3b1..44d94eaf 100644 --- a/user/root_thread.c +++ b/user/root_thread.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -16,13 +17,19 @@ extern user_struct user_runtime_end[]; int __USER_TEXT L4_Map(L4_ThreadId_t where, memptr_t base, size_t size) { + volatile L4_Word_t where_raw = where.raw; + volatile L4_Word_t base_saved = base; + volatile L4_Word_t size_saved = size; + L4_Msg_t msg; - L4_Word_t page[2] = {(base & 0xFFFFFFC0) | 0xA, size & 0xFFFFFFC0}; + volatile L4_Word_t page[2] = {(base_saved & 0xFFFFFFC0) | 0x0A, + size_saved & 0xFFFFFFC0}; - L4_MsgPut(&msg, 0, 0, NULL, 2, page); + L4_MsgPut(&msg, 0, 0, NULL, 2, (L4_Word_t *) page); L4_MsgLoad(&msg); - L4_Send(where); + L4_ThreadId_t where_reload = {.raw = where_raw}; + L4_Send(where_reload); return 0; } @@ -43,59 +50,70 @@ memptr_t __USER_TEXT get_free_base(kip_t *kip_ptr) void __USER_TEXT map_user_sections(kip_t *kip_ptr, L4_ThreadId_t tid) { - kip_mem_desc_t *desc = - ((void *) kip_ptr) + kip_ptr->memory_info.s.memory_desc_ptr; - int n = kip_ptr->memory_info.s.n; - int i = 0; + (void) kip_ptr; + volatile L4_Word_t tid_raw = tid.raw; + + volatile L4_Word_t utext_base = (L4_Word_t) &user_text_start; + volatile L4_Word_t utext_size = (L4_Word_t) &user_text_end - utext_base; + if (utext_size > 0) { + L4_ThreadId_t tid_reload = {.raw = tid_raw}; + L4_Map(tid_reload, utext_base, utext_size); + } - for (i = 0; i < n; ++i) { - uint32_t tag = desc[i].size & 0x3F; - if (tag == 2 || tag == 3) { - L4_Map(tid, desc[i].base, desc[i].size); - } + volatile L4_Word_t udata_base = (L4_Word_t) &user_data_start; + volatile L4_Word_t udata_size = (L4_Word_t) &user_data_end - udata_base; + if (udata_size > 0) { + L4_ThreadId_t tid_reload = {.raw = tid_raw}; + L4_Map(tid_reload, udata_base, udata_size); + } + + volatile L4_Word_t ubss_base = (L4_Word_t) &user_bss_start; + volatile L4_Word_t ubss_size = (L4_Word_t) &user_bss_end - ubss_base; + if (ubss_size > 0) { + L4_ThreadId_t tid_reload = {.raw = tid_raw}; + L4_Map(tid_reload, ubss_base, ubss_size); } } -static void __USER_TEXT start_thread(L4_ThreadId_t t, - L4_Word_t ip, - L4_Word_t sp, - L4_Word_t stack_size) +extern void thread_container(void); + +__USER_TEXT +static void start_thread(L4_Word_t tid_raw, + L4_Word_t entry, + L4_Word_t sp, + L4_Word_t stack_size) { + volatile L4_Word_t saved_tid_raw = tid_raw; + volatile L4_Word_t saved_entry = entry; + volatile L4_Word_t saved_sp = sp; + volatile L4_Word_t saved_stack_size = stack_size; + L4_Msg_t msg; + L4_ThreadId_t tid = {.raw = saved_tid_raw}; L4_MsgClear(&msg); - L4_MsgAppendWord(&msg, ip); - L4_MsgAppendWord(&msg, sp); - L4_MsgAppendWord(&msg, stack_size); + L4_MsgAppendWord(&msg, (L4_Word_t) thread_container); + L4_MsgAppendWord(&msg, saved_sp); + L4_MsgAppendWord(&msg, saved_stack_size); + L4_MsgAppendWord(&msg, saved_entry); L4_MsgAppendWord(&msg, 0); - L4_MsgAppendWord(&msg, 0); - L4_MsgLoad(&msg); - - L4_Send(t); + L4_Send(tid); } -#define STACK_SIZE 0x200 - -/* Align to minimum fpage size (256 bytes) to prevent overlap issues. - * Safe version that returns max aligned address on overflow. +/* Bootstrap user threads with a real stack. + * 512 bytes is too small for the semihosting-backed test path and can fault + * before the thread reaches its entry function. */ -#define FPAGE_ALIGN_SIZE 256 -#define FPAGE_ALIGN_MASK (~(FPAGE_ALIGN_SIZE - 1)) -static inline L4_Word_t fpage_align_safe(L4_Word_t addr) -{ - L4_Word_t aligned = (addr + FPAGE_ALIGN_SIZE - 1) & FPAGE_ALIGN_MASK; - /* Check for overflow: if aligned < addr, we wrapped around */ - if (aligned < addr) - return FPAGE_ALIGN_MASK; /* Return max aligned address */ - return aligned; -} -#define FPAGE_ALIGN(addr) fpage_align_safe((L4_Word_t) (addr)) +#define STACK_SIZE PAGER_BOOTSTRAP_STACK_SIZE void __USER_TEXT __root_thread(kip_t *kip_ptr, utcb_t *utcb_ptr) { + extern void *current_utcb; + *(void *volatile *) ¤t_utcb = utcb_ptr; + L4_ThreadId_t myself = {.raw = utcb_ptr->t_globalid}; - char *free_mem = (char *) get_free_base(kip_ptr); + volatile char *free_mem = (char *) get_free_base(kip_ptr); /* Validate free_mem base - 0 means no free memory found */ if (!free_mem) { @@ -104,64 +122,106 @@ void __USER_TEXT __root_thread(kip_t *kip_ptr, utcb_t *utcb_ptr) L4_Sleep(L4_Never); } - for (user_struct *ptr = user_runtime_start; ptr != user_runtime_end; - ++ptr) { - L4_ThreadId_t tid; - L4_Word_t stack; + int num_users = user_runtime_end - user_runtime_start; + + for (int i = 0; i < num_users; ++i) { + user_struct *ptr = &user_runtime_start[i]; user_fpage_t *fpage = ptr->fpages; + user_fpage_t *res_fpage = &ptr->fpages[RES_FPAGE]; - tid = L4_GlobalId(ptr->tid + kip_ptr->thread_info.s.user_base, 2); + volatile L4_Word_t tid_raw; + { + L4_ThreadId_t tid_tmp = + L4_GlobalId(ptr->tid + kip_ptr->thread_info.s.user_base, 2); + tid_raw = tid_tmp.raw; + } + ptr->thread_num = tid_raw; - /* Align UTCB base BEFORE ThreadControl to prevent kernel's - * mempool_align_base() from rounding down into previous allocation + /* Allocate RES_FPAGE first and place the pager thread's initial UTCB + * and bootstrap stack inside its reserved prefix. That keeps the + * pager's working set inside the same large user fpage it will later + * use for child threads. */ - free_mem = (char *) FPAGE_ALIGN(free_mem); + { + L4_Word_t res_size = res_fpage->size; + volatile L4_Word_t stack_align = res_size; + volatile L4_Word_t stack_mask = ~(stack_align - 1); + volatile L4_Word_t fm = (L4_Word_t) free_mem; + fm = (fm + stack_align - 1) & stack_mask; + res_fpage->base = fm; + free_mem = (char *) (fm + res_size); + } + + volatile L4_Word_t boot_base = res_fpage->base; + volatile L4_Word_t utcb_base = boot_base; /* create thread */ - L4_ThreadControl(tid, tid, L4_nilthread, myself, free_mem); - free_mem += UTCB_SIZE; + { + volatile L4_Word_t tid_saved = tid_raw; + L4_ThreadId_t tid = {.raw = tid_saved}; + L4_ThreadControl(tid, tid, L4_nilthread, myself, + (void *) utcb_base); + } /* map user_text, user_data and user_bss */ - map_user_sections(kip_ptr, tid); + { + volatile L4_Word_t tid_saved = tid_raw; + L4_ThreadId_t tid_for_sections = {.raw = tid_saved}; + map_user_sections(kip_ptr, tid_for_sections); + } - /* map thread stack - align first to prevent overlap */ - free_mem = (char *) FPAGE_ALIGN(free_mem); - L4_Map(tid, (L4_Word_t) free_mem, STACK_SIZE); - free_mem += STACK_SIZE; - stack = (L4_Word_t) free_mem; + { + volatile L4_Word_t tid_saved = tid_raw; + L4_ThreadId_t tid_for_stack = {.raw = tid_saved}; + L4_Map(tid_for_stack, res_fpage->base, res_fpage->size); + } + volatile L4_Word_t stack_top = + (L4_Word_t) res_fpage->base + UTCB_SIZE + STACK_SIZE; + volatile L4_Word_t stack_size = STACK_SIZE; /* map fpages */ while (fpage->base || fpage->size) { + if (fpage == res_fpage) { + fpage++; + continue; + } if (fpage->base) { - L4_Map(tid, fpage->base, fpage->size); + volatile L4_Word_t tid_saved = tid_raw; + L4_ThreadId_t tid_reload = {.raw = tid_saved}; + L4_Map(tid_reload, fpage->base, fpage->size); } else { /* Align dynamic allocations to the fpage's own size. * This ensures the fpage can be a single MPU region. * fpage->size MUST be a non-zero power of 2. */ - if (!fpage->size || (fpage->size & (fpage->size - 1))) { + L4_Word_t fpage_size = fpage->size; + if (!fpage_size || (fpage_size & (fpage_size - 1))) { printf("ERROR: invalid fpage size %p\n", - (void *) fpage->size); + (void *) fpage_size); fpage++; continue; } - L4_Word_t align_mask = ~(fpage->size - 1); - free_mem = (char *) (((L4_Word_t) free_mem + fpage->size - 1) & - align_mask); - L4_Map(tid, (L4_Word_t) free_mem, fpage->size); - fpage->base = (L4_Word_t) free_mem; - free_mem += fpage->size; + volatile L4_Word_t align_mask = ~(fpage_size - 1); + volatile L4_Word_t fm = (L4_Word_t) free_mem; + fm = (fm + fpage_size - 1) & align_mask; + { + volatile L4_Word_t tid_saved = tid_raw; + L4_ThreadId_t tid_reload = {.raw = tid_saved}; + L4_Map(tid_reload, fm, fpage_size); + } + fpage->base = fm; + free_mem = (char *) (fm + fpage_size); } fpage++; } /* start thread */ - start_thread(tid, (L4_Word_t) ptr->entry, stack, STACK_SIZE); + { + volatile L4_Word_t entry_saved = (L4_Word_t) ptr->entry; + start_thread(tid_raw, entry_saved, stack_top, stack_size); + } } - - printf("root_thread: all user threads started\n"); - while (1) L4_Sleep(L4_Never); }