STM32H5E5ZJ Startup assembly Code raising core to VOS0 and System Clock to 248MHz
I have written compact assembler code, with assistance from ChatGPT and Gemini, for the STM32H5E5ZJ to raise its core voltage to VOS0, configure PLL1 and PLL2 and switch system clock to 248MHz.
Any comments much appreciated as to the sequencing and safety of this code or any problems seen please.
It is tested and working reliably and occupies less than 512 Bytes. At the moment it runs in RAM and only after reset (not to be called later. To run in Flash it must also raise Flash wait states.
The code also configures MCO1 and MCO2, configures SPI1 as master, running at 4MBaud, it puts SPI1 into a delayed loop sending test data readings from TIM2.
SPI1 is configured to use PA4 SPI1_NSS, PA6 SPI1_MISO, PA7 SPI1_MOSI and PG11 SPI1_SCK.
Any comments much appreciated as to the sequencing and safety of this code.
I have used ST Core MX extensively to help build the code by reading MX generated C code. Here is the code, anyone is free to make use of it as a supplement to official ST code if they so wish:-
.syntax unified; .cpu cortex-m33; .thumb
.equ PWR_BASE, 0x44020800; .equ VOSCR, 0x0010; .equ VOSSR, 0x0014
.equ RCC_BASE, 0x44020C00; .equ RCC_CR, 0x00; .equ RCC_CFGR1, 0x1C; .equ RCC_CFGR2, 0x20
.equ RCC_PLL1CFGR, 0x28; .equ RCC_PLL2CFGR, 0x2C; .equ RCC_PLL1DIVR, 0x34; .equ RCC_PLL2DIVR, 0x3C
.equ AFRL, 0x20; .equ AFRH, 0x24; .equ APB2ENR, 0xA4; .equ APB1LENR, 0x9C; .equ AHB2ENR, 0x8C; .equ CCIPR3, 0x0E0
.equ GPIO_BASE, 0x42020000; .equ GPIOA,0x0000; .equ GPIOB,0x0400; .equ GPIOC,0x0800; .equ GPIOD,0x0C00
.equ GPIOE,0x1000; .equ GPIOF,0x1400; .equ GPIOG,0x1800; .equ GPIOH,0x1C00; .equ MODER,0x00; .equ ODR,0x14
.equ SPI1_BASE, 0x40013000; .equ SPI1_CR1, 0x00; .equ SPI1_CR2, 0x04; .equ SPI1_CFG1, 0x08; .equ SPI1_CFG2, 0x0C
.equ SPI1_SR, 0x14; .equ SPI1_TXDR, 0x20
.equ TIM2_BASE, 0x40000000; .equ TIM2_CR1, 0x00; .equ TIM2_CNT, 0x24
.section .text; .word 0x20004000; .word init + 1; .global init; init:
@increase core voltage from vos3 0x00 to vos0 0x30
ldr r0,=PWR_BASE; ldr r1,=0x30; str r1,[r0,#VOSCR]
wait_vos: ldr r1,[r0,#VOSSR]; tst r1,#(1<<3); beq wait_vos
@enable GPIO A B C D E F G clocks
ldr r0,=RCC_BASE;
ldr r1,[r0,#AHB2ENR]; orr r1,r1,#0x7f; str r1,[r0,#AHB2ENR]
@enable TIM2 clock
ldr r1,[r0,#APB1LENR]; orr r1,r1,#(0x1<<0x00); str r1,[r0,#APB1LENR]
@enable SPI1 clock
ldr r1,[r0,#APB2ENR]; orr r1,r1,#(0x1<<12); str r1,[r0,#APB2ENR]
@select pll2_p as kernel clock for SPI1
ldr r1,[r0,#CCIPR3]; bic r1,r1,#(0x7<<0); orr r1,r1,#(0x1 << 0); str r1,[r0,#CCIPR3]
@route and scale PA8 MCO1 and PC9 MCO2 both /10 MCO1 is PLL1Q /10 MCO2 is PLL2P /10
ldr r1,[r0,#RCC_CFGR1]; ldr r3,=((0x07<<29)|(0x0f<<25)|(0x07<<22)|(0xf<<18)); bic r1,r1,r3
ldr r3,=((0x01<<29)|(0x0a<<25)|(0x03<<22)|(0x0a<<18)); orr r1,r1,r3; str r1,[r0,#RCC_CFGR1]
@set HSIDIV /1 PLL1 needs 64MHz clock
ldr r1, [r0,#RCC_CR]; bic r1,r1,#(0x3<<3); str r1,[r0,#RCC_CR]
@configure PLL1 for PLLM /4 N x31 P /2 Q /2 to give pll1p 248MHz
ldr r1,=0x0003040d; str r1,[r0,#RCC_PLL1CFGR]; ldr r1,=0x0101021e; str r1,[r0,#RCC_PLL1DIVR]
@configure PLL2 for PLLM /16 N x64 P /4 Q /4 R /4 to give pll2p 64MHz
ldr r1,=0x00071029; str r1,[r0,#RCC_PLL2CFGR]; ldr r1,=0x0303063f; str r1,[r0,#RCC_PLL2DIVR]
@ Enable PLL1 (RCC_CR Bit 24)
ldr r1,[r0,#RCC_CR]; orr r1,r1,#(1<<24); str r1,[r0,#RCC_CR]
wait_pll1: ldr r1,[r0,#RCC_CR]; tst r1,#(1<<25); beq wait_pll1
@ Enable PLL2 (RCC_CR Bit 26)
ldr r1,[r0,#RCC_CR]; orr r1,r1,#(1<<26); str r1,[r0,#RCC_CR]
wait_pll2: ldr r1,[r0,#RCC_CR]; tst r1,#(1<<27); beq wait_pll2
@switch sysclk to PLL1P
ldr r1,[r0,#RCC_CFGR1]; orr r1,r1,#(0x3<<0); str r1,[r0,#RCC_CFGR1]
wait_switch: ldr r1,[r0,#RCC_CFGR1]; and r1,r1,#(0x3<<3); cmp r1,#(0x3<<3); bne wait_switch
ldr r0,=GPIO_BASE; ldr r3,=GPIO_BASE+GPIOG
@GPIO pin configuration PA8 MCO1, PC9 MCO2 both AF0
ldr r1,[r0,#GPIOA+AFRH]; bic r1,r1,#(0x0f<<0); str r1,[r0,#GPIOA+AFRH]
ldr r1,[r0,#GPIOC+AFRH]; bic r1,r1,#(0x0f<<4); str r1,[r0,#GPIOC+AFRH]
@SPI1 pin configuration PA4 SPI1_NSS, PA6 SPI1_MISO, PA7 SPI1_MOSI, PG11 SPI1_SCK all AF5
ldr r1,[r0,#GPIOA+AFRL]; bic r1,r1,#(0x0f<<16); orr r1,r1,#(0x5<<16); str r1,[r0,#GPIOA+AFRL]
ldr r1,[r0,#GPIOA+AFRL]; bic r1,r1,#(0x0f<<24); orr r1,r1,#(0x5<<24); str r1,[r0,#GPIOA+AFRL]
ldr r1,[r0,#GPIOA+AFRL]; bic r1,r1,#(0x0f<<28); orr r1,r1,#(0x5<<28); str r1,[r0,#GPIOA+AFRL]
ldr r1,[r3,#AFRH]; bic r1,r1,#(0x0f << 12); orr r1,r1,#(0x5<<12); str r1,[r3,#AFRH]
@configure PA8 and PC9, PA4, PA6, PA7 and PG11 for alternates
ldr r1,[r0,#GPIOA+MODER]; bic r1,r1,#(0x3<<16); orr r1,r1,#(0x2<<16); str r1,[r0,#GPIOA+MODER]
ldr r1,[r0,#GPIOA+MODER]; bic r1,r1,#(0x3<<8); orr r1,r1,#(0x2<<8); str r1,[r0,#GPIOA+MODER]
ldr r1,[r0,#GPIOA+MODER]; bic r1,r1,#(0x3<<12); orr r1,r1,#(0x2<<12); str r1,[r0,#GPIOA+MODER]
ldr r1,[r0,#GPIOA+MODER]; bic r1,r1,#(0x3<<14); orr r1,r1,#(0x2<<14); str r1,[r0,#GPIOA+MODER]
ldr r1,[r0,#GPIOC+MODER]; bic r1,r1,#(0x3<<18); orr r1,r1,#(0x2<<18); str r1,[r0,#GPIOC+MODER]
ldr r1,[r3,#MODER]; bic r1,r1,#(0x3<<22); orr r1,r1,#(0x2<<22); str r1,[r3,#MODER]
@enable TIM2 to count down
ldr r0,=TIM2_BASE; ldr r1,=0x11; str r1,[r0,#TIM2_CR1]
ldr r0,=SPI1_BASE
@32-bit data /16 prescaler SPI1_CFG1
ldr r1,=(0x03<<28)|(0x1f<<0); str r1,[r0,#SPI1_CFG1]
@master Hardware NSS SPI1_CFG2
ldr r1,=(1<<31)|(1<<29)|(1<<22); str r1,[r0,#SPI1_CFG2]
@TSIZE set to 1 SPI1_CR2
ldr r1,=0x00; str r1,[r0,#SPI1_CR2]
@enable SPI peripheral SPE bit 0 in SPI1_CR1
ldr r1,[r0,#SPI1_CR1]; orr r1,r1,#0x1; str r1,[r0,#SPI1_CR1]
@start transfer CSTART bit 9 in SPI1_CR1
ldr r1,[r0,#SPI1_CR1]; orr r1,r1,#(1<<9); str r1,[r0,#SPI1_CR1]
@reload TXDR and then delay
ldr r1,=TIM2_BASE; ldr r3,[r1,#TIM2_CNT]
tx_loop: str r3,[r0,#SPI1_TXDR]; subs r3,r3,#0x1000
time1: ldr r4,[r1,#TIM2_CNT]; subs r4,r4,r3; bpl time1; b tx_loop
.ltorg; .org 0x200
