In my project I need to have one class as singleton which must be globally accessible:
board.h:
#pragma once
#include "io/io.h"
#include "lib/drv/gpio.hpp"
class Board {
public:
static const unsigned int CORE_FREQ = 48000000;
static const unsigned int SYSTICK_FREQ = 1000;
volatile uint64_t tickCounter;
GpioPin<io::base::GPIOA, 8> mco;
GpioPin<io::base::GPIOA, 0> button;
GpioPin<io::base::GPIOC, 9> ledGreen;
GpioPin<io::base::GPIOC, 8> ledBlue;
Board();
/* Return clock ticks since restart
* @return number of ticks since restart */
uint64_t getTicks();
static Board board;
};
board.cpp:
#include "board.hpp"
Board::Board() {
// Enable HSI oscillator 8MHz
io::rcc::r.CR.b.HSION = true;
while (!io::rcc::r.CR.b.HSIRDY);
io::rcc::r.CFGR.b.SW = (int)io::rcc::Cfgr::Sw::HSI;
// Set prescalers for AHB and APB
io::rcc::r.CFGR.b.HPRE = (int)io::rcc::Cfgr::Hpre::DIV_1;
io::rcc::r.CFGR.b.PPRE = (int)io::rcc::Cfgr::Ppre::DIV_1;
// set PLL to 48MHz from HSI clock
io::rcc::r.CFGR.b.PLLSRC = (int)io::rcc::Cfgr::Pllsrc::HSI_DIV_2;
io::rcc::r.CFGR.b.PLLMUL = (int)io::rcc::Cfgr::Pllmul::MUL_12;
io::rcc::r.CR.b.PLLON = true;
while (!io::rcc::r.CR.b.PLLRDY);
io::rcc::r.CFGR.b.SW = (int)io::rcc::Cfgr::Sw::PLL;
// Send HCI to MCO output
io::rcc::r.CFGR.b.MCOPRE = (int)io::rcc::Cfgr::Mcopre::DIV_1;
io::rcc::r.CFGR.b.MCO = (int)io::rcc::Cfgr::Mco::HSI;
// NVIC
io::nvic::isrEnable();
// SYSTICK
io::systick::r.configure(CORE_FREQ / SYSTICK_FREQ);
tickCounter = 0;
// CLOCK ENABLE
io::rcc::r.AHBENR.b.GPIOA = true;
io::rcc::r.AHBENR.b.GPIOC = true;
// GPIO
mco.setAf(0).setOtype(io::gpio::Otype::PUSH_PULL).setOspeed(io::gpio::Ospeed::HIGH);
// Configure button
button.setInput();
// Configure LEDs
ledGreen.setOutput().setOtype(io::gpio::Otype::PUSH_PULL);
ledBlue.setOutput().setOtype(io::gpio::Otype::PUSH_PULL);
}
unsigned long long Board::getTicks() {
unsigned long long major;
unsigned int minor;
do {
major = tickCounter;
minor = io::systick::r.VAL.CURRENT;
} while (major != tickCounter);
major += 1;
major *= CORE_FREQ / SYSTICK_FREQ;
return major - minor;
}
void HARDFAULT_handler() {
while (true) {
Board::board.ledBlue.toggle();
}
}
void SYSTICK_handler() {
Board::board.tickCounter++;
}
Board Board::board;
main.cpp:
#include "board.hpp"
class MainClass {
private:
unsigned int blinkTicks;
uint64_t ticks;
void process(unsigned int delta) {
blinkTicks += delta;
if (blinkTicks > 4800000) {
blinkTicks = 0;
Board::board.ledGreen.toggle();
}
}
public:
MainClass() {
blinkTicks = 0;
ticks = Board::board.getTicks();
}
void run() {
Board::board.ledBlue.set();
while (true) {
uint64_t tm = ticks;
ticks = Board::board.getTicks();
tm = ticks - tm;
if (tm > 0) process(tm);
}
}
};
MainClass mainClass;
void mainApp() {
mainClass.run();
}
(This class define some board specific configurations and definitions for microcontroller.)
In my case singleton is necessary, because it is called from HW interrupts handlers.
Is it good practice? How can I do it better?