-
Notifications
You must be signed in to change notification settings - Fork 2.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
14 changed files
with
601 additions
and
0 deletions.
There are no files selected for viewing
58 changes: 58 additions & 0 deletions
58
examples/stm32/opta-h747xi-make-baremetal-builtin/Makefile
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
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 -DCORE_CM7 | ||
CFLAGS += -mcpu=cortex-m7 -mthumb -mfloat-abi=hard -mfpu=fpv5-d16 $(CFLAGS_EXTRA) | ||
LDFLAGS ?= -Tlink.ld -nostdlib -nostartfiles --specs nano.specs -lc -lgcc -Wl,--gc-sections -Wl,-Map=$@.map | ||
|
||
SOURCES = main.c syscalls.c sysinit.c | ||
SOURCES += cmsis_h7/Source/Templates/gcc/startup_stm32h747xx.s # ST startup file. Compiler-dependent! | ||
|
||
# Mongoose options are defined in mongoose_custom.h | ||
SOURCES += mongoose.c net.c packed_fs.c | ||
|
||
# Example specific build options. See README.md | ||
CFLAGS += -DHTTP_URL=\"http://0.0.0.0/\" -DHTTPS_URL=\"https://0.0.0.0/\" | ||
|
||
ifeq ($(OS),Windows_NT) | ||
RM = cmd /C del /Q /F /S | ||
else | ||
RM = rm -rf | ||
endif | ||
|
||
all build example: firmware.bin | ||
|
||
firmware.bin: firmware.elf | ||
arm-none-eabi-objcopy -O binary $< $@ | ||
|
||
firmware.elf: cmsis_core cmsis_h7 $(SOURCES) hal.h link.ld Makefile | ||
arm-none-eabi-gcc $(SOURCES) $(CFLAGS) $(LDFLAGS) -o $@ | ||
|
||
flash: firmware.bin | ||
st-flash --reset write $< 0x8000000 | ||
|
||
cmsis_core: # ARM CMSIS core headers | ||
git clone --depth 1 -b 5.9.0 https://github.com/ARM-software/CMSIS_5 $@ | ||
cmsis_h7: # ST CMSIS headers for STM32H7 series | ||
git clone --depth 1 -b v1.10.3 https://github.com/STMicroelectronics/cmsis_device_h7 $@ | ||
mbedtls: # mbedTLS library | ||
git clone --depth 1 -b v2.28.2 https://github.com/mbed-tls/mbedtls $@ | ||
|
||
ifeq ($(TLS), mbedtls) | ||
CFLAGS += -DMG_TLS=MG_TLS_MBED -Wno-conversion -Imbedtls/include | ||
CFLAGS += -DMBEDTLS_CONFIG_FILE=\"mbedtls_config.h\" mbedtls/library/*.c | ||
firmware.elf: mbedtls | ||
endif | ||
|
||
# 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 | ||
update: firmware.bin | ||
curl --fail-with-body -su :$(VCON_API_KEY) $(DEVICE_URL)/ota --data-binary @$< | ||
|
||
test update: CFLAGS += -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 | ||
|
||
clean: | ||
$(RM) firmware.* *.su cmsis_core cmsis_h7 mbedtls |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
# Baremetal web device dashboard on NUCLEO-H743ZI | ||
|
||
See https://mongoose.ws/tutorials/stm32/all-make-baremetal-builtin/ |
186 changes: 186 additions & 0 deletions
186
examples/stm32/opta-h747xi-make-baremetal-builtin/hal.h
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,186 @@ | ||
// Copyright (c) 2022-2023 Cesanta Software Limited | ||
// All rights reserved | ||
// | ||
// RM0399 | ||
// https://www.st.com/resource/en/reference_manual/rm0399-stm32h745755-and-stm32h747757-advanced-armbased-32bit-mcus-stmicroelectronics.pdf | ||
// https://www.st.com/resource/en/datasheet/stm32h747xi.pdf | ||
|
||
#pragma once | ||
|
||
#include <stm32h747xx.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) | ||
|
||
#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 yellow LED for blinking | ||
|
||
#ifndef UART_DEBUG | ||
#define UART_DEBUG USART1 | ||
#endif | ||
|
||
// 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); | ||
} | ||
|
||
// 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 '?'; | ||
} | ||
|
||
static inline 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('C', 1), PIN('C', 4), PIN('C', 5), | ||
PIN('G', 11), PIN('G', 12), 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); // 11 is the Ethernet function | ||
} | ||
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 | ||
} | ||
|
||
#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] \ | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
ENTRY(Reset_Handler); | ||
MEMORY { | ||
flash(rx) : ORIGIN = 0x08000000, LENGTH = 2048k | ||
sram(rwx) : ORIGIN = 0x24000000, LENGTH = 512k | ||
} | ||
_estack = ORIGIN(sram) + LENGTH(sram); /* stack points to end of SRAM */ | ||
|
||
SECTIONS { | ||
.vectors : { KEEP(*(.isr_vector)) } > flash | ||
.text : { *(.text* .text.*) } > flash | ||
.rodata : { *(.rodata*) } > flash | ||
|
||
.data : { | ||
_sdata = .; | ||
*(.first_data) | ||
*(.data SORT(.data.*)) | ||
_edata = .; | ||
} > sram AT > flash | ||
_sidata = LOADADDR(.data); | ||
|
||
.bss : { | ||
_sbss = .; | ||
*(.bss SORT(.bss.*) COMMON) | ||
_ebss = .; | ||
} > sram | ||
|
||
. = ALIGN(8); | ||
_end = .; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
// Copyright (c) 2023 Cesanta Software Limited | ||
// All rights reserved | ||
|
||
#include "hal.h" | ||
#include "mongoose.h" | ||
#include "net.h" | ||
|
||
#define BLINK_PERIOD_MS 1000 // LED blinking period in millis | ||
|
||
static volatile uint64_t s_ticks; // Milliseconds since boot | ||
void SysTick_Handler(void) { // SyStick IRQ handler, triggered every 1ms | ||
s_ticks++; | ||
} | ||
|
||
uint64_t mg_millis(void) { // Let Mongoose use our uptime function | ||
return s_ticks; // Return number of milliseconds since boot | ||
} | ||
|
||
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", "req", "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)); | ||
} | ||
|
||
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_ota_boot(); // Call bootloader: continue to load, or boot another FW | ||
|
||
#if MG_OTA == MG_OTA_FLASH | ||
// Demonstrate the use of mg_flash_{load/save} functions for keeping device | ||
// configuration data on flash. Increment boot count on every boot. | ||
struct deviceconfig { | ||
uint32_t boot_count; | ||
char some_other_data[40]; | ||
}; | ||
uint32_t key = 0x12345678; // A unique key, one per data type | ||
struct deviceconfig dc = {}; // Initialise to some default values | ||
mg_flash_load(NULL, key, &dc, sizeof(dc)); // Load from flash | ||
dc.boot_count++; // Increment boot count | ||
mg_flash_save(NULL, key, &dc, sizeof(dc)); // And save back | ||
MG_INFO(("Boot count: %u", dc.boot_count)); | ||
#endif | ||
|
||
// Initialise Mongoose network stack | ||
struct mg_tcpip_driver_stm32h_data driver_data = {.mdc_cr = 4}; | ||
struct mg_tcpip_if mif = {.mac = GENERATE_LOCALLY_ADMINISTERED_MAC(), | ||
// Uncomment below for static configuration: | ||
// .ip = mg_htonl(MG_U32(192, 168, 0, 223)), | ||
// .mask = mg_htonl(MG_U32(255, 255, 255, 0)), | ||
// .gw = mg_htonl(MG_U32(192, 168, 0, 1)), | ||
.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(("MAC: %M. Waiting for IP...", mg_print_mac, mif.mac)); | ||
while (mif.state != MG_TCPIP_STATE_READY) { | ||
mg_mgr_poll(&mgr, 0); | ||
} | ||
|
||
MG_INFO(("Initialising application...")); | ||
web_init(&mgr); | ||
|
||
MG_INFO(("Starting event loop")); | ||
for (;;) { | ||
mg_mgr_poll(&mgr, 0); | ||
} | ||
|
||
return 0; | ||
} |
Oops, something went wrong.