diff --git a/drv/afio.h b/drv/afio.h index f1a06de..f32253a 100644 --- a/drv/afio.h +++ b/drv/afio.h @@ -9,10 +9,8 @@ //--includes-------------------------------------------------------------------- -#include "stdint.h" -#include "stdbool.h" - #include "exti.h" +#include "gpio.h" //--type definitions------------------------------------------------------------ diff --git a/drv/afio_regs.h b/drv/afio_regs.h index aa34561..fcf906e 100644 --- a/drv/afio_regs.h +++ b/drv/afio_regs.h @@ -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; diff --git a/drv/bkp.c b/drv/bkp.c new file mode 100644 index 0000000..69630b9 --- /dev/null +++ b/drv/bkp.c @@ -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); +} + diff --git a/drv/bkp.h b/drv/bkp.h new file mode 100644 index 0000000..28da3f8 --- /dev/null +++ b/drv/bkp.h @@ -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_ + diff --git a/drv/bkp_regs.h b/drv/bkp_regs.h new file mode 100644 index 0000000..8a3b6c7 --- /dev/null +++ b/drv/bkp_regs.h @@ -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_ + diff --git a/drv/dma.c b/drv/dma.c index 7d68b09..e33ab88 100644 --- a/drv/dma.c +++ b/drv/dma.c @@ -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]); } } diff --git a/drv/dma_regs.h b/drv/dma_regs.h index bfbb8f9..e343e6f 100644 --- a/drv/dma_regs.h +++ b/drv/dma_regs.h @@ -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]; diff --git a/drv/exti.c b/drv/exti.c index 686f37f..c1d56af 100644 --- a/drv/exti.c +++ b/drv/exti.c @@ -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](); } diff --git a/drv/exti.h b/drv/exti.h index 3349aca..dc8a337 100644 --- a/drv/exti.h +++ b/drv/exti.h @@ -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 */ diff --git a/drv/exti_regs.h b/drv/exti_regs.h index 74c0ddd..5b27582 100644 --- a/drv/exti_regs.h +++ b/drv/exti_regs.h @@ -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; diff --git a/drv/flash.c b/drv/flash.c index 3378d06..dfa69e2 100644 --- a/drv/flash.c +++ b/drv/flash.c @@ -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; diff --git a/drv/flash_regs.h b/drv/flash_regs.h index de1068a..aaa945d 100644 --- a/drv/flash_regs.h +++ b/drv/flash_regs.h @@ -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; diff --git a/drv/gpio_regs.h b/drv/gpio_regs.h index 5ab539b..222678d 100644 --- a/drv/gpio_regs.h +++ b/drv/gpio_regs.h @@ -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]; }; diff --git a/drv/nvic_regs.h b/drv/nvic_regs.h index 7d9d02f..bc12de7 100644 --- a/drv/nvic_regs.h +++ b/drv/nvic_regs.h @@ -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; }; diff --git a/drv/pwr.c b/drv/pwr.c new file mode 100644 index 0000000..19f17f7 --- /dev/null +++ b/drv/pwr.c @@ -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------------------------------------------------------------------------ + + diff --git a/drv/pwr.h b/drv/pwr.h new file mode 100644 index 0000000..f20ad9a --- /dev/null +++ b/drv/pwr.h @@ -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_ + diff --git a/drv/pwr_regs.h b/drv/pwr_regs.h new file mode 100644 index 0000000..c9da4cf --- /dev/null +++ b/drv/pwr_regs.h @@ -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_ + diff --git a/drv/rcc.c b/drv/rcc.c index 20dfcff..4369a79 100644 --- a/drv/rcc.c +++ b/drv/rcc.c @@ -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; } diff --git a/drv/rcc.h b/drv/rcc.h index 770b7a0..9d1e9d4 100644 --- a/drv/rcc.h +++ b/drv/rcc.h @@ -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 diff --git a/drv/rcc_regs.h b/drv/rcc_regs.h index 44f7eff..7e36f7a 100644 --- a/drv/rcc_regs.h +++ b/drv/rcc_regs.h @@ -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; }; diff --git a/drv/reg.h b/drv/reg.h deleted file mode 100644 index 5334e18..0000000 --- a/drv/reg.h +++ /dev/null @@ -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) \ - diff --git a/drv/scb.c b/drv/scb.c new file mode 100644 index 0000000..ba0fb96 --- /dev/null +++ b/drv/scb.c @@ -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------------------------------------------------------------------------ + diff --git a/drv/scb.h b/drv/scb.h new file mode 100644 index 0000000..c814cde --- /dev/null +++ b/drv/scb.h @@ -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_ + diff --git a/drv/scb_regs.h b/drv/scb_regs.h new file mode 100644 index 0000000..90622e4 --- /dev/null +++ b/drv/scb_regs.h @@ -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_ + diff --git a/drv/stk.c b/drv/stk.c new file mode 100644 index 0000000..3e9ce61 --- /dev/null +++ b/drv/stk.c @@ -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(); +} + diff --git a/drv/stk.h b/drv/stk.h new file mode 100644 index 0000000..9cdd685 --- /dev/null +++ b/drv/stk.h @@ -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 + + +//--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_ + diff --git a/drv/stk_regs.h b/drv/stk_regs.h new file mode 100644 index 0000000..fe5e0c6 --- /dev/null +++ b/drv/stk_regs.h @@ -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 + + +//--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_ + diff --git a/drv/usart.c b/drv/usart.c index 25167a2..36eaebb 100644 --- a/drv/usart.c +++ b/drv/usart.c @@ -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; } diff --git a/drv/usart_regs.h b/drv/usart_regs.h index 2c84cc3..54c86a9 100644 --- a/drv/usart_regs.h +++ b/drv/usart_regs.h @@ -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; diff --git a/openocd.cfg b/openocd.cfg new file mode 100644 index 0000000..06dd5e9 --- /dev/null +++ b/openocd.cfg @@ -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 + diff --git a/srv/delay.c b/srv/delay.c new file mode 100644 index 0000000..9ce5bf6 --- /dev/null +++ b/srv/delay.c @@ -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------------------------------------------------------------- + diff --git a/srv/delay.h b/srv/delay.h new file mode 100644 index 0000000..7b6d46d --- /dev/null +++ b/srv/delay.h @@ -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_ + diff --git a/srv/task.c b/srv/task.c new file mode 100644 index 0000000..047fca1 --- /dev/null +++ b/srv/task.c @@ -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; +} diff --git a/srv/task.h b/srv/task.h new file mode 100644 index 0000000..00e0d32 --- /dev/null +++ b/srv/task.h @@ -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 +#include + + +//--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_ +