2025-03-10 7:04 AM
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