TRNG module reference

Header :
#include <trng.h>
Makefile :
MODULES+=trng

Description

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.

API

void enable()
Enable the generator. A constant stream of numbers will be generated and can be retrieved using available() and get() or using an interrupt.
bool available()
Return true if a new random number is available.
uint32_t get()
Return the new random number.
void enableInterrupt(void (*handler)(uint32_t))
Enable the interrupt to call the specified handler when a new random number is available.
void disableInterrupt()
Disable the interrupt.

Hacking

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.

Code

Header

#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

Module

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

}