Compare commits

...

36 Commits

Author SHA1 Message Date
6d95bce6df Merge pull request 'task' (#5) from task into dev
Reviewed-on: https://git.steins7.ovh/Steins7/stm32f1xx_HBL/pulls/5
2024-08-04 18:30:15 +00:00
ebc7ad4235 Fix compilation warning in task module 2024-08-04 20:18:45 +02:00
bc4bab4704 Fix include issue in afio module 2024-08-04 20:17:52 +02:00
a4ca0d30c3 Force the use of system's reset in openocd
Using the system's reset avoids the debug getting stuck when the chip
enters low power. Hopefully this works all the time
2024-08-04 20:14:34 +02:00
89c81b8c42 Integrate the RTC to the task module 2024-08-04 20:14:24 +02:00
24e412446d Implement bkp's rtc alarm configuration
Since the alarm must be set each time it is to be used, a separated
function is a better fit
2024-08-04 20:12:28 +02:00
7ab6622908 Rework exti module to use a simpler API
The "specific" lines configuration would not work due to index error in
the callback configuration. While fixing the error, simplifying the API
by moving the afio calls to the calling context seemed a cleaner way to
do things
2024-08-04 19:38:24 +02:00
ba9bc57a49 Add openocd configuration
The target's debug would sometime get stuck while in low-power, making
it difficult to resume communications, even after hardware resets. Some
peripherals were also kept running when halted. This config should fix
these issues
2024-08-04 15:52:24 +02:00
947df53ecb Add missing file documentation 2024-07-27 22:19:29 +02:00
80c027370b Document BKP module 2024-07-27 22:13:46 +02:00
b1d25561b4 Temporarily fix warning 2024-07-27 21:57:53 +02:00
507f1e6863 Move rtc control to new BKP module
RCC's BCDR register has been moved to the BKP module since it is part of
the backup circuit and thus also aboeys some restrictions access-wise
2024-07-27 20:11:51 +02:00
3e3d4d2bff Implement RTC module's basic functionnalities
FUnctions need a cleanup and some details need be ironned, like the
clock management since the whole backup domain must be reset to
configure them
2024-07-27 16:41:36 +02:00
b37eb1dd6e Add RTC configuration to RCC module 2024-07-27 14:17:58 +02:00
0b483c535b Ensure PWR is enabled before configuration 2024-07-27 14:15:55 +02:00
a02bcecaec Implement RTC module's registers 2024-07-16 22:21:05 +02:00
699569ec99 Add LSI configuration function to RCC 2024-07-16 21:50:01 +02:00
3e97d4fe7e Implement sleep modes 2024-07-14 19:17:20 +02:00
5c89df4324 Fix typo in PWR registers 2024-07-13 21:35:42 +02:00
1741d47546 Implement SCB module 2024-07-13 21:35:22 +02:00
97dad53621 Define SCB module's registers 2024-07-13 21:14:44 +02:00
9681755168 Define PWR module's registers 2024-07-13 13:19:17 +02:00
5e4d87474a Fix major reg bitfield issue
A while back, macros had to be put in place to avoid letting the
compiler directly use the bitfields. This was necessary because the
compiler used strb instruction which only write bytes. On the AHB bus,
byte writes are transformed into word writes by repeating the byte,
which caused mayhem in the registers. After a lot of research, turns out
the packed attribute stops the compiler from does optimal (word) writes
and isn't needed anyway. Removing them fixes the issue
2024-07-10 23:16:49 +02:00
d5c70a3a04 Document the task module 2024-07-10 21:54:23 +02:00
93b383be49 Add API to access task's system time 2024-07-09 22:07:35 +02:00
dd1756221d Fix typo in task macros 2024-07-09 21:46:15 +02:00
173e16eb2e Add back task features in a simplified way 2024-07-09 11:53:05 +02:00
b7951f2211 Simplify task module 2024-07-06 22:43:50 +02:00
7cb33f65a5 Create new delay module 2024-05-14 15:03:18 +02:00
c09d2cda67 Remove priority parameter from tasks
In the end, priorities are only usefull in preemptive systems. Here, it would
only garentee the execution order, which we don't care about most of the time
2024-05-14 14:53:51 +02:00
34fb4dac76 Make stk_read function usable
This function used to return the raw current value, but that exposes the
prescaling used internaly
2024-04-30 20:17:58 +02:00
432310a52d Implement task module
For now, most code is temporary to validate that the system can work as
envisionned. Optimisations and cleaning will be done shortly
2024-04-30 20:15:58 +02:00
7e69bfd89c Document systick module 2024-04-28 22:11:37 +02:00
ddd05da6eb Implement systick module 2024-04-28 22:04:10 +02:00
7ba9063d02 Define systick's registers 2024-04-28 19:43:37 +02:00
fb1c11132f Write first API macros 2024-04-28 19:14:28 +02:00
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_