TRNG
module reference#include <trng.h>Makefile :
MODULES+=trng
The TRNG (True Random Number Generator) is a peripheral dedicated, as its name implies, to generate random numbers. It uses hardware dedicated to this purpose and passes multiple test suites aimed at verifying the quality of the "randomness" of the generated numbers, which makes it suitable for cryptography. The generator is able to provide a 32-bit random number every 84 clock cycles.
available()
and get()
or using an interrupt.This module is extremely simple : an enable bit, an output register, and a single interrupt channel. Even the chapter in the datasheet is only 9 pages long. Sorry, there isn't much to hack here.
#ifndef _TRNG_H_ #define _TRNG_H_ #include <stdint.h> // True Random Number Generator // This module provides 32-bit highly random numbers // based on specified hardware. namespace TRNG { // Peripheral memory space base address const uint32_t BASE = 0x40068000; // Registers addresses const uint32_t OFFSET_CR = 0x00; // Control Register const uint32_t OFFSET_IER = 0x10; // Interrupt Enable Register const uint32_t OFFSET_IDR = 0x14; // Interrupt Disable Register const uint32_t OFFSET_IMR = 0x18; // Interrupt Mask Register const uint32_t OFFSET_ISR = 0x1C; // Interrupt Status Register const uint32_t OFFSET_ODATA = 0x50; // Output Data Register // Constants const uint32_t CR_ENABLE = 0; const uint32_t CR_KEY = 0x524E47 << 8; const uint32_t ISR_DATRDY = 0; void enable(); bool available(); uint32_t get(); void enableInterrupt(void (*handler)(uint32_t)); void disableInterrupt(); } #endif
#include "trng.h" #include "core.h" #include "pm.h" namespace TRNG { // Interrupt handler extern uint8_t INTERRUPT_PRIORITY; uint32_t _dataReadyHandler = 0; void interruptHandlerWrapper(); void enable() { // Enable the clock PM::enablePeripheralClock(PM::CLK_TRNG); // CR (Control Register) : enable the TRNG (*(volatile uint32_t*)(BASE + OFFSET_CR)) = 1 << CR_ENABLE | CR_KEY; } bool available() { // Return true if a new random number is available return (*(volatile uint32_t*)(BASE + OFFSET_ISR)) & 1 << ISR_DATRDY; } uint32_t get() { // Clear the DATARDY bit by reading ISR available(); // Return the new random number return (*(volatile uint32_t*)(BASE + OFFSET_ODATA)); } void enableInterrupt(void (*handler)(uint32_t)) { // Save the user handler _dataReadyHandler = (uint32_t)handler; // IER (Interrupt Enable Register) : enable the Data Ready interrupt (this is the // only interrupt available) (*(volatile uint32_t*)(BASE + OFFSET_IER)) = 1 << ISR_DATRDY; // Set the handler and enable the module interrupt at the Core level Core::setInterruptHandler(Core::Interrupt::TRNG, interruptHandlerWrapper); Core::enableInterrupt(Core::Interrupt::TRNG, INTERRUPT_PRIORITY); } void disableInterrupt() { // IER (Interrupt Disable Register) : disable the interrupt (*(volatile uint32_t*)(BASE + OFFSET_IDR)) = 1 << ISR_DATRDY; // Disable the module interrupt at the Core level Core::disableInterrupt(Core::Interrupt::TRNG); } void interruptHandlerWrapper() { // Call the user handler void (*handler)(uint32_t) = (void (*)(uint32_t))_dataReadyHandler; if (handler != nullptr) { handler(get()); } // Clear the interrupt by reading ISR available(); } }