Skip to content

Commit 1820e65

Browse files
committed
Add nucleo-u5a5zj-q
1 parent a92f203 commit 1820e65

File tree

5 files changed

+401
-0
lines changed

5 files changed

+401
-0
lines changed
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
CFLAGS ?= -W -Wall -Wextra -Werror -Wundef -Wshadow -Wdouble-promotion -Wformat-truncation -fno-common
2+
CFLAGS += -g3 -Os -ffunction-sections -fdata-sections -Wno-shadow
3+
CFLAGS += -I. -Iinclude -Icmsis_core/CMSIS/Core/Include -Icmsis_u5/Include
4+
CFLAGS += -mcpu=cortex-m33 -mthumb -mfpu=fpv5-sp-d16 -mfloat-abi=hard $(CFLAGS_EXTRA)
5+
LDFLAGS ?= -Tlink.ld -nostartfiles -nostdlib --specs nano.specs -lc -lgcc -Wl,--gc-sections -Wl,-Map=$@.map
6+
SOURCES = main.c syscalls.c
7+
SOURCES += cmsis_u5/Source/Templates/gcc/startup_stm32u5a5xx.s
8+
9+
ifeq ($(OS),Windows_NT)
10+
RM = cmd /C del /Q /F
11+
else
12+
RM = rm -rf
13+
endif
14+
15+
build: firmware.bin
16+
17+
firmware.elf: cmsis_core cmsis_u5 hal.h link.ld Makefile $(SOURCES)
18+
arm-none-eabi-gcc $(SOURCES) $(CFLAGS) $(CFLAGS_EXTRA) $(LDFLAGS) -o $@
19+
20+
firmware.bin: firmware.elf
21+
arm-none-eabi-objcopy -O binary $< $@
22+
23+
flash: firmware.bin
24+
STM32_Programmer_CLI -c port=swd -e all -w $< 0x8000000 -hardRst
25+
# st-flash --reset write $< 0x8000000
26+
27+
cmsis_core:
28+
git clone -q -c advice.detachedHead=false --depth 1 -b 5.9.0 https://github.com/ARM-software/CMSIS_5 $@
29+
30+
cmsis_u5:
31+
git clone -q -c advice.detachedHead=false --depth 1 -b v1.4.1 https://github.com/STMicroelectronics/cmsis_device_u5 $@
32+
33+
clean:
34+
$(RM) firmware.* cmsis_*
Lines changed: 200 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,200 @@
1+
// Copyright (c) 2025 Cesanta Software Limited
2+
// https://www.st.com/resource/en/reference_manual/rm0456-stm32u5-series-armbased-32bit-mcus-stmicroelectronics.pdf
3+
// SPDX-License-Identifier: MIT
4+
5+
#pragma once
6+
#include <stm32u5a5xx.h>
7+
8+
#include <stdbool.h>
9+
#include <stdint.h>
10+
#include <stdio.h>
11+
#include <string.h>
12+
13+
#define BIT(x) (1UL << (x))
14+
#define CLRSET(R, CLEARMASK, SETMASK) (R) = ((R) & ~(CLEARMASK)) | (SETMASK)
15+
#define PIN(bank, num) ((((bank) - 'A') << 8) | (num))
16+
#define PINNO(pin) (pin & 255)
17+
#define PINBANK(pin) (pin >> 8)
18+
19+
// System clock
20+
enum { AHB_DIV = 1, APB1_DIV = 1, APB2_DIV = 1 };
21+
enum { PLL_HSI = 16, PLL_M = 1, PLL_N = 10, PLL_R = 2 }; // 80 Mhz
22+
// #define SYS_FREQUENCY ((PLL_HSI * PLL_N / PLL_M / PLL_R) * 1000000)
23+
#define SYS_FREQUENCY 16000000
24+
#define APB2_FREQUENCY (SYS_FREQUENCY / APB2_DIV)
25+
#define APB1_FREQUENCY (SYS_FREQUENCY / APB1_DIV)
26+
27+
static inline void spin(volatile uint32_t count) {
28+
while (count--) (void) 0;
29+
}
30+
31+
enum { GPIO_MODE_INPUT, GPIO_MODE_OUTPUT, GPIO_MODE_AF, GPIO_MODE_ANALOG };
32+
enum { GPIO_OTYPE_PUSH_PULL, GPIO_OTYPE_OPEN_DRAIN };
33+
enum { GPIO_SPEED_LOW, GPIO_SPEED_MEDIUM, GPIO_SPEED_HIGH, GPIO_SPEED_INSANE };
34+
enum { GPIO_PULL_NONE, GPIO_PULL_UP, GPIO_PULL_DOWN };
35+
36+
static inline GPIO_TypeDef *gpio_bank(uint16_t pin) {
37+
switch (PINBANK(pin)) {
38+
case 0: return GPIOA;
39+
case 1: return GPIOB;
40+
case 2: return GPIOC;
41+
case 3: return GPIOD;
42+
case 4: return GPIOE;
43+
case 5: return GPIOF;
44+
case 6: return GPIOG;
45+
case 7: return GPIOH;
46+
case 8: return GPIOI;
47+
case 9: return GPIOJ;
48+
default: return NULL;
49+
}
50+
}
51+
static inline void gpio_toggle(uint16_t pin) {
52+
GPIO_TypeDef *gpio = gpio_bank(pin);
53+
uint32_t mask = BIT(PINNO(pin));
54+
gpio->BSRR = mask << (gpio->ODR & mask ? 16 : 0);
55+
}
56+
static inline int gpio_read(uint16_t pin) {
57+
return gpio_bank(pin)->IDR & BIT(PINNO(pin)) ? 1 : 0;
58+
}
59+
static inline void gpio_write(uint16_t pin, bool val) {
60+
GPIO_TypeDef *gpio = gpio_bank(pin);
61+
gpio->BSRR = BIT(PINNO(pin)) << (val ? 0 : 16);
62+
}
63+
static inline void gpio_init(uint16_t pin, uint8_t mode, uint8_t type,
64+
uint8_t speed, uint8_t pull, uint8_t af) {
65+
GPIO_TypeDef *gpio = gpio_bank(pin);
66+
uint8_t n = (uint8_t) (PINNO(pin));
67+
RCC->AHB2ENR1 |= BIT(PINBANK(pin)); // Enable GPIO clock
68+
CLRSET(gpio->OTYPER, 1UL << n, ((uint32_t) type) << n);
69+
CLRSET(gpio->OSPEEDR, 3UL << (n * 2), ((uint32_t) speed) << (n * 2));
70+
CLRSET(gpio->PUPDR, 3UL << (n * 2), ((uint32_t) pull) << (n * 2));
71+
CLRSET(gpio->AFR[n >> 3], 15UL << ((n & 7) * 4),
72+
((uint32_t) af) << ((n & 7) * 4));
73+
CLRSET(gpio->MODER, 3UL << (n * 2), ((uint32_t) mode) << (n * 2));
74+
}
75+
static inline void gpio_input(uint16_t pin) {
76+
gpio_init(pin, GPIO_MODE_INPUT, GPIO_OTYPE_PUSH_PULL, GPIO_SPEED_HIGH,
77+
GPIO_PULL_NONE, 0);
78+
}
79+
static inline void gpio_output(uint16_t pin) {
80+
gpio_init(pin, GPIO_MODE_OUTPUT, GPIO_OTYPE_PUSH_PULL, GPIO_SPEED_HIGH,
81+
GPIO_PULL_NONE, 0);
82+
}
83+
84+
static inline bool uart_init(USART_TypeDef *uart, unsigned long baud) {
85+
// https://www.st.com/resource/en/datasheet/stm32u5a5aj.pdf
86+
uint8_t af = 7; // Alternate function
87+
uint16_t rx = 0, tx = 0; // pins
88+
uint32_t freq = 0; // Bus frequency. UART1 is on APB2, rest on APB1
89+
90+
if (uart == USART1) {
91+
freq = APB2_FREQUENCY, RCC->APB2ENR |= RCC_APB2ENR_USART1EN;
92+
tx = PIN('A', 9), rx = PIN('A', 10);
93+
} else if (uart == USART2) {
94+
freq = APB1_FREQUENCY, RCC->APB1ENR1 |= RCC_APB1ENR1_USART2EN;
95+
tx = PIN('A', 2), rx = PIN('A', 3);
96+
} else if (uart == USART2) {
97+
freq = APB1_FREQUENCY, RCC->APB1ENR1 |= RCC_APB1ENR1_USART3EN;
98+
tx = PIN('B', 10), rx = PIN('B', 11);
99+
} else {
100+
return false;
101+
}
102+
103+
gpio_init(tx, GPIO_MODE_AF, GPIO_OTYPE_PUSH_PULL, GPIO_SPEED_HIGH, 0, af);
104+
gpio_init(rx, GPIO_MODE_AF, GPIO_OTYPE_PUSH_PULL, GPIO_SPEED_HIGH, 0, af);
105+
uart->CR1 = 0; // Disable this UART
106+
uart->BRR = freq / baud; // Set baud rate
107+
uart->CR1 |= BIT(0) | BIT(2) | BIT(3); // Set UE, RE, TE
108+
return true;
109+
}
110+
static inline void uart_write_byte(USART_TypeDef *uart, uint8_t byte) {
111+
uart->TDR = byte;
112+
while ((uart->ISR & BIT(7)) == 0) spin(1);
113+
}
114+
static inline void uart_write_buf(USART_TypeDef *uart, char *buf, size_t len) {
115+
while (len-- > 0) uart_write_byte(uart, *(uint8_t *) buf++);
116+
}
117+
static inline int uart_read_ready(USART_TypeDef *uart) {
118+
return uart->ISR & BIT(5); // If RXNE bit is set, data is ready
119+
}
120+
static inline uint8_t uart_read_byte(USART_TypeDef *uart) {
121+
return (uint8_t) (uart->RDR & 255);
122+
}
123+
124+
static inline void rng_init(void) {
125+
RCC->AHB2ENR1 |= RCC_AHB2ENR1_RNGEN;
126+
RNG->CR |= RNG_CR_RNGEN;
127+
}
128+
static inline uint32_t rng_read(void) {
129+
while ((RNG->SR & RNG_SR_DRDY) == 0) (void) 0;
130+
return RNG->DR;
131+
}
132+
133+
#define UUID ((uint8_t *) UID_BASE) // Unique 96-bit chip ID. TRM 41.1
134+
135+
// Helper macro for MAC generation
136+
#define GENERATE_LOCALLY_ADMINISTERED_MAC() \
137+
{2, \
138+
UUID[0] ^ UUID[1], \
139+
UUID[2] ^ UUID[3], \
140+
UUID[4] ^ UUID[5], \
141+
UUID[6] ^ UUID[7] ^ UUID[8], \
142+
UUID[9] ^ UUID[10] ^ UUID[11]}
143+
144+
// t: expiration time, prd: period, now: current time. Return true if expired
145+
static inline bool timer_expired(volatile uint64_t *t, uint64_t prd,
146+
uint64_t now) {
147+
if (now + prd < *t) *t = 0; // Time wrapped? Reset timer
148+
if (*t == 0) *t = now + prd; // Firt poll? Set expiration
149+
if (*t > now) return false; // Not expired yet, return
150+
*t = (now - *t) > prd ? now + prd : *t + prd; // Next expiration time
151+
return true; // Expired, return true
152+
}
153+
// Fill in stack with markers, in order to calculate stack usage later
154+
extern unsigned char _estack, _end;
155+
static inline void stack_fill(void) {
156+
uint32_t dummy, *p = (uint32_t *) &_end;
157+
while (p < &dummy) *p++ = 0xa5a5a5a5;
158+
}
159+
160+
static inline long stack_usage(void) {
161+
uint32_t *sp = (uint32_t *) &_estack, *end = (uint32_t *) &_end, *p = sp - 1;
162+
while (p > end && *p != 0xa5a5a5a5) p--;
163+
return (sp - p) * sizeof(*p);
164+
}
165+
166+
static inline void clock_init(void) {
167+
SCB->CPACR |= 15 << 20; // Enable FPU
168+
FLASH->ACR |= FLASH_ACR_LATENCY_4WS;
169+
// FLASH->ACR |= FLASH_ACR_LATENCY_4WS | FLASH_ACR_ICEN | FLASH_ACR_DCEN;
170+
#if 0
171+
#if 0
172+
CLRSET(RCC->PLLCFGR, RCC_PLLCFGR_PLLM, (PLL_M - 1) << RCC_PLLCFGR_PLLM_Pos);
173+
CLRSET(RCC->PLLCFGR, RCC_PLLCFGR_PLLN, PLL_N << RCC_PLLCFGR_PLLN_Pos);
174+
CLRSET(RCC->PLLCFGR, RCC_PLLCFGR_PLLSRC, RCC_PLLCFGR_PLLSRC_HSI);
175+
RCC->PLLCFGR |= RCC_PLLCFGR_PLLREN;
176+
#else
177+
RCC->PLLCFGR = BIT(24) | BIT(20) | (PLL_N << 8) | RCC_PLLCFGR_PLLSRC_HSI |
178+
(7 << 27) | BIT(16);
179+
RCC->CR |= RCC_CR_PLLON;
180+
#endif
181+
while (!(RCC->CR & RCC_CR_PLLRDY)) spin(1);
182+
#if 0
183+
CLRSET(RCC->CFGR, RCC_CFGR_PPRE1, (3 + APB1_DIV / 2) << RCC_CFGR_PPRE1_Pos);
184+
CLRSET(RCC->CFGR, RCC_CFGR_PPRE2, (3 + APB2_DIV / 2) << RCC_CFGR_PPRE1_Pos);
185+
#endif
186+
RCC->CFGR |= RCC_CFGR_SW_PLL;
187+
while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL) spin(1);
188+
#else
189+
RCC->CR |= RCC_CR_HSION;
190+
while (!(RCC->CR & RCC_CR_HSIRDY)) spin(1);
191+
RCC->CFGR1 &= ~(RCC_CFGR1_SW);
192+
RCC->CFGR1 |= (RCC_CFGR1_SW_0);
193+
while ((RCC->CFGR1 & RCC_CFGR1_SWS) != RCC_CFGR1_SWS_0) spin(1);
194+
#endif
195+
196+
rng_init(); // Initialise random number generator
197+
RCC->APB3ENR |= RCC_APB3ENR_SYSCFGEN; // Enable SYSCFG
198+
SystemCoreClock = SYS_FREQUENCY; // Required by CMSIS
199+
SysTick_Config(SystemCoreClock / 1000); // Sys tick every 1ms
200+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
ENTRY(Reset_Handler);
2+
MEMORY {
3+
flash(rx) : ORIGIN = 0x08000000, LENGTH = 256k
4+
sram(rwx) : ORIGIN = 0x20000000, LENGTH = 64k
5+
}
6+
_estack = ORIGIN(sram) + LENGTH(sram); /* stack points to end of SRAM */
7+
_eflash = ORIGIN(flash) + LENGTH(flash); /* points to end of flash */
8+
9+
SECTIONS {
10+
.vectors : { KEEP(*(.isr_vector)) } > flash
11+
.text : { *(.text* .text.*) } > flash
12+
.rodata : { *(.rodata*) } > flash
13+
.data : { _sdata = .; *(.first_data) *(.data SORT(.data.*)) _edata = .; } > sram AT > flash
14+
_sidata = LOADADDR(.data);
15+
.bss : { _sbss = .; *(.bss SORT(.bss.*) COMMON) _ebss = .; } > sram
16+
. = ALIGN(8);
17+
_end = .;
18+
}
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
// Copyright (c) 2025 Cesanta Software Limited
2+
// SPDX-License-Identifier: MIT
3+
4+
#include "hal.h"
5+
6+
#define UART_DEBUG USART1
7+
8+
#define LED1_PIN PIN('C', 7) // Green
9+
#define LED2_PIN PIN('B', 7) // Blue
10+
#define LED3_PIN PIN('G', 2) // Red
11+
12+
#define BLINK_PERIOD_MS 500 // LED blinking period in millis
13+
#define LOG_PERIOD_MS 1000 // Info log period in millis
14+
15+
static uint16_t s_pins[] = {LED1_PIN, LED2_PIN, LED3_PIN};
16+
//static uint16_t s_pins[] = {LED1_PIN, PIN('A', 3)};
17+
#define NUM_LEDS (sizeof(s_pins) / sizeof(s_pins[0]))
18+
19+
int _write(int fd, char *ptr, int len) {
20+
if (fd == 1) uart_write_buf(UART_DEBUG, ptr, (size_t) len);
21+
return len;
22+
}
23+
24+
uint32_t SystemCoreClock; // Required by CMSIS. Holds system core cock value
25+
void SystemInit(void) { // Called automatically by startup code
26+
clock_init(); // Sets SystemCoreClock
27+
}
28+
29+
static volatile uint64_t s_ticks; // Milliseconds since boot
30+
void SysTick_Handler(void) { // SyStick IRQ handler, triggered every 1ms
31+
s_ticks++;
32+
}
33+
34+
static void led_task(void) { // Blink LED every BLINK_PERIOD_MS
35+
static uint64_t timer = 0;
36+
static size_t idx;
37+
if (timer_expired(&timer, BLINK_PERIOD_MS, s_ticks)) {
38+
for (size_t i = 0; i < NUM_LEDS; i++) gpio_write(s_pins[i], false);
39+
gpio_write(s_pins[idx], true);
40+
if (++idx >= NUM_LEDS) idx = 0;
41+
}
42+
}
43+
44+
static void log_task(void) { // Print a log every LOG_PERIOD_MS
45+
static uint64_t timer = 0;
46+
if (timer_expired(&timer, LOG_PERIOD_MS, s_ticks)) {
47+
printf("tick: %5lu, CPU %lu MHz\n", (unsigned long) s_ticks,
48+
(unsigned long) (SystemCoreClock / 1000000));
49+
for (size_t i = 0; i < 8; i++) {
50+
printf("%#lx\n", gpio_bank(i)->LCKR);
51+
}
52+
}
53+
}
54+
55+
int main(void) {
56+
for (size_t i = 0; i < NUM_LEDS; i++) gpio_output(s_pins[i]);
57+
uart_init(UART_DEBUG, 115200);
58+
59+
for (;;) {
60+
led_task();
61+
log_task();
62+
}
63+
64+
return 0;
65+
}

0 commit comments

Comments
 (0)