Use CMSIS for H7

This commit is contained in:
cpq 2023-02-08 20:14:39 +00:00
parent 6294ce59f7
commit 35924ce550
17 changed files with 356 additions and 586 deletions

View File

@ -84,11 +84,18 @@ jobs:
runs-on: macos-latest runs-on: macos-latest
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- run: HOMEBREW_NO_AUTO_UPDATE=1 brew install jq mbedtls openssl with: { fetch-depth: 2 }
- run: make test upload-coverage TFLAGS=-DNO_SNTP_CHECK SSL=OPENSSL ASAN_OPTIONS= OPENSSL=`echo /usr/local/Cellar/openssl*/*` - id: check
- run: make test SSL=MBEDTLS TFLAGS=-DNO_SNTP_CHECK ASAN_OPTIONS= MBEDTLS=`echo /usr/local/Cellar/mbedtls*/*` 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 mip_test ASAN_OPTIONS=
- run: make mg_prefix - if: steps.check.outputs.MATCH == 1
run: make mg_prefix
windows: windows:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:

View File

@ -10,7 +10,7 @@
#define BTN1 PIN('C', 13) // On-board user button #define BTN1 PIN('C', 13) // On-board user button
#define BLINK_PERIOD_MS 1000 // LED blinking period in millis #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 uint64_t mg_millis(void) { // Declare our own uptime function
return s_ticks; // Return number of milliseconds since boot return s_ticks; // Return number of milliseconds since boot

View File

@ -41,4 +41,4 @@ test: update
grep 'MQTT connected' /tmp/output.txt # Check for MQTT connection success grep 'MQTT connected' /tmp/output.txt # Check for MQTT connection success
clean: clean:
@rm -rf firmware.* *.su cmsis_core cmsis_device_f7 @rm -rf firmware.* *.su cmsis_core cmsis_f7

View File

@ -132,3 +132,12 @@ static inline uint32_t rng_read(void) {
while ((RNG->SR & RNG_SR_DRDY) == 0) (void) 0; while ((RNG->SR & RNG_SR_DRDY) == 0) (void) 0;
return RNG->DR; 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] \
}

View File

@ -7,13 +7,12 @@
#define LED1 PIN('B', 0) // On-board LED pin (green) #define LED1 PIN('B', 0) // On-board LED pin (green)
#define LED2 PIN('B', 7) // On-board LED pin (blue) #define LED2 PIN('B', 7) // On-board LED pin (blue)
#define LED3 PIN('B', 14) // On-board LED pin (red) #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 LED LED2 // Use blue LED for blinking
#define BLINK_PERIOD_MS 1000 // LED blinking period in millis #define BLINK_PERIOD_MS 1000 // LED blinking period in millis
static uint64_t s_ticks; // Milliseconds since boot static volatile uint64_t s_ticks; // Milliseconds since boot
void SysTick_Handler(void) { // SyStick IRQ handler, triggered every 1ms void SysTick_Handler(void) { // SyStick IRQ handler, triggered every 1ms
s_ticks++; s_ticks++;
} }
@ -30,7 +29,7 @@ void mg_random(void *buf, size_t len) { // Use on-board RNG
static void timer_fn(void *arg) { static void timer_fn(void *arg) {
gpio_toggle(LED); // Blink LED 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 const char *names[] = {"down", "up", "ready"}; // network stats
MG_INFO(("Ethernet: %s, IP: %M, rx:%u, tx:%u, dr:%u, er:%u", 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, 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 gpio_output(LED); // Setup green LED
uart_init(UART_DEBUG, 115200); // Initialise debug printf uart_init(UART_DEBUG, 115200); // Initialise debug printf
ethernet_init(); // Initialise ethernet pins 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 struct mg_mgr mgr; // Initialise
mg_mgr_init(&mgr); // Mongoose event manager mg_mgr_init(&mgr); // Mongoose event manager
@ -66,13 +65,14 @@ int main(void) {
// Initialise Mongoose network stack // Initialise Mongoose network stack
// Specify MAC address, and IP/mask/GW in network byte order for static // 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 // 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_driver_stm32_data driver_data = {.mdc_cr = 4};
struct mg_tcpip_if mif = {.driver = &mg_tcpip_driver_stm32, struct mg_tcpip_if mif = {.mac = GENERATE_LOCALLY_ADMINISTERED_MAC(),
.driver_data = &driver_data}; .driver = &mg_tcpip_driver_stm32,
.driver_data = &driver_data};
mg_tcpip_init(&mgr, &mif); mg_tcpip_init(&mgr, &mif);
mg_timer_add(&mgr, BLINK_PERIOD_MS, MG_TIMER_REPEAT, timer_fn, &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) { while (mif.state != MIP_STATE_READY) {
mg_mgr_poll(&mgr, 0); mg_mgr_poll(&mgr, 0);
} }

View File

@ -1,38 +1,45 @@
CFLAGS ?= -W -Wall -Wextra -Werror -Wundef -Wshadow -Wdouble-promotion \ CFLAGS = -W -Wall -Wextra -Werror -Wundef -Wshadow -Wdouble-promotion
-Wformat-truncation -fno-common -Wconversion -Wno-sign-conversion \ CFLAGS += -Wformat-truncation -fno-common -Wconversion -Wno-sign-conversion
-g3 -Os -ffunction-sections -fdata-sections \ CFLAGS += -g3 -Os -ffunction-sections -fdata-sections
-I. -Ih7/Include -Icmsis/CMSIS/Core/Include \ CFLAGS += -I. -Icmsis_core/CMSIS/Core/Include -Icmsis_h7/Include
-mcpu=cortex-m7 -mthumb -mfloat-abi=hard -mfpu=fpv5-sp-d16 \ CFLAGS += -mcpu=cortex-m7 -mthumb -mfloat-abi=hard -mfpu=fpv5-sp-d16
$(EXTRA_CFLAGS) LDFLAGS ?= -Tlink.ld -nostdlib -nostartfiles --specs nano.specs -lc -lgcc -Wl,--gc-sections -Wl,-Map=$@.map
LDFLAGS ?= -Tlink.ld -nostartfiles -nostdlib --specs nano.specs -lc -lgcc -Wl,--gc-sections -Wl,-Map=$@.map
SOURCES = startup.c main.c syscalls.c
# Add Mongoose-specific flags and source files SOURCES = main.c syscalls.c sysinit.c
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 += cmsis_h7/Source/Templates/gcc/startup_stm32h743xx.s # ST startup file. Compiler-dependent!
SOURCES += ../../../mongoose.c ../../device-dashboard/net.c ../../device-dashboard/packed_fs.c
# 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 all build example: firmware.bin
firmware.bin: firmware.elf firmware.bin: firmware.elf
arm-none-eabi-objcopy -O binary $< $@ 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 $@ 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 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 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 update: firmware.bin
curl --fail-with-body -su :$(VCON_API_KEY) $(DEVICE_URL)/ota --data-binary @$< 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: clean:
@rm -rf firmware.* *.su @rm -rf firmware.* *.su cmsis_core cmsis_h7

View File

@ -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 <stm32h743xx.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#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] \
}

View File

@ -1,4 +1,4 @@
ENTRY(_reset); ENTRY(Reset_Handler);
MEMORY { MEMORY {
flash(rx) : ORIGIN = 0x08000000, LENGTH = 2048k flash(rx) : ORIGIN = 0x08000000, LENGTH = 2048k
sram(rwx) : ORIGIN = 0x24000000, LENGTH = 512k /* AXI SRAM in domain D1 */ 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 */ _estack = ORIGIN(sram) + LENGTH(sram); /* stack points to end of SRAM */
SECTIONS { SECTIONS {
.vectors : { KEEP(*(.vectors)) } > flash .vectors : { KEEP(*(.isr_vector)) } > flash
.text : { *(.text*) } > flash .text : { *(.text* .text.*) } > flash
.rodata : { *(.rodata*) } > flash .rodata : { *(.rodata*) } > flash
.data : { .data : {
_sdata = .; /* for init_ram() */ _sdata = .; /* for init_ram() */

View File

@ -1,79 +1,92 @@
// Copyright (c) 2023 Cesanta Software Limited // Copyright (c) 2023 Cesanta Software Limited
// All rights reserved // All rights reserved
#include "mcu.h" #include "hal.h"
#include "mongoose.h" #include "mongoose.h"
#define LED1 PIN('B', 0) // On-board LED pin (green) #define LED1 PIN('B', 0) // On-board LED pin (green)
#define LED2 PIN('E', 1) // On-board LED pin (yellow) #define LED2 PIN('E', 1) // On-board LED pin (yellow)
#define LED3 PIN('B', 14) // On-board LED pin (red) #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 #define BLINK_PERIOD_MS 1000 // LED blinking period in millis
static uint64_t s_ticks; static volatile uint64_t s_ticks; // Milliseconds since boot
void SysTick_Handler(void) { s_ticks++; } void SysTick_Handler(void) { // SyStick IRQ handler, triggered every 1ms
uint64_t mg_millis(void) { return s_ticks; } s_ticks++;
static void timer_cb(void *arg) {
gpio_toggle(LED2); // Blink LED
MG_INFO(("ticks: %lld", mg_millis())); // Log something
(void) arg;
} }
int main(void) { uint64_t mg_millis(void) { // Let Mongoose use our uptime function
clock_init(); return s_ticks; // Return number of milliseconds since boot
systick_init(CPU_FREQUENCY / 1000); // Increment s_ticks every ms }
gpio_output(LED2); // Setup LED
uart_init(UART_DEBUG, 115200); // Initialise debug printf
char rev = chiprev(); void mg_random(void *buf, size_t len) { // Use on-board RNG
MG_INFO(("Chip revision: %c, max cpu clock: %u MHz", rev, (rev == 'V') ? 480 : 400)); 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 static void ethernet_init(void) {
// section 6.6.7: // Initialise Ethernet. Enable MAC GPIO pins, see
// https://www.st.com/resource/en/user_manual/um2407-stm32h7-nucleo144-boards-mb1364-stmicroelectronics.pdf // 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), uint16_t pins[] = {PIN('A', 1), PIN('A', 2), PIN('A', 7),
PIN('B', 13), PIN('C', 1), PIN('C', 4), PIN('B', 13), PIN('C', 1), PIN('C', 4),
PIN('C', 5), PIN('G', 11), PIN('G', 13)}; PIN('C', 5), PIN('G', 11), PIN('G', 13)};
for (size_t i = 0; i < sizeof(pins) / sizeof(pins[0]); i++) { 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_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 NVIC_EnableIRQ(ETH_IRQn); // Setup Ethernet IRQ handler
RCC->APB4ENR |= BIT(1); // Enable SYSCFG
SETBITS(SYSCFG->PMCR, 7 << 21, 4 << 21); // Use RMII (12.3.1) SETBITS(SYSCFG->PMCR, 7 << 21, 4 << 21); // Use RMII (12.3.1)
RCC->AHB1ENR |= BIT(15) | BIT(16) | BIT(17); // Enable Ethernet clocks 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...")); int main(void) {
struct mg_mgr mgr; // Initialise Mongoose event manager gpio_output(LED); // Setup green LED
mg_mgr_init(&mgr); // and attach it to the MIP interface 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_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 // Initialise Mongoose network stack
// Specify MAC address, and IP/mask/GW in network byte order for static // 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 // 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_driver_stm32h_data driver_data = {.mdc_cr = 4};
struct mg_tcpip_if mif = { struct mg_tcpip_if mif = {.mac = GENERATE_LOCALLY_ADMINISTERED_MAC(),
.mac = {2, 0, 1, 2, 3, 5}, .driver = &mg_tcpip_driver_stm32h,
.driver = &mg_tcpip_driver_stm32h, .driver_data = &driver_data};
.driver_data = &driver_data,
};
mg_tcpip_init(&mgr, &mif); 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) { while (mif.state != MIP_STATE_READY) {
mg_mgr_poll(&mgr, 0); mg_mgr_poll(&mgr, 0);
} }
MG_INFO(("Initialising application...")); MG_INFO(("Initialising application..."));
extern void device_dashboard_fn(struct mg_connection *, int, void *, void *); 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")); MG_INFO(("Starting event loop"));
for (;;) mg_mgr_poll(&mgr, 0); // Infinite event loop for (;;) {
mg_mgr_poll(&mgr, 0);
}
return 0; return 0;
} }

View File

@ -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 <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#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
}

View File

@ -0,0 +1 @@
../../../mongoose.c

View File

@ -0,0 +1 @@
../../../mongoose.h

View File

@ -0,0 +1 @@
../../device-dashboard/net.c

View File

@ -0,0 +1 @@
../../device-dashboard/packed_fs.c

View File

@ -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
}
;

View File

@ -1,6 +1,6 @@
#include <sys/stat.h> #include <sys/stat.h>
#include "mcu.h" #include "hal.h"
int _fstat(int fd, struct stat *st) { int _fstat(int fd, struct stat *st) {
if (fd < 0) return -1; if (fd < 0) return -1;
@ -43,9 +43,13 @@ void _exit(int status) {
for (;;) asm volatile("BKPT #0"); 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) { int _write(int fd, char *ptr, int len) {
(void) fd, (void) ptr, (void) len; (void) fd, (void) ptr, (void) len;
@ -77,3 +81,5 @@ int mkdir(const char *path, mode_t mode) {
(void) path, (void) mode; (void) path, (void) mode;
return -1; return -1;
} }
void _init(void) {}

View File

@ -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
}