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();
}
}