Merge pull request 'task' (#5) from task into dev

Reviewed-on: https://git.steins7.ovh/Steins7/stm32f1xx_HBL/pulls/5
This commit is contained in:
Steins7 2024-08-04 18:30:15 +00:00
commit 6d95bce6df
34 changed files with 1835 additions and 737 deletions

View File

@ -9,10 +9,8 @@
//--includes--------------------------------------------------------------------
#include "stdint.h"
#include "stdbool.h"
#include "exti.h"
#include "gpio.h"
//--type definitions------------------------------------------------------------

View File

@ -19,7 +19,7 @@
#define AFIO_BASE_ADDRESS 0x40010000
union EVCR {
struct __attribute__((packed)) {
struct {
uint32_t PIN:4;
uint32_t PORT:3;
uint32_t EVOE:1;
@ -29,7 +29,7 @@ union EVCR {
};
union MAPR {
struct __attribute__((packed)) {
struct {
uint32_t SPI1_REMAP:1;
uint32_t I2C1_REMAP:1;
uint32_t USART1_REMAP:1;
@ -54,7 +54,7 @@ union MAPR {
};
union EXTICR1 {
struct __attribute__((packed)) {
struct {
uint32_t EXTI0:4;
uint32_t EXTI1:4;
uint32_t EXTI2:4;
@ -65,7 +65,7 @@ union EXTICR1 {
};
union EXTICR2 {
struct __attribute__((packed)) {
struct {
uint32_t EXTI4:4;
uint32_t EXTI5:4;
uint32_t EXTI6:4;
@ -76,7 +76,7 @@ union EXTICR2 {
};
union EXTICR3 {
struct __attribute__((packed)) {
struct {
uint32_t EXTI8:4;
uint32_t EXTI9:4;
uint32_t EXTI10:4;
@ -87,7 +87,7 @@ union EXTICR3 {
};
union EXTICR4 {
struct __attribute__((packed)) {
struct {
uint32_t EXTI12:4;
uint32_t EXTI13:4;
uint32_t EXTI14:4;
@ -98,7 +98,7 @@ union EXTICR4 {
};
union MAPR2 {
struct __attribute__((packed)) {
struct {
uint32_t reserved1:5;
uint32_t TIM9_REMAP:1;
uint32_t TIM10_REMAP:1;
@ -111,7 +111,7 @@ union MAPR2 {
uint32_t word;
};
struct __attribute__((packed)) AFIO {
struct AFIO {
union EVCR EVCR;
union MAPR MAPR;
union EXTICR1 EXTICR1;

152
drv/bkp.c Normal file
View File

@ -0,0 +1,152 @@
/** @file bkp.c
* Module handling the Backup (BKP) domain functionalities.
*
* This module includes management of the Real Time Clock (RTC), Tamper
* protection system and a limited space (20 bytes) for persistent data storage
*
* All features present in this module stay running in standby mode / when
* no-longer powered, so long as VBAT is maintained
*/
//--includes--------------------------------------------------------------------
#include "bkp.h"
#include "bkp_regs.h"
#include "rcc.h"
#include "nvic.h"
//--local definitions-----------------------------------------------------------
uint32_t compute_prescaler(uint32_t period_ms, enum BkpRtcClockSrc clock_src);
//--local variables-------------------------------------------------------------
//static volatile struct BKP* bkp_regs = (struct BKP*)BKP_BASE_ADDRESS;
static volatile struct RCC* rcc_regs = (struct RCC*)RCC_BASE_ADDRESS;
static volatile struct RTC* rtc_regs = (struct RTC*)RTC_BASE_ADDRESS;
static BkpRtcCallback rtc_callback;
//--public functions------------------------------------------------------------
void bkp_configure_rtc(uint32_t period_ms, enum BkpRtcClockSrc clock_src,
enum BkpRtcIrq irq_mask, BkpRtcCallback callback)
{
rcc_enable(RCC_AHB_NONE, RCC_APB1_BKP, RCC_APB2_NONE);
//start RTC
rcc_regs->BDCR.RTCSEL = clock_src + 1;
rcc_regs->BDCR.RTCEN = 1;
uint32_t prescaler = compute_prescaler(period_ms, clock_src);
//wait for registers to synchronize
rtc_regs->CRL.RSF = 0;
while (rtc_regs->CRL.RSF != 1) {}
//wait for last operation to finish
while (rtc_regs->CRL.RTOFF != 1) {}
//enable core configuration
rtc_regs->CRL.CNF = 1;
//configure core registers
rtc_regs->PRLH.PRL = prescaler >> 16;
rtc_regs->PRLL.PRL = prescaler;
//apply irq config
rtc_regs->CRH.word |= irq_mask & 0x7;
//disable/apply core configuration
rtc_regs->CRL.CNF = 0;
//wait for last operation to finish
while (rtc_regs->CRL.RTOFF != 1) {}
if (callback) {
rtc_callback = callback;
nvic_enable(NVIC_IRQ_RTC);
}
}
void bkp_set_rtc_alam(uint32_t offset)
{
uint32_t alarm = bkp_read_rtc() + offset;
//wait for last operation to finish
while (rtc_regs->CRL.RTOFF != 1) {}
//enable core configuration
rtc_regs->CRL.CNF = 1;
//write alarm value
rtc_regs->ALRH.RTC_ALR = alarm >> 16;
rtc_regs->ALRL.RTC_ALR = alarm;
//disable/apply core configuration
rtc_regs->CRL.CNF = 0;
//wait for last operation to finish
while (rtc_regs->CRL.RTOFF != 1) {}
}
uint32_t bkp_read_rtc(void)
{
//wait for core registers to be synchronized, immediate most of the time
while (rtc_regs->CRL.RSF != 1) {}
uint32_t time = rtc_regs->CNTH.RTC_CNT << 16;
time |= rtc_regs->CNTL.RTC_CNT << 0;
return time;
}
void bkp_reset(void)
{
rcc_regs->BDCR.BDRST = 1;
rcc_regs->BDCR.BDRST = 0;
}
//--local functions-------------------------------------------------------------
/**
* Computes the prescaler value based on the clock source and the required
* period
*/
uint32_t compute_prescaler(uint32_t period_ms, enum BkpRtcClockSrc clock_src)
{
uint32_t prescaler;
switch (clock_src) {
case BKP_RTC_CLOCK_SRC_LSE:
prescaler = 32768000; //32.768kHz
break;
case BKP_RTC_CLOCK_SRC_LSI:
prescaler = 40000000; //40khz
break;
case BKP_RTC_CLOCK_SRC_HSE:
prescaler = 62500000; //8Mhz / 128
break;
default:
return 0;
}
return prescaler / period_ms;
}
//--ISRs------------------------------------------------------------------------
void hdr_rtc(void)
{
nvic_clear_pending(NVIC_IRQ_RTC);
//copy and clear and pass along src flags
enum BkpRtcIrq src = rtc_regs->CRL.word & 0x7;
rtc_regs->CRL.word &= ~(0x7);
rtc_callback(src);
}

102
drv/bkp.h Normal file
View File

@ -0,0 +1,102 @@
/** @file bkp.h
* Module handling the Backup (BKP) domain functionalities.
*
* This module includes management of the Real Time Clock (RTC), Tamper
* protection system and a limited space (20 bytes) for persistent data storage
*
* All features present in this module stay running in standby mode / when
* no-longer powered, so long as VBAT is maintained
*/
#ifndef _BKP_H_
#define _BKP_H_
//--includes--------------------------------------------------------------------
#include "stdint.h"
//--type definitions------------------------------------------------------------
/**
* Available clock sources for the RTC. See bkp_configure_rtc() for more
* information
*/
enum BkpRtcClockSrc {
BKP_RTC_CLOCK_SRC_LSE = 0x0,
BKP_RTC_CLOCK_SRC_LSI = 0x1,
BKP_RTC_CLOCK_SRC_HSE = 0x2,
};
/**
* Available IRQ sources. This enum is passed to the RTC callback to allow
* differentiating IRQ sources
*/
enum BkpRtcIrq {
BKP_RTC_IRQ_NONE = 0,
BKP_RTC_IRQ_SECOND = 0x1 << 0,
BKP_RTC_IRQ_ALARM = 0x1 << 1,
BKP_RTC_IRQ_OVERFLOW = 0x1 << 2,
};
/**
* Prototype of the IRQ callbacks that the applicative code can provide
*/
typedef void (*BkpRtcCallback)(enum BkpRtcIrq src);
//--functions-------------------------------------------------------------------
/**
* Configures the RTC, starting it immediately. Configuration is saved between
* boots as long as VBAT is present
*
* The RTC can run on a period of up to 1s and using one of 3 clocks. Clock
* choice is a question of compromise :
* - LSE consumes the less energy and continues to run in standby mode, but
* requires an extra oscillator circuit
* - LSI consumes little but isn't very accurate and requires extra calibration
* (see bkp_callibrate_lsi)
* - HSE consumes the most.
* WARNING : once configured, the clock source can only changed by reseting the
* whole backup domain via bkp_reset()
* Clocks must be enabled prior to calling this function
*
* Mulitple IRQs can be enabled and redirected to single callback. The alarm
* IRQ, triggered at the tick value specified by bkp_set_rtc_alam() can be
* rerouted to an exti line for wakeup from stop and standby, in wich case it
* doesn't need to be enabled here.
*
* Ensure backup domain writes are enabled (see pwr_configure_bkp_write()) while
* calling this function
*/
void bkp_configure_rtc(uint32_t period_ms, enum BkpRtcClockSrc clock_src,
enum BkpRtcIrq irq_mask, BkpRtcCallback callback);
/**
* Configure the alarm to trigger after the specified time in ticks, which can
* be viewed as an offset to the current time value. This offset is only precise
* to the tick and thus if the tick changes right after this function is
* called, the observed offset will be close to 1 tick short
*/
void bkp_set_rtc_alam(uint32_t offset);
/**
* Returns the current counter value of the RTC
*/
uint32_t bkp_read_rtc(void);
/**
* Resets the entire backup domain, composed of everything configured through
* this module
*/
void bkp_reset(void);
//unimplemented functions
void bkp_configure_tamper();
void bkp_calibrate_lsi(void);
void bkp_configure_lse(bool enable);
#endif //_BKP_H_

196
drv/bkp_regs.h Normal file
View File

@ -0,0 +1,196 @@
/** @file bkp_regs.h
* Module defining the Backup (bkp) domain registers.
*
* Mainly made to be used by the bkp module. It is recommanded to go through
* the functions provided by that module instead of directly using the registers
* defined here.
*/
#ifndef _BKP_REGS_H_
#define _BKP_REGS_H_
//--includes--------------------------------------------------------------------
#include "stdint.h"
//--type definitions------------------------------------------------------------
#define BKP_BASE_ADDRESS 0x40006C00
#define RCC_BASE_ADDRESS 0x40021020
#define RTC_BASE_ADDRESS 0x40002800
union BKP_DR {
struct {
uint32_t D:16;
uint32_t reserved1:16;
};
uint32_t word;
};
union BKP_RTCCR {
struct {
uint32_t CAL:7;
uint32_t CCO:1;
uint32_t ASOE:1;
uint32_t ASOS:1;
uint32_t reserved1:22;
};
uint32_t word;
};
union BKP_CR {
struct {
uint32_t TPE:1;
uint32_t TPAL:1;
uint32_t reserved1:30;
};
uint32_t word;
};
union BKP_CSR {
struct {
uint32_t CTE:1;
uint32_t CTI:1;
uint32_t TPIE:1;
uint32_t reserved1:5;
uint32_t TEF:1;
uint32_t TIF:1;
uint32_t reserved2:22;
};
uint32_t word;
};
struct BKP {
union BKP_DR DR[20];
union BKP_RTCCR RTCCR;
union BKP_CR CR;
union BKP_CSR CSR;
};
union RCC_BDCR {
struct {
uint32_t LSEON:1;
uint32_t LSERDY:1;
uint32_t LSEBYP:1;
uint32_t reserved1:5;
uint32_t RTCSEL:2;
uint32_t reserved2:5;
uint32_t RTCEN:1;
uint32_t BDRST:1;
uint32_t reserved3:15;
};
uint32_t word;
};
struct RCC {
union RCC_BDCR BDCR;
};
union RTC_CRH {
struct {
uint32_t SECIE:1;
uint32_t ALRIE:1;
uint32_t OWIE:1;
uint32_t reserved1:29;
};
uint32_t word;
};
union RTC_CRL {
struct {
uint32_t SECF:1;
uint32_t ALRF:1;
uint32_t OWF:1;
uint32_t RSF:1;
uint32_t CNF:1;
uint32_t RTOFF:1;
uint32_t reserved1:26;
};
uint32_t word;
};
union RTC_PRLH {
struct {
uint32_t PRL:4;
uint32_t reserved1:28;
};
uint32_t word;
};
union RTC_PRLL {
struct {
uint32_t PRL:16;
uint32_t reserved1:16;
};
uint32_t word;
};
union RTC_DIVH {
struct {
uint32_t RTC_DIV:4;
uint32_t reserved1:28;
};
uint32_t word;
};
union RTC_DIVL {
struct {
uint32_t RTC_DIV:16;
uint32_t reserved1:16;
};
uint32_t word;
};
union RTC_CNTH {
struct {
uint32_t RTC_CNT:16;
uint32_t reserved1:16;
};
uint32_t word;
};
union RTC_CNTL {
struct {
uint32_t RTC_CNT:16;
uint32_t reserved1:16;
};
uint32_t word;
};
union RTC_ALRH {
struct {
uint32_t RTC_ALR:16;
uint32_t reserved1:16;
};
uint32_t word;
};
union RTC_ALRL {
struct {
uint32_t RTC_ALR:16;
uint32_t reserved1:16;
};
uint32_t word;
};
struct RTC {
union RTC_CRH CRH;
union RTC_CRL CRL;
union RTC_PRLH PRLH;
union RTC_PRLL PRLL;
union RTC_DIVH DIVH;
union RTC_DIVL DIVL;
union RTC_CNTH CNTH;
union RTC_CNTL CNTL;
union RTC_ALRH ALRH;
union RTC_ALRL ALRL;
};
//--functions-------------------------------------------------------------------
#endif //_BKP_REGS_H_

View File

@ -121,13 +121,13 @@ void dma_stop(enum DmaPeriph dma, enum DmaChannel channel)
{
switch (dma) {
case DMA_PERIPH_1:
reg_reset(dma1->CHANNELS[channel].CCR, DMA_CCR_EN);
dma1->CHANNELS[channel].CCR.EN = 0;
if (dma1_callbacks[channel]) {
nvic_disable(NVIC_IRQ_DMA1_CHANNEL1 + channel);
}
break;
case DMA_PERIPH_2:
reg_reset(dma2->CHANNELS[channel].CCR, DMA_CCR_EN);
dma2->CHANNELS[channel].CCR.EN;
if (dma2_callbacks[channel]) {
nvic_disable(NVIC_IRQ_DMA2_CHANNEL1 + channel);
}
@ -207,11 +207,11 @@ static void start_dma(volatile struct DMA* dma, enum DmaChannel channel,
volatile struct DMA_CHANNEL* regs = &dma->CHANNELS[channel];
//registers should already be configured, apply transfer config
reg_write(regs->CNDTR, DMA_CNDTR_NDT, size);
regs->CNDTR.NDT = size;
regs->CMAR = (uint32_t)mem;
//only start transfer when everything is configured
reg_set(regs->CCR, DMA_CCR_EN);
regs->CCR.EN = 1;
}
//--ISRs------------------------------------------------------------------------
@ -221,7 +221,7 @@ void hdr_dma1_channel1(void)
nvic_clear_pending(NVIC_IRQ_DMA1_CHANNEL1);
enum DmaIRQSource src = (dma1->IFCR.word >> 1) & 0x7;
reg_set(dma1->IFCR, DMA_IFCR_CGIF1);
dma1->IFCR.CGIF1 = 1;
dma1_callbacks[0](src, dma1_cb_params[0]);
}
@ -231,7 +231,7 @@ void hdr_dma1_channel2(void)
nvic_clear_pending(NVIC_IRQ_DMA1_CHANNEL2);
enum DmaIRQSource src = (dma1->IFCR.word >> 5) & 0x7;
reg_set(dma1->IFCR, DMA_IFCR_CGIF2);
dma1->IFCR.CGIF2 = 1;
dma1_callbacks[1](src, dma1_cb_params[1]);
}
@ -241,7 +241,7 @@ void hdr_dma1_channel3(void)
nvic_clear_pending(NVIC_IRQ_DMA1_CHANNEL3);
enum DmaIRQSource src = (dma1->IFCR.word >> 9) & 0x7;
reg_set(dma1->IFCR, DMA_IFCR_CGIF3);
dma1->IFCR.CGIF3 = 1;
dma1_callbacks[2](src, dma1_cb_params[2]);
}
@ -251,7 +251,7 @@ void hdr_dma1_channel4(void)
nvic_clear_pending(NVIC_IRQ_DMA1_CHANNEL4);
enum DmaIRQSource src = (dma1->IFCR.word >> 13) & 0x7;
reg_set(dma1->IFCR, DMA_IFCR_CGIF4);
dma1->IFCR.CGIF4 = 1;
dma1_callbacks[3](src, dma1_cb_params[3]);
}
@ -261,7 +261,7 @@ void hdr_dma1_channel5(void)
nvic_clear_pending(NVIC_IRQ_DMA1_CHANNEL5);
enum DmaIRQSource src = (dma1->IFCR.word >> 17) & 0x7;
reg_set(dma1->IFCR, DMA_IFCR_CGIF5);
dma1->IFCR.CGIF5 = 1;
dma1_callbacks[4](src, dma1_cb_params[4]);
}
@ -271,7 +271,7 @@ void hdr_dma1_channel6(void)
nvic_clear_pending(NVIC_IRQ_DMA1_CHANNEL6);
enum DmaIRQSource src = (dma1->IFCR.word >> 21) & 0x7;
reg_set(dma1->IFCR, DMA_IFCR_CGIF6);
dma1->IFCR.CGIF6 = 1;
dma1_callbacks[5](src, dma1_cb_params[5]);
}
@ -281,7 +281,7 @@ void hdr_dma1_channel7(void)
nvic_clear_pending(NVIC_IRQ_DMA1_CHANNEL7);
enum DmaIRQSource src = (dma1->IFCR.word >> 25) & 0x7;
reg_set(dma1->IFCR, DMA_IFCR_CGIF7);
dma1->IFCR.CGIF7 = 1;
dma1_callbacks[6](src, dma1_cb_params[6]);
}
@ -291,7 +291,7 @@ void hdr_dma2_channel1(void)
nvic_clear_pending(NVIC_IRQ_DMA2_CHANNEL1);
enum DmaIRQSource src = (dma2->IFCR.word >> 1) & 0x7;
reg_set(dma2->IFCR, DMA_IFCR_CGIF1);
dma2->IFCR.CGIF1 = 1;
dma2_callbacks[0](src, dma2_cb_params[0]);
}
@ -301,7 +301,7 @@ void hdr_dma2_channel2(void)
nvic_clear_pending(NVIC_IRQ_DMA2_CHANNEL2);
enum DmaIRQSource src = (dma2->IFCR.word >> 5) & 0x7;
reg_set(dma2->IFCR, DMA_IFCR_CGIF2);
dma2->IFCR.CGIF2 = 1;
dma2_callbacks[1](src, dma2_cb_params[1]);
}
@ -311,7 +311,7 @@ void hdr_dma2_channel3(void)
nvic_clear_pending(NVIC_IRQ_DMA2_CHANNEL3);
enum DmaIRQSource src = (dma2->IFCR.word >> 9) & 0x7;
reg_set(dma2->IFCR, DMA_IFCR_CGIF3);
dma2->IFCR.CGIF3 = 1;
dma2_callbacks[2](src, dma2_cb_params[2]);
}
@ -322,13 +322,13 @@ void hdr_dma2_channel4_5(void)
enum DmaIRQSource src = (dma2->IFCR.word >> 13) & 0x7;
if (src != 0) {
reg_set(dma2->IFCR, DMA_IFCR_CGIF4);
dma2->IFCR.CGIF4 = 1;
dma1_callbacks[3](src, dma2_cb_params[3]);
}
src = (dma2->IFCR.word >> 17) & 0x7;
if (src != 0) {
reg_set(dma2->IFCR, DMA_IFCR_CGIF5);
dma2->IFCR.CGIF5 = 1;
dma1_callbacks[4](src, dma2_cb_params[4]);
}
}

View File

@ -11,8 +11,6 @@
//--includes--------------------------------------------------------------------
#include "reg.h"
#include "stdint.h"
@ -22,7 +20,7 @@
#define DMA2_BASE_ADDRESS 0x40020400
union DMA_ISR {
struct __attribute__((packed)) {
struct {
uint32_t GIF1:1;
uint32_t TCIF1:1;
uint32_t HTIF1:1;
@ -56,38 +54,8 @@ union DMA_ISR {
uint32_t word;
};
#define DMA_ISR_GIF1 reg_def( 0, 1)
#define DMA_ISR_TCIF1 reg_def( 1, 1)
#define DMA_ISR_HTIF1 reg_def( 2, 1)
#define DMA_ISR_TEIF1 reg_def( 3, 1)
#define DMA_ISR_GIF2 reg_def( 4, 1)
#define DMA_ISR_TCIF2 reg_def( 5, 1)
#define DMA_ISR_HTIF2 reg_def( 6, 1)
#define DMA_ISR_TEIF2 reg_def( 7, 1)
#define DMA_ISR_GIF3 reg_def( 8, 1)
#define DMA_ISR_TCIF3 reg_def( 9, 1)
#define DMA_ISR_HTIF3 reg_def(10, 1)
#define DMA_ISR_TEIF3 reg_def(11, 1)
#define DMA_ISR_GIF4 reg_def(12, 1)
#define DMA_ISR_TCIF4 reg_def(13, 1)
#define DMA_ISR_HTIF4 reg_def(14, 1)
#define DMA_ISR_TEIF4 reg_def(15, 1)
#define DMA_ISR_GIF5 reg_def(16, 1)
#define DMA_ISR_TCIF5 reg_def(17, 1)
#define DMA_ISR_HTIF5 reg_def(18, 1)
#define DMA_ISR_TEIF5 reg_def(19, 1)
#define DMA_ISR_GIF6 reg_def(20, 1)
#define DMA_ISR_TCIF6 reg_def(21, 1)
#define DMA_ISR_HTIF6 reg_def(22, 1)
#define DMA_ISR_TEIF6 reg_def(23, 1)
#define DMA_ISR_GIF7 reg_def(24, 1)
#define DMA_ISR_TCIF7 reg_def(25, 1)
#define DMA_ISR_HTIF7 reg_def(26, 1)
#define DMA_ISR_TEIF7 reg_def(27, 1)
#define DMA_ISR_reserved1 reg_def(28, 4)
union DMA_IFCR {
struct __attribute__((packed)) {
struct {
uint32_t CGIF1:1;
uint32_t CTCIF1:1;
uint32_t CHTIF1:1;
@ -121,38 +89,8 @@ union DMA_IFCR {
uint32_t word;
};
#define DMA_IFCR_CGIF1 reg_def( 0, 1)
#define DMA_IFCR_CTCIF1 reg_def( 1, 1)
#define DMA_IFCR_CHTIF1 reg_def( 2, 1)
#define DMA_IFCR_CTEIF1 reg_def( 3, 1)
#define DMA_IFCR_CGIF2 reg_def( 4, 1)
#define DMA_IFCR_CTCIF2 reg_def( 5, 1)
#define DMA_IFCR_CHTIF2 reg_def( 6, 1)
#define DMA_IFCR_CTEIF2 reg_def( 7, 1)
#define DMA_IFCR_CGIF3 reg_def( 8, 1)
#define DMA_IFCR_CTCIF3 reg_def( 9, 1)
#define DMA_IFCR_CHTIF3 reg_def(10, 1)
#define DMA_IFCR_CTEIF3 reg_def(11, 1)
#define DMA_IFCR_CGIF4 reg_def(12, 1)
#define DMA_IFCR_CTCIF4 reg_def(13, 1)
#define DMA_IFCR_CHTIF4 reg_def(14, 1)
#define DMA_IFCR_CTEIF4 reg_def(15, 1)
#define DMA_IFCR_CGIF5 reg_def(16, 1)
#define DMA_IFCR_CTCIF5 reg_def(17, 1)
#define DMA_IFCR_CHTIF5 reg_def(18, 1)
#define DMA_IFCR_CTEIF5 reg_def(19, 1)
#define DMA_IFCR_CGIF6 reg_def(20, 1)
#define DMA_IFCR_CTCIF6 reg_def(21, 1)
#define DMA_IFCR_CHTIF6 reg_def(22, 1)
#define DMA_IFCR_CTEIF6 reg_def(23, 1)
#define DMA_IFCR_CGIF7 reg_def(24, 1)
#define DMA_IFCR_CTCIF7 reg_def(25, 1)
#define DMA_IFCR_CHTIF7 reg_def(26, 1)
#define DMA_IFCR_CTEIF7 reg_def(27, 1)
#define DMA_IFCR_reserved1 reg_def(28, 4)
union DMA_CCR {
struct __attribute__((packed)) {
struct {
uint32_t EN:1;
uint32_t TCIE:1;
uint32_t HTIE:1;
@ -170,32 +108,15 @@ union DMA_CCR {
uint32_t word;
};
#define DMA_CCR_EN reg_def( 0, 1)
#define DMA_CCR_TCIE reg_def( 1, 1)
#define DMA_CCR_HTIE reg_def( 2, 1)
#define DMA_CCR_TEIE reg_def( 3, 1)
#define DMA_CCR_DIR reg_def( 4, 1)
#define DMA_CCR_CIRC reg_def( 5, 1)
#define DMA_CCR_PINC reg_def( 6, 1)
#define DMA_CCR_MINC reg_def( 7, 1)
#define DMA_CCR_PSIZE reg_def( 8, 2)
#define DMA_CCR_MSIZE reg_def(10, 2)
#define DMA_CCR_PL reg_def(12, 2)
#define DMA_CCR_MEM2MEM reg_def(14, 1)
#define DMA_CCR_reserved1 reg_def(15, 17)
union DMA_CNDTR {
struct __attribute__((packed)) {
struct {
uint32_t NDT:16;
uint32_t reserved1:16;
};
uint32_t word;
};
#define DMA_CNDTR_NDT reg_def( 0, 16)
#define DMA_CNDTR_reserved1 reg_def(16, 16)
struct __attribute__((packed)) DMA_CHANNEL {
struct DMA_CHANNEL {
union DMA_CCR CCR;
union DMA_CNDTR CNDTR;
uint32_t CPAR;
@ -203,7 +124,7 @@ struct __attribute__((packed)) DMA_CHANNEL {
uint32_t reserved1;
};
struct __attribute__((packed)) DMA {
struct DMA {
union DMA_ISR ISR;
union DMA_IFCR IFCR;
struct DMA_CHANNEL CHANNELS[7];

View File

@ -11,7 +11,6 @@
#include "exti_regs.h"
#include "nvic.h"
#include "afio.h"
//--local definitions-----------------------------------------------------------
@ -24,13 +23,11 @@ static ExtiCallback callbacks[19];
//--public functions------------------------------------------------------------
void exti_configure(enum ExtiLine line_mask, enum GpioPort port,
enum ExtiConfig config_mask, ExtiCallback callback)
void exti_configure(enum ExtiLine line_mask, enum ExtiConfig config_mask,
ExtiCallback callback)
{
exti_reset(line_mask);
afio_map_exti(line_mask, port);
//configure edge detections
if (config_mask & EXTI_CONFIG_RISING_EDGE) {
regs->RTSR.word |= line_mask;
@ -48,7 +45,7 @@ void exti_configure(enum ExtiLine line_mask, enum GpioPort port,
regs->EMR.word |= line_mask;
if (callback) {
//register callbacks for each line selected
for (uint8_t i = 0; i < 16; ++i) {
for (uint8_t i = 0; i < 19; ++i) {
if (line_mask & (0x1 << i)) {
callbacks[i] = callback;
}
@ -66,6 +63,15 @@ void exti_configure(enum ExtiLine line_mask, enum GpioPort port,
if (line_mask & 0x7c00) {
nvic_enable(NVIC_IRQ_EXTI15_10);
}
if (line_mask & EXTI_LINE_PVD) {
nvic_enable(NVIC_IRQ_PVD);
}
if (line_mask & EXTI_LINE_RTC) {
nvic_enable(NVIC_IRQ_RTC_ALARM);
}
if (line_mask & EXTI_LINE_USB) {
nvic_enable(NVIC_IRQ_USB_WAKEUP);
}
//enable irqs in last to avoid triggers during config
regs->IMR.word |= line_mask;
@ -94,56 +100,6 @@ void exti_reset(enum ExtiLine line_mask)
nvic_disable(NVIC_IRQ_EXTI15_10);
}
afio_map_exti(0xFFFF, 0x0);
}
void exti_configure_specific(enum ExtiLineSpecific line_mask,
enum ExtiConfig config_mask, ExtiCallback callback)
{
//reset is identical to normal lines
exti_reset_specific(line_mask);
//configure edge detections
if (config_mask & EXTI_CONFIG_RISING_EDGE) {
regs->RTSR.word |= line_mask;
} else {
regs->RTSR.word &= ~line_mask;
}
if (config_mask & EXTI_CONFIG_FALLING_EDGE) {
regs->FTSR.word |= line_mask;
} else {
regs->FTSR.word &= ~line_mask;
}
//reconfigure events/irqs
regs->EMR.word |= line_mask;
if (callback) {
//register callbacks for each line selected
for (uint8_t i = 0; i < 16; ++i) {
if (line_mask & (0x1 << i)) {
callbacks[i] = callback;
}
}
//enable interrupts lines in nvic
if (line_mask & EXTI_LINE_PVD) {
nvic_enable(NVIC_IRQ_PVD);
}
if (line_mask & EXTI_LINE_RTC) {
nvic_enable(NVIC_IRQ_RTC_ALARM);
}
if (line_mask & EXTI_LINE_USB) {
nvic_enable(NVIC_IRQ_USB_WAKEUP);
}
//enable irqs in last to avoid triggers during config
regs->IMR.word |= line_mask;
}
}
void exti_reset_specific(enum ExtiLineSpecific line_mask)
{
//disable events/irqs
regs->IMR.word &= ~line_mask;
regs->EMR.word &= ~line_mask;
@ -163,6 +119,7 @@ void exti_reset_specific(enum ExtiLineSpecific line_mask)
}
}
void exti_reset_peripheral(void)
{
//reset peripheral config
@ -182,8 +139,6 @@ void exti_reset_peripheral(void)
nvic_disable(NVIC_IRQ_PVD);
nvic_disable(NVIC_IRQ_RTC_ALARM);
nvic_disable(NVIC_IRQ_USB_WAKEUP);
afio_map_exti(0xFFFF, 0x0);
}
//--local functions-------------------------------------------------------------
@ -193,35 +148,35 @@ void exti_reset_peripheral(void)
void hdr_exti0(void)
{
nvic_clear_pending(NVIC_IRQ_EXTI0);
reg_set(regs->PR, EXTI_PR_PR0);
regs->PR.PR0 = 1;
callbacks[0]();
}
void hdr_exti1(void)
{
nvic_clear_pending(NVIC_IRQ_EXTI1);
reg_set(regs->PR, EXTI_PR_PR1);
regs->PR.PR1 = 1;
callbacks[1]();
}
void hdr_exti2(void)
{
nvic_clear_pending(NVIC_IRQ_EXTI2);
reg_set(regs->PR, EXTI_PR_PR2);
regs->PR.PR2 = 1;
callbacks[2]();
}
void hdr_exti3(void)
{
nvic_clear_pending(NVIC_IRQ_EXTI3);
reg_set(regs->PR, EXTI_PR_PR3);
regs->PR.PR3 = 1;
callbacks[3]();
}
void hdr_exti4(void)
{
nvic_clear_pending(NVIC_IRQ_EXTI4);
reg_set(regs->PR, EXTI_PR_PR4);
regs->PR.PR4 = 1;
callbacks[4]();
}
@ -250,21 +205,21 @@ void hdr_exti15_10(void)
void hdr_pvd(void)
{
nvic_clear_pending(NVIC_IRQ_PVD);
reg_set(regs->PR, EXTI_PR_PR16);
regs->PR.PR16 = 1;
callbacks[16]();
}
void hdr_rtc_alarm(void)
{
nvic_clear_pending(NVIC_IRQ_RTC_ALARM);
reg_set(regs->PR, EXTI_PR_PR17);
regs->PR.PR17 = 1;
callbacks[17]();
}
void hdr_usb_wakeup(void)
{
nvic_clear_pending(NVIC_IRQ_USB_WAKEUP);
reg_set(regs->PR, EXTI_PR_PR18);
regs->PR.PR18 = 1;
callbacks[18]();
}

View File

@ -10,16 +10,11 @@
//--includes--------------------------------------------------------------------
#include "stdint.h"
#include "stdbool.h"
#include "gpio.h"
//--type definitions------------------------------------------------------------
/**
* Available exti lines. These lines correspond to gpios
* Available exti lines. The numbered lines correspond to gpios while the
* remaining are directly mapped to peripherals
*/
enum ExtiLine {
EXTI_LINE_0 = (0x1 << 0),
@ -38,12 +33,6 @@ enum ExtiLine {
EXTI_LINE_13 = (0x1 << 13),
EXTI_LINE_14 = (0x1 << 14),
EXTI_LINE_15 = (0x1 << 15),
};
/**
* Available exti lines. These lines correspond to specific peripherals
*/
enum ExtiLineSpecific {
EXTI_LINE_PVD = (0x1 << 16),
EXTI_LINE_RTC = (0x1 << 17),
EXTI_LINE_USB = (0x1 << 18),
@ -64,43 +53,31 @@ typedef void (*ExtiCallback)(void);
//--functions-------------------------------------------------------------------
/**
* Configure lines on a single GPIO port. The ExtiLine enum can be used as a
* mask to configure multiple lines at the same time. Every line can only be
* configured for a single port, reconfiguring it will override the previous
* configuration. Each line is linked to the pins of the same id (ex : pin 1 for
* exti 1). When possible, it is recommanded to use the lowest id possible for
* better performance. The ExtiConfig enum can be used as mask. If no callback
* is specified, the interrupt won't be enabled, but an event will still be sent
* to wake the cpu up.
* Configure lines to call a single callback. The ExtiLine enum can be used as a
* mask to configure multiple lines at the same time.
*
* Note: wich port is linked to a line can be changed atfer the fact using
* afio_map_exti()
* Every numbered line must be linked to a gpio port using afio_map_exti(). Each
* line is linked to the pins of the same id (ex : pin 1 for exti 1). When
* possible, it is recommended to use the lowest id possible for better
* performance. Each pin must be configured independently through the gpio
* driver module
*
* The remaining lines are linked to specific peripherals which must be
* configured independently through the corresponding driver module.
*
* The ExtiConfig enum can be used as mask. If no callback is specified, the
* interrupt won't be enabled, but an event will still be sent to wake the cpu
* up.
*/
void exti_configure(enum ExtiLine line_mask, enum GpioPort port,
enum ExtiConfig config_mask, ExtiCallback callback);
void exti_configure(enum ExtiLine line_mask, enum ExtiConfig config_mask,
ExtiCallback callback);
/**
* Resets lines. The ExtiLine enum can be used as a mask to configure multiple
* lines at the same time
* Resets lines. The ExtiLine enum can be used as a mask to reset multiple lines
* at the same time
*/
void exti_reset(enum ExtiLine line_mask);
/**
* Configure lines for specific, non-gpio peripherals. The ExtiLineSpecific enum
* can be used as a mask to configure multiple lines at the same time. The
* ExtiConfig enum can be used as mask. If no callback is specified, the
* interrupt won't be enabled, but an event will still be sent to wake the cpu
* up
*/
void exti_configure_specific(enum ExtiLineSpecific line_mask,
enum ExtiConfig config_mask, ExtiCallback callback);
/**
* Resets lines for specific, non-gpio peripherals. The ExtiLineSpecific enum
* can be used as a mask to configure multiple lines at the same time.
*/
void exti_reset_specific(enum ExtiLineSpecific line_mask);
/**
* Resets all lines. The exti peripheral is returned to its reset configuration
*/

View File

@ -11,8 +11,6 @@
//--includes--------------------------------------------------------------------
#include "reg.h"
#include "stdint.h"
@ -21,7 +19,7 @@
#define EXTI_BASE_ADDRESS 0x40010400
union EXTI_IMR {
struct __attribute__((packed)) {
struct {
uint32_t MR0:1;
uint32_t MR1:1;
uint32_t MR2:1;
@ -46,29 +44,8 @@ union EXTI_IMR {
uint32_t word;
};
#define EXTI_IMR_MR0 reg_def( 0, 1)
#define EXTI_IMR_MR1 reg_def( 1, 1)
#define EXTI_IMR_MR2 reg_def( 2, 1)
#define EXTI_IMR_MR3 reg_def( 3, 1)
#define EXTI_IMR_MR4 reg_def( 4, 1)
#define EXTI_IMR_MR5 reg_def( 5, 1)
#define EXTI_IMR_MR6 reg_def( 6, 1)
#define EXTI_IMR_MR7 reg_def( 7, 1)
#define EXTI_IMR_MR8 reg_def( 8, 1)
#define EXTI_IMR_MR9 reg_def( 9, 1)
#define EXTI_IMR_MR10 reg_def(10, 1)
#define EXTI_IMR_MR11 reg_def(11, 1)
#define EXTI_IMR_MR12 reg_def(12, 1)
#define EXTI_IMR_MR13 reg_def(13, 1)
#define EXTI_IMR_MR14 reg_def(14, 1)
#define EXTI_IMR_MR15 reg_def(15, 1)
#define EXTI_IMR_MR16 reg_def(16, 1)
#define EXTI_IMR_MR17 reg_def(17, 1)
#define EXTI_IMR_MR18 reg_def(18, 1)
#define EXTI_IMR_reserved1 reg_def(19, 13)
union EXTI_EMR {
struct __attribute__((packed)) {
struct {
uint32_t MR0:1;
uint32_t MR1:1;
uint32_t MR2:1;
@ -93,29 +70,8 @@ union EXTI_EMR {
uint32_t word;
};
#define EXTI_EMR_MR0 reg_def( 0, 1)
#define EXTI_EMR_MR1 reg_def( 1, 1)
#define EXTI_EMR_MR2 reg_def( 2, 1)
#define EXTI_EMR_MR3 reg_def( 3, 1)
#define EXTI_EMR_MR4 reg_def( 4, 1)
#define EXTI_EMR_MR5 reg_def( 5, 1)
#define EXTI_EMR_MR6 reg_def( 6, 1)
#define EXTI_EMR_MR7 reg_def( 7, 1)
#define EXTI_EMR_MR8 reg_def( 8, 1)
#define EXTI_EMR_MR9 reg_def( 9, 1)
#define EXTI_EMR_MR10 reg_def(10, 1)
#define EXTI_EMR_MR11 reg_def(11, 1)
#define EXTI_EMR_MR12 reg_def(12, 1)
#define EXTI_EMR_MR13 reg_def(13, 1)
#define EXTI_EMR_MR14 reg_def(14, 1)
#define EXTI_EMR_MR15 reg_def(15, 1)
#define EXTI_EMR_MR16 reg_def(16, 1)
#define EXTI_EMR_MR17 reg_def(17, 1)
#define EXTI_EMR_MR18 reg_def(18, 1)
#define EXTI_EMR_reserved1 reg_def(19, 13)
union EXTI_RTSR {
struct __attribute__((packed)) {
struct {
uint32_t TR0:1;
uint32_t TR1:1;
uint32_t TR2:1;
@ -140,29 +96,8 @@ union EXTI_RTSR {
uint32_t word;
};
#define EXTI_RTSR_TR0 reg_def( 0, 1)
#define EXTI_RTSR_TR1 reg_def( 1, 1)
#define EXTI_RTSR_TR2 reg_def( 2, 1)
#define EXTI_RTSR_TR3 reg_def( 3, 1)
#define EXTI_RTSR_TR4 reg_def( 4, 1)
#define EXTI_RTSR_TR5 reg_def( 5, 1)
#define EXTI_RTSR_TR6 reg_def( 6, 1)
#define EXTI_RTSR_TR7 reg_def( 7, 1)
#define EXTI_RTSR_TR8 reg_def( 8, 1)
#define EXTI_RTSR_TR9 reg_def( 9, 1)
#define EXTI_RTSR_TR10 reg_def(10, 1)
#define EXTI_RTSR_TR11 reg_def(11, 1)
#define EXTI_RTSR_TR12 reg_def(12, 1)
#define EXTI_RTSR_TR13 reg_def(13, 1)
#define EXTI_RTSR_TR14 reg_def(14, 1)
#define EXTI_RTSR_TR15 reg_def(15, 1)
#define EXTI_RTSR_TR16 reg_def(16, 1)
#define EXTI_RTSR_TR17 reg_def(17, 1)
#define EXTI_RTSR_TR18 reg_def(18, 1)
#define EXTI_RTSR_reserved1 reg_def(19, 13)
union EXTI_FTSR {
struct __attribute__((packed)) {
struct {
uint32_t TR0:1;
uint32_t TR1:1;
uint32_t TR2:1;
@ -187,29 +122,8 @@ union EXTI_FTSR {
uint32_t word;
};
#define EXTI_FTSR_TR0 reg_def( 0, 1)
#define EXTI_FTSR_TR1 reg_def( 1, 1)
#define EXTI_FTSR_TR2 reg_def( 2, 1)
#define EXTI_FTSR_TR3 reg_def( 3, 1)
#define EXTI_FTSR_TR4 reg_def( 4, 1)
#define EXTI_FTSR_TR5 reg_def( 5, 1)
#define EXTI_FTSR_TR6 reg_def( 6, 1)
#define EXTI_FTSR_TR7 reg_def( 7, 1)
#define EXTI_FTSR_TR8 reg_def( 8, 1)
#define EXTI_FTSR_TR9 reg_def( 9, 1)
#define EXTI_FTSR_TR10 reg_def(10, 1)
#define EXTI_FTSR_TR11 reg_def(11, 1)
#define EXTI_FTSR_TR12 reg_def(12, 1)
#define EXTI_FTSR_TR13 reg_def(13, 1)
#define EXTI_FTSR_TR14 reg_def(14, 1)
#define EXTI_FTSR_TR15 reg_def(15, 1)
#define EXTI_FTSR_TR16 reg_def(16, 1)
#define EXTI_FTSR_TR17 reg_def(17, 1)
#define EXTI_FTSR_TR18 reg_def(18, 1)
#define EXTI_FTSR_reserved1 reg_def(19, 13)
union EXTI_SWIER {
struct __attribute__((packed)) {
struct {
uint32_t SWIER0:1;
uint32_t SWIER1:1;
uint32_t SWIER2:1;
@ -234,29 +148,8 @@ union EXTI_SWIER {
uint32_t word;
};
#define EXTI_SWIER_SWIER0 reg_def( 0, 1)
#define EXTI_SWIER_SWIER1 reg_def( 1, 1)
#define EXTI_SWIER_SWIER2 reg_def( 2, 1)
#define EXTI_SWIER_SWIER3 reg_def( 3, 1)
#define EXTI_SWIER_SWIER4 reg_def( 4, 1)
#define EXTI_SWIER_SWIER5 reg_def( 5, 1)
#define EXTI_SWIER_SWIER6 reg_def( 6, 1)
#define EXTI_SWIER_SWIER7 reg_def( 7, 1)
#define EXTI_SWIER_SWIER8 reg_def( 8, 1)
#define EXTI_SWIER_SWIER9 reg_def( 9, 1)
#define EXTI_SWIER_SWIER10 reg_def(10, 1)
#define EXTI_SWIER_SWIER11 reg_def(11, 1)
#define EXTI_SWIER_SWIER12 reg_def(12, 1)
#define EXTI_SWIER_SWIER13 reg_def(13, 1)
#define EXTI_SWIER_SWIER14 reg_def(14, 1)
#define EXTI_SWIER_SWIER15 reg_def(15, 1)
#define EXTI_SWIER_SWIER16 reg_def(16, 1)
#define EXTI_SWIER_SWIER17 reg_def(17, 1)
#define EXTI_SWIER_SWIER18 reg_def(18, 1)
#define EXTI_SWIER_reserved1 reg_def(19, 13)
union EXTI_PR {
struct __attribute__((packed)) {
struct {
uint32_t PR0:1;
uint32_t PR1:1;
uint32_t PR2:1;
@ -281,28 +174,7 @@ union EXTI_PR {
uint32_t word;
};
#define EXTI_PR_PR0 reg_def( 0, 1)
#define EXTI_PR_PR1 reg_def( 1, 1)
#define EXTI_PR_PR2 reg_def( 2, 1)
#define EXTI_PR_PR3 reg_def( 3, 1)
#define EXTI_PR_PR4 reg_def( 4, 1)
#define EXTI_PR_PR5 reg_def( 5, 1)
#define EXTI_PR_PR6 reg_def( 6, 1)
#define EXTI_PR_PR7 reg_def( 7, 1)
#define EXTI_PR_PR8 reg_def( 8, 1)
#define EXTI_PR_PR9 reg_def( 9, 1)
#define EXTI_PR_PR10 reg_def(10, 1)
#define EXTI_PR_PR11 reg_def(11, 1)
#define EXTI_PR_PR12 reg_def(12, 1)
#define EXTI_PR_PR13 reg_def(13, 1)
#define EXTI_PR_PR14 reg_def(14, 1)
#define EXTI_PR_PR15 reg_def(15, 1)
#define EXTI_PR_PR16 reg_def(16, 1)
#define EXTI_PR_PR17 reg_def(17, 1)
#define EXTI_PR_PR18 reg_def(18, 1)
#define EXTI_PR_reserved1 reg_def(19, 13)
struct __attribute__((packed)) EXTI {
struct EXTI {
union EXTI_IMR IMR;
union EXTI_EMR EMR;
union EXTI_RTSR RTSR;

View File

@ -34,15 +34,13 @@ void flash_configure(enum FlashPreset preset)
//apply new configuration
switch (preset) {
case FLASH_PRESET_LOW_CLOCK_SPEED:
reg_set(regs->ACR, FLASH_ACR_HLFCYA); //half cycle for power saving
regs->ACR.HLFCYA = 1; //half cycle for power saving
break;
case FLASH_PRESET_MEDIUM_CLOCK_SPEED:
reg_reset(regs->ACR, FLASH_ACR_LATENCY);
reg_write(regs->ACR, FLASH_ACR_LATENCY, 0x1);
regs->ACR.LATENCY = 0x1;
break;
case FLASH_PRESET_HIGH_CLOCK_SPEED:
reg_reset(regs->ACR, FLASH_ACR_LATENCY);
reg_write(regs->ACR, FLASH_ACR_LATENCY, 0x2);
regs->ACR.LATENCY = 0x2;
break;
default:
break;

View File

@ -11,8 +11,6 @@
//--includes--------------------------------------------------------------------
#include "reg.h"
#include "stdint.h"
@ -21,7 +19,7 @@
#define FLASH_BASE_ADDRESS 0x40022000
union FLASH_ACR {
struct __attribute__((packed)) {
struct {
uint32_t LATENCY:3;
uint32_t HLFCYA:1;
uint32_t PRFTBE:1;
@ -31,62 +29,56 @@ union FLASH_ACR {
uint32_t word;
};
#define FLASH_ACR_LATENCY reg_def(0, 3)
#define FLASH_ACR_HLFCYA reg_def(3, 1)
#define FLASH_ACR_PRFTBE reg_def(4, 1)
#define FLASH_ACR_PRFTBS reg_def(5, 1)
#define FLASH_ACR_reserved1 reg_def(6, 26)
union FLASH_KEYR {
struct __attribute__((packed)) {
struct {
uint32_t reserved1; //TODO
};
uint32_t word;
};
union FLASH_OPTKEYR {
struct __attribute__((packed)) {
struct {
uint32_t reserved1; //TODO
};
uint32_t word;
};
union FLASH_SR {
struct __attribute__((packed)) {
struct {
uint32_t reserved1; //TODO
};
uint32_t word;
};
union FLASH_CR {
struct __attribute__((packed)) {
struct {
uint32_t reserved1; //TODO
};
uint32_t word;
};
union FLASH_AR {
struct __attribute__((packed)) {
struct {
uint32_t reserved1; //TODO
};
uint32_t word;
};
union FLASH_OBR {
struct __attribute__((packed)) {
struct {
uint32_t reserved1; //TODO
};
uint32_t word;
};
union FLASH_WRPR {
struct __attribute__((packed)) {
struct {
uint32_t reserved1; //TODO
};
uint32_t word;
};
struct __attribute__((packed)) FLASH {
struct FLASH {
union FLASH_ACR ACR;
union FLASH_KEYR KEYR;
union FLASH_OPTKEYR OPTKEYR;

View File

@ -19,7 +19,7 @@
#define GPIO_BASE_ADDRESS 0x40010800
union GPIO_CRL {
struct __attribute__((packed)) {
struct {
uint32_t MODE0:2;
uint32_t CNF0:2;
uint32_t MODE1:2;
@ -41,7 +41,7 @@ union GPIO_CRL {
};
union GPIO_CRH {
struct __attribute__((packed)) {
struct {
uint32_t MODE8:2;
uint32_t CNF8:2;
uint32_t MODE9:2;
@ -63,7 +63,7 @@ union GPIO_CRH {
};
union GPIO_IDR {
struct __attribute__((packed)) {
struct {
uint32_t IDR0:1;
uint32_t IDR1:1;
uint32_t IDR2:1;
@ -86,7 +86,7 @@ union GPIO_IDR {
};
union GPIO_ODR {
struct __attribute__((packed)) {
struct {
uint32_t ODR0:1;
uint32_t ODR1:1;
uint32_t ODR2:1;
@ -109,7 +109,7 @@ union GPIO_ODR {
};
union GPIO_BSRR {
struct __attribute__((packed)) {
struct {
uint32_t BS0:1;
uint32_t BS1:1;
uint32_t BS2:1;
@ -147,7 +147,7 @@ union GPIO_BSRR {
};
union GPIO_BRR {
struct __attribute__((packed)) {
struct {
uint32_t BR0:1;
uint32_t BR1:1;
uint32_t BR2:1;
@ -170,7 +170,7 @@ union GPIO_BRR {
};
union GPIO_LCKK {
struct __attribute__((packed)) {
struct {
uint32_t LCK0:1;
uint32_t LCK1:1;
uint32_t LCK2:1;
@ -193,7 +193,7 @@ union GPIO_LCKK {
uint32_t word;
};
struct __attribute__((packed)) GPIO_PORT {
struct GPIO_PORT {
union GPIO_CRL CRL;
union GPIO_CRH CRH;
union GPIO_IDR IDR;
@ -204,7 +204,7 @@ struct __attribute__((packed)) GPIO_PORT {
uint32_t reserved1[249];
};
struct __attribute__((packed)) GPIO {
struct GPIO {
struct GPIO_PORT PORTS[7];
};

View File

@ -19,7 +19,7 @@
#define NVIC1_BASE_ADDRESS 0xE000E100
#define NVIC2_BASE_ADDRESS 0xE000EF00
struct __attribute__((packed)) NVIC1 {
struct NVIC1 {
uint32_t ISERX[3];
uint32_t ICERX[3];
uint32_t ISPRX[3];
@ -28,7 +28,7 @@ struct __attribute__((packed)) NVIC1 {
uint32_t IPRX[20];
};
struct __attribute__((packed)) NVIC2 {
struct NVIC2 {
uint32_t INTID;
};

61
drv/pwr.c Normal file
View File

@ -0,0 +1,61 @@
/** @file pwr.c
* Module handling the power management's control
*
* The module provides functions to enter the different sleep states, control
* and filter wakeup events (WKUP and RTC) and configure power voltage
* detection
*/
//--includes--------------------------------------------------------------------
#include "pwr.h"
#include "pwr_regs.h"
#include "scb.h"
#include "rcc.h"
//--local definitions-----------------------------------------------------------
//--local variables-------------------------------------------------------------
static volatile struct PWR* regs = (struct PWR*)PWR_BASE_ADDRESS;
//--public functions------------------------------------------------------------
void pwr_sleep(void)
{
scb_configure_deepsleep(false);
__asm("wfi");
}
void pwr_stop(enum PwrWakeupSpeed speed)
{
rcc_enable(RCC_AHB_NONE, RCC_APB1_PWR, RCC_APB2_NONE);
scb_configure_deepsleep(true);
regs->CR.PDDS = 0;
regs->CR.LPDS = speed;
__asm("wfi");
rcc_configure(RCC_PRESET_SPEED);
}
void pwr_standby(void)
{
rcc_enable(RCC_AHB_NONE, RCC_APB1_PWR, RCC_APB2_NONE);
scb_configure_deepsleep(true);
regs->CR.PDDS = 1;
__asm("wfi");
rcc_configure(RCC_PRESET_SPEED);
}
void pwr_configure_bkp_write(bool enable)
{
rcc_enable(RCC_AHB_NONE, RCC_APB1_PWR, RCC_APB2_NONE);
regs->CR.DBP = enable;
}
//--local functions-------------------------------------------------------------
//--ISRs------------------------------------------------------------------------

51
drv/pwr.h Normal file
View File

@ -0,0 +1,51 @@
/** @file pwr.h
* Module handling the power management's control
*
* The module provides functions to enter the different sleep states, control
* and filter wakeup events (WKUP and RTC) and configure power voltage
* detection
*/
#ifndef _PWR_H_
#define _PWR_H_
//--includes--------------------------------------------------------------------
//--type definitions------------------------------------------------------------
enum PwrWakeupSpeed {
PWR_WAKEUP_SPEED_FAST, //faster wakeup, higher consumption in stop mode
PWR_WAKEUP_SPEED_SLOW, //slower wakeup, lower consumption in stop mode
};
enum PwrPvdThreshold {
PWR_PVD_THRESHOLD_2_2V,
PWR_PVD_THRESHOLD_2_3V,
PWR_PVD_THRESHOLD_2_4V,
PWR_PVD_THRESHOLD_2_5V,
PWR_PVD_THRESHOLD_2_6V,
PWR_PVD_THRESHOLD_2_7V,
PWR_PVD_THRESHOLD_2_8V,
PWR_PVD_THRESHOLD_2_9V,
};
typedef void (*PwrPvdCallback)(void);
//--functions-------------------------------------------------------------------
void pwr_sleep(void);
void pwr_stop(enum PwrWakeupSpeed speed);
void pwr_standby(void);
bool pwr_wakeup_event(void);
bool pwr_standby_exit(void);
void pwr_configure_bkp_write(bool enable);
void pwr_configure_wakeup_pin(bool enable);
void pwr_configure_pvd(enum PwrPvdThreshold treshold);
#endif //_PWR_H_

56
drv/pwr_regs.h Normal file
View File

@ -0,0 +1,56 @@
/** @file pwr_regs.h
* Module defining Power control (PWR) registers.
*
* Mainly made to be used by the pwr module. It is recommanded to go through
* the functions provided by that module instead of directly using the registers
* defined here.
*/
#ifndef _PWR_REGS_H_
#define _PWR_REGS_H_
//--includes--------------------------------------------------------------------
#include "stdint.h"
//--type definitions------------------------------------------------------------
#define PWR_BASE_ADDRESS 0x40007000
union PWR_CR {
struct {
uint32_t LPDS:1;
uint32_t PDDS:1;
uint32_t CWUF:1;
uint32_t CSBF:1;
uint32_t PVDE:1;
uint32_t PLS:3;
uint32_t DBP:1;
uint32_t reserved1:23;
};
uint32_t word;
};
union PWR_CSR {
struct {
uint32_t WUF:1;
uint32_t SBF:1;
uint32_t PVDO:1;
uint32_t reserved1:5;
uint32_t EWUP:1;
uint32_t reserved2:23;
};
uint32_t word;
};
struct PWR {
union PWR_CR CR;
union PWR_CSR CSR;
};
//--functions-------------------------------------------------------------------
#endif //_PWR_REGS_H_

View File

@ -60,6 +60,16 @@ void rcc_configure(enum RccPreset preset)
regs->APB2ENR = apb2_enr;
}
void rcc_configure_lsi(bool enable)
{
regs->CSR.LSION = enable;
//ensure LSI is enabled
if (enable) {
while (regs->CSR.LSIRDY != 0x1) {}
}
}
void rcc_enable(enum RccAhb ahb_mask, enum RccApb1 apb1_mask,
enum RccApb2 apb2_mask)
{
@ -113,26 +123,26 @@ void rcc_get_clocks(struct RccClocks* clocks)
static void apply_default_preset(void)
{
//ensures HSI is enabled
reg_set(regs->CR, RCC_CR_HSION);
regs->CR.HSION = 1;
while (regs->CR.HSIRDY != 0x1);
//set HSI as main clock source and disable prescalers
regs->CFGR.word &= ~0x077fff3;
//disable all options
reg_reset(regs->CR, RCC_CR_HSITRIM);
reg_write(regs->CR, RCC_CR_HSITRIM, 0x10);
reg_reset(regs->CR, RCC_CR_HSEON);
reg_reset(regs->CR, RCC_CR_HSEBYP);
reg_reset(regs->CR, RCC_CR_CCSON);
reg_reset(regs->CR, RCC_CR_PLLON);
regs->CR.HSITRIM = 0;
regs->CR.HSITRIM = 0x10;
regs->CR.HSEON = 0;
regs->CR.HSEBYP = 0;
regs->CR.CCSON = 0;
regs->CR.PLLON = 0;
//disable all interrupts
reg_reset(regs->CIR, RCC_CIR_LSIRDYIE);
reg_reset(regs->CIR, RCC_CIR_LSERDYIE);
reg_reset(regs->CIR, RCC_CIR_HSIRDYIE);
reg_reset(regs->CIR, RCC_CIR_HSERDYIE);
reg_reset(regs->CIR, RCC_CIR_PLLRDYIE);
regs->CIR.LSIRDYIE = 0;
regs->CIR.LSERDYIE = 0;
regs->CIR.HSIRDYIE = 0;
regs->CIR.HSERDYIE = 0;
regs->CIR.PLLRDYIE = 0;
//reconfigure flash
flash_configure(FLASH_PRESET_LOW_CLOCK_SPEED);
@ -149,35 +159,35 @@ static void apply_speed_preset(void)
apply_default_preset();
//try enabling HSE, fallback to HSI if HSE fails
reg_set(regs->CR, RCC_CR_HSEON);
regs->CR.HSEON = 1;
for (uint32_t i=0; i<1000; ++i) {
__asm__("nop");
}
if (regs->CR.HSERDY == 0x1) {
reg_set(regs->CFGR, RCC_CFGR_PLLSCR);
regs->CFGR.PLLSCR = 1;
} else {
reg_reset(regs->CR, RCC_CR_HSEON);
regs->CR.HSEON = 0;
}
//configure PLL, fallback to HSI if PLL fails
reg_write(regs->CFGR, RCC_CFGR_PLLMUL, 0x7); //PLL x9
reg_set(regs->CR, RCC_CR_PLLON);
regs->CFGR.PLLMUL = 0x7; //PLL x9
regs->CR.PLLON = 1;
for (uint32_t i=0; i<1000; ++i) {
__asm__("nop");
}
if (regs->CR.PLLRDY != 0x1) {
reg_reset(regs->CR, RCC_CR_PLLON);
regs->CR.PLLON = 0;
return; //clock low enough, no need for prescalers
}
//configure prescalers
reg_write(regs->CFGR, RCC_CFGR_PPRE1, 0x4); // /2
reg_write(regs->CFGR, RCC_CFGR_ADCPRE, 0x2); // /6
regs->CFGR.PPRE1 = 0x4; // /2
regs->CFGR.ADCPRE = 0x2; // /6
//reconfigure flash
flash_configure(FLASH_PRESET_HIGH_CLOCK_SPEED);
//switch to PLL output
reg_write(regs->CFGR, RCC_CFGR_SW, 0x2);
regs->CFGR.SW = 0x2;
}

View File

@ -95,6 +95,13 @@ enum RccApb2 {
RCC_APB2_TIM11 = (0x1 << 21),
};
enum RccRtcClockSrc {
RCC_RTC_CLOCK_SRC_NONE = 0x0,
RCC_RTC_CLOCK_SRC_LSE = 0x1,
RCC_RTC_CLOCK_SRC_LSI = 0x2,
RCC_RTC_CLOCK_SRC_HSE = 0x3,
};
struct RccClocks {
uint32_t ahb_freq;
uint32_t apb1_freq;
@ -112,6 +119,12 @@ struct RccClocks {
*/
void rcc_configure(enum RccPreset preset);
/**
* Configures the Low Speed Internal (LSI) oscillator for low power
* applications.
*/
void rcc_configure_lsi(bool enable);
/**
* Enables peripherals on the different buses. The enums values can used as
* masks to enable multiple peripherals at the same time. Invalid values will be

View File

@ -11,8 +11,6 @@
//--includes--------------------------------------------------------------------
#include "reg.h"
#include "stdint.h"
@ -21,7 +19,7 @@
#define RCC_BASE_ADDRESS 0x40021000
union RCC_CR {
struct __attribute__((packed)) {
struct {
uint32_t HSION:1;
uint32_t HSIRDY:1;
uint32_t reserved1:1;
@ -39,22 +37,8 @@ union RCC_CR {
uint32_t word;
};
#define RCC_CR_HSION reg_def( 0, 1)
#define RCC_CR_HSIRDY reg_def( 1, 1)
#define RCC_CR_reserved1 reg_def( 2, 1)
#define RCC_CR_HSITRIM reg_def( 3, 5)
#define RCC_CR_HSICAL reg_def( 8, 8)
#define RCC_CR_HSEON reg_def(16, 1)
#define RCC_CR_HSERDY reg_def(17, 1)
#define RCC_CR_HSEBYP reg_def(18, 1)
#define RCC_CR_CCSON reg_def(19, 1)
#define RCC_CR_reserved2 reg_def(20, 4)
#define RCC_CR_PLLON reg_def(24, 1)
#define RCC_CR_PLLRDY reg_def(25, 1)
#define RCC_CR_reserved3 reg_def(26, 6)
union RCC_CFGR {
struct __attribute__((packed)) {
struct {
uint32_t SW:2;
uint32_t SWS:2;
uint32_t HPRE:4;
@ -72,22 +56,8 @@ union RCC_CFGR {
uint32_t word;
};
#define RCC_CFGR_SW reg_def( 0, 2)
#define RCC_CFGR_SWS reg_def( 2, 2)
#define RCC_CFGR_HPRE reg_def( 4, 4)
#define RCC_CFGR_PPRE1 reg_def( 8, 3)
#define RCC_CFGR_PPRE2 reg_def(11, 3)
#define RCC_CFGR_ADCPRE reg_def(14, 2)
#define RCC_CFGR_PLLSCR reg_def(16, 1)
#define RCC_CFGR_PLLXTPRE reg_def(17, 1)
#define RCC_CFGR_PLLMUL reg_def(18, 4)
#define RCC_CFGR_USBPRE reg_def(22, 1)
#define RCC_CFGR_reserved1 reg_def(23, 1)
#define RCC_CFGR_MCO reg_def(24, 3)
#define RCC_CFGR_reserved2 reg_def(27, 5)
union RCC_CIR {
struct __attribute__((packed)) {
struct {
uint32_t LSIRDYF:1;
uint32_t LSERDYF:1;
uint32_t HSIRDYF:1;
@ -113,30 +83,8 @@ union RCC_CIR {
uint32_t word;
};
#define RCC_CIR_LSIRDYF reg_def( 0, 1)
#define RCC_CIR_LSERDYF reg_def( 1, 1)
#define RCC_CIR_HSIRDYF reg_def( 2, 1)
#define RCC_CIR_HSERDYF reg_def( 3, 1)
#define RCC_CIR_PLLRDYF reg_def( 4, 1)
#define RCC_CIR_reserved1 reg_def( 5, 2)
#define RCC_CIR_CSSF reg_def( 7, 1)
#define RCC_CIR_LSIRDYIE reg_def( 8, 1)
#define RCC_CIR_LSERDYIE reg_def( 9, 1)
#define RCC_CIR_HSIRDYIE reg_def(10, 1)
#define RCC_CIR_HSERDYIE reg_def(11, 1)
#define RCC_CIR_PLLRDYIE reg_def(12, 1)
#define RCC_CIR_RSE2 reg_def(13, 3)
#define RCC_CIR_LSIRDYC reg_def(16, 1)
#define RCC_CIR_LSERDYC reg_def(17, 1)
#define RCC_CIR_HSIRDYC reg_def(18, 1)
#define RCC_CIR_HSERDYC reg_def(19, 1)
#define RCC_CIR_PLLRDYC reg_def(20, 1)
#define RCC_CIR_reserved3 reg_def(21, 2)
#define RCC_CIR_CSSC reg_def(23, 1)
#define RCC_CIR_reserved4 reg_def(24, 8)
union RCC_APB2RSTR {
struct __attribute__((packed)) {
struct {
uint32_t AFIORST:1;
uint32_t reserved1:1;
uint32_t IOPARST:1;
@ -162,30 +110,8 @@ union RCC_APB2RSTR {
uint32_t word;
};
#define RCC_APB2RSTR_AFIORST reg_def( 0, 1)
#define RCC_APB2RSTR_reserved1 reg_def( 1, 1)
#define RCC_APB2RSTR_IOPARST reg_def( 2, 1)
#define RCC_APB2RSTR_IOPBRST reg_def( 3, 1)
#define RCC_APB2RSTR_IOPCRST reg_def( 4, 1)
#define RCC_APB2RSTR_IOPDRST reg_def( 5, 1)
#define RCC_APB2RSTR_IOPERST reg_def( 6, 1)
#define RCC_APB2RSTR_IOPFRST reg_def( 7, 1)
#define RCC_APB2RSTR_IOPGRST reg_def( 8, 1)
#define RCC_APB2RSTR_ADC1RST reg_def( 9, 1)
#define RCC_APB2RSTR_ACD2RST reg_def(10, 1)
#define RCC_APB2RSTR_TIM1RST reg_def(11, 1)
#define RCC_APB2RSTR_SPI1RST reg_def(12, 1)
#define RCC_APB2RSTR_TIM8RST reg_def(13, 1)
#define RCC_APB2RSTR_USART1RST reg_def(14, 1)
#define RCC_APB2RSTR_ADC3RST reg_def(15, 1)
#define RCC_APB2RSTR_reserved2 reg_def(16, 3)
#define RCC_APB2RSTR_TIM9RST reg_def(19, 1)
#define RCC_APB2RSTR_TIM10RST reg_def(20, 1)
#define RCC_APB2RSTR_TIM11RST reg_def(21, 1)
#define RCC_APB2RSTR_reserved3 reg_def(22, 10)
union RCC_APB1RSTR {
struct __attribute__((packed)) {
struct {
uint32_t TIM2RST:1;
uint32_t TIM3RST:1;
uint32_t TIM4RST:1;
@ -219,38 +145,8 @@ union RCC_APB1RSTR {
uint32_t word;
};
#define RCC_APB1RSTR_TIM2RST reg_def( 0, 1)
#define RCC_APB1RSTR_TIM3RST reg_def( 1, 1)
#define RCC_APB1RSTR_TIM4RST reg_def( 2, 1)
#define RCC_APB1RSTR_TIM5RST reg_def( 3, 1)
#define RCC_APB1RSTR_TIM6RST reg_def( 4, 1)
#define RCC_APB1RSTR_TIM7RST reg_def( 5, 1)
#define RCC_APB1RSTR_TIM12RST reg_def( 6, 1)
#define RCC_APB1RSTR_TIM13RST reg_def( 7, 1)
#define RCC_APB1RSTR_TIM14RST reg_def( 8, 1)
#define RCC_APB1RSTR_reserved1 reg_def( 9, 2)
#define RCC_APB1RSTR_WWDGRST reg_def(11, 1)
#define RCC_APB1RSTR_reserved2 reg_def(12, 2)
#define RCC_APB1RSTR_SPI2RST reg_def(14, 1)
#define RCC_APB1RSTR_SPI3RST reg_def(15, 1)
#define RCC_APB1RSTR_reserved3 reg_def(16, 1)
#define RCC_APB1RSTR_USART2RST reg_def(17, 1)
#define RCC_APB1RSTR_USART3RST reg_def(18, 1)
#define RCC_APB1RSTR_UART4RST reg_def(19, 1)
#define RCC_APB1RSTR_UART5RST reg_def(20, 1)
#define RCC_APB1RSTR_I2C12RST reg_def(21, 1)
#define RCC_APB1RSTR_I2C2RST reg_def(22, 1)
#define RCC_APB1RSTR_USB2RST reg_def(23, 1)
#define RCC_APB1RSTR_reserved4 reg_def(24, 1)
#define RCC_APB1RSTR_CANRST reg_def(25, 1)
#define RCC_APB1RSTR_reserved5 reg_def(26, 1)
#define RCC_APB1RSTR_BKPRST reg_def(27, 1)
#define RCC_APB1RSTR_PWRRST reg_def(28, 1)
#define RCC_APB1RSTR_DACRST reg_def(29, 1)
#define RCC_APB1RSTR_reserved6 reg_def(30, 2)
union RCC_AHBENR {
struct __attribute__((packed)) {
struct {
uint32_t DMA1EN:1;
uint32_t DMA2EN:1;
uint32_t SRAMEN:1;
@ -267,21 +163,8 @@ union RCC_AHBENR {
uint32_t word;
};
#define RCC_AHBENR_DMA1EN reg_def( 0, 1)
#define RCC_AHBENR_DMA2EN reg_def( 1, 1)
#define RCC_AHBENR_SRAMEN reg_def( 2, 1)
#define RCC_AHBENR_reserved1 reg_def( 3, 1)
#define RCC_AHBENR_FLITFEN reg_def( 4, 1)
#define RCC_AHBENR_reserved2 reg_def( 5, 1)
#define RCC_AHBENR_CRCEN reg_def( 6, 1)
#define RCC_AHBENR_reserved3 reg_def( 7, 1)
#define RCC_AHBENR_FSMCEN reg_def( 8, 1)
#define RCC_AHBENR_reserved4 reg_def( 9, 1)
#define RCC_AHBENR_SDIOEN reg_def(10, 1)
#define RCC_AHBENR_reserved5 reg_def(11, 21)
union RCC_APB2ENR {
struct __attribute__((packed)) {
struct {
uint32_t AFIOEN:1;
uint32_t reserved1:1;
uint32_t IOPAEN:1;
@ -307,30 +190,8 @@ union RCC_APB2ENR {
uint32_t word;
};
#define RCC_APB2ENR_AFIOEN reg_def( 0, 1)
#define RCC_APB2ENR_reserved1 reg_def( 1, 1)
#define RCC_APB2ENR_IOPAEN reg_def( 2, 1)
#define RCC_APB2ENR_IOPBEN reg_def( 3, 1)
#define RCC_APB2ENR_IOPCEN reg_def( 4, 1)
#define RCC_APB2ENR_IOPDEN reg_def( 5, 1)
#define RCC_APB2ENR_IOPEEN reg_def( 6, 1)
#define RCC_APB2ENR_IOPFEN reg_def( 7, 1)
#define RCC_APB2ENR_IOPGEN reg_def( 8, 1)
#define RCC_APB2ENR_ADC1EN reg_def( 9, 1)
#define RCC_APB2ENR_ACD2EN reg_def(10, 1)
#define RCC_APB2ENR_TIM1EN reg_def(11, 1)
#define RCC_APB2ENR_SPI1EN reg_def(12, 1)
#define RCC_APB2ENR_TIM8EN reg_def(13, 1)
#define RCC_APB2ENR_USART1EN reg_def(14, 1)
#define RCC_APB2ENR_ADC3EN reg_def(15, 1)
#define RCC_APB2ENR_reserved2 reg_def(16, 3)
#define RCC_APB2ENR_TIM9EN reg_def(19, 1)
#define RCC_APB2ENR_TIM10EN reg_def(20, 1)
#define RCC_APB2ENR_TIM11EN reg_def(21, 1)
#define RCC_APB2ENR_reserved3 reg_def(22, 10)
union RCC_APB1ENR {
struct __attribute__((packed)) {
struct {
uint32_t TIM2EN:1;
uint32_t TIM3EN:1;
uint32_t TIM4EN:1;
@ -364,63 +225,8 @@ union RCC_APB1ENR {
uint32_t word;
};
#define RCC_APB1ENR_TIM2EN reg_def( 0, 1)
#define RCC_APB1ENR_TIM3EN reg_def( 1, 1)
#define RCC_APB1ENR_TIM4EN reg_def( 2, 1)
#define RCC_APB1ENR_TIM5EN reg_def( 3, 1)
#define RCC_APB1ENR_TIM6EN reg_def( 4, 1)
#define RCC_APB1ENR_TIM7EN reg_def( 5, 1)
#define RCC_APB1ENR_TIM12EN reg_def( 6, 1)
#define RCC_APB1ENR_TIM13EN reg_def( 7, 1)
#define RCC_APB1ENR_TIM14EN reg_def( 8, 1)
#define RCC_APB1ENR_reserved1 reg_def( 9, 2)
#define RCC_APB1ENR_WWDGEN reg_def(11, 1)
#define RCC_APB1ENR_reserved reg_def(12, 2)
#define RCC_APB1ENR_SPI2EN reg_def(14, 1)
#define RCC_APB1ENR_SPI3EN reg_def(15, 1)
#define RCC_APB1ENR_reserved2 reg_def(16, 1)
#define RCC_APB1ENR_USART2EN reg_def(17, 1)
#define RCC_APB1ENR_USART3EN reg_def(18, 1)
#define RCC_APB1ENR_UART4EN reg_def(19, 1)
#define RCC_APB1ENR_UART5EN reg_def(20, 1)
#define RCC_APB1ENR_I2C12EN reg_def(21, 1)
#define RCC_APB1ENR_I2C2EN reg_def(22, 1)
#define RCC_APB1ENR_USB2EN reg_def(23, 1)
#define RCC_APB1ENR_reserved3 reg_def(24, 1)
#define RCC_APB1ENR_CANEN reg_def(25, 1)
#define RCC_APB1ENR_reserved4 reg_def(26, 1)
#define RCC_APB1ENR_BKPEN reg_def(27, 1)
#define RCC_APB1ENR_PWREN reg_def(28, 1)
#define RCC_APB1ENR_DACEN reg_def(29, 1)
#define RCC_APB1ENR_reserved5 reg_def(30, 2)
union RCC_BDCR {
struct __attribute__((packed)) {
uint32_t LSEON:1;
uint32_t LSERDY:1;
uint32_t LSEBYP:1;
uint32_t reserved1:5;
uint32_t RTCSEL:2;
uint32_t reserved2:5;
uint32_t RTCEN:1;
uint32_t BDRST:1;
uint32_t reserved3:15;
};
uint32_t word;
};
#define RCC_BDCR_LSEON reg_def( 0, 1)
#define RCC_BDCR_LSERDY reg_def( 1, 1)
#define RCC_BDCR_LSEBYP reg_def( 2, 1)
#define RCC_BDCR_reserved1 reg_def( 3, 5)
#define RCC_BDCR_RTCSEL reg_def( 8, 2)
#define RCC_BDCR_reserved2 reg_def(10, 5)
#define RCC_BDCR_RTCEN reg_def(15, 1)
#define RCC_BDCR_BDRST reg_def(16, 1)
#define RCC_BDCR_reserved3 reg_def(17, 15)
union RCC_CSR {
struct __attribute__((packed)) {
struct {
uint32_t LSION:1;
uint32_t LSIRDY:1;
uint32_t reserved1:22;
@ -436,19 +242,7 @@ union RCC_CSR {
uint32_t word;
};
#define RCC_CSR_LSION reg_def( 0, 1)
#define RCC_CSR_LSIRDY reg_def( 1, 1)
#define RCC_CSR_reserved1 reg_def( 2, 22)
#define RCC_CSR_RMVF reg_def(24, 1)
#define RCC_CSR_reserved2 reg_def(25, 1)
#define RCC_CSR_PINRSTF reg_def(26, 1)
#define RCC_CSR_PORRSTF reg_def(27, 1)
#define RCC_CSR_SFTRSTF reg_def(28, 1)
#define RCC_CSR_IWDGRSTF reg_def(29, 1)
#define RCC_CSR_WWDGRSTF reg_def(30, 1)
#define RCC_CSR_LPWRSTF reg_def(31, 1)
struct __attribute__((packed)) RCC {
struct RCC {
union RCC_CR CR;
union RCC_CFGR CFGR;
union RCC_CIR CIR;
@ -457,7 +251,7 @@ struct __attribute__((packed)) RCC {
union RCC_AHBENR AHBENR;
union RCC_APB2ENR APB2ENR;
union RCC_APB1ENR APB1ENR;
union RCC_BDCR BDCR;
uint32_t reserved1;
union RCC_CSR CSR;
};

View File

@ -1,15 +0,0 @@
#define reg_def(pos, size) pos, (((0x1 << size) - 1) << pos)
#define reg_set(reg, field) _reg_set(reg, field)
#define _reg_set(reg, pos, mask) do { reg.word |= mask; } while (false)
#define reg_reset(reg, field) _reg_reset(reg, field)
#define _reg_reset(reg, pos, mask) do { reg.word &= ~mask; } while (false)
#define reg_write(reg, field, value) _reg_write(reg, field, (value))
#define _reg_write(reg, pos, mask, value) \
do { \
reg.word |= value << pos; \
} while (false) \

64
drv/scb.c Normal file
View File

@ -0,0 +1,64 @@
/** @file scb.c
* Module handling the System Control Block
*
* The module provides functions to configure miscelaneous options of the cortex
* m3, including sleep behavior, event handler priorities, resets and fault
* handlers
*/
//--includes--------------------------------------------------------------------
#include "scb.h"
#include "scb_regs.h"
//--local definitions-----------------------------------------------------------
//--local variables-------------------------------------------------------------
static volatile struct SCB* regs = (struct SCB*)SCB_BASE_ADDRESS;
//--public functions------------------------------------------------------------
uint16_t scb_pending_exception(void)
{
return regs->ICSR.VECTPENDING;
}
uint16_t scb_active_exception(void)
{
return regs->ICSR.VECTACTIVE;
}
void scb_configure_vector_table(uint32_t offset)
{
//TODO check that last LSB is 0 (alignement restrictions)
regs->VTOR.TABLEOFF = offset & 0x1FFFFF;
}
void scb_reset_system(void)
{
regs->AIRCR.SYSRESETREQ = 1;
}
void scb_configure_deepsleep(bool enable)
{
regs->SCR.SLEEPDEEP = enable;
}
void scb_configure_div0_fault(bool enable)
{
regs->CCR.DIV_0_TRP = enable;
}
void scb_configure_unalign_fault(bool enable)
{
regs->CCR.UNALIGN_TRP = enable;
}
//--local functions-------------------------------------------------------------
//--ISRs------------------------------------------------------------------------

32
drv/scb.h Normal file
View File

@ -0,0 +1,32 @@
/** @file scb.h
* Module handling the System Control Block
*
* The module provides functions to configure miscelaneous options of the cortex
* m3, including sleep behavior, event handler priorities, resets and fault
* handlers
*/
#ifndef _SCB_H_
#define _SCB_H_
//--includes--------------------------------------------------------------------
#include "stdint.h"
//--type definitions------------------------------------------------------------
//--functions-------------------------------------------------------------------
uint16_t scb_pending_exception(void);
uint16_t scb_active_exception(void);
void scb_configure_vector_table(uint32_t offset);
void scb_reset_system(void);
void scb_configure_deepsleep(bool enable);
void scb_configure_div0_fault(bool enable);
void scb_configure_unalign_fault(bool enable);
#endif //_SCB_H_

192
drv/scb_regs.h Normal file
View File

@ -0,0 +1,192 @@
/** @file scb_regs.h
* Module defining System Control Block (SCB) registers.
*
* Mainly made to be used by the scb module. It is recommanded to go through
* the functions provided by that module instead of directly using the registers
* defined here.
*/
#ifndef _SCB_REGS_H_
#define _SCB_REGS_H_
//--includes--------------------------------------------------------------------
#include "stdint.h"
//--type definitions------------------------------------------------------------
#define SCB_BASE_ADDRESS 0xE000ED00
union SCB_CPUID {
struct {
uint32_t revision:4;
uint32_t part_no:12;
uint32_t constant:4;
uint32_t variant:4;
uint32_t implementer:8;
};
uint32_t word;
};
union SCB_ICSR {
struct {
uint32_t VECTACTIVE:9;
uint32_t reserved1:2;
uint32_t RETOBASE:1;
uint32_t VECTPENDING:10;
uint32_t ISRPENDING:1;
uint32_t reserved2:2;
uint32_t PENDSTCLR:1;
uint32_t PENDSTSET:1;
uint32_t PENDSVCRL:1;
uint32_t PENDSVSET:1;
uint32_t reserved3:2;
uint32_t NMIPENDSET:1;
};
uint32_t word;
};
union SCB_VTOR {
struct {
uint32_t reserved1:9;
uint32_t TABLEOFF:21;
uint32_t reserved2:2;
};
uint32_t word;
};
union SCB_AIRCR {
struct {
uint32_t VECTRESET:1;
uint32_t VECTCRLACTIVE:1;
uint32_t SYSRESETREQ:1;
uint32_t reserved1:5;
uint32_t PRIGROUP:3;
uint32_t reserved2:4;
uint32_t ENDIANESS:1;
uint32_t VECTKEY:16;
};
uint32_t word;
};
union SCB_SCR {
struct {
uint32_t reserved1:1;
uint32_t SLEEPONEXIT:1;
uint32_t SLEEPDEEP:1;
uint32_t reserved2:1;
uint32_t SEVONPEND:1;
uint32_t reserved3:27;
};
uint32_t word;
};
union SCB_CCR {
struct {
uint32_t NONBASETHRDEN:1;
uint32_t USERSETMPEND:1;
uint32_t reserved1:1;
uint32_t UNALIGN_TRP:1;
uint32_t DIV_0_TRP:1;
uint32_t reserved2:3;
uint32_t BFHFNIGN:1;
uint32_t STKALIGN:1;
uint32_t reserved3:22;
};
uint32_t word;
};
union SCB_SHPR1 {
struct {
uint32_t PRI4:8;
uint32_t PRI5:8;
uint32_t PRI6:8;
uint32_t reserved1:8;
};
uint32_t word;
};
union SCB_SHPR2 {
struct {
uint32_t reserved1:24;
uint32_t PRI11:8;
};
uint32_t word;
};
union SCB_SHPR3 {
struct {
uint32_t reserved1:16;
uint32_t PRI14:8;
uint32_t PRI15:8;
};
uint32_t word;
};
union SCB_SHCRS {
struct {
uint32_t MEMFAULTACT:1;
uint32_t BUSFAULTACT:1;
uint32_t reserved1:1;
uint32_t USGFAULTACT:1;
uint32_t reserved2:3;
uint32_t SVCALLACT:1;
uint32_t MONITORACT:1;
uint32_t reserved3:1;
uint32_t PENDSVACT:1;
uint32_t SYSTICKACT:1;
uint32_t USGFAULTPENDED:1;
uint32_t MEMFAULTPENDED:1;
uint32_t BUSFAULTPENDED:1;
uint32_t SVCALLPENDED:1;
uint32_t MEMFAULTENA:1;
uint32_t BUSFAULTENA:1;
uint32_t USGFAULTENA:1;
uint32_t reserved4:13;
};
uint32_t word;
};
union SCB_CFSR {
struct {
uint32_t MMFSR:8;
uint32_t BFSR:8;
uint32_t UFSR:16;
};
uint32_t word;
};
union SCB_HFSR {
struct {
uint32_t reserved1:1;
uint32_t VECTTBL:1;
uint32_t reserved2:28;
uint32_t FORCED:1;
uint32_t DEBUG_VT:1;
};
uint32_t word;
};
struct SCB {
union SCB_CPUID CPUID;
union SCB_ICSR ICSR;
union SCB_VTOR VTOR;
union SCB_AIRCR AIRCR;
union SCB_SCR SCR;
union SCB_CCR CCR;
union SCB_SHPR1 SHPR1;
union SCB_SHPR2 SHPR2;
union SCB_SHPR3 SHPR3;
union SCB_SHCRS SHCRS;
union SCB_CFSR CFSR;
union SCB_HFSR HFSR;
uint32_t MMAR;
uint32_t BFAR;
};
//--functions-------------------------------------------------------------------
#endif //_PWR_REGS_H_

90
drv/stk.c Normal file
View File

@ -0,0 +1,90 @@
/** @file stk.c
* Module handling the system timer (systick or STK for short)
*
* The module provides functions to configure and use the system timer embedded
* in the cortex m core
*/
//--includes--------------------------------------------------------------------
#include "stk.h"
#include "stk_regs.h"
#include "rcc.h"
//--local definitions-----------------------------------------------------------
static volatile struct STK* regs = (struct STK*)STK_BASE_ADDRESS;
//--local variables-------------------------------------------------------------
static StkCallback callback;
static uint32_t prescaler;
//--public functions------------------------------------------------------------
uint32_t stk_configure(uint32_t period_us, StkCallback cb)
{
stk_reset();
struct RccClocks clocks;
rcc_get_clocks(&clocks);
uint32_t prescaler = (clocks.ahb_freq / 1000000 / 8);
uint32_t reload = period_us * prescaler;
if (reload < 1) {
//period is too small, try using the non-prescaled clock
prescaler *= 8;
reload = period_us * prescaler;
if (reload < 1) {
//period is still too small
return 1;
}
regs->CTRL.CLKSOURCE = 1;
}
regs->LOAD.RELOAD = reload;
regs->CTRL.TICKINT = 1;
callback = cb;
return 0;
}
void stk_reset(void)
{
regs->CTRL.ENABLE = 0;
regs->CTRL.TICKINT = 0;
regs->CTRL.CLKSOURCE = 0;
regs->CTRL.COUNTFLAG = 0;
regs->LOAD.RELOAD = 0;
regs->VAL.CURRENT = 0;
}
void stk_start(void)
{
regs->CTRL.ENABLE = 1;
}
void stk_stop(void)
{
regs->CTRL.ENABLE = 0;
}
uint32_t stk_read_us(void)
{
return (regs->VAL.word & 0x00FFFFFF) / prescaler;
}
//--local functions-------------------------------------------------------------
void hdr_sys_tick(void)
{
//clearing the pending bit in SCB_ICSR isn't needed, though I don't know why
callback();
}

55
drv/stk.h Normal file
View File

@ -0,0 +1,55 @@
/** @file stk.h
* Module handling the system timer (systick or STK for short)
*
* The module provides functions to configure and use the system timer embedded
* in the cortex m core
*/
#ifndef _STK_H_
#define _STK_H_
//--includes--------------------------------------------------------------------
#include <stdint.h>
//--type definitions------------------------------------------------------------
typedef void (*StkCallback)(void);
//--functions-------------------------------------------------------------------
/**
* Configures the system timer to run at the specified period in µs and call the
* given callback when said period is reached. Due to the limited configuration
* options, 1.8s is the maximum period when running in speed preset (see rcc
* module). The maximum period can be substantially increased by reducing the
* core clock
*/
uint32_t stk_configure(uint32_t period_us, StkCallback cb);
/**
* Resets the system timer configuration, restoring the default configuration
* and stopping it
*/
void stk_reset(void);
/**
* Starts the system timer. The timer will run until stopped
*/
void stk_start(void);
/**
* Stops the system timer
*/
void stk_stop(void);
/**
* Read the current value of the timer's counter in µs
*/
uint32_t stk_read_us(void);
#endif //_STK_H_

70
drv/stk_regs.h Normal file
View File

@ -0,0 +1,70 @@
/** @file stk_regs.h
* Module defining systick (STK) registers.
*
* Mainly made to be used by the stk module. It is recommanded to go through
* the functions provided by that module instead of directly using the registers
* defined here.
*/
#ifndef _STK_REGS_H_
#define _STK_REGS_H_
//--includes--------------------------------------------------------------------
#include <stdint.h>
//--type definitions------------------------------------------------------------
#define STK_BASE_ADDRESS 0xE000E010
union STK_CTRL {
struct {
uint32_t ENABLE:1;
uint32_t TICKINT:1;
uint32_t CLKSOURCE:1;
uint32_t reserved1:13;
uint32_t COUNTFLAG:1;
uint32_t reserved2:15;
};
uint32_t word;
};
union STK_LOAD {
struct {
uint32_t RELOAD:24;
uint32_t reserved1:8;
};
uint32_t word;
};
union STK_VAL {
struct {
uint32_t CURRENT:24;
uint32_t reserved1:8;
};
uint32_t word;
};
union STK_CALIB {
struct {
uint32_t TENMS:24;
uint32_t reserved1:6;
uint32_t SKEW:1;
uint32_t NOREF:1;
};
uint32_t word;
};
struct STK {
union STK_CTRL CTRL;
union STK_LOAD LOAD;
union STK_VAL VAL;
union STK_CALIB CALIB;
};
//--functions-------------------------------------------------------------------
#endif //_STK_REGS_H_

View File

@ -9,7 +9,6 @@
#include "usart.h"
#include "usart_regs.h"
#include "reg.h"
#include "rcc.h"
#include "dma.h"
@ -132,7 +131,7 @@ uint32_t usart_write_byte(enum UsartPeriph periph, uint8_t byte)
//only write data if the tx register it empty, give up otherwise
if (usarts[periph]->SR.TXE) {
reg_write(usarts[periph]->DR, USART_DR_DR, byte);
usarts[periph]->DR.DR = byte;
return 0;
} else {
return 1;
@ -145,7 +144,7 @@ const struct DmaParam* usart_configure_rx_dma(enum UsartPeriph periph)
return nullptr;
}
reg_set(usarts[periph]->CR3, USART_CR3_DMAR);
usarts[periph]->CR3.DMAR = 1;
return &usarts_rx_param[periph];
}
@ -155,7 +154,7 @@ const struct DmaParam* usart_configure_tx_dma(enum UsartPeriph periph)
return nullptr;
}
reg_set(usarts[periph]->CR3, USART_CR3_DMAT);
usarts[periph]->CR3.DMAT = 1;
return &usarts_tx_param[periph];
}
@ -176,19 +175,19 @@ static void configure_usart(volatile struct USART* regs,
case USART_CONFIG_8E1:
case USART_CONFIG_7E2:
case USART_CONFIG_8E2:
reg_set(regs->CR1, USART_CR1_PCE);
reg_reset(regs->CR1, USART_CR1_PS);
regs->CR1.PCE = 1;
regs->CR1.PS = 0;
break;
case USART_CONFIG_7O1:
case USART_CONFIG_7O2:
case USART_CONFIG_8O1:
case USART_CONFIG_8O2:
reg_set(regs->CR1, USART_CR1_PCE);
reg_set(regs->CR1, USART_CR1_PS);
regs->CR1.PCE = 1;
regs->CR1.PS = 1;
break;
case USART_CONFIG_8N1:
case USART_CONFIG_8N2:
reg_reset(regs->CR1, USART_CR1_PCE);
regs->CR1.PCE = 0;
break;
default:
break;
@ -203,13 +202,13 @@ static void configure_usart(volatile struct USART* regs,
case USART_CONFIG_7O2:
case USART_CONFIG_8N1:
case USART_CONFIG_8N2:
reg_reset(regs->CR1, USART_CR1_M);
regs->CR1.M = 0;
break;
case USART_CONFIG_8E2:
case USART_CONFIG_8E1:
case USART_CONFIG_8O1:
case USART_CONFIG_8O2:
reg_set(regs->CR1, USART_CR1_M);
regs->CR1.M = 1;
break;
default:
break;
@ -223,24 +222,23 @@ static void configure_usart(volatile struct USART* regs,
case USART_CONFIG_8N1:
case USART_CONFIG_8E1:
case USART_CONFIG_8O1:
reg_reset(regs->CR2, USART_CR2_STOP);
regs->CR2.STOP = 0;
break;
case USART_CONFIG_7E2:
case USART_CONFIG_7O2:
case USART_CONFIG_8N2:
case USART_CONFIG_8E2:
case USART_CONFIG_8O2:
reg_reset(regs->CR2, USART_CR2_STOP);
reg_write(regs->CR2, USART_CR2_STOP, 2);
regs->CR2.STOP = 2;
break;
default:
break;
}
//enable Rx/Tx
reg_set(regs->CR1, USART_CR1_TE);
reg_set(regs->CR1, USART_CR1_RE);
reg_set(regs->CR1, USART_CR1_UE);
regs->CR1.TE = 1;
regs->CR1.RE = 1;
regs->CR1.UE = 1;
}
/**
@ -255,9 +253,7 @@ static void configure_baudrate(volatile struct USART* regs, uint32_t clock,
uint32_t factor = clock / baudrate;
volatile uint32_t divider = factor - (mantissa * 16);
reg_reset(regs->BRR, USART_BRR_DIV_Mantissa);
reg_write(regs->BRR, USART_BRR_DIV_Mantissa, mantissa & 0xFFF);
reg_reset(regs->BRR, USART_BRR_DIV_Fraction);
reg_write(regs->BRR, USART_BRR_DIV_Fraction, divider & 0xF);
regs->BRR.DIV_Mantissa = mantissa & 0xFFF;
regs->BRR.DIV_Fraction = divider & 0xF;
}

View File

@ -11,8 +11,6 @@
//--includes--------------------------------------------------------------------
#include "reg.h"
#include "stdint.h"
@ -23,7 +21,7 @@
#define USART3_BASE_ADDRESS 0x40004800
union USART_SR {
struct __attribute__((packed)) {
struct {
uint32_t PE:1;
uint32_t FE:1;
uint32_t NE:1;
@ -39,31 +37,16 @@ union USART_SR {
uint32_t word;
};
#define USART_SR_PE reg_def( 0, 1)
#define USART_SR_FE reg_def( 1, 1)
#define USART_SR_NE reg_def( 2, 1)
#define USART_SR_ORE reg_def( 3, 1)
#define USART_SR_IDLE reg_def( 4, 1)
#define USART_SR_RXNE reg_def( 5, 1)
#define USART_SR_TC reg_def( 6, 1)
#define USART_SR_TXE reg_def( 7, 1)
#define USART_SR_LBD reg_def( 8, 1)
#define USART_SR_CTS reg_def( 9, 1)
#define USART_SR_reserved1 reg_def(10, 22)
union USART_DR {
struct __attribute__((packed)) {
struct {
uint32_t DR:9;
uint32_t reserved1:23;
};
uint32_t word;
};
#define USART_DR_DR reg_def( 0, 9)
#define USART_DR_reserved1 reg_def( 9, 23)
union USART_BRR {
struct __attribute__((packed)) {
struct {
uint32_t DIV_Fraction:4;
uint32_t DIV_Mantissa:12;
uint32_t reserved1:16;
@ -71,12 +54,8 @@ union USART_BRR {
uint32_t word;
};
#define USART_BRR_DIV_Fraction reg_def( 0, 4)
#define USART_BRR_DIV_Mantissa reg_def( 4, 12)
#define USART_BRR_reserved1 reg_def(16, 16)
union USART_CR1 {
struct __attribute__((packed)) {
struct {
uint32_t SBK:1;
uint32_t RWU:1;
uint32_t RE:1;
@ -96,24 +75,8 @@ union USART_CR1 {
uint32_t word;
};
#define USART_CR1_SBK reg_def( 0, 1)
#define USART_CR1_RWU reg_def( 1, 1)
#define USART_CR1_RE reg_def( 2, 1)
#define USART_CR1_TE reg_def( 3, 1)
#define USART_CR1_IDLEIE reg_def( 4, 1)
#define USART_CR1_RXNEIE reg_def( 5, 1)
#define USART_CR1_TCIE reg_def( 6, 1)
#define USART_CR1_TXEIE reg_def( 7, 1)
#define USART_CR1_PEI reg_def( 8, 1)
#define USART_CR1_PS reg_def( 9, 1)
#define USART_CR1_PCE reg_def(10, 1)
#define USART_CR1_WAKE reg_def(11, 1)
#define USART_CR1_M reg_def(12, 1)
#define USART_CR1_UE reg_def(13, 1)
#define USART_CR1_reserved1 reg_def(14, 18)
union USART_CR2 {
struct __attribute__((packed)) {
struct {
uint32_t ADD:4;
uint32_t reserved1:1;
uint32_t LBDL:1;
@ -130,21 +93,8 @@ union USART_CR2 {
uint32_t word;
};
#define USART_CR2_ADD reg_def( 0, 4)
#define USART_CR2_reserved1 reg_def( 4, 1)
#define USART_CR2_LBDL reg_def( 5, 1)
#define USART_CR2_LBDIE reg_def( 6, 1)
#define USART_CR2_reserved2 reg_def( 7, 1)
#define USART_CR2_LBCL reg_def( 8, 1)
#define USART_CR2_CPHA reg_def( 9, 1)
#define USART_CR2_CPOL reg_def(10, 1)
#define USART_CR2_CLKEN reg_def(11, 1)
#define USART_CR2_STOP reg_def(12, 2)
#define USART_CR2_LINEN reg_def(14, 1)
#define USART_CR2_reserved3 reg_def(15, 17)
union USART_CR3 {
struct __attribute__((packed)) {
struct {
uint32_t EIE:1;
uint32_t IREN:1;
uint32_t IRLP:1;
@ -161,21 +111,8 @@ union USART_CR3 {
uint32_t word;
};
#define USART_CR3_EIE reg_def( 0, 1)
#define USART_CR3_IREN reg_def( 1, 1)
#define USART_CR3_IRLP reg_def( 2, 1)
#define USART_CR3_HDSEL reg_def( 3, 1)
#define USART_CR3_NACK reg_def( 4, 1)
#define USART_CR3_SCEN reg_def( 5, 1)
#define USART_CR3_DMAR reg_def( 6, 1)
#define USART_CR3_DMAT reg_def( 7, 1)
#define USART_CR3_RTSE reg_def( 8, 1)
#define USART_CR3_CTSE reg_def( 9, 1)
#define USART_CR3_CTSIE reg_def(10, 1)
#define USART_CR3_reserved3 reg_def(11, 21)
union USART_GTPR {
struct __attribute__((packed)) {
struct {
uint32_t PSC:8;
uint32_t GT:8;
uint32_t reserved1:16;
@ -183,10 +120,6 @@ union USART_GTPR {
uint32_t word;
};
#define USART_GTPR_PSC reg_def( 0, 8)
#define USART_GTPR_GT reg_def( 8, 8)
#define USART_GTPR_reserved1 reg_def(16, 16)
struct USART {
union USART_SR SR;
union USART_DR DR;

25
openocd.cfg Normal file
View File

@ -0,0 +1,25 @@
# using a STM32f103CB wich has 128kB of flash instead of the more common 64KB
set CHIPNAME stm32f103CB
set FLASH_SIZE 0x20000
# load default configurations
source [find interface/stlink.cfg]
source [find target/stm32f1x.cfg]
# override examine-end event
$CHIPNAME.cpu configure -event examine-end {
# write DBGMCU_CR, disable all peripherals (timers, dmas, watchdogs while
# halted by debug. Trace is not affected
mmw 0xE0042004 0x7E3FFF07 0
}
reset_config srst_only srst_nogate connect_assert_srst
# inits debugging, from that point, commands can be used
init
# resets the target and halt it immediately afterward. Stops debug from being
# inacessible due to low-power states
reset halt

23
srv/delay.c Normal file
View File

@ -0,0 +1,23 @@
/** @file delay.c
* Module handling delays definitions and operations
*
* The module provides an API to delay the code execution with the most
* accuraccy possible, putting the system in sleep whenever possible. The RTC is
* required when using delays superior to a 1.5s. Accuraccy is only garenteed up
* to the unit being used (to the millisecond when delaying in ms, to the second
* when delaying in seconds)
*/
//--includes--------------------------------------------------------------------
#include "delay.h"
//--local definitions-----------------------------------------------------------
//--local variables-------------------------------------------------------------
//--public functions------------------------------------------------------------
//--local functions-------------------------------------------------------------

23
srv/delay.h Normal file
View File

@ -0,0 +1,23 @@
/** @file delay.h
* Module handling delays definitions and operations
*
* The module provides an API to delay the code execution with the most
* accuraccy possible, putting the system in sleep whenever possible. The RTC is
* required when using delays superior to a 1.5s. Accuraccy is only garenteed up
* to the unit being used (to the millisecond when delaying in ms, to the second
* when delaying in seconds)
*/
#ifndef _DELAY_H_
#define _DELAY_H_
//--includes--------------------------------------------------------------------
//--type definitions------------------------------------------------------------
//--functions-------------------------------------------------------------------
//--internal_functions----------------------------------------------------------
#endif //_DELAY_H_

175
srv/task.c Normal file
View File

@ -0,0 +1,175 @@
/** @file task.h
* Module handling the task creation and management
*
* The module provides an API to create, run and manage lightweight, stack-less
* threads (tasks). This system is based on protothreads,
* see https://dunkels.com/adam/pt/index.html
*
* Task can be viewed as a lightweight, somewhat restricted, cooperative OS.
* Tasks are runned on every events. Since the RTC is enabled by the scheduler,
* every task should be run at least once per second. If at least one task is
* currently paused, the systick is enabled and all tasks are updated every
* millisecond
*
* State machine should mainly yield (see TASK_YIELD) while time sensitive
* applications should pause (see TASK_PAUSE) instead. This configuration allows
* state machines to be updated every time something changes in the system while
* allowing the cpu to enter low power mode when possible. When time sensitive
* applications are paused, they cause the systick to start which stops the cpu
* from entering low power but making sure that the task is polled quickly
* enough. Tasks requiring longer delay and less sensitive to timings can sleep
* (see TASK_SLEEP) instead, which relies on the RTC rather than the systick
*/
//--includes--------------------------------------------------------------------
#include "task.h"
#include "error.h"
#include "../drv/stk.h"
#include "../drv/pwr.h"
#include "../drv/rcc.h"
#include "../drv/bkp.h"
#include "../drv/exti.h"
//--local definitions-----------------------------------------------------------
#define MAX_TASK_NB 10
static bool execute_task(struct Task* restrict task, uint8_t triggers);
static void callback_stk(void);
static void callback_rtc(void);
//--local variables-------------------------------------------------------------
static struct Task task_list[MAX_TASK_NB];
static uint8_t task_nb;
static volatile bool stk_irq;
static volatile bool rtc_irq;
static volatile uint32_t timestamp;
//--public functions------------------------------------------------------------
void task_start_scheduler(void)
{
stk_configure(1000, callback_stk);
rcc_configure_lsi(true);
pwr_configure_bkp_write(true);
bkp_reset();
bkp_configure_rtc(1000, BKP_RTC_CLOCK_SRC_LSI, BKP_RTC_IRQ_NONE, nullptr);
pwr_configure_bkp_write(false);
exti_configure(EXTI_LINE_RTC, EXTI_CONFIG_RISING_EDGE, callback_rtc);
while (true) {
uint8_t triggers = stk_irq << 0 | rtc_irq << 1;
stk_irq = false;
rtc_irq = false;
bool stk_needed = false;
for (uint8_t i = 0; i < task_nb; ++i) {
stk_needed |= execute_task(&task_list[i], triggers);
}
if (stk_needed) {
stk_start();
pwr_sleep();
} else {
pwr_configure_bkp_write(true);
bkp_set_rtc_alam(1);
pwr_configure_bkp_write(false);
stk_stop();
pwr_sleep();
}
}
}
uint32_t task_current_time(void)
{
return timestamp;
}
void task_start(TaskFunction function)
{
for (uint8_t i = 0; i < MAX_TASK_NB; ++i) {
if (task_list[i].function == nullptr) {
task_list[i].function = function;
task_list[i].state.timestamp = 0;
task_list[i].state.count = 0;
++task_nb;
return;
}
}
error_trigger("task list is full");
}
void task_stop(TaskFunction function)
{
for (uint8_t i = 0; i < task_nb; ++i) {
if (task_list[i].function == function) {
task_list[i].state.count = _TASK_COUNT_CLEANUP & 0x1F;
task_list[i].function(&task_list[i].state, timestamp);
task_list[i].function = nullptr;
return;
}
}
error_trigger("task does not exist");
}
bool task_is_running(TaskFunction function)
{
for (uint8_t i = 0; i < task_nb; ++i) {
if (task_list[i].function == function) {
return true;
}
}
return false;
}
//--local functions-------------------------------------------------------------
static bool execute_task(struct Task* restrict task, uint8_t triggers)
{
if (task->function != nullptr) {
if (task->state.trigger == TASK_TRIGGER_ANY) {
task->function(&task->state, timestamp);
} else {
if ((task->state.trigger & triggers) != 0) {
if (task->state.timestamp <= timestamp) {
task->state.timestamp = 0;
}
if ((task->state.timestamp == 0) ||
task->state.timeout_mode) {
task->function(&task->state,
timestamp);
}
}
}
return (task->state.trigger & TASK_TRIGGER_STK) != 0;
}
return false;
}
static void callback_stk(void)
{
stk_irq = true;
++timestamp;
}
static void callback_rtc(void)
{
rtc_irq = true;
timestamp = bkp_read_rtc() * 1000;
}

287
srv/task.h Normal file
View File

@ -0,0 +1,287 @@
/** @file task.h
* Module handling the task creation and management
*
* The module provides an API to create, run and manage lightweight, stack-less
* threads (tasks). This system is based on protothreads,
* see https://dunkels.com/adam/pt/index.html
*
* Task can be viewed as a lightweight, somewhat restricted, cooperative OS.
* Tasks are runned on every events. Since the RTC is enabled by the scheduler,
* every task should be run at least once per second. If at least one task is
* currently paused, the systick is enabled and all tasks are updated every
* millisecond
*
* State machine should mainly yield (see TASK_YIELD) while time sensitive
* applications should pause (see TASK_PAUSE) instead. This configuration allows
* state machines to be updated every time something changes in the system while
* allowing the cpu to enter low power mode when possible. When time sensitive
* applications are paused, they cause the systick to start which stops the cpu
* from entering low power but making sure that the task is polled quickly
* enough. Tasks requiring longer delay and less sensitive to timings can sleep
* (see TASK_SLEEP) instead, which relies on the RTC rather than the systick
*/
#ifndef _task_h_
#define _task_h_
//--includes--------------------------------------------------------------------
#include <stdint.h>
#include <stdbool.h>
//--type definitions------------------------------------------------------------
/**
* Available triggers for a task
*/
enum TaskTrigger {
TASK_TRIGGER_ANY,
TASK_TRIGGER_STK,
TASK_TRIGGER_RTC,
TASK_TRIGGER_BOTH,
};
/**
* State of a task at any given time. Every single task is described by such a
* struct
*/
struct TaskState {
uint32_t timestamp; //timestamp at wich to wakeup the task, if any
uint8_t count:5; //task counter: active step of task
enum TaskTrigger trigger:2; //triggers on wich to execute the task
uint8_t timeout_mode:1; //whether the timestamp is a timeout or a delay
};
/**
* Function prototype of tasks
*/
typedef void(*TaskFunction)(struct TaskState*, uint32_t);
/**
* Full definition of a task. Contains the function supporting the task as well
* as the state of said task
*/
struct Task {
TaskFunction function;
struct TaskState state;
};
//--functions-------------------------------------------------------------------
/**
* Task declaration macro, to be used to declare and define a task instead of a
* regular function declaration/defintion
*/
#define TASK(fct_name) void fct_name(struct TaskState* restrict __task_state, \
uint32_t __task_time)
/**
* Task entry macro, must be present at the begin of every task. Setup code to
* be run indepently of the task state may be put before that (static variables,
* init code, ...)
*/
#define TASK_ENTRY \
_TASK_COUNT_INIT; \
(void) __task_time; \
switch (__task_state->count) {
/**
* Task cleanup macro. Option, can be use right before TASK_EXIT. This step
* will be executed before exiting the task when task_stop() is called. As the
* name suggest, this is mainly usefull to implement cleanup code and allow for
* gracefull shutdowns
*/
#define TASK_CLEANUP \
case (_TASK_COUNT_CLEANUP): \
/* fall through */
/**
* Tasks exit macro, must be present at the end of every task. Any code written
* after that will never be executed
*/
#define TASK_EXIT \
} \
__task_state->count = _TASK_COUNT_EXIT & 0x1F; \
return;
/**
* Returns whether the task was timed-out or not. This macro can be used after
* TASK_PAUSE_UNTIL and TASK_SLEEP_UNTIL to know if the task resumed because of
* the condition or because of the timeout. Does not correspond to anything
* when called after any other step
*/
#define TASK_TIMEOUT (__task_state->timeout == 0)
/**
* Give up the cpu, allowing the other tasks to run. The task will resume at the
* next event. Between events, the cpu can enter various power saving states
* depending on the other tasks running
*/
#define TASK_YIELD() _TASK_YIELD(_TASK_COUNT_INCR)
/**
* Suspend the task for the specified amount of milliseconds. The systick will
* remain active while the task is suspended to provide milliseconds counting,
* limiting the ability of the cpu to save power
*/
#define TASK_PAUSE(delay_ms) _TASK_PAUSE(delay_ms, _TASK_COUNT_INCR)
/**
* Suspend the task for the specified amount of seconds. The RTC will be used to
* provide seconds counting. If no other tasks requires it, the systick is
* disabled to save more power
*/
#define TASK_SLEEP(delay_s) _TASK_SLEEP(delay_s, _TASK_COUNT_INCR)
/**
* Execute TASK_YIELD until the provided condition is reached. The condition
* will be checked on every event
*/
#define TASK_YIELD_UNTIL(cond) _TASK_YIELD_UNTIL(cond, _TASK_COUNT_INCR)
/**
* Execute TASK_PAUSE until either the condition or the delay is reached.
* TASK_TIMEOUT can be used to know what cause the task to resume. The condition
* will be checked every millisecond
*/
#define TASK_PAUSE_UNTIL(cond, delay_ms) \
_TASK_PAUSE_UNTIL(cond, delay_ms, _TASK_COUNT_INCR)
/**
* Execute TASK_SLEEP until either the condition or the delay is reached.
* TASK_TIMEOUT can be used to know what cause the task to resume. The condition
* will be checked every seconds
*/
#define TASK_SLEEP_UNTIL(cond, delay_s) \
_TASK_SLEEP_UNTIL(cond, delay_s, _TASK_COUNT_INCR)
/**
* Execute the specified task, suspending the current one until the task exits
*/
#define TASK_EXECUTE(task) _TASK_EXECUTE(task, _TASK_COUNT_INCR)
/**
* Starts the task scheduler and run it until the system is shutdown. This
* function never returns.
*
* All tasks started using task_start() are run according to their current
* state (see TASK_* macros). Since this system is cooperative, the scheduler
* does not preempt the tasks when running. The RTC is automatically configured
* and started to provide events every seconds. The systick is automatically
* started and stop to provide events every milliseconds when needed
*/
void task_start_scheduler(void);
/**
* Returns the current system time. The epoc is undefined. The time is provided
* in milliseconds, though the millisecond precision is only available while the
* systick is running (at least one task paused)
*/
uint32_t task_current_time(void);
/**
* Starts the specified task. The task will only trully be runned after
* task_start_scheduler() is called.
* A task already started will be left as-is
*/
void task_start(TaskFunction task);
/**
* Stops the specified task. The task's cleanup state will be executed before
* it exits
*/
void task_stop(TaskFunction task);
/**
* Returns whether the specified task is currently running or not
*/
bool task_is_running(TaskFunction task);
//--internal_functions----------------------------------------------------------
#define _TASK_COUNT_INIT enum { TASK_COUNTER_BASE = __COUNTER__ }
#define _TASK_COUNT_INCR (uint8_t)(__COUNTER__ - TASK_COUNTER_BASE - 1)
#define _TASK_COUNT_EXIT (UINT8_MAX & 0x3F)
#define _TASK_COUNT_CLEANUP (UINT8_MAX - 1)
#define _TASK_YIELD(count_val) do { \
__task_state->count = count_val; \
__task_state->trigger = TASK_TRIGGER_ANY; \
return; \
case (count_val): \
/* fall through */ \
} while (0)
#define _TASK_PAUSE(delay_ms, count_val) do { \
__task_state->count = count_val; \
__task_state->timestamp = __task_time + delay_ms; \
__task_state->trigger = TASK_TRIGGER_STK; \
return; \
case (count_val): \
/* fall through */ \
} while (0)
#define _TASK_SLEEP(delay_s, count_val) do { \
__task_state->count = count_val; \
__task_state->timestamp = __task_time + delay_s * 1000; \
__task_state->trigger = TASK_TRIGGER_RTC; \
return; \
case (count_val): \
/* fall through */ \
} while (0)
#define _TASK_YIELD_UNTIL(cond, count_val) do { \
__task_state->count = count_val; \
__task_state->trigger = TASK_TRIGGER_ANY; \
case (count_val): \
if (!(cond)) { \
return; \
} \
/* fall through */ \
} while (0)
#define _TASK_PAUSE_UNTIL(cond, delay_ms, count_val) do { \
__task_state->count = count_val; \
__task_state->timestamp = __task_time + delay_ms; \
__task_state->trigger = TASK_TRIGGER_STK; \
__task_state->timeout_mode = true; \
case (count_val): \
if (!(cond) && __task_state->timestamp != 0) { \
return; \
} else { \
__task_state->timeout_mode = false; \
} \
/* fall through */ \
} while (0)
#define _TASK_SLEEP_UNTIL(cond, delay_s, count_val) do { \
__task_state->count = count_val; \
__task_state->timestamp = __taks_time + delay_s * 1000; \
__task_state->trigger = TASK_TRIGGER_RTC; \
__task_state->timeout_mode = true; \
case (count_val): \
if (!(cond) && __task_state->timestamp != 0) { \
return; \
} else { \
__task_state->timeout_mode = false; \
} \
/* fall through */ \
} while (0)
#define _TASK_EXECUTE(task, count_val) do { \
__task_state->count = count_val; \
__task_state->trigger = TASK_TRIGGER_ANY; \
task_start(Task task); \
return; \
case (count_val): \
if (task_is_running(task)) { \
return; \
} \
/* fall through */ \
} while (0)
#endif //_task_h_