diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index c6fb04d6..288bc968 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -84,11 +84,18 @@ jobs: runs-on: macos-latest steps: - uses: actions/checkout@v3 - - run: HOMEBREW_NO_AUTO_UPDATE=1 brew install jq mbedtls openssl - - run: make test upload-coverage TFLAGS=-DNO_SNTP_CHECK SSL=OPENSSL ASAN_OPTIONS= OPENSSL=`echo /usr/local/Cellar/openssl*/*` - - run: make test SSL=MBEDTLS TFLAGS=-DNO_SNTP_CHECK ASAN_OPTIONS= MBEDTLS=`echo /usr/local/Cellar/mbedtls*/*` + with: { fetch-depth: 2 } + - id: check + run: /bin/bash test/check.sh '^test|^src/*.[ch]' + - if: steps.check.outputs.MATCH == 1 + run: HOMEBREW_NO_AUTO_UPDATE=1 brew install jq mbedtls openssl + - if: steps.check.outputs.MATCH == 1 + run: make test upload-coverage TFLAGS=-DNO_SNTP_CHECK SSL=OPENSSL ASAN_OPTIONS= OPENSSL=`echo /usr/local/Cellar/openssl*/*` + - if: steps.check.outputs.MATCH == 1 + run: make test SSL=MBEDTLS TFLAGS=-DNO_SNTP_CHECK ASAN_OPTIONS= MBEDTLS=`echo /usr/local/Cellar/mbedtls*/*` #- run: make mip_test ASAN_OPTIONS= - - run: make mg_prefix + - if: steps.check.outputs.MATCH == 1 + run: make mg_prefix windows: runs-on: ubuntu-latest steps: diff --git a/examples/stm32/nucleo-f429zi-baremetal/main.c b/examples/stm32/nucleo-f429zi-baremetal/main.c index b0835cea..f9fdf0cb 100644 --- a/examples/stm32/nucleo-f429zi-baremetal/main.c +++ b/examples/stm32/nucleo-f429zi-baremetal/main.c @@ -10,7 +10,7 @@ #define BTN1 PIN('C', 13) // On-board user button #define BLINK_PERIOD_MS 1000 // LED blinking period in millis -static uint64_t s_ticks, s_exti; // Counters, increased by IRQ handlers +static volatile uint64_t s_ticks, s_exti; // Counters uint64_t mg_millis(void) { // Declare our own uptime function return s_ticks; // Return number of milliseconds since boot diff --git a/examples/stm32/nucleo-f746zg-baremetal/Makefile b/examples/stm32/nucleo-f746zg-baremetal/Makefile index f3391c8b..1d3db013 100644 --- a/examples/stm32/nucleo-f746zg-baremetal/Makefile +++ b/examples/stm32/nucleo-f746zg-baremetal/Makefile @@ -41,4 +41,4 @@ test: update grep 'MQTT connected' /tmp/output.txt # Check for MQTT connection success clean: - @rm -rf firmware.* *.su cmsis_core cmsis_device_f7 + @rm -rf firmware.* *.su cmsis_core cmsis_f7 diff --git a/examples/stm32/nucleo-f746zg-baremetal/hal.h b/examples/stm32/nucleo-f746zg-baremetal/hal.h index 4aac3b3f..4783d309 100644 --- a/examples/stm32/nucleo-f746zg-baremetal/hal.h +++ b/examples/stm32/nucleo-f746zg-baremetal/hal.h @@ -132,3 +132,12 @@ static inline uint32_t rng_read(void) { while ((RNG->SR & RNG_SR_DRDY) == 0) (void) 0; return RNG->DR; } + +#define UUID ((uint8_t *) 0x1ff0f420) // Unique 96-bit chip ID. TRM 41.1 + +// Helper macro for MAC generation +#define GENERATE_LOCALLY_ADMINISTERED_MAC() \ + { \ + 2, UUID[0] ^ UUID[1], UUID[2] ^ UUID[3], UUID[4] ^ UUID[5], \ + UUID[6] ^ UUID[7] ^ UUID[8], UUID[9] ^ UUID[10] ^ UUID[11] \ + } diff --git a/examples/stm32/nucleo-f746zg-baremetal/main.c b/examples/stm32/nucleo-f746zg-baremetal/main.c index a2666906..91eb5477 100644 --- a/examples/stm32/nucleo-f746zg-baremetal/main.c +++ b/examples/stm32/nucleo-f746zg-baremetal/main.c @@ -7,13 +7,12 @@ #define LED1 PIN('B', 0) // On-board LED pin (green) #define LED2 PIN('B', 7) // On-board LED pin (blue) #define LED3 PIN('B', 14) // On-board LED pin (red) -#define BTN1 PIN('C', 13) // On-board user button #define LED LED2 // Use blue LED for blinking #define BLINK_PERIOD_MS 1000 // LED blinking period in millis -static uint64_t s_ticks; // Milliseconds since boot -void SysTick_Handler(void) { // SyStick IRQ handler, triggered every 1ms +static volatile uint64_t s_ticks; // Milliseconds since boot +void SysTick_Handler(void) { // SyStick IRQ handler, triggered every 1ms s_ticks++; } @@ -30,7 +29,7 @@ void mg_random(void *buf, size_t len) { // Use on-board RNG static void timer_fn(void *arg) { gpio_toggle(LED); // Blink LED - struct mg_tcpip_if *ifp = arg; // And show + struct mg_tcpip_if *ifp = arg; // And show const char *names[] = {"down", "up", "ready"}; // network stats MG_INFO(("Ethernet: %s, IP: %M, rx:%u, tx:%u, dr:%u, er:%u", names[ifp->state], mg_print_ip4, &ifp->ip, ifp->nrecv, ifp->nsent, @@ -57,7 +56,7 @@ int main(void) { gpio_output(LED); // Setup green LED uart_init(UART_DEBUG, 115200); // Initialise debug printf ethernet_init(); // Initialise ethernet pins - MG_INFO(("Starting, CPU freq %g MHz", (double) SYS_FREQUENCY / 1000000)); + MG_INFO(("Starting, CPU freq %g MHz", (double) SystemCoreClock / 1000000)); struct mg_mgr mgr; // Initialise mg_mgr_init(&mgr); // Mongoose event manager @@ -66,13 +65,14 @@ int main(void) { // Initialise Mongoose network stack // Specify MAC address, and IP/mask/GW in network byte order for static // IP configuration. If IP/mask/GW are unset, DHCP is going to be used - struct mg_tcpip_driver_stm32_data driver_data = {.mdc_cr = 4}; // driver_stm32.h - struct mg_tcpip_if mif = {.driver = &mg_tcpip_driver_stm32, - .driver_data = &driver_data}; + struct mg_tcpip_driver_stm32_data driver_data = {.mdc_cr = 4}; + struct mg_tcpip_if mif = {.mac = GENERATE_LOCALLY_ADMINISTERED_MAC(), + .driver = &mg_tcpip_driver_stm32, + .driver_data = &driver_data}; mg_tcpip_init(&mgr, &mif); mg_timer_add(&mgr, BLINK_PERIOD_MS, MG_TIMER_REPEAT, timer_fn, &mif); - MG_INFO(("Waiting until network is up...")); + MG_INFO(("MAC: %M. Waiting for IP...", mg_print_mac, mif.mac)); while (mif.state != MIP_STATE_READY) { mg_mgr_poll(&mgr, 0); } diff --git a/examples/stm32/nucleo-h743zi-baremetal/Makefile b/examples/stm32/nucleo-h743zi-baremetal/Makefile index ec71187e..09dd9af8 100644 --- a/examples/stm32/nucleo-h743zi-baremetal/Makefile +++ b/examples/stm32/nucleo-h743zi-baremetal/Makefile @@ -1,38 +1,45 @@ -CFLAGS ?= -W -Wall -Wextra -Werror -Wundef -Wshadow -Wdouble-promotion \ - -Wformat-truncation -fno-common -Wconversion -Wno-sign-conversion \ - -g3 -Os -ffunction-sections -fdata-sections \ - -I. -Ih7/Include -Icmsis/CMSIS/Core/Include \ - -mcpu=cortex-m7 -mthumb -mfloat-abi=hard -mfpu=fpv5-sp-d16 \ - $(EXTRA_CFLAGS) -LDFLAGS ?= -Tlink.ld -nostartfiles -nostdlib --specs nano.specs -lc -lgcc -Wl,--gc-sections -Wl,-Map=$@.map -SOURCES = startup.c main.c syscalls.c +CFLAGS = -W -Wall -Wextra -Werror -Wundef -Wshadow -Wdouble-promotion +CFLAGS += -Wformat-truncation -fno-common -Wconversion -Wno-sign-conversion +CFLAGS += -g3 -Os -ffunction-sections -fdata-sections +CFLAGS += -I. -Icmsis_core/CMSIS/Core/Include -Icmsis_h7/Include +CFLAGS += -mcpu=cortex-m7 -mthumb -mfloat-abi=hard -mfpu=fpv5-sp-d16 +LDFLAGS ?= -Tlink.ld -nostdlib -nostartfiles --specs nano.specs -lc -lgcc -Wl,--gc-sections -Wl,-Map=$@.map -# Add Mongoose-specific flags and source files -CFLAGS += -I../../.. -DMG_ARCH=MG_ARCH_NEWLIB -DMG_ENABLE_CUSTOM_MILLIS=1 -DMG_ENABLE_TCPIP=1 -DMG_ENABLE_DRIVER_STM32H=1 -DMG_ENABLE_PACKED_FS=1 -SOURCES += ../../../mongoose.c ../../device-dashboard/net.c ../../device-dashboard/packed_fs.c +SOURCES = main.c syscalls.c sysinit.c +SOURCES += cmsis_h7/Source/Templates/gcc/startup_stm32h743xx.s # ST startup file. Compiler-dependent! + +# Mongoose-specific source code files and build options. See https://mongoose.ws/documentation/#build-options +SOURCES += mongoose.c net.c packed_fs.c +CFLAGS += -DMG_ENABLE_TCPIP=1 -DMG_ARCH=MG_ARCH_NEWLIB -DMG_ENABLE_PACKED_FS=1 +CFLAGS += -DMG_ENABLE_CUSTOM_RANDOM=1 -DMG_ENABLE_CUSTOM_MILLIS=1 +CFLAGS += -DMG_ENABLE_DRIVER_STM32H=1 $(CFLAGS_EXTRA) all build example: firmware.bin firmware.bin: firmware.elf arm-none-eabi-objcopy -O binary $< $@ -firmware.elf: $(SOURCES) mcu.h +firmware.elf: cmsis_core cmsis_h7 $(SOURCES) hal.h link.ld arm-none-eabi-gcc $(SOURCES) $(CFLAGS) $(LDFLAGS) -o $@ -# Note: on "unknown chip id" flash error, wire BOOT0 to VDD and st-flash erase flash: firmware.bin - st-flash --freq 600 --reset write $< 0x8000000 + st-flash --reset write $< 0x8000000 -# Requires env variable VCON_API_KEY set +cmsis_h7: # ARM CMSIS core headers + git clone --depth 1 -b v1.10.3 https://github.com/STMicroelectronics/cmsis_device_h7 $@ +cmsis_core: # ST CMSIS headers for STM32F7 series + git clone --depth 1 -b 5.9.0 https://github.com/ARM-software/CMSIS_5 $@ + +# Automated remote test. Requires env variable VCON_API_KEY set. See https://vcon.io/automated-firmware-tests/ DEVICE_URL ?= https://dash.vcon.io/api/v3/devices/6 -test: EXTRA_CFLAGS += -DUART_DEBUG=UART1 -test: update - curl --fail-with-body -su :$(VCON_API_KEY) $(DEVICE_URL)/tx?t=5 | tee /tmp/output.txt - grep 'READY, IP:' /tmp/output.txt - grep 'MQTT connected' /tmp/output.txt - update: firmware.bin curl --fail-with-body -su :$(VCON_API_KEY) $(DEVICE_URL)/ota --data-binary @$< +update test: CFLAGS_EXTRA += -DUART_DEBUG=USART1 +test: update + curl --fail-with-body -su :$(VCON_API_KEY) $(DEVICE_URL)/tx?t=5 | tee /tmp/output.txt + grep 'READY, IP:' /tmp/output.txt # Check for network init + grep 'MQTT connected' /tmp/output.txt # Check for MQTT connection success + clean: - @rm -rf firmware.* *.su + @rm -rf firmware.* *.su cmsis_core cmsis_h7 diff --git a/examples/stm32/nucleo-h743zi-baremetal/hal.h b/examples/stm32/nucleo-h743zi-baremetal/hal.h new file mode 100644 index 00000000..26effcb9 --- /dev/null +++ b/examples/stm32/nucleo-h743zi-baremetal/hal.h @@ -0,0 +1,163 @@ +// Copyright (c) 2022-2023 Cesanta Software Limited +// All rights reserved +// +// Datasheet: RM0433, devboard manual: UM2407 +// https://www.st.com/resource/en/reference_manual/rm0433-stm32h742-stm32h743753-and-stm32h750-value-line-advanced-armbased-32bit-mcus-stmicroelectronics.pdf +// Alternate functions: https://www.st.com/resource/en/datasheet/stm32h743vi.pdf + +#pragma once + +#include + +#include +#include +#include +#include + +#define BIT(x) (1UL << (x)) +#define SETBITS(R, CLEARMASK, SETMASK) (R) = ((R) & ~(CLEARMASK)) | (SETMASK) +#define PIN(bank, num) ((((bank) - 'A') << 8) | (num)) +#define PINNO(pin) (pin & 255) +#define PINBANK(pin) (pin >> 8) + +// System clock (2.1, Figure 1; 8.5, Figure 45; 8.5.5, Figure 47; 8.5.6, Figure +// 49) CPU_FREQUENCY <= 480 MHz; hclk = CPU_FREQUENCY / HPRE ; hclk <= 240 MHz; +// APB clocks <= 120 MHz. D1 domain bus matrix (and so flash) runs at hclk +// frequency. Configure flash latency (WS) in accordance to hclk freq (4.3.8, +// Table 17) The Ethernet controller is in D2 domain and runs at hclk frequency +enum { + D1CPRE = 1, // actual divisor value + HPRE = 2, // actual divisor value + D1PPRE = 4, // register values, divisor value = BIT(value - 3) = / 2 + D2PPRE1 = 4, + D2PPRE2 = 4, + D3PPRE = 4 +}; +// PLL1_P: odd division factors are not allowed (8.7.13) (according to Cube, '1' +// is also an "odd division factor"). +// Make sure your chip is revision 'V', otherwise set PLL1_N = 400 +enum { PLL1_HSI = 64, PLL1_M = 32, PLL1_N = 480, PLL1_P = 2 }; +#define FLASH_LATENCY 0x24 // WRHIGHFREQ LATENCY +#define CPU_FREQUENCY ((PLL1_HSI * PLL1_N / PLL1_M / PLL1_P / D1CPRE) * 1000000) +// #define CPU_FREQUENCY ((PLL1_HSI / D1CPRE) * 1000000) +#define AHB_FREQUENCY (CPU_FREQUENCY / HPRE) +#define APB2_FREQUENCY (AHB_FREQUENCY / (BIT(D2PPRE2 - 3))) +#define APB1_FREQUENCY (AHB_FREQUENCY / (BIT(D2PPRE1 - 3))) + +static inline void spin(volatile uint32_t n) { + while (n--) (void) 0; +} + +enum { GPIO_MODE_INPUT, GPIO_MODE_OUTPUT, GPIO_MODE_AF, GPIO_MODE_ANALOG }; +enum { GPIO_OTYPE_PUSH_PULL, GPIO_OTYPE_OPEN_DRAIN }; +enum { GPIO_SPEED_LOW, GPIO_SPEED_MEDIUM, GPIO_SPEED_HIGH, GPIO_SPEED_INSANE }; +enum { GPIO_PULL_NONE, GPIO_PULL_UP, GPIO_PULL_DOWN }; + +#define GPIO(N) ((GPIO_TypeDef *) (0x40000000 + 0x18020000UL + 0x400 * (N))) + +static GPIO_TypeDef *gpio_bank(uint16_t pin) { return GPIO(PINBANK(pin)); } +static inline void gpio_toggle(uint16_t pin) { + GPIO_TypeDef *gpio = gpio_bank(pin); + uint32_t mask = BIT(PINNO(pin)); + gpio->BSRR = mask << (gpio->ODR & mask ? 16 : 0); +} +static inline int gpio_read(uint16_t pin) { + return gpio_bank(pin)->IDR & BIT(PINNO(pin)) ? 1 : 0; +} +static inline void gpio_write(uint16_t pin, bool val) { + GPIO_TypeDef *gpio = gpio_bank(pin); + gpio->BSRR = BIT(PINNO(pin)) << (val ? 0 : 16); +} +static inline void gpio_init(uint16_t pin, uint8_t mode, uint8_t type, + uint8_t speed, uint8_t pull, uint8_t af) { + GPIO_TypeDef *gpio = gpio_bank(pin); + uint8_t n = (uint8_t) (PINNO(pin)); + RCC->AHB4ENR |= BIT(PINBANK(pin)); // Enable GPIO clock + SETBITS(gpio->OTYPER, 1UL << n, ((uint32_t) type) << n); + SETBITS(gpio->OSPEEDR, 3UL << (n * 2), ((uint32_t) speed) << (n * 2)); + SETBITS(gpio->PUPDR, 3UL << (n * 2), ((uint32_t) pull) << (n * 2)); + SETBITS(gpio->AFR[n >> 3], 15UL << ((n & 7) * 4), + ((uint32_t) af) << ((n & 7) * 4)); + SETBITS(gpio->MODER, 3UL << (n * 2), ((uint32_t) mode) << (n * 2)); +} +static inline void gpio_input(uint16_t pin) { + gpio_init(pin, GPIO_MODE_INPUT, GPIO_OTYPE_PUSH_PULL, GPIO_SPEED_HIGH, + GPIO_PULL_NONE, 0); +} +static inline void gpio_output(uint16_t pin) { + gpio_init(pin, GPIO_MODE_OUTPUT, GPIO_OTYPE_PUSH_PULL, GPIO_SPEED_HIGH, + GPIO_PULL_NONE, 0); +} + +#ifndef UART_DEBUG +#define UART_DEBUG USART1 +#endif + +// D2 Kernel clock (8.7.21) USART1 defaults to pclk2 (APB2), while USART2,3 +// default to pclk1 (APB1). Even if using other kernel clocks, the APBx clocks +// must be enabled for CPU access, as the kernel clock drives the BRR, not the +// APB bus interface +static inline void uart_init(USART_TypeDef *uart, unsigned long baud) { + uint8_t af = 7; // Alternate function + uint16_t rx = 0, tx = 0; // pins + uint32_t freq = 0; // Bus frequency. UART1 is on APB2, rest on APB1 + + if (uart == USART1) freq = APB2_FREQUENCY, RCC->APB2ENR |= BIT(4); + if (uart == USART2) freq = APB1_FREQUENCY, RCC->APB1LENR |= BIT(17); + if (uart == USART3) freq = APB1_FREQUENCY, RCC->APB1LENR |= BIT(18); + + if (uart == USART1) tx = PIN('A', 9), rx = PIN('A', 10); + if (uart == USART2) tx = PIN('A', 2), rx = PIN('A', 3); + if (uart == USART3) tx = PIN('D', 8), rx = PIN('D', 9); + +#if 0 // CONSTANT BAUD RATE FOR REMOTE DEBUGGING WHILE SETTING THE PLL + SETBITS(RCC->D2CCIP2R, 7 << 3, 3 << 3); // use HSI for UART1 + freq = 64000000; +#endif + + gpio_init(tx, GPIO_MODE_AF, GPIO_OTYPE_PUSH_PULL, GPIO_SPEED_HIGH, 0, af); + gpio_init(rx, GPIO_MODE_AF, GPIO_OTYPE_PUSH_PULL, GPIO_SPEED_HIGH, 0, af); + uart->CR1 = 0; // Disable this UART + uart->BRR = freq / baud; // Set baud rate + uart->CR1 = BIT(0) | BIT(2) | BIT(3); // Set UE, RE, TE +} +static inline void uart_write_byte(USART_TypeDef *uart, uint8_t byte) { + uart->TDR = byte; + while ((uart->ISR & BIT(7)) == 0) spin(1); +} +static inline void uart_write_buf(USART_TypeDef *uart, char *buf, size_t len) { + while (len-- > 0) uart_write_byte(uart, *(uint8_t *) buf++); +} +static inline int uart_read_ready(USART_TypeDef *uart) { + return uart->ISR & BIT(5); // If RXNE bit is set, data is ready +} +static inline uint8_t uart_read_byte(USART_TypeDef *uart) { + return (uint8_t) (uart->RDR & 255); +} + +static inline void rng_init(void) { + RCC->D2CCIP2R |= RCC_D2CCIP2R_RNGSEL_0; // RNG clock source pll1_q_ck + RCC->AHB2ENR |= RCC_AHB2ENR_RNGEN; // Enable RNG clock + RNG->CR = RNG_CR_RNGEN; // Enable RNG +} + +static inline uint32_t rng_read(void) { + while ((RNG->SR & RNG_SR_DRDY) == 0) (void) 0; + return RNG->DR; +} + +static inline char chiprev(void) { + uint16_t rev = (uint16_t) (((uint32_t) DBGMCU->IDCODE) >> 16); + if (rev == 0x1003) return 'Y'; + if (rev == 0x2003) return 'V'; + return '?'; +} + +#define UUID ((uint8_t *) UID_BASE) // Unique 96-bit chip ID. TRM 61.1 + +// Helper macro for MAC generation +#define GENERATE_LOCALLY_ADMINISTERED_MAC() \ + { \ + 2, UUID[0] ^ UUID[1], UUID[2] ^ UUID[3], UUID[4] ^ UUID[5], \ + UUID[6] ^ UUID[7] ^ UUID[8], UUID[9] ^ UUID[10] ^ UUID[11] \ + } diff --git a/examples/stm32/nucleo-h743zi-baremetal/link.ld b/examples/stm32/nucleo-h743zi-baremetal/link.ld index 94162029..715a6217 100644 --- a/examples/stm32/nucleo-h743zi-baremetal/link.ld +++ b/examples/stm32/nucleo-h743zi-baremetal/link.ld @@ -1,4 +1,4 @@ -ENTRY(_reset); +ENTRY(Reset_Handler); MEMORY { flash(rx) : ORIGIN = 0x08000000, LENGTH = 2048k sram(rwx) : ORIGIN = 0x24000000, LENGTH = 512k /* AXI SRAM in domain D1 */ @@ -9,9 +9,9 @@ MEMORY { _estack = ORIGIN(sram) + LENGTH(sram); /* stack points to end of SRAM */ SECTIONS { - .vectors : { KEEP(*(.vectors)) } > flash - .text : { *(.text*) } > flash - .rodata : { *(.rodata*) } > flash + .vectors : { KEEP(*(.isr_vector)) } > flash + .text : { *(.text* .text.*) } > flash + .rodata : { *(.rodata*) } > flash .data : { _sdata = .; /* for init_ram() */ diff --git a/examples/stm32/nucleo-h743zi-baremetal/main.c b/examples/stm32/nucleo-h743zi-baremetal/main.c index 1dfc7d39..893f2f71 100644 --- a/examples/stm32/nucleo-h743zi-baremetal/main.c +++ b/examples/stm32/nucleo-h743zi-baremetal/main.c @@ -1,79 +1,92 @@ // Copyright (c) 2023 Cesanta Software Limited // All rights reserved -#include "mcu.h" +#include "hal.h" #include "mongoose.h" -#define LED1 PIN('B', 0) // On-board LED pin (green) -#define LED2 PIN('E', 1) // On-board LED pin (yellow) -#define LED3 PIN('B', 14) // On-board LED pin (red) +#define LED1 PIN('B', 0) // On-board LED pin (green) +#define LED2 PIN('E', 1) // On-board LED pin (yellow) +#define LED3 PIN('B', 14) // On-board LED pin (red) + +#define LED LED2 // Use blue LED for blinking #define BLINK_PERIOD_MS 1000 // LED blinking period in millis -static uint64_t s_ticks; -void SysTick_Handler(void) { s_ticks++; } -uint64_t mg_millis(void) { return s_ticks; } - -static void timer_cb(void *arg) { - gpio_toggle(LED2); // Blink LED - MG_INFO(("ticks: %lld", mg_millis())); // Log something - (void) arg; +static volatile uint64_t s_ticks; // Milliseconds since boot +void SysTick_Handler(void) { // SyStick IRQ handler, triggered every 1ms + s_ticks++; } -int main(void) { - clock_init(); - systick_init(CPU_FREQUENCY / 1000); // Increment s_ticks every ms - gpio_output(LED2); // Setup LED - uart_init(UART_DEBUG, 115200); // Initialise debug printf +uint64_t mg_millis(void) { // Let Mongoose use our uptime function + return s_ticks; // Return number of milliseconds since boot +} - char rev = chiprev(); - MG_INFO(("Chip revision: %c, max cpu clock: %u MHz", rev, (rev == 'V') ? 480 : 400)); +void mg_random(void *buf, size_t len) { // Use on-board RNG + for (size_t n = 0; n < len; n += sizeof(uint32_t)) { + uint32_t r = rng_read(); + memcpy((char *) buf + n, &r, n + sizeof(r) > len ? len - n : sizeof(r)); + } +} +static void timer_fn(void *arg) { + gpio_toggle(LED); // Blink LED + struct mg_tcpip_if *ifp = arg; // And show + const char *names[] = {"down", "up", "ready"}; // network stats + MG_INFO(("Ethernet: %s, IP: %M, rx:%u, tx:%u, dr:%u, er:%u", + names[ifp->state], mg_print_ip4, &ifp->ip, ifp->nrecv, ifp->nsent, + ifp->ndrop, ifp->nerr)); +} - // Initialise Ethernet. Enable MAC GPIO pins, see UM2407 for MB1364 boards - // section 6.6.7: +static void ethernet_init(void) { + // Initialise Ethernet. Enable MAC GPIO pins, see // https://www.st.com/resource/en/user_manual/um2407-stm32h7-nucleo144-boards-mb1364-stmicroelectronics.pdf uint16_t pins[] = {PIN('A', 1), PIN('A', 2), PIN('A', 7), PIN('B', 13), PIN('C', 1), PIN('C', 4), PIN('C', 5), PIN('G', 11), PIN('G', 13)}; for (size_t i = 0; i < sizeof(pins) / sizeof(pins[0]); i++) { gpio_init(pins[i], GPIO_MODE_AF, GPIO_OTYPE_PUSH_PULL, GPIO_SPEED_INSANE, - GPIO_PULL_NONE, 11); + GPIO_PULL_NONE, 11); // 11 is the Ethernet function } - nvic_enable_irq(61); // Setup Ethernet IRQ handler - RCC->APB4ENR |= BIT(1); // Enable SYSCFG + NVIC_EnableIRQ(ETH_IRQn); // Setup Ethernet IRQ handler SETBITS(SYSCFG->PMCR, 7 << 21, 4 << 21); // Use RMII (12.3.1) RCC->AHB1ENR |= BIT(15) | BIT(16) | BIT(17); // Enable Ethernet clocks - RCC->AHB1RSTR |= BIT(15); // ETHMAC force reset - RCC->AHB1RSTR &= ~BIT(15); // ETHMAC release reset +} - MG_INFO(("Initialising Mongoose...")); - struct mg_mgr mgr; // Initialise Mongoose event manager - mg_mgr_init(&mgr); // and attach it to the MIP interface +int main(void) { + gpio_output(LED); // Setup green LED + uart_init(UART_DEBUG, 115200); // Initialise debug printf + ethernet_init(); // Initialise ethernet pins + + MG_INFO(("Chip revision: %c, max cpu clock: %u MHz", chiprev(), + (chiprev() == 'V') ? 480 : 400)); + MG_INFO(("Starting, CPU freq %g MHz", (double) SystemCoreClock / 1000000)); + + struct mg_mgr mgr; // Initialise + mg_mgr_init(&mgr); // Mongoose event manager mg_log_set(MG_LL_DEBUG); // Set log level - mg_timer_add(&mgr, BLINK_PERIOD_MS, MG_TIMER_REPEAT, timer_cb, NULL); // Initialise Mongoose network stack // Specify MAC address, and IP/mask/GW in network byte order for static // IP configuration. If IP/mask/GW are unset, DHCP is going to be used struct mg_tcpip_driver_stm32h_data driver_data = {.mdc_cr = 4}; - struct mg_tcpip_if mif = { - .mac = {2, 0, 1, 2, 3, 5}, - .driver = &mg_tcpip_driver_stm32h, - .driver_data = &driver_data, - }; + struct mg_tcpip_if mif = {.mac = GENERATE_LOCALLY_ADMINISTERED_MAC(), + .driver = &mg_tcpip_driver_stm32h, + .driver_data = &driver_data}; mg_tcpip_init(&mgr, &mif); + mg_timer_add(&mgr, BLINK_PERIOD_MS, MG_TIMER_REPEAT, timer_fn, &mif); - MG_INFO(("Waiting until network is up...")); + MG_INFO(("MAC: %M. Waiting for IP...", mg_print_mac, mif.mac)); while (mif.state != MIP_STATE_READY) { mg_mgr_poll(&mgr, 0); } MG_INFO(("Initialising application...")); extern void device_dashboard_fn(struct mg_connection *, int, void *, void *); - mg_http_listen(&mgr, "http://0.0.0.0", device_dashboard_fn, &mgr); + mg_http_listen(&mgr, "http://0.0.0.0", device_dashboard_fn, NULL); MG_INFO(("Starting event loop")); - for (;;) mg_mgr_poll(&mgr, 0); // Infinite event loop + for (;;) { + mg_mgr_poll(&mgr, 0); + } return 0; } diff --git a/examples/stm32/nucleo-h743zi-baremetal/mcu.h b/examples/stm32/nucleo-h743zi-baremetal/mcu.h deleted file mode 100644 index c9d123b7..00000000 --- a/examples/stm32/nucleo-h743zi-baremetal/mcu.h +++ /dev/null @@ -1,278 +0,0 @@ -// Copyright (c) 2022-2023 Cesanta Software Limited -// All rights reserved -// -// Datasheet: RM0433, devboard manual: UM2407 -// https://www.st.com/resource/en/reference_manual/rm0433-stm32h742-stm32h743753-and-stm32h750-value-line-advanced-armbased-32bit-mcus-stmicroelectronics.pdf -// Alternate functions: https://www.st.com/resource/en/datasheet/stm32h743vi.pdf - -#pragma once - -#include -#include -#include -#include - -#define BIT(x) (1UL << (x)) -#define SETBITS(R, CLEARMASK, SETMASK) (R) = ((R) & ~(CLEARMASK)) | (SETMASK) -#define PIN(bank, num) ((((bank) - 'A') << 8) | (num)) -#define PINNO(pin) (pin & 255) -#define PINBANK(pin) (pin >> 8) - -// System clock (2.1, Figure 1; 8.5, Figure 45; 8.5.5, Figure 47; 8.5.6, Figure -// 49) CPU_FREQUENCY <= 480 MHz; hclk = CPU_FREQUENCY / HPRE ; hclk <= 240 MHz; -// APB clocks <= 120 MHz. D1 domain bus matrix (and so flash) runs at hclk -// frequency. Configure flash latency (WS) in accordance to hclk freq (4.3.8, -// Table 17) The Ethernet controller is in D2 domain and runs at hclk frequency -enum { - D1CPRE = 1, // actual divisor value - HPRE = 2, // actual divisor value - D1PPRE = 4, // register values, divisor value = BIT(value - 3) = / 2 - D2PPRE1 = 4, - D2PPRE2 = 4, - D3PPRE = 4 -}; -// PLL1_P: odd division factors are not allowed (8.7.13) (according to Cube, '1' -// is also an "odd division factor"). -// Make sure your chip is revision 'V', otherwise set PLL1_N = 400 -enum { PLL1_HSI = 64, PLL1_M = 32, PLL1_N = 480, PLL1_P = 2 }; -#define FLASH_LATENCY 0x24 // WRHIGHFREQ LATENCY -#define CPU_FREQUENCY ((PLL1_HSI * PLL1_N / PLL1_M / PLL1_P / D1CPRE) * 1000000) -// #define CPU_FREQUENCY ((PLL1_HSI / D1CPRE) * 1000000) -#define AHB_FREQUENCY (CPU_FREQUENCY / HPRE) -#define APB2_FREQUENCY (AHB_FREQUENCY / (BIT(D2PPRE2 - 3))) -#define APB1_FREQUENCY (AHB_FREQUENCY / (BIT(D2PPRE1 - 3))) - -static inline void spin(volatile uint32_t n) { - while (n--) (void) 0; -} - -struct rcc { - volatile uint32_t CR, HSICFGR, CRRCR, CSICFGR, CFGR, RESERVED1, D1CFGR, - D2CFGR, D3CFGR, RESERVED2, PLLCKSELR, PLLCFGR, PLL1DIVR, PLL1FRACR, - PLL2DIVR, PLL2FRACR, PLL3DIVR, PLL3FRACR, RESERVED3, D1CCIPR, D2CCIP1R, - D2CCIP2R, D3CCIPR, RESERVED4, CIER, CIFR, CICR, RESERVED5, BDCR, CSR, - RESERVED6, AHB3RSTR, AHB1RSTR, AHB2RSTR, AHB4RSTR, APB3RSTR, APB1LRSTR, - APB1HRSTR, APB2RSTR, APB4RSTR, GCR, RESERVED8, D3AMR, RESERVED11[9], RSR, - AHB3ENR, AHB1ENR, AHB2ENR, AHB4ENR, APB3ENR, APB1LENR, APB1HENR, APB2ENR, - APB4ENR, RESERVED12, AHB3LPENR, AHB1LPENR, AHB2LPENR, AHB4LPENR, - APB3LPENR, APB1LLPENR, APB1HLPENR, APB2LPENR, APB4LPENR, RESERVED13[4]; -}; -#define RCC ((struct rcc *) (0x40000000 + 0x18020000 + 0x4400)) -struct pwr { - volatile uint32_t CR1, CSR1, CR2, CR3, CPUCR, RESERVED0, D3CR, RESERVED1, - WKUPCR, WKUPFR, WKUPEPR; -}; -#define PWR ((struct pwr *) (0x40000000 + 0x18020000 + 0x4800)) - -struct nvic { - volatile uint32_t ISER[8], RESERVED0[24], ICER[8], RSERVED1[24], ISPR[8], - RESERVED2[24], ICPR[8], RESERVED3[24], IABR[8], RESERVED4[56], IP[240], - RESERVED5[644], STIR; -}; -#define NVIC ((struct nvic *) 0xe000e100) -static inline void nvic_set_prio(int irq, uint32_t prio) { - NVIC->IP[irq] = prio << 4; -} -static inline void nvic_enable_irq(int irq) { - NVIC->ISER[irq >> 5] = (uint32_t) (1 << (irq & 31)); -} - -struct systick { - volatile uint32_t CTRL, LOAD, VAL, CALIB; -}; -#define SYSTICK ((struct systick *) 0xe000e010) -static inline void systick_init(uint32_t ticks) { - if ((ticks - 1) > 0xffffff) return; // Systick timer is 24 bit - SYSTICK->LOAD = ticks - 1; - SYSTICK->VAL = 0; - SYSTICK->CTRL = BIT(0) | BIT(1) | BIT(2); // Enable systick -} - -struct flash { - volatile uint32_t ACR, KEYR1, OPTKEYR, CR1, SR1, CCR1, OPTCR, OPTSR_CUR, - OPTSR_PRG, OPTCCR, PRAR_CUR1, PRAR_PRG1, SCAR_CUR1, SCAR_PRG1, WPSN_CUR1, - WPSN_PRG1, BOOT_CUR, BOOT_PRG, RESERVED0, CRCCR1, CRCSADD1, CRCEADD1, - CRCDATA, ECC_FA1, RESERVED1, KEYR2, RESERVED2, CR2, SR2, CCR2, RESERVED3, - PRAR_CUR2, PRAR_PRG2, SCAR_CUR2, SCAR_PRG2, WPSN_CUR2, WPSN_PRG2, - RESERVED4, CRCCR2, CRCSADD2, CRCEADD2, CRCDATA2, ECC_FA2; -}; -#define FLASH ((struct flash *) (0x40000000UL + 0x12000000UL + 0x2000UL)) - -struct scb { - volatile uint32_t CPUID, ICSR, VTOR, AIRCR, SCR, CCR, SHPR[3], SHCSR, CFSR, - HFSR, DFSR, MMFAR, BFAR, AFSR, ID_PFR[2], ID_DFR, ID_AFR, ID_MFR[4], - ID_ISAR[5], RESERVED0[1], CLIDR, CTR, CCSIDR, CSSELR, CPACR, - RESERVED3[93], STIR, RESERVED4[15], MVFR0, MVFR1, MVFR2, RESERVED5[1], - ICIALLU, RESERVED6[1], ICIMVAU, DCIMVAC, DCISW, DCCMVAU, DCCMVAC, DCCSW, - DCCIMVAC, DCCISW, RESERVED7[6], ITCMCR, DTCMCR, AHBPCR, CACR, AHBSCR, - RESERVED8[1], ABFSR; -}; -#define SCB ((struct scb *) 0xe000ed00) - -enum { GPIO_MODE_INPUT, GPIO_MODE_OUTPUT, GPIO_MODE_AF, GPIO_MODE_ANALOG }; -enum { GPIO_OTYPE_PUSH_PULL, GPIO_OTYPE_OPEN_DRAIN }; -enum { GPIO_SPEED_LOW, GPIO_SPEED_MEDIUM, GPIO_SPEED_HIGH, GPIO_SPEED_INSANE }; -enum { GPIO_PULL_NONE, GPIO_PULL_UP, GPIO_PULL_DOWN }; - -struct gpio { - volatile uint32_t MODER, OTYPER, OSPEEDR, PUPDR, IDR, ODR, BSRR, LCKR, AFR[2]; -}; -#define GPIO(N) ((struct gpio *) (0x40000000 + 0x18020000UL + 0x400 * (N))) - -static struct gpio *gpio_bank(uint16_t pin) { - return GPIO(PINBANK(pin)); -} -static inline void gpio_toggle(uint16_t pin) { - struct gpio *gpio = gpio_bank(pin); - uint32_t mask = BIT(PINNO(pin)); - gpio->BSRR = mask << (gpio->ODR & mask ? 16 : 0); -} -static inline int gpio_read(uint16_t pin) { - return gpio_bank(pin)->IDR & BIT(PINNO(pin)) ? 1 : 0; -} -static inline void gpio_write(uint16_t pin, bool val) { - struct gpio *gpio = gpio_bank(pin); - gpio->BSRR = BIT(PINNO(pin)) << (val ? 0 : 16); -} -static inline void gpio_init(uint16_t pin, uint8_t mode, uint8_t type, - uint8_t speed, uint8_t pull, uint8_t af) { - struct gpio *gpio = gpio_bank(pin); - uint8_t n = (uint8_t) (PINNO(pin)); - RCC->AHB4ENR |= BIT(PINBANK(pin)); // Enable GPIO clock - SETBITS(gpio->OTYPER, 1UL << n, ((uint32_t) type) << n); - SETBITS(gpio->OSPEEDR, 3UL << (n * 2), ((uint32_t) speed) << (n * 2)); - SETBITS(gpio->PUPDR, 3UL << (n * 2), ((uint32_t) pull) << (n * 2)); - SETBITS(gpio->AFR[n >> 3], 15UL << ((n & 7) * 4), - ((uint32_t) af) << ((n & 7) * 4)); - SETBITS(gpio->MODER, 3UL << (n * 2), ((uint32_t) mode) << (n * 2)); -} -static inline void gpio_input(uint16_t pin) { - gpio_init(pin, GPIO_MODE_INPUT, GPIO_OTYPE_PUSH_PULL, GPIO_SPEED_HIGH, - GPIO_PULL_NONE, 0); -} -static inline void gpio_output(uint16_t pin) { - gpio_init(pin, GPIO_MODE_OUTPUT, GPIO_OTYPE_PUSH_PULL, GPIO_SPEED_HIGH, - GPIO_PULL_NONE, 0); -} - -struct syscfg { - volatile uint32_t RESERVED1, PMCR, EXTICR[4], CFGR, RESERVED2, CCCSR, CCVR, - CCCR, PWRCR, RESERVED3[61], PKGR, RESERVED4[118], UR0, UR1, UR2, UR3, UR4, - UR5, UR6, UR7, UR8, UR9, UR10, UR11, UR12, UR13, UR14, UR15, UR16, UR17; -}; -#define SYSCFG ((struct syscfg *) (0x40000000UL + 0x18000000UL + 0x0400UL)) - -struct uart { - volatile uint32_t CR1, CR2, CR3, BRR, GTPR, RTOR, RQR, ISR, ICR, RDR, TDR, - PRESC; -}; -#define UART1 ((struct uart *) 0x40011000) -#define UART2 ((struct uart *) 0x40004400) -#define UART3 ((struct uart *) 0x40004800) -#define UART_DEBUG UART1 - -// D2 Kernel clock (8.7.21) USART1 defaults to pclk2 (APB2), while USART2,3 -// default to pclk1 (APB1). Even if using other kernel clocks, the APBx clocks -// must be enabled for CPU access, as the kernel clock drives the BRR, not the -// APB bus interface -static inline void uart_init(struct uart *uart, unsigned long baud) { - uint8_t af = 7; // Alternate function - uint16_t rx = 0, tx = 0; // pins - uint32_t freq = 0; // Bus frequency. UART1 is on APB2, rest on APB1 - - if (uart == UART1) freq = APB2_FREQUENCY, RCC->APB2ENR |= BIT(4); - if (uart == UART2) freq = APB1_FREQUENCY, RCC->APB1LENR |= BIT(17); - if (uart == UART3) freq = APB1_FREQUENCY, RCC->APB1LENR |= BIT(18); - - if (uart == UART1) tx = PIN('A', 9), rx = PIN('A', 10); - if (uart == UART2) tx = PIN('A', 2), rx = PIN('A', 3); - if (uart == UART3) tx = PIN('D', 8), rx = PIN('D', 9); - -#if 0 // CONSTANT BAUD RATE FOR REMOTE DEBUGGING WHILE SETTING THE PLL - SETBITS(RCC->D2CCIP2R, 7 << 3, 3 << 3); // use HSI for UART1 - freq = 64000000; -#endif - - gpio_init(tx, GPIO_MODE_AF, GPIO_OTYPE_PUSH_PULL, GPIO_SPEED_HIGH, 0, af); - gpio_init(rx, GPIO_MODE_AF, GPIO_OTYPE_PUSH_PULL, GPIO_SPEED_HIGH, 0, af); - uart->CR1 = 0; // Disable this UART - uart->BRR = freq / baud; // Set baud rate - uart->CR1 = BIT(0) | BIT(2) | BIT(3); // Set UE, RE, TE -} -static inline void uart_write_byte(struct uart *uart, uint8_t byte) { - uart->TDR = byte; - while ((uart->ISR & BIT(7)) == 0) spin(1); -} -static inline void uart_write_buf(struct uart *uart, char *buf, size_t len) { - while (len-- > 0) uart_write_byte(uart, *(uint8_t *) buf++); -} -static inline int uart_read_ready(struct uart *uart) { - return uart->ISR & BIT(5); // If RXNE bit is set, data is ready -} -static inline uint8_t uart_read_byte(struct uart *uart) { - return (uint8_t) (uart->RDR & 255); -} - -struct dbgmcu { - volatile uint32_t IDCODE, CR, RESERVED4, APB3FZ1, RESERVED5, APB1LFZ1, - RESERVED6, APB1HFZ1, RESERVED7, APB2FZ1, RESERVED8, APB4FZ1; -}; -#define DBGMCU ((struct dbgmcu *) 0x5C001000UL) - -static inline char chiprev(void) { - uint16_t rev = (uint16_t)(((uint32_t) DBGMCU->IDCODE) >> 16); - if (rev == 0x1003) return 'Y'; - if (rev == 0x2003) return 'V'; - return '?'; -} - -static inline unsigned int div2prescval(unsigned int div) { - // 0 --> /1; 8 --> /2 ... 11 --> /16; 12 --> /64 ... 15 --> /512 - if (div == 1) return 0; - if (div > 16) div /= 2; - unsigned int val = 7; - while (div >>= 1) ++val; - return val; -} - -static inline unsigned int pllrge(unsigned int f) { - unsigned int val = 0; - while (f >>= 1) ++val; - return val - 1; -} - -static inline void clock_init(void) { - SCB->CPACR |= ((3UL << 10 * 2) | (3UL << 11 * 2)); // Enable FPU - asm("DSB"); - asm("ISB"); - PWR->CR3 |= BIT(1); // select LDO (reset value) - while ((PWR->CSR1 && BIT(13)) == 0) spin(1); // ACTVOSRDY - PWR->D3CR |= BIT(15) | BIT(14); // Select VOS1 - uint32_t f = PWR->D3CR; // fake read to wait for bus clocking - while ((PWR->CSR1 && BIT(13)) == 0) spin(1); // ACTVOSRDY - SYSCFG->PWRCR |= BIT(0); // ODEN - f = SYSCFG->PWRCR; - while ((PWR->CSR1 && BIT(13)) == 0) spin(1); // ACTVOSRDY - (void) f; - SETBITS( - RCC->D1CFGR, (0x0F << 8) | (7 << 4) | (0x0F << 0), - (div2prescval(D1CPRE) << 8) | (D1PPRE << 4) | (div2prescval(HPRE) << 0)); - RCC->D2CFGR = (D2PPRE2 << 8) | (D2PPRE1 << 4); - RCC->D3CFGR = (D3PPRE << 4); - SETBITS(RCC->PLLCFGR, 3 << 2, - pllrge(PLL1_HSI / PLL1_M) - << 2); // keep reset config (DIVP1EN, !PLL1VCOSEL), PLL1RGE - SETBITS(RCC->PLL1DIVR, (0x7F << 9) | (0x1FF << 0), - ((PLL1_P - 1) << 9) | ((PLL1_N - 1) << 0)); // Set PLL1_P PLL1_N - SETBITS(RCC->PLLCKSELR, 0x3F << 4, - PLL1_M << 4); // Set PLL1_M (source defaults to HSI) - RCC->CR |= BIT(24); // Enable PLL1 - while ((RCC->CR & BIT(25)) == 0) spin(1); // Wait until done - RCC->CFGR |= (3 << 0); // Set clock source to PLL1 - while ((RCC->CFGR & (7 << 3)) != (3 << 3)) spin(1); // Wait until done - FLASH->ACR |= FLASH_LATENCY; // default is larger -#if 0 - // Enable SRAM block if you want to use it for ETH buffer (needs proper attributes in driver code) - // RCC->AHB2ENR |= BIT(29) | BIT(30) | BIT(31); -#endif -} diff --git a/examples/stm32/nucleo-h743zi-baremetal/mongoose.c b/examples/stm32/nucleo-h743zi-baremetal/mongoose.c new file mode 120000 index 00000000..5e522bbc --- /dev/null +++ b/examples/stm32/nucleo-h743zi-baremetal/mongoose.c @@ -0,0 +1 @@ +../../../mongoose.c \ No newline at end of file diff --git a/examples/stm32/nucleo-h743zi-baremetal/mongoose.h b/examples/stm32/nucleo-h743zi-baremetal/mongoose.h new file mode 120000 index 00000000..ee4ac823 --- /dev/null +++ b/examples/stm32/nucleo-h743zi-baremetal/mongoose.h @@ -0,0 +1 @@ +../../../mongoose.h \ No newline at end of file diff --git a/examples/stm32/nucleo-h743zi-baremetal/net.c b/examples/stm32/nucleo-h743zi-baremetal/net.c new file mode 120000 index 00000000..fe0e6f06 --- /dev/null +++ b/examples/stm32/nucleo-h743zi-baremetal/net.c @@ -0,0 +1 @@ +../../device-dashboard/net.c \ No newline at end of file diff --git a/examples/stm32/nucleo-h743zi-baremetal/packed_fs.c b/examples/stm32/nucleo-h743zi-baremetal/packed_fs.c new file mode 120000 index 00000000..e06bf092 --- /dev/null +++ b/examples/stm32/nucleo-h743zi-baremetal/packed_fs.c @@ -0,0 +1 @@ +../../device-dashboard/packed_fs.c \ No newline at end of file diff --git a/examples/stm32/nucleo-h743zi-baremetal/startup.c b/examples/stm32/nucleo-h743zi-baremetal/startup.c deleted file mode 100644 index 78feab2f..00000000 --- a/examples/stm32/nucleo-h743zi-baremetal/startup.c +++ /dev/null @@ -1,226 +0,0 @@ -// Copyright (c) 2022 Cesanta Software Limited -// All rights reserved - -// Startup code -__attribute__((naked, noreturn)) void _reset(void) { - // Initialise memory - extern long _sbss, _ebss, _sdata, _edata, _sidata; - for (long *src = &_sbss; src < &_ebss; src++) *src = 0; - for (long *src = &_sdata, *dst = &_sidata; src < &_edata;) *src++ = *dst++; - - // Call main() - extern void main(void); - main(); - for (;;) (void) 0; -} - -void __attribute__((weak)) DefaultIRQHandler(void) { - for (;;) (void) 0; -} - -#define WEAK_ALIAS __attribute__((weak, alias("DefaultIRQHandler"))) - -WEAK_ALIAS void NMI_Handler(void); -WEAK_ALIAS void HardFault_Handler(void); -WEAK_ALIAS void MemManage_Handler(void); -WEAK_ALIAS void BusFault_Handler(void); -WEAK_ALIAS void UsageFault_Handler(void); -WEAK_ALIAS void SVC_Handler(void); -WEAK_ALIAS void DebugMon_Handler(void); -WEAK_ALIAS void PendSV_Handler(void); -WEAK_ALIAS void SysTick_Handler(void); - -WEAK_ALIAS void WWDG_IRQHandler(void); -WEAK_ALIAS void PVD_AVD_IRQHandler(void); -WEAK_ALIAS void TAMP_STAMP_IRQHandler(void); -WEAK_ALIAS void RTC_WKUP_IRQHandler(void); -WEAK_ALIAS void FLASH_IRQHandler(void); -WEAK_ALIAS void RCC_IRQHandler(void); -WEAK_ALIAS void EXTI0_IRQHandler(void); -WEAK_ALIAS void EXTI1_IRQHandler(void); -WEAK_ALIAS void EXTI2_IRQHandler(void); -WEAK_ALIAS void EXTI3_IRQHandler(void); -WEAK_ALIAS void EXTI4_IRQHandler(void); -WEAK_ALIAS void DMA1_Stream0_IRQHandler(void); -WEAK_ALIAS void DMA1_Stream1_IRQHandler(void); -WEAK_ALIAS void DMA1_Stream2_IRQHandler(void); -WEAK_ALIAS void DMA1_Stream3_IRQHandler(void); -WEAK_ALIAS void DMA1_Stream4_IRQHandler(void); -WEAK_ALIAS void DMA1_Stream5_IRQHandler(void); -WEAK_ALIAS void DMA1_Stream6_IRQHandler(void); -WEAK_ALIAS void ADC_IRQHandler(void); -WEAK_ALIAS void FDCAN1_IT0_IRQHandler(void); -WEAK_ALIAS void FDCAN2_IT0_IRQHandler(void); -WEAK_ALIAS void FDCAN1_IT1_IRQHandler(void); -WEAK_ALIAS void FDCAN2_IT1_IRQHandler(void); -WEAK_ALIAS void EXTI9_5_IRQHandler(void); -WEAK_ALIAS void TIM1_BRK_IRQHandler(void); -WEAK_ALIAS void TIM1_UP_IRQHandler(void); -WEAK_ALIAS void TIM1_TRG_COM_IRQHandler(void); -WEAK_ALIAS void TIM1_CC_IRQHandler(void); -WEAK_ALIAS void TIM2_IRQHandler(void); -WEAK_ALIAS void TIM3_IRQHandler(void); -WEAK_ALIAS void TIM4_IRQHandler(void); -WEAK_ALIAS void I2C1_EV_IRQHandler(void); -WEAK_ALIAS void I2C1_ER_IRQHandler(void); -WEAK_ALIAS void I2C2_EV_IRQHandler(void); -WEAK_ALIAS void I2C2_ER_IRQHandler(void); -WEAK_ALIAS void SPI1_IRQHandler(void); -WEAK_ALIAS void SPI2_IRQHandler(void); -WEAK_ALIAS void USART1_IRQHandler(void); -WEAK_ALIAS void USART2_IRQHandler(void); -WEAK_ALIAS void USART3_IRQHandler(void); -WEAK_ALIAS void EXTI15_10_IRQHandler(void); -WEAK_ALIAS void RTC_Alarm_IRQHandler(void); -WEAK_ALIAS void TIM8_BRK_TIM12_IRQHandler(void); -WEAK_ALIAS void TIM8_UP_TIM13_IRQHandler(void); -WEAK_ALIAS void TIM8_TRG_COM_TIM14_IRQHandler(void); -WEAK_ALIAS void TIM8_CC_IRQHandler(void); -WEAK_ALIAS void DMA1_Stream7_IRQHandler(void); -WEAK_ALIAS void FMC_IRQHandler(void); -WEAK_ALIAS void SDMMC1_IRQHandler(void); -WEAK_ALIAS void TIM5_IRQHandler(void); -WEAK_ALIAS void SPI3_IRQHandler(void); -WEAK_ALIAS void UART4_IRQHandler(void); -WEAK_ALIAS void UART5_IRQHandler(void); -WEAK_ALIAS void TIM6_DAC_IRQHandler(void); -WEAK_ALIAS void TIM7_IRQHandler(void); -WEAK_ALIAS void DMA2_Stream0_IRQHandler(void); -WEAK_ALIAS void DMA2_Stream1_IRQHandler(void); -WEAK_ALIAS void DMA2_Stream2_IRQHandler(void); -WEAK_ALIAS void DMA2_Stream3_IRQHandler(void); -WEAK_ALIAS void DMA2_Stream4_IRQHandler(void); -WEAK_ALIAS void ETH_IRQHandler(void); -WEAK_ALIAS void ETH_WKUP_IRQHandler(void); -WEAK_ALIAS void FDCAN_CAL_IRQHandler(void); -WEAK_ALIAS void DMA2_Stream5_IRQHandler(void); -WEAK_ALIAS void DMA2_Stream6_IRQHandler(void); -WEAK_ALIAS void DMA2_Stream7_IRQHandler(void); -WEAK_ALIAS void USART6_IRQHandler(void); -WEAK_ALIAS void I2C3_EV_IRQHandler(void); -WEAK_ALIAS void I2C3_ER_IRQHandler(void); -WEAK_ALIAS void OTG_HS_EP1_OUT_IRQHandler(void); -WEAK_ALIAS void OTG_HS_EP1_IN_IRQHandler(void); -WEAK_ALIAS void OTG_HS_WKUP_IRQHandler(void); -WEAK_ALIAS void OTG_HS_IRQHandler(void); -WEAK_ALIAS void DCMI_IRQHandler(void); -WEAK_ALIAS void RNG_IRQHandler(void); -WEAK_ALIAS void FPU_IRQHandler(void); -WEAK_ALIAS void UART7_IRQHandler(void); -WEAK_ALIAS void UART8_IRQHandler(void); -WEAK_ALIAS void SPI4_IRQHandler(void); -WEAK_ALIAS void SPI5_IRQHandler(void); -WEAK_ALIAS void SPI6_IRQHandler(void); -WEAK_ALIAS void SAI1_IRQHandler(void); -WEAK_ALIAS void LTDC_IRQHandler(void); -WEAK_ALIAS void LTDC_ER_IRQHandler(void); -WEAK_ALIAS void DMA2D_IRQHandler(void); -WEAK_ALIAS void SAI2_IRQHandler(void); -WEAK_ALIAS void QUADSPI_IRQHandler(void); -WEAK_ALIAS void LPTIM1_IRQHandler(void); -WEAK_ALIAS void CEC_IRQHandler(void); -WEAK_ALIAS void I2C4_EV_IRQHandler(void); -WEAK_ALIAS void I2C4_ER_IRQHandler(void); -WEAK_ALIAS void SPDIF_RX_IRQHandler(void); -WEAK_ALIAS void OTG_FS_EP1_OUT_IRQHandler(void); -WEAK_ALIAS void OTG_FS_EP1_IN_IRQHandler(void); -WEAK_ALIAS void OTG_FS_WKUP_IRQHandler(void); -WEAK_ALIAS void OTG_FS_IRQHandler(void); -WEAK_ALIAS void DMAMUX1_OVR_IRQHandler(void); -WEAK_ALIAS void HRTIM1_Master_IRQHandler(void); -WEAK_ALIAS void HRTIM1_TIMA_IRQHandler(void); -WEAK_ALIAS void HRTIM1_TIMB_IRQHandler(void); -WEAK_ALIAS void HRTIM1_TIMC_IRQHandler(void); -WEAK_ALIAS void HRTIM1_TIMD_IRQHandler(void); -WEAK_ALIAS void HRTIM1_TIME_IRQHandler(void); -WEAK_ALIAS void HRTIM1_FLT_IRQHandler(void); -WEAK_ALIAS void DFSDM1_FLT0_IRQHandler(void); -WEAK_ALIAS void DFSDM1_FLT1_IRQHandler(void); -WEAK_ALIAS void DFSDM1_FLT2_IRQHandler(void); -WEAK_ALIAS void DFSDM1_FLT3_IRQHandler(void); -WEAK_ALIAS void SAI3_IRQHandler(void); -WEAK_ALIAS void SWPMI1_IRQHandler(void); -WEAK_ALIAS void TIM15_IRQHandler(void); -WEAK_ALIAS void TIM16_IRQHandler(void); -WEAK_ALIAS void TIM17_IRQHandler(void); -WEAK_ALIAS void MDIOS_WKUP_IRQHandler(void); -WEAK_ALIAS void MDIOS_IRQHandler(void); -WEAK_ALIAS void JPEG_IRQHandler(void); -WEAK_ALIAS void MDMA_IRQHandler(void); -WEAK_ALIAS void SDMMC2_IRQHandler(void); -WEAK_ALIAS void HSEM1_IRQHandler(void); -WEAK_ALIAS void ADC3_IRQHandler(void); -WEAK_ALIAS void DMAMUX2_OVR_IRQHandler(void); -WEAK_ALIAS void BDMA_Channel0_IRQHandler(void); -WEAK_ALIAS void BDMA_Channel1_IRQHandler(void); -WEAK_ALIAS void BDMA_Channel2_IRQHandler(void); -WEAK_ALIAS void BDMA_Channel3_IRQHandler(void); -WEAK_ALIAS void BDMA_Channel4_IRQHandler(void); -WEAK_ALIAS void BDMA_Channel5_IRQHandler(void); -WEAK_ALIAS void BDMA_Channel6_IRQHandler(void); -WEAK_ALIAS void BDMA_Channel7_IRQHandler(void); -WEAK_ALIAS void COMP1_IRQHandler(void); -WEAK_ALIAS void LPTIM2_IRQHandler(void); -WEAK_ALIAS void LPTIM3_IRQHandler(void); -WEAK_ALIAS void LPTIM4_IRQHandler(void); -WEAK_ALIAS void LPTIM5_IRQHandler(void); -WEAK_ALIAS void LPUART1_IRQHandler(void); -WEAK_ALIAS void CRS_IRQHandler(void); -WEAK_ALIAS void ECC_IRQHandler(void); -WEAK_ALIAS void SAI4_IRQHandler(void); -WEAK_ALIAS void WAKEUP_PIN_IRQHandler(void); - -// IRQ table -extern void _estack(); -__attribute__((section(".vectors"))) void (*tab[16 + 150])(void) = { - // Cortex interrupts - _estack, _reset, NMI_Handler, HardFault_Handler, MemManage_Handler, - BusFault_Handler, UsageFault_Handler, 0, 0, 0, 0, SVC_Handler, - DebugMon_Handler, 0, PendSV_Handler, SysTick_Handler, - - // Interrupts from peripherals - WWDG_IRQHandler, PVD_AVD_IRQHandler, TAMP_STAMP_IRQHandler, - RTC_WKUP_IRQHandler, FLASH_IRQHandler, RCC_IRQHandler, EXTI0_IRQHandler, - EXTI1_IRQHandler, EXTI2_IRQHandler, EXTI3_IRQHandler, EXTI4_IRQHandler, - DMA1_Stream0_IRQHandler, DMA1_Stream1_IRQHandler, DMA1_Stream2_IRQHandler, - DMA1_Stream3_IRQHandler, DMA1_Stream4_IRQHandler, DMA1_Stream5_IRQHandler, - DMA1_Stream6_IRQHandler, ADC_IRQHandler, FDCAN1_IT0_IRQHandler, - FDCAN2_IT0_IRQHandler, FDCAN1_IT1_IRQHandler, FDCAN2_IT1_IRQHandler, - EXTI9_5_IRQHandler, TIM1_BRK_IRQHandler, TIM1_UP_IRQHandler, - TIM1_TRG_COM_IRQHandler, TIM1_CC_IRQHandler, TIM2_IRQHandler, - TIM3_IRQHandler, TIM4_IRQHandler, I2C1_EV_IRQHandler, I2C1_ER_IRQHandler, - I2C2_EV_IRQHandler, I2C2_ER_IRQHandler, SPI1_IRQHandler, SPI2_IRQHandler, - USART1_IRQHandler, USART2_IRQHandler, USART3_IRQHandler, - EXTI15_10_IRQHandler, RTC_Alarm_IRQHandler, 0, TIM8_BRK_TIM12_IRQHandler, - TIM8_UP_TIM13_IRQHandler, TIM8_TRG_COM_TIM14_IRQHandler, TIM8_CC_IRQHandler, - DMA1_Stream7_IRQHandler, FMC_IRQHandler, SDMMC1_IRQHandler, TIM5_IRQHandler, - SPI3_IRQHandler, UART4_IRQHandler, UART5_IRQHandler, TIM6_DAC_IRQHandler, - TIM7_IRQHandler, DMA2_Stream0_IRQHandler, DMA2_Stream1_IRQHandler, - DMA2_Stream2_IRQHandler, DMA2_Stream3_IRQHandler, DMA2_Stream4_IRQHandler, - ETH_IRQHandler, ETH_WKUP_IRQHandler, FDCAN_CAL_IRQHandler, 0, 0, 0, 0, - DMA2_Stream5_IRQHandler, DMA2_Stream6_IRQHandler, DMA2_Stream7_IRQHandler, - USART6_IRQHandler, I2C3_EV_IRQHandler, I2C3_ER_IRQHandler, - OTG_HS_EP1_OUT_IRQHandler, OTG_HS_EP1_IN_IRQHandler, OTG_HS_WKUP_IRQHandler, - OTG_HS_IRQHandler, DCMI_IRQHandler, 0, RNG_IRQHandler, FPU_IRQHandler, - UART7_IRQHandler, UART8_IRQHandler, SPI4_IRQHandler, SPI5_IRQHandler, - SPI6_IRQHandler, SAI1_IRQHandler, LTDC_IRQHandler, LTDC_ER_IRQHandler, - DMA2D_IRQHandler, SAI2_IRQHandler, QUADSPI_IRQHandler, LPTIM1_IRQHandler, - CEC_IRQHandler, I2C4_EV_IRQHandler, I2C4_ER_IRQHandler, SPDIF_RX_IRQHandler, - OTG_FS_EP1_OUT_IRQHandler, OTG_FS_EP1_IN_IRQHandler, OTG_FS_WKUP_IRQHandler, - OTG_FS_IRQHandler, DMAMUX1_OVR_IRQHandler, HRTIM1_Master_IRQHandler, - HRTIM1_TIMA_IRQHandler, HRTIM1_TIMB_IRQHandler, HRTIM1_TIMC_IRQHandler, - HRTIM1_TIMD_IRQHandler, HRTIM1_TIME_IRQHandler, HRTIM1_FLT_IRQHandler, - DFSDM1_FLT0_IRQHandler, DFSDM1_FLT1_IRQHandler, DFSDM1_FLT2_IRQHandler, - DFSDM1_FLT3_IRQHandler, SAI3_IRQHandler, SWPMI1_IRQHandler, - TIM15_IRQHandler, TIM16_IRQHandler, TIM17_IRQHandler, MDIOS_WKUP_IRQHandler, - MDIOS_IRQHandler, JPEG_IRQHandler, MDMA_IRQHandler, 0, SDMMC2_IRQHandler, - HSEM1_IRQHandler, 0, ADC3_IRQHandler, DMAMUX2_OVR_IRQHandler, - BDMA_Channel0_IRQHandler, BDMA_Channel1_IRQHandler, - BDMA_Channel2_IRQHandler, BDMA_Channel3_IRQHandler, - BDMA_Channel4_IRQHandler, BDMA_Channel5_IRQHandler, - BDMA_Channel6_IRQHandler, BDMA_Channel7_IRQHandler, COMP1_IRQHandler, - LPTIM2_IRQHandler, LPTIM3_IRQHandler, LPTIM4_IRQHandler, LPTIM5_IRQHandler, - LPUART1_IRQHandler, 0, CRS_IRQHandler, ECC_IRQHandler, SAI4_IRQHandler, 0, - 0, WAKEUP_PIN_IRQHandler -} -; diff --git a/examples/stm32/nucleo-h743zi-baremetal/syscalls.c b/examples/stm32/nucleo-h743zi-baremetal/syscalls.c index ca0e064d..be3210aa 100644 --- a/examples/stm32/nucleo-h743zi-baremetal/syscalls.c +++ b/examples/stm32/nucleo-h743zi-baremetal/syscalls.c @@ -1,6 +1,6 @@ #include -#include "mcu.h" +#include "hal.h" int _fstat(int fd, struct stat *st) { if (fd < 0) return -1; @@ -43,9 +43,13 @@ void _exit(int status) { for (;;) asm volatile("BKPT #0"); } -void _kill(int pid, int sig) { (void) pid, (void) sig; } +void _kill(int pid, int sig) { + (void) pid, (void) sig; +} -int _getpid(void) { return -1; } +int _getpid(void) { + return -1; +} int _write(int fd, char *ptr, int len) { (void) fd, (void) ptr, (void) len; @@ -77,3 +81,5 @@ int mkdir(const char *path, mode_t mode) { (void) path, (void) mode; return -1; } + +void _init(void) {} diff --git a/examples/stm32/nucleo-h743zi-baremetal/sysinit.c b/examples/stm32/nucleo-h743zi-baremetal/sysinit.c new file mode 100644 index 00000000..1c13b1fa --- /dev/null +++ b/examples/stm32/nucleo-h743zi-baremetal/sysinit.c @@ -0,0 +1,65 @@ +// Copyright (c) 2023 Cesanta Software Limited +// All rights reserved +// +// This file contains essentials required by the CMSIS: +// uint32_t SystemCoreClock - holds the system core clock value +// SystemInit() - initialises the system, e.g. sets up clocks + +#include "hal.h" + +uint32_t SystemCoreClock = CPU_FREQUENCY; + +static inline unsigned int div2prescval(unsigned int div) { + // 0 --> /1; 8 --> /2 ... 11 --> /16; 12 --> /64 ... 15 --> /512 + if (div == 1) return 0; + if (div > 16) div /= 2; + unsigned int val = 7; + while (div >>= 1) ++val; + return val; +} + +static inline unsigned int pllrge(unsigned int f) { + unsigned int val = 0; + while (f >>= 1) ++val; + return val - 1; +} + +void SystemInit(void) { // Called automatically by startup code + SCB->CPACR |= ((3UL << 10 * 2) | (3UL << 11 * 2)); // Enable FPU + asm("DSB"); + asm("ISB"); + PWR->CR3 |= BIT(1); // select LDO (reset value) + while ((PWR->CSR1 && BIT(13)) == 0) spin(1); // ACTVOSRDY + PWR->D3CR |= BIT(15) | BIT(14); // Select VOS1 + uint32_t f = PWR->D3CR; // fake read to wait for bus clocking + while ((PWR->CSR1 && BIT(13)) == 0) spin(1); // ACTVOSRDY + SYSCFG->PWRCR |= BIT(0); // ODEN + f = SYSCFG->PWRCR; + while ((PWR->CSR1 && BIT(13)) == 0) spin(1); // ACTVOSRDY + (void) f; + SETBITS( + RCC->D1CFGR, (0x0F << 8) | (7 << 4) | (0x0F << 0), + (div2prescval(D1CPRE) << 8) | (D1PPRE << 4) | (div2prescval(HPRE) << 0)); + RCC->D2CFGR = (D2PPRE2 << 8) | (D2PPRE1 << 4); + RCC->D3CFGR = (D3PPRE << 4); + SETBITS(RCC->PLLCFGR, 3 << 2, + pllrge(PLL1_HSI / PLL1_M) + << 2); // keep reset config (DIVP1EN, !PLL1VCOSEL), PLL1RGE + SETBITS(RCC->PLL1DIVR, (0x7F << 9) | (0x1FF << 0), + ((PLL1_P - 1) << 9) | ((PLL1_N - 1) << 0)); // Set PLL1_P PLL1_N + SETBITS(RCC->PLLCKSELR, 0x3F << 4, + PLL1_M << 4); // Set PLL1_M (source defaults to HSI) + RCC->CR |= BIT(24); // Enable PLL1 + while ((RCC->CR & BIT(25)) == 0) spin(1); // Wait until done + RCC->CFGR |= (3 << 0); // Set clock source to PLL1 + while ((RCC->CFGR & (7 << 3)) != (3 << 3)) spin(1); // Wait until done + FLASH->ACR |= FLASH_LATENCY; // default is larger +#if 0 + // Enable SRAM block if you want to use it for ETH buffer (needs proper attributes in driver code) + // RCC->AHB2ENR |= BIT(29) | BIT(30) | BIT(31); +#endif + + RCC->APB4ENR |= RCC_APB4ENR_SYSCFGEN; // Enable SYSCFG + rng_init(); // Initialise random number generator + SysTick_Config(CPU_FREQUENCY / 1000); // Sys tick every 1ms +}