Skip to main content
Associate
March 10, 2025
Question

STM32WBA PKA bare-metal implementation. Troubles loading data into RAM

  • March 10, 2025
  • 1 reply
  • 553 views

Hello all,

I am working on a bare-metal implementation of the PKA engine using the STM32WBA55CG. I have managed to properly initialize both the RNG and the PKA engines, but I cannot seem to load the operands on the RAM. 

I am trying to implement the modular addition, following the datasheet (https://www.st.com/resource/en/reference_manual/rm0493-multiprotocol-wireless-bluetooth-lowenergy-and-ieee802154-stm32wba5xxx-armbased-32bit-mcus-stmicroelectronics.pdf page 863). I am using Rust as programming language. 

I attach the code. The problem is that whenever trying to write the data, using core::ptr::write_volatile, the code just stops and nothing is done.

 

The outputs I have are:

 

#![no_std]
#![no_main]

use stm32wba::stm32wba55::{self, RAMCFG};
use {defmt_rtt as _, panic_probe as _};
use cortex_m_rt::entry;
use cortex_m::asm;
use defmt::info;

// PKA RAM locations - these are already offsets from PKA base address
const PKA_RAM_OFFSET: u32 = 0x400; 
const OPERAND_LENGTH_OFFSET: u32 = 0x408 - 0x400; // Relative to PKA_RAM_OFFSET
const OPERAND_A_OFFSET: u32 = 0xA50 - 0x400;
const OPERAND_B_OFFSET: u32 = 0xC68 - 0x400;
const MODULUS_OFFSET: u32 = 0x1088 - 0x400;
const RESULT_OFFSET: u32 = 0xE78 - 0x400;

const OPERAND_LENGTH: u32 = 64;
const A: u32 = 3; // First operand
const B: u32 = 11; // Second operand
const N: u32 = 13; // Modulus for addition

#[entry]
unsafe fn main() -> ! {
 let p = stm32wba55::Peripherals::take().unwrap();
 let pka = &p.PKA;
 let clock = &p.RCC;
 let rng = &p.RNG;

 // Enable HSI as a stable clock source
 clock.rcc_cr().modify(|_, w| w
 .hseon().set_bit()
 // .hsikeron().set_bit()
 );
 while clock.rcc_cr().read().hserdy().bit_is_clear() {
 asm::nop();
 }

 // Enable RNG clock. Select the source clock
 clock.rcc_ccipr2().write(|w| w.rngsel().b_0x2());
 // Enable RNG clock. Select the AHB clock
 clock.rcc_ahb2enr().modify(|_, w| w.rngen().set_bit());
 while clock.rcc_ahb2enr().read().rngen().bit_is_clear() {
 asm::nop();
 }

 rng.rng_cr().write(|w| w
 .rngen().clear_bit()
 .condrst().set_bit()
 .configlock().clear_bit()
 // .clkdiv().b_0x0() 
 .nistc().clear_bit() // Hardware default values for NIST compliant RNG
 .ced().clear_bit() // Clock error detection enabled
 );
 rng.rng_cr().modify(|_, w| w
 .condrst().clear_bit()
 );
 rng.rng_cr().modify(|_, w| w
 .rngen().set_bit()
 .ie().set_bit()
 );
 
 while rng.rng_sr().read().drdy().bit_is_clear() {
 asm::nop();
 }
 // Enable PKA peripheral clock via RCC_AHB2ENR register
 clock.rcc_ahb2enr().modify(|_, w| w.pkaen().set_bit());

 // Reset PKA before enabling (sometimes helps with initialization)
 pka.pka_cr().modify(|_, w| w.en().clear_bit());
 for _ in 0..10 {
 asm::nop();
 }

 // Enable PKA peripheral
 pka.pka_cr().write(|w| w
 .en().set_bit()
 .mode().bits(0x0E) // Modular addition mode
 );
 
 // Wait for PKA to initialize
 while pka.pka_sr().read().initok().bit_is_clear() {
 asm::nop();
 }

 // PKA RAM base address
 let pka_base = &p.PKA as *const _ as u32;
 let pka_ram_base = pka_base + PKA_RAM_OFFSET;
 
 info!("PKA peripheral base address: {:#08x}", pka_base);
 info!("PKA RAM base address: {:#08x}", pka_ram_base);

 // Access PKA RAM as 32-bit words 
 let pka_ram = pka_ram_base as *mut u32;
 
 // Calculate correct offsets in 32-bit words (divide by 4 instead of 8)
 let length_addr = pka_ram.add((OPERAND_LENGTH_OFFSET / 4) as usize);
 let a_addr = pka_ram.add((OPERAND_A_OFFSET / 4) as usize);
 let b_addr = pka_ram.add((OPERAND_B_OFFSET / 4) as usize);
 let modulus_addr = pka_ram.add((MODULUS_OFFSET / 4) as usize);
 let result_addr = pka_ram.add((RESULT_OFFSET / 4) as usize);

 // Clear any previous error flags
 pka.pka_clrfr().write(|w| w
 .addrerrfc().set_bit()
 .ramerrfc().set_bit()
 .procendfc().set_bit()
 );

 // Write the values - using 32-bit words
 info!("Writing operand length...");
 core::ptr::write_volatile(length_addr, OPERAND_LENGTH);
 
 info!("Writing operand A...");
 core::ptr::write_volatile(a_addr, A);
 core::ptr::write_volatile(a_addr.add(1), 0); // Additional zero word
 
 info!("Writing operand B...");
 core::ptr::write_volatile(b_addr, B);
 core::ptr::write_volatile(b_addr.add(1), 0); // Additional zero word
 
 info!("Writing modulus...");
 core::ptr::write_volatile(modulus_addr, N);
 core::ptr::write_volatile(modulus_addr.add(1), 0); // Additional zero word

 info!("Data loaded");
 info!("ADDRERRF is clear: {}", pka.pka_sr().read().addrerrf().bit_is_clear());

 // Configure PKA operation mode and start
 info!("Starting PKA operation...");
 pka.pka_cr().modify(|_, w| w
 .mode().bits(0x0E) // Modular addition mode
 .start().set_bit() // Start the operation
 );

 // Wait for processing to complete - PROCENDF is 1 when done
 info!("Waiting for operation to complete...");
 while pka.pka_sr().read().procendf().bit_is_clear() {
 asm::nop();
 }
 info!("Operation complete!");

 // Read the result
 let result = core::ptr::read_volatile(result_addr);
 info!("Modular Addition: {} + {} (mod {}) = {}", A, B, N, result);
 
 // Clear the completion flag
 pka.pka_clrfr().write(|w| w.procendfc().set_bit());

 loop {}
}

 

INFO HSE ready: true
└─ pka::__cortex_m_rt_main @ src/bin/pka.rs:40
INFO RNG clock enabled: true
└─ pka::__cortex_m_rt_main @ src/bin/pka.rs:49
INFO SEIS bit is 0: true SECS bit is 0: true CEIS bit is 0: true CECS bit is 0: true
└─ pka::__cortex_m_rt_main @ src/bin/pka.rs:73
INFO RNG enabled successfully
└─ pka::__cortex_m_rt_main @ src/bin/pka.rs:84
INFO PKA clock enabled: true
└─ pka::__cortex_m_rt_main @ src/bin/pka.rs:89
INFO PKA enabled: true
└─ pka::__cortex_m_rt_main @ src/bin/pka.rs:104
INFO INITOK bit set: true
└─ pka::__cortex_m_rt_main @ src/bin/pka.rs:107
INFO PKA initialized successfully!
└─ pka::__cortex_m_rt_main @ src/bin/pka.rs:111
INFO PKA RAM base address: 0x2001fe92
└─ pka::__cortex_m_rt_main @ src/bin/pka.rs:118
INFO Writing operand length...
└─ pka::__cortex_m_rt_main @ src/bin/pka.rs:144  

 

And it then stops. I am thinking it might be something off with the memory addresses or how I am trying to access the RAM memory. 

 

Thanks for the help,

 

Elsa

1 reply

Jocelyn RICARD
ST Employee
March 10, 2025

Hello @elopezpe ,

please check examples provided in

STM32Cube_FW_WB_V1.21.0\Projects\P-NUCLEO-WB55.Nucleo\Examples\PKA\

This should give you a working reference that allows understanding what is not working in your case.

Best regards

Jocelyn

elopezpeAuthor
Associate
March 16, 2025

Hello,

 

Thank you for your answer. I went over the information you sent, but I cannot see where the PKA base address is located. I found a link to a PKA impelmentation in Rust for the micro stm32wlxx (https://docs.rs/stm32wlxx-hal/latest/src/stm32wlxx_hal/pka.rs.html#241-243), and they define base as 0x5800_2000. However, when I go to the documentation of that said micro (https://www.st.com/resource/en/reference_manual/rm0453-stm32wl5x-advanced-armbased-32bit-mcus-with-subghz-radio-solution-stmicroelectronics.pdf), there is no such definition and in the memory map I see that the AHB2 is located at address 0x5800_0000. In the section of the PKA RAM, they say exactly the same as in the section of the STM32WBAxx:

STM32WLxx:

PKA RAM
The PKA RAM is mapped at the offset address of 0x0400 compared to the PKA base
address. Only 32-bit word single accesses are supported, through PKA.AHB interface.
RAM size is 3576 bytes (max word offset: 0x11F4).

STM32WBAxx:

PKA RAM
The PKA RAM is mapped at the offset address of 0x0400 compared to the PKA base
address. Only 32-bit word single accesses are supported, through PKA.AHB interface.
RAM size is 5336 bytes (max word offset: 0x14D0)
Note: PKA RAM cannot be used just after a PKA reset or a product reset, as described in
Section 28.3.3: PKA reset and clocks

 

I have managed to write into the memory, but when reading the result I get something wrong, which does not change before or after computation. So my guess is that I am not writing in the correct memory region. If you could point to where to find this information it would be very much appreciated.

 

Elsa