Add nucleo-h743zi-baremetal boilerplate, with HW test

This commit is contained in:
cpq 2023-01-22 11:31:06 +00:00
parent 987f8bc949
commit 1ead940623
7 changed files with 376 additions and 0 deletions

View File

@ -92,6 +92,8 @@ jobs:
- path: esp32/device-dashboard
- path: esp32/uart-bridge
- path: esp8266/http-client-server
- path: stm32/nucleo-h743zi-baremetal
target: test
- path: stm32/stm32-freertos-tcp
- path: stm32/stm32-nucleo-f746z
- path: stm32/stm32-nucleo-f746zg

View File

@ -0,0 +1,38 @@
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=soft \
$(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
# Add Mongoose-specific flags and source files
CFLAGS += -I../../.. -DMG_ARCH=MG_ARCH_NEWLIB -DMG_ENABLE_CUSTOM_MILLIS=1 -DMG_ENABLE_MIP=1 #-DMG_ENABLE_PACKED_FS=1
SOURCES += ../../../mongoose.c #../../device-dashboard/net.c ../../device-dashboard/packed_fs.c
all build example: firmware.bin
firmware.bin: firmware.elf
arm-none-eabi-objcopy -O binary $< $@
firmware.elf: $(SOURCES) mcu.h
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
# Requires env variable VCON_API_KEY set
DEVICE_URL ?= https://dash.vcon.io/api/v3/devices/6
test: update
curl --fail-with-body -su :$(VCON_API_KEY) $(DEVICE_URL)/tx?t=5 | tee /tmp/output.txt
grep 'ticks:' /tmp/output.txt
# grep 'Ethernet: up' /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 @$<
clean:
@rm -rf firmware.* *.su

View File

@ -0,0 +1,29 @@
ENTRY(_reset);
MEMORY {
flash(rx) : ORIGIN = 0x08000000, LENGTH = 2048k
sram(rwx) : ORIGIN = 0x20000000, LENGTH = 64k
}
_estack = ORIGIN(sram) + LENGTH(sram); /* stack points to end of SRAM */
SECTIONS {
.vectors : { KEEP(*(.vectors)) } > flash
.text : { *(.text*) } > flash
.rodata : { *(.rodata*) } > flash
.data : {
_sdata = .; /* for init_ram() */
*(.first_data)
*(.data SORT(.data.*))
_edata = .; /* for init_ram() */
} > sram AT > flash
_sidata = LOADADDR(.data);
.bss : {
_sbss = .; /* for init_ram() */
*(.bss SORT(.bss.*) COMMON)
_ebss = .; /* for init_ram() */
} > sram
. = ALIGN(8);
_end = .; /* for cmsis_gcc.h and init_ram() */
}

View File

@ -0,0 +1,40 @@
// Copyright (c) 2022 Cesanta Software Limited
// All rights reserved
#include "mcu.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 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;
}
int main(void) {
clock_init();
systick_init(SYS_FREQUENCY / 1000); // Increment s_ticks every ms
gpio_output(LED2); // Setup LED
uart_init(UART_DEBUG, 115200); // Initialise debug printf
MG_INFO(("Initialising Mongoose..."));
struct mg_mgr mgr; // Initialise Mongoose event manager
mg_mgr_init(&mgr); // and attach it to the MIP interface
mg_log_set(MG_LL_DEBUG); // Set log level
mg_timer_add(&mgr, BLINK_PERIOD_MS, MG_TIMER_REPEAT, timer_cb, NULL);
MG_INFO(("Starting event loop"));
for (;;) {
mg_mgr_poll(&mgr, 0);
}
return 0;
}

View File

@ -0,0 +1,146 @@
// 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)
// TODO: Set clock. Now, running @ default of 64 MHz
enum { PLL_HSI = 64, PLL_M = 1, PLL_N = 1, PLL_P = 1 };
#define FLASH_LATENCY 7
#define SYS_FREQUENCY ((PLL_HSI * PLL_N / PLL_M / PLL_P) * 1000000)
#define APB2_FREQUENCY SYS_FREQUENCY
#define APB1_FREQUENCY SYS_FREQUENCY
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 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))
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 };
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 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
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);
freq = SYS_FREQUENCY;
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);
}
static inline void clock_init(void) {
// TODO: Enable FPU, set flash latency, set clock
}

View File

@ -0,0 +1,42 @@
// 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);
// 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
DefaultIRQHandler};

View File

@ -0,0 +1,79 @@
#include <sys/stat.h>
#include "mcu.h"
int _fstat(int fd, struct stat *st) {
if (fd < 0) return -1;
st->st_mode = S_IFCHR;
return 0;
}
void *_sbrk(int incr) {
extern char _end;
static unsigned char *heap = NULL;
unsigned char *prev_heap;
if (heap == NULL) heap = (unsigned char *) &_end;
prev_heap = heap;
heap += incr;
return prev_heap;
}
int _open(const char *path) {
(void) path;
return -1;
}
int _close(int fd) {
(void) fd;
return -1;
}
int _isatty(int fd) {
(void) fd;
return 1;
}
int _lseek(int fd, int ptr, int dir) {
(void) fd, (void) ptr, (void) dir;
return 0;
}
void _exit(int status) {
(void) status;
for (;;) asm volatile("BKPT #0");
}
void _kill(int pid, int sig) { (void) pid, (void) sig; }
int _getpid(void) { return -1; }
int _write(int fd, char *ptr, int len) {
(void) fd, (void) ptr, (void) len;
if (fd == 1) uart_write_buf(UART_DEBUG, ptr, (size_t) len);
return -1;
}
int _read(int fd, char *ptr, int len) {
(void) fd, (void) ptr, (void) len;
return -1;
}
int _link(const char *a, const char *b) {
(void) a, (void) b;
return -1;
}
int _unlink(const char *a) {
(void) a;
return -1;
}
int _stat(const char *path, struct stat *st) {
(void) path, (void) st;
return -1;
}
int mkdir(const char *path, mode_t mode) {
(void) path, (void) mode;
return -1;
}