Compare commits

...

5 Commits

Author SHA1 Message Date
Ea-r-th
e822b8d9ec Issue: cannot read core 2025-10-17 12:50:16 -07:00
Ea-r-th
04f79cc543 Finished UART refactor 2025-10-17 02:23:56 -07:00
Ea-r-th
d846897296 Finished timer refactor 2025-10-17 01:16:11 -07:00
Ea-r-th
6c8fa459f8 Finished ADC, updating timer code 2025-10-17 00:59:12 -07:00
Ea-r-th
af21480aff ADC sequence abstracted 2025-10-16 21:34:01 -07:00
32 changed files with 714 additions and 377 deletions

View File

@@ -10,8 +10,8 @@ set(CPU_PARAMETERS
-mcpu=cortex-m0 -mcpu=cortex-m0
-mthumb) -mthumb)
set(STARTUP_SCRIPT MX/L432KC/startup_stm32l432kcux.s) set(STARTUP_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/MX/L432KC/startup_stm32l432kcux.s)
set(MCU_LINKER_SCRIPT MX/L432KC/STM32L432KCUX_FLASH.ld) set(MCU_LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/MX/L432KC/STM32L432KCUX_FLASH.ld)
set(EXECUTABLE ${CMAKE_PROJECT_NAME}) set(EXECUTABLE ${CMAKE_PROJECT_NAME})
enable_language(C CXX ASM) enable_language(C CXX ASM)
@@ -73,6 +73,8 @@ target_compile_options(${EXECUTABLE} PRIVATE
-Wextra -Wextra
-Wpedantic -Wpedantic
-Wno-unused-parameter -Wno-unused-parameter
-Wno-switch
-Wno-implicit-fallthrough
$<$<COMPILE_LANGUAGE:CXX>: $<$<COMPILE_LANGUAGE:CXX>:
-Wno-volatile -Wno-volatile
-Wsuggest-override> -Wsuggest-override>
@@ -104,4 +106,4 @@ add_custom_command(TARGET ${EXECUTABLE} POST_BUILD
${EXECUTABLE}.hex ${EXECUTABLE}.hex
COMMAND ${CMAKE_OBJCOPY} -O binary $<TARGET_FILE:${EXECUTABLE}> COMMAND ${CMAKE_OBJCOPY} -O binary $<TARGET_FILE:${EXECUTABLE}>
${EXECUTABLE}.bin ${EXECUTABLE}.bin
) )

View File

@@ -70,17 +70,31 @@ bool SHAL_wait_for_condition_ms(Condition cond, uint32_t timeout_ms) {
return false; // timeout return false; // timeout
} }
void SHAL_set_bits(volatile uint32_t* reg, uint32_t size, uint32_t bits, uint32_t offset){ //Sets bits starting from offset as the LSB
static inline void SHAL_set_bits(volatile uint32_t* reg, uint32_t size, uint32_t bits, uint32_t offset){
uint32_t mask = (1 << (size)) - 1; uint32_t mask = (1 << (size)) - 1;
*reg &= ~(mask << offset); *reg &= ~(mask << offset);
*reg |= bits << offset; *reg |= bits << offset;
} }
void SHAL_apply_bitmask(volatile uint32_t* reg, uint32_t mask){ //Sets bits starting from offset as the LSB (for uint16_t)
static inline void SHAL_set_bits_16(volatile uint16_t* reg, uint32_t size, uint32_t bits, uint32_t offset){
uint16_t mask = (1 << (size)) - 1;
*reg &= ~(mask << offset);
*reg |= bits << offset;
}
static inline void SHAL_clear_bitmask(volatile uint32_t* reg, uint32_t mask){
*reg &= ~(mask); *reg &= ~(mask);
}
static inline void SHAL_apply_bitmask(volatile uint32_t* reg, uint32_t mask){
SHAL_clear_bitmask(reg,mask);
*reg |= mask; *reg |= mask;
} }
//--------------------------------------------------------- //---------------------------------------------------------

View File

@@ -11,6 +11,32 @@
#define SHAL_ADC1 SHAL_ADC(1) #define SHAL_ADC1 SHAL_ADC(1)
#define NUM_ADCS 1
#define NUM_ADC_CHANNELS 16
enum class SHAL_ADC_Channel : uint32_t {
CH0,
CH1,
CH2,
CH3,
CH4,
CH5,
CH6,
CH7,
CH8,
CH9,
CH10,
CH11,
CH12,
CH13,
CH14,
CH15,
CHTemp,
CHRef,
CHBat
};
enum class ADC_Key : uint8_t{ enum class ADC_Key : uint8_t{
S_ADC1 = 0, S_ADC1 = 0,
NUM_ADC = 1, NUM_ADC = 1,
@@ -28,18 +54,18 @@ static volatile ADC_TypeDef* ADC_TABLE[1] = { //Lookup table for ADCs
ADC1, ADC1,
}; };
SHAL_ADC_Common_Control_Reg getADCCommonControl() { static inline SHAL_ADC_Common_Control_Reg getADCCommonControl() {
return {&ADC1_COMMON->CCR ,ADC_CCR_VREFEN,ADC_CCR_TSEN,ADC_CCR_VBATEN}; return {&ADC1_COMMON->CCR ,ADC_CCR_VREFEN,ADC_CCR_TSEN,ADC_CCR_VBATEN};
} }
SHAL_ADC_RCC_Enable_Reg getADCRCCEnableRegister(ADC_Key key){ static inline SHAL_ADC_RCC_Enable_Reg getADCRCCEnableRegister(ADC_Key key){
SHAL_ADC_RCC_Enable_Reg res = {nullptr, RCC_AHB2ENR_ADCEN}; SHAL_ADC_RCC_Enable_Reg res = {nullptr, RCC_AHB2ENR_ADCEN};
res.reg = &(ADC_TABLE[static_cast<uint8_t>(key)]->ISR); res.reg = &(ADC_TABLE[static_cast<uint8_t>(key)]->ISR);
return res; return res;
} }
SHAL_ADC_Control_Reg getADCControlReg(ADC_Key key) { static inline SHAL_ADC_Control_Reg getADCControlReg(ADC_Key key) {
SHAL_ADC_Control_Reg res = {nullptr, ADC_CR_ADEN, ADC_CR_ADDIS, ADC_CR_ADCAL, ADC_CR_ADSTART}; SHAL_ADC_Control_Reg res = {nullptr, ADC_CR_ADEN, ADC_CR_ADDIS, ADC_CR_ADCAL, ADC_CR_ADSTART};
@@ -47,7 +73,7 @@ SHAL_ADC_Control_Reg getADCControlReg(ADC_Key key) {
return res; return res;
} }
SHAL_ADC_Config_Reg getADCConfigReg(ADC_Key key) { static inline SHAL_ADC_Config_Reg getADCConfigReg(ADC_Key key) {
SHAL_ADC_Config_Reg res = {nullptr, ADC_CFGR_CONT, ADC_CFGR_RES_Pos, ADC_CFGR_ALIGN_Pos}; SHAL_ADC_Config_Reg res = {nullptr, ADC_CFGR_CONT, ADC_CFGR_RES_Pos, ADC_CFGR_ALIGN_Pos};
@@ -55,21 +81,21 @@ SHAL_ADC_Config_Reg getADCConfigReg(ADC_Key key) {
return res; return res;
} }
SHAL_ADC_ISR getADCISR(ADC_Key key){ static inline SHAL_ADC_ISR_Reg getADCISRReg(ADC_Key key){
SHAL_ADC_ISR res = {nullptr, ADC_ISR_EOC}; SHAL_ADC_ISR_Reg res = {nullptr, ADC_ISR_EOC, ADC_ISR_EOS, ADC_ISR_ADRDY};
res.reg = &(ADC_TABLE[static_cast<uint8_t>(key)]->ISR); res.reg = &(ADC_TABLE[static_cast<uint8_t>(key)]->ISR);
return res; return res;
} }
SHAL_ADC_Data_Reg getADCDataReg(ADC_Key key){ static inline SHAL_ADC_Data_Reg getADCDataReg(ADC_Key key){
SHAL_ADC_Data_Reg res = {nullptr, 0xFFFF}; SHAL_ADC_Data_Reg res = {nullptr, 0xFFFF};
res.reg = &(ADC_TABLE[static_cast<uint8_t>(key)]->DR); res.reg = &(ADC_TABLE[static_cast<uint8_t>(key)]->DR);
return res; return res;
} }
SHAL_ADC_Clock_Reg getADCClockSelectRegister(ADC_Clock_Source clockSource) { static inline SHAL_ADC_Clock_Reg getADCClockSelectRegister(ADC_Clock_Source clockSource) {
SHAL_ADC_Clock_Reg res = {&RCC->CCIPR, RCC_CCIPR_ADCSEL_Msk, 1U << RCC_CCIPR_ADCSEL_Pos}; //Default to PLLSAI1 SHAL_ADC_Clock_Reg res = {&RCC->CCIPR, RCC_CCIPR_ADCSEL_Msk, 1U << RCC_CCIPR_ADCSEL_Pos}; //Default to PLLSAI1
switch(clockSource){ switch(clockSource){
@@ -85,11 +111,11 @@ SHAL_ADC_Clock_Reg getADCClockSelectRegister(ADC_Clock_Source clockSource) {
return res; return res;
} }
SHAL_ADC_Channel_Sampling_Time_Reg getADCChannelSamplingTimeRegister(ADC_Key key, SHAL_ADC_Channel channel){ static inline SHAL_ADC_Channel_Sampling_Time_Reg getADCChannelSamplingTimeRegister(ADC_Key key, SHAL_ADC_Channel channel){
volatile ADC_TypeDef* ADCReg = ADC_TABLE[static_cast<uint8_t>(key)]; volatile ADC_TypeDef* ADCReg = ADC_TABLE[static_cast<uint8_t>(key)];
volatile uint32_t* SMPReg = nullptr; volatile uint32_t* SMPReg = nullptr;
uint32_t pos = 0; uint32_t pos;
auto channelNum = static_cast<uint8_t>(channel); auto channelNum = static_cast<uint8_t>(channel);
@@ -104,6 +130,34 @@ SHAL_ADC_Channel_Sampling_Time_Reg getADCChannelSamplingTimeRegister(ADC_Key key
return {SMPReg, pos}; return {SMPReg, pos};
} }
static inline SHAL_ADC_Sequence_Amount_Reg getADCSequenceAmountRegister(ADC_Key key){
SHAL_ADC_Sequence_Amount_Reg res = {nullptr, ADC_SQR1_L_Pos};
res.reg = &(ADC_TABLE[static_cast<uint8_t>(key)]->SQR1);
return res;
}
static inline SHAL_ADC_Sequence_Reg getADCSequenceRegisters(ADC_Key key){
volatile ADC_TypeDef* adc_reg = ADC_TABLE[static_cast<uint8_t>(key)];
SHAL_ADC_Sequence_Reg res = {{&adc_reg->SQR1,
&adc_reg->SQR2,
&adc_reg->SQR3,
&adc_reg->SQR4,
nullptr,
nullptr},
{1UL << 0,
1UL << 6,
1UL << 12,
1UL << 18,
1UL << 24}
};
return res;
}
constexpr ADC_TypeDef* getADCRegister(ADC_Key key){ constexpr ADC_TypeDef* getADCRegister(ADC_Key key){
switch(key){ switch(key){
case ADC_Key::S_ADC1: case ADC_Key::S_ADC1:

View File

@@ -26,16 +26,16 @@ public:
/// Performs analog to digital conversion on a single channel, one time /// Performs analog to digital conversion on a single channel, one time
/// \param channel Channel to be converted /// \param channel Channel to be converted
/// \param time ADC_SampleTime - amount of clock cycles per conversion /// \param time SHAL_ADC_SampleTime - amount of clock cycles per conversion
/// \return resulting value /// \return resulting value
uint16_t singleConvertSingle(SHAL_ADC_Channel channel, ADC_SampleTime time = ADC_SampleTime::C239); uint16_t singleConvertSingle(SHAL_ADC_Channel channel, SHAL_ADC_SampleTime time = SHAL_ADC_SampleTime::C8);
/// Performs analog to digital conversion on multiple channels, one time /// Performs analog to digital conversion on multiple channels, one time
/// \param channels Pointer to an array of channels to convert /// \param channels Pointer to an array of channels to convert
/// \param numChannels Number of channels to convert /// \param numChannels Number of channels to convert
/// \param result Pointer to store converted channel results in /// \param result Pointer to store converted channel results in
/// \param time ADC_SampleTime - amount of clock cycles per conversion /// \param time SHAL_ADC_SampleTime - amount of clock cycles per conversion
void multiConvertSingle(SHAL_ADC_Channel* channels, int numChannels, uint16_t* result, ADC_SampleTime time = ADC_SampleTime::C239); SHAL_Result multiConvertSingle(SHAL_ADC_Channel* channels, int numChannels, uint16_t* result, SHAL_ADC_SampleTime time = SHAL_ADC_SampleTime::C8);
@@ -45,9 +45,28 @@ private:
ADC_Key m_ADCKey = ADC_Key::INVALID; ADC_Key m_ADCKey = ADC_Key::INVALID;
//Checks to see if instance is initialized with a proper ADC peripheral tag
bool isValid(); bool isValid();
//Enabled peripheral
SHAL_Result enable();
//Disables peripheral
SHAL_Result disable(); SHAL_Result disable();
SHAL_Result startConversion();
/// Adds an ADC channel to the conversion sequence
/// \param channel Channel to add
/// \param index Index to add channel to (ADC channel will be the nth channel to convert
/// \return Result
SHAL_Result addADCChannelToSequence(SHAL_ADC_Channel channel, uint32_t index);
/// Sets the amount of ADC channels to convert
/// \param amount Number of channels to convert
/// \return
SHAL_Result setADCSequenceAmount(uint32_t amount);
}; };

View File

@@ -5,21 +5,21 @@
#ifndef SHMINGO_HAL_SHAL_ADC_TYPES_H #ifndef SHMINGO_HAL_SHAL_ADC_TYPES_H
#define SHMINGO_HAL_SHAL_ADC_TYPES_H #define SHMINGO_HAL_SHAL_ADC_TYPES_H
//Common register among all ADC peripherals
struct SHAL_ADC_Common_Control_Reg { struct SHAL_ADC_Common_Control_Reg {
volatile uint32_t* reg; volatile uint32_t* reg;
uint32_t VoltageRefEnable; uint32_t VoltageRefEnable;
uint32_t TempSensorEnable; uint32_t TempSensorEnable;
uint32_t VBatteryEnable; uint32_t VBatteryEnable;
}; };
//Register controlling the ADC peripheral clock
struct SHAL_ADC_RCC_Enable_Reg { struct SHAL_ADC_RCC_Enable_Reg {
volatile uint32_t* reg; volatile uint32_t* reg;
uint32_t mask; uint32_t mask;
}; };
//Register with ADC controls
struct SHAL_ADC_Control_Reg { struct SHAL_ADC_Control_Reg {
volatile uint32_t* reg; volatile uint32_t* reg;
uint32_t enable_mask; uint32_t enable_mask;
@@ -28,6 +28,7 @@ struct SHAL_ADC_Control_Reg {
uint32_t start_mask; uint32_t start_mask;
}; };
//Register controlling ADC configuration
struct SHAL_ADC_Config_Reg { struct SHAL_ADC_Config_Reg {
volatile uint32_t* reg; volatile uint32_t* reg;
uint32_t continue_mask; uint32_t continue_mask;
@@ -36,53 +37,53 @@ struct SHAL_ADC_Config_Reg {
uint32_t alignment_offset; uint32_t alignment_offset;
}; };
//Register for all ADC data
struct SHAL_ADC_Data_Reg { struct SHAL_ADC_Data_Reg {
volatile uint32_t* reg; volatile uint32_t* reg;
uint32_t mask; uint32_t mask;
}; };
struct SHAL_ADC_ISR { //Register for the interrupt service routine for ADCs
struct SHAL_ADC_ISR_Reg {
volatile uint32_t* reg; volatile uint32_t* reg;
uint32_t end_of_conversion_mask; uint32_t end_of_conversion_mask;
uint32_t end_of_sequence_mask;
uint32_t ready_mask;
}; };
//Register controlling the clock source for the ADC
struct SHAL_ADC_Clock_Reg { struct SHAL_ADC_Clock_Reg {
volatile uint32_t* reg; volatile uint32_t* reg;
uint32_t clear; uint32_t clear;
uint32_t mask; uint32_t mask;
}; };
//Register controlling the sampling time of ADC samples
struct SHAL_ADC_Channel_Sampling_Time_Reg { struct SHAL_ADC_Channel_Sampling_Time_Reg {
volatile uint32_t* reg; volatile uint32_t* reg;
uint32_t channel_offset; uint32_t channel_offset;
}; };
//Register controlling the number of conversions to do in one sequence
enum class SHAL_ADC_Channel : uint32_t { struct SHAL_ADC_Sequence_Amount_Reg {
CH0, volatile uint32_t* reg;
CH1, uint32_t offset;
CH2,
CH3,
CH4,
CH5,
CH6,
CH7,
CH8,
CH9,
CH10,
CH11,
CH12,
CH13,
CH14,
CH15,
CHTemp,
CHRef,
CHBat
}; };
enum class ADC_SampleTime : uint32_t { /*Register group controlling which ADC channels to convert. DO NOT USE THE FOLLOWING ILLEGAL COMBINATIONS:
C1 = 0x00, //1.5 cycles per sample F0 *reg 1 + offset 1
*Any sections after the last one (for example, max for a 16 channel register is reg 4 offset 2*/
struct SHAL_ADC_Sequence_Reg {
volatile uint32_t* regs[6];
uint32_t offsets[5];
};
enum class SHAL_ADC_SampleTime : uint32_t {
C1 = 0x00, //1.5 cycles per sample (F0 only, timings change on other ADC architectures)
C2 = 0x01, //7.5 cycles C2 = 0x01, //7.5 cycles
C3 = 0x02, //13.5 cycles C3 = 0x02, //13.5 cycles
C4 = 0x03, //28.5 cycles C4 = 0x03, //28.5 cycles

View File

@@ -6,7 +6,23 @@
#define SHMINGO_HAL_SHAL_EXTI_REG_L432KC_H #define SHMINGO_HAL_SHAL_EXTI_REG_L432KC_H
#include "SHAL_CORE.h" #include "SHAL_CORE.h"
#include "SHAL_EXTI_TYPES.h"
#define EXTI_PENDING_REG(line) ((line) < 32 ? EXTI->PR1 : EXTI->PR2) #define EXTI_PENDING_REG(line) ((line) < 32 ? EXTI->PR1 : EXTI->PR2)
static inline SHAL_EXTI_Interrupt_Mask_Register getEXTIInterruptMaskRegister(uint32_t line){
auto imr = line < 32 ? EXTI->IMR1 : EXTI->IMR2;
return {&imr};
}
static inline SHAL_EXTI_Rising_Trigger_Selection_Register getEXTIRisingTriggerSelectionRegister(uint32_t line){
auto reg = line < 32 ? EXTI->RTSR1 : EXTI->RTSR2;
return {&reg};
}
static inline SHAL_EXTI_Falling_Trigger_Selection_Register getEXTIFallingTriggerSelectionRegister(uint32_t line){
auto reg = line < 32 ? EXTI->FTSR1 : EXTI->FTSR2;
return {&reg};
}
#endif //SHMINGO_HAL_SHAL_EXTI_REG_L432KC_H #endif //SHMINGO_HAL_SHAL_EXTI_REG_L432KC_H

View File

@@ -0,0 +1,22 @@
//
// Created by Luca on 10/17/2025.
//
#ifndef SHMINGO_HAL_SHAL_EXTI_TYPES_H
#define SHMINGO_HAL_SHAL_EXTI_TYPES_H
#include "SHAL_CORE.h"
struct SHAL_EXTI_Interrupt_Mask_Register {
volatile uint32_t* reg;
};
struct SHAL_EXTI_Rising_Trigger_Selection_Register {
volatile uint32_t* reg;
};
struct SHAL_EXTI_Falling_Trigger_Selection_Register {
volatile uint32_t* reg;
};
#endif //SHMINGO_HAL_SHAL_EXTI_TYPES_H

View File

@@ -16,8 +16,7 @@
#define AVAILABLE_GPIO \ #define AVAILABLE_GPIO \
X(A0) X(A1) X(A2) X(A3) X(A4) X(A5) X(A6) X(A7) X(A8) X(A9) X(A10) X(A11) X(A12) X(A13) X(A14) X(A15) \ X(A0) X(A1) X(A2) X(A3) X(A4) X(A5) X(A6) X(A7) X(A8) X(A9) X(A10) X(A11) X(A12) X(A13) X(A14) X(A15) \
X(B0) X(B1) X(B2) X(B3) X(B4) X(B5) X(B6) X(B7) X(B8) X(B9) X(B10) X(B11) X(B12) X(B13) X(B14) X(B15) \ X(B0) X(B1) X(B3) X(B4) X(B5) X(B6) X(B7)
X(C0) X(C1) X(C2) X(C3) X(C4) X(C5) X(C6) X(C7) X(C8) X(C9) X(C10) X(C11) X(C12) X(C13) X(C14) X(C15)
//Build enum map of available SHAL_GPIO pins //Build enum map of available SHAL_GPIO pins
@@ -29,8 +28,6 @@ enum class GPIO_Key : uint8_t {
INVALID INVALID
}; };
constexpr SHAL_GPIO_Peripheral getGPIORegister(const GPIO_Key g){ constexpr SHAL_GPIO_Peripheral getGPIORegister(const GPIO_Key g){
switch(g) { switch(g) {
case GPIO_Key::A0: return {GPIOA,0}; case GPIO_Key::A0: return {GPIOA,0};
@@ -51,36 +48,11 @@ constexpr SHAL_GPIO_Peripheral getGPIORegister(const GPIO_Key g){
case GPIO_Key::A15: return {GPIOA,15}; case GPIO_Key::A15: return {GPIOA,15};
case GPIO_Key::B0: return {GPIOB,0}; case GPIO_Key::B0: return {GPIOB,0};
case GPIO_Key::B1: return {GPIOB,1}; case GPIO_Key::B1: return {GPIOB,1};
case GPIO_Key::B2: return {GPIOB,2};
case GPIO_Key::B3: return {GPIOB,3}; case GPIO_Key::B3: return {GPIOB,3};
case GPIO_Key::B4: return {GPIOB,4}; case GPIO_Key::B4: return {GPIOB,4};
case GPIO_Key::B5: return {GPIOB,5}; case GPIO_Key::B5: return {GPIOB,5};
case GPIO_Key::B6: return {GPIOB,6}; case GPIO_Key::B6: return {GPIOB,6};
case GPIO_Key::B7: return {GPIOB,7}; case GPIO_Key::B7: return {GPIOB,7};
case GPIO_Key::B8: return {GPIOB,8};
case GPIO_Key::B9: return {GPIOB,9};
case GPIO_Key::B10: return {GPIOB,10};
case GPIO_Key::B11: return {GPIOB,11};
case GPIO_Key::B12: return {GPIOB,12};
case GPIO_Key::B13: return {GPIOB,13};
case GPIO_Key::B14: return {GPIOB,14};
case GPIO_Key::B15: return {GPIOB,15};
case GPIO_Key::C0: return {GPIOC,0};
case GPIO_Key::C1: return {GPIOC,1};
case GPIO_Key::C2: return {GPIOC,2};
case GPIO_Key::C3: return {GPIOC,3};
case GPIO_Key::C4: return {GPIOC,4};
case GPIO_Key::C5: return {GPIOC,5};
case GPIO_Key::C6: return {GPIOC,6};
case GPIO_Key::C7: return {GPIOC,7};
case GPIO_Key::C8: return {GPIOC,8};
case GPIO_Key::C9: return {GPIOC,9};
case GPIO_Key::C10: return {GPIOC,10};
case GPIO_Key::C11: return {GPIOC,11};
case GPIO_Key::C12: return {GPIOC,12};
case GPIO_Key::C13: return {GPIOC,13};
case GPIO_Key::C14: return {GPIOC,14};
case GPIO_Key::C15: return {GPIOC,15};
case GPIO_Key::INVALID: case GPIO_Key::INVALID:
case GPIO_Key::NUM_GPIO: case GPIO_Key::NUM_GPIO:
assert(false); assert(false);
@@ -114,8 +86,7 @@ constexpr SHAL_GPIO_EXTI_Register getGPIOEXTICR(const GPIO_Key g){
case GPIO_Key::B5: return {&SYSCFG->EXTICR[1],SYSCFG_EXTICR2_EXTI5_PB,EXTI9_5_IRQn}; case GPIO_Key::B5: return {&SYSCFG->EXTICR[1],SYSCFG_EXTICR2_EXTI5_PB,EXTI9_5_IRQn};
case GPIO_Key::B6: return {&SYSCFG->EXTICR[1],SYSCFG_EXTICR2_EXTI6_PB,EXTI9_5_IRQn}; case GPIO_Key::B6: return {&SYSCFG->EXTICR[1],SYSCFG_EXTICR2_EXTI6_PB,EXTI9_5_IRQn};
case GPIO_Key::B7: return {&SYSCFG->EXTICR[1],SYSCFG_EXTICR2_EXTI7_PB,EXTI9_5_IRQn}; case GPIO_Key::B7: return {&SYSCFG->EXTICR[1],SYSCFG_EXTICR2_EXTI7_PB,EXTI9_5_IRQn};
case GPIO_Key::C14: return {&SYSCFG->EXTICR[3],SYSCFG_EXTICR4_EXTI14_PC,EXTI15_10_IRQn};
case GPIO_Key::C15: return {&SYSCFG->EXTICR[3],SYSCFG_EXTICR4_EXTI15_PC,EXTI15_10_IRQn};
case GPIO_Key::INVALID: case GPIO_Key::INVALID:
case GPIO_Key::NUM_GPIO: case GPIO_Key::NUM_GPIO:
@@ -146,38 +117,12 @@ constexpr SHAL_Peripheral_Register getGPIORCCEnable(const GPIO_Key g){
return {&RCC->AHB2ENR, RCC_AHB2ENR_GPIOAEN_Pos}; return {&RCC->AHB2ENR, RCC_AHB2ENR_GPIOAEN_Pos};
case GPIO_Key::B0: case GPIO_Key::B0:
case GPIO_Key::B1: case GPIO_Key::B1:
case GPIO_Key::B2:
case GPIO_Key::B3: case GPIO_Key::B3:
case GPIO_Key::B4: case GPIO_Key::B4:
case GPIO_Key::B5: case GPIO_Key::B5:
case GPIO_Key::B6: case GPIO_Key::B6:
case GPIO_Key::B7: case GPIO_Key::B7:
case GPIO_Key::B8:
case GPIO_Key::B9:
case GPIO_Key::B10:
case GPIO_Key::B11:
case GPIO_Key::B12:
case GPIO_Key::B13:
case GPIO_Key::B14:
case GPIO_Key::B15:
return {&RCC->AHB2ENR, RCC_AHB2ENR_GPIOBEN_Pos}; return {&RCC->AHB2ENR, RCC_AHB2ENR_GPIOBEN_Pos};
case GPIO_Key::C0:
case GPIO_Key::C1:
case GPIO_Key::C2:
case GPIO_Key::C3:
case GPIO_Key::C4:
case GPIO_Key::C5:
case GPIO_Key::C6:
case GPIO_Key::C7:
case GPIO_Key::C8:
case GPIO_Key::C9:
case GPIO_Key::C10:
case GPIO_Key::C11:
case GPIO_Key::C12:
case GPIO_Key::C13:
case GPIO_Key::C14:
case GPIO_Key::C15:
return {&RCC->AHB2ENR, RCC_AHB2ENR_GPIOCEN_Pos};
case GPIO_Key::INVALID: case GPIO_Key::INVALID:
case GPIO_Key::NUM_GPIO: case GPIO_Key::NUM_GPIO:
assert(false); assert(false);
@@ -207,38 +152,11 @@ constexpr uint32_t getGPIOPortNumber(const GPIO_Key g){
return 0; return 0;
case GPIO_Key::B0: case GPIO_Key::B0:
case GPIO_Key::B1: case GPIO_Key::B1:
case GPIO_Key::B2:
case GPIO_Key::B3: case GPIO_Key::B3:
case GPIO_Key::B4: case GPIO_Key::B4:
case GPIO_Key::B5: case GPIO_Key::B5:
case GPIO_Key::B6: case GPIO_Key::B6:
case GPIO_Key::B7: case GPIO_Key::B7:
case GPIO_Key::B8:
case GPIO_Key::B9:
case GPIO_Key::B10:
case GPIO_Key::B11:
case GPIO_Key::B12:
case GPIO_Key::B13:
case GPIO_Key::B14:
case GPIO_Key::B15:
return 1;
case GPIO_Key::C0:
case GPIO_Key::C1:
case GPIO_Key::C2:
case GPIO_Key::C3:
case GPIO_Key::C4:
case GPIO_Key::C5:
case GPIO_Key::C6:
case GPIO_Key::C7:
case GPIO_Key::C8:
case GPIO_Key::C9:
case GPIO_Key::C10:
case GPIO_Key::C11:
case GPIO_Key::C12:
case GPIO_Key::C13:
case GPIO_Key::C14:
case GPIO_Key::C15:
return 2;
case GPIO_Key::INVALID: case GPIO_Key::INVALID:
case GPIO_Key::NUM_GPIO: case GPIO_Key::NUM_GPIO:
assert(false); assert(false);
@@ -251,67 +169,42 @@ constexpr SHAL_GPIO_Port_Info getGPIOPortInfo(GPIO_Key key){
switch(key){ switch(key){
case GPIO_Key::A0: case GPIO_Key::A0:
case GPIO_Key::B0: case GPIO_Key::B0:
case GPIO_Key::C0:
return {0, SHAL_ADC_Channel::CH0}; return {0, SHAL_ADC_Channel::CH0};
case GPIO_Key::A1: case GPIO_Key::A1:
case GPIO_Key::B1: case GPIO_Key::B1:
case GPIO_Key::C1:
return {1, SHAL_ADC_Channel::CH1}; return {1, SHAL_ADC_Channel::CH1};
case GPIO_Key::A2: case GPIO_Key::A2:
case GPIO_Key::B2:
case GPIO_Key::C2:
return {2, SHAL_ADC_Channel::CH2}; return {2, SHAL_ADC_Channel::CH2};
case GPIO_Key::A3: case GPIO_Key::A3:
case GPIO_Key::B3: case GPIO_Key::B3:
case GPIO_Key::C3:
return {3, SHAL_ADC_Channel::CH3}; return {3, SHAL_ADC_Channel::CH3};
case GPIO_Key::A4: case GPIO_Key::A4:
case GPIO_Key::B4: case GPIO_Key::B4:
case GPIO_Key::C4:
return {4, SHAL_ADC_Channel::CH4}; return {4, SHAL_ADC_Channel::CH4};
case GPIO_Key::A5: case GPIO_Key::A5:
case GPIO_Key::B5: case GPIO_Key::B5:
case GPIO_Key::C5:
return {5, SHAL_ADC_Channel::CH5}; return {5, SHAL_ADC_Channel::CH5};
case GPIO_Key::A6: case GPIO_Key::A6:
case GPIO_Key::B6: case GPIO_Key::B6:
case GPIO_Key::C6:
return {6, SHAL_ADC_Channel::CH6}; return {6, SHAL_ADC_Channel::CH6};
case GPIO_Key::A7: case GPIO_Key::A7:
case GPIO_Key::B7: case GPIO_Key::B7:
case GPIO_Key::C7:
return {7, SHAL_ADC_Channel::CH7}; return {7, SHAL_ADC_Channel::CH7};
case GPIO_Key::A8: case GPIO_Key::A8:
case GPIO_Key::B8:
case GPIO_Key::C8:
return {8, SHAL_ADC_Channel::CH8}; return {8, SHAL_ADC_Channel::CH8};
case GPIO_Key::A9: case GPIO_Key::A9:
case GPIO_Key::B9:
case GPIO_Key::C9:
return {9, SHAL_ADC_Channel::CH9}; return {9, SHAL_ADC_Channel::CH9};
case GPIO_Key::A10: case GPIO_Key::A10:
case GPIO_Key::B10:
case GPIO_Key::C10:
return {10, SHAL_ADC_Channel::CH10}; return {10, SHAL_ADC_Channel::CH10};
case GPIO_Key::A11: case GPIO_Key::A11:
case GPIO_Key::B11:
case GPIO_Key::C11:
return {11, SHAL_ADC_Channel::CH11}; return {11, SHAL_ADC_Channel::CH11};
case GPIO_Key::A12: case GPIO_Key::A12:
case GPIO_Key::B12:
case GPIO_Key::C12:
return {12, SHAL_ADC_Channel::CH12}; return {12, SHAL_ADC_Channel::CH12};
case GPIO_Key::A13: case GPIO_Key::A13:
case GPIO_Key::B13:
case GPIO_Key::C13:
return {13, SHAL_ADC_Channel::CH13}; return {13, SHAL_ADC_Channel::CH13};
case GPIO_Key::A14: case GPIO_Key::A14:
case GPIO_Key::B14:
case GPIO_Key::C14:
return {14, SHAL_ADC_Channel::CH14}; return {14, SHAL_ADC_Channel::CH14};
case GPIO_Key::A15: case GPIO_Key::A15:
case GPIO_Key::B15:
case GPIO_Key::C15:
return {15, SHAL_ADC_Channel::CH15}; return {15, SHAL_ADC_Channel::CH15};
case GPIO_Key::NUM_GPIO: case GPIO_Key::NUM_GPIO:
case GPIO_Key::INVALID: case GPIO_Key::INVALID:
@@ -320,6 +213,4 @@ constexpr SHAL_GPIO_Port_Info getGPIOPortInfo(GPIO_Key key){
__builtin_unreachable(); __builtin_unreachable();
} }
#endif //SHAL_GPIO_REG_F072XB_H
#endif //SHAL_GPIO_REG_F072XB_H

View File

@@ -27,7 +27,7 @@ public:
/// Uses the ADC to read an analog voltage value /// Uses the ADC to read an analog voltage value
/// \param sampleTime The amount of clock cycles to use for the ADC /// \param sampleTime The amount of clock cycles to use for the ADC
/// \return ADC result /// \return ADC result
uint16_t analogRead(ADC_SampleTime sampleTime = ADC_SampleTime::C239); uint16_t analogRead(SHAL_ADC_SampleTime sampleTime = SHAL_ADC_SampleTime::C8);
void setPinMode(PinMode mode) volatile; void setPinMode(PinMode mode) volatile;

View File

@@ -8,6 +8,8 @@
#include "SHAL_CORE.h" #include "SHAL_CORE.h"
#include "SHAL_I2C_TYPES.h" #include "SHAL_I2C_TYPES.h"
#define NUM_I2C_BUSES 3
enum class I2C_Pair : uint8_t{ enum class I2C_Pair : uint8_t{
//I2C_1 //I2C_1
SCL1A9_SDA1A10, //AF4 SCL1A9_SDA1A10, //AF4
@@ -62,9 +64,6 @@ constexpr SHAL_I2C_Reset_Reg getI2CResetReg(const I2C_Pair pair){
__builtin_unreachable(); __builtin_unreachable();
} }
constexpr SHAL_I2C_Reset_Reg getI2CResetRe() {
return {&RCC->APB1RSTR1,RCC_APB1RSTR1_I2C1RST};
}
//Gets all the bits in the I2C timer register, these values should rarely be manually set, but I wanted to support it anyway //Gets all the bits in the I2C timer register, these values should rarely be manually set, but I wanted to support it anyway
constexpr SHAL_I2C_Timing_Reg getI2CTimerReg(const I2C_Pair pair){ constexpr SHAL_I2C_Timing_Reg getI2CTimerReg(const I2C_Pair pair){
switch(pair){ switch(pair){

View File

@@ -6,8 +6,8 @@
****************************************************************************** ******************************************************************************
*/ */
#ifndef SHAL_TIM_REG_H #ifndef SHAL_TIM_REG_F072XB_H
#define SHAL_TIM_REG_H #define SHAL_TIM_REG_F072XB_H
#include <cassert> #include <cassert>
#include <stm32f072xb.h> #include <stm32f072xb.h>

View File

@@ -0,0 +1,140 @@
/**
******************************************************************************
* @file SHAL_TIM_REG.h
* @author Luca Lizaranzu
* @brief Defines universal macros and objects used across all STM32 families
******************************************************************************
*/
#ifndef SHAL_TIM_REG_L432KC_H
#define SHAL_TIM_REG_L432KC_H
#include <cassert>
#include <stm32l432xx.h>
#include "SHAL_CORE.h"
#include "SHAL_TIM_TYPES.h"
enum class Timer_Key : uint8_t { //For STM32L432
S_TIM1,
S_TIM2,
S_TIM6,
S_TIM7,
S_TIM15,
S_TIM16,
NUM_TIMERS,
S_TIM_INVALID
};
//Lookup table for timer typedefs
static volatile TIM_TypeDef* TIM_TABLE[6] = {
TIM1,
TIM2,
TIM6,
TIM7,
TIM15,
TIM16,
};
static IRQn_Type IRQN_TABLE[6] = {
TIM1_TRG_COM_IRQn,
TIM2_IRQn,
TIM6_DAC_IRQn,
TIM7_IRQn,
TIM1_BRK_TIM15_IRQn,
TIM1_UP_TIM16_IRQn
};
#define SHAL_TIM1 TimerManager::get(Timer_Key::S_TIM1)
#define SHAL_TIM2 TimerManager::get(Timer_Key::S_TIM2)
#define SHAL_TIM6 TimerManager::get(Timer_Key::S_TIM6)
#define SHAL_TIM7 TimerManager::get(Timer_Key::S_TIM7)
#define SHAL_TIM15 TimerManager::get(Timer_Key::S_TIM15)
#define SHAL_TIM16 TimerManager::get(Timer_Key::S_TIM16)
static inline SHAL_TIM_Status_Register getTimerStatusRegister(Timer_Key key){
SHAL_TIM_Status_Register res = {nullptr, TIM_SR_UIF};
volatile TIM_TypeDef* tim = TIM_TABLE[static_cast<uint8_t>(key)];
res.reg = &tim->SR;
return res;
}
static inline SHAL_TIM_Control_Register_1 getTimerControlRegister1(Timer_Key key){
SHAL_TIM_Control_Register_1 res = {nullptr, TIM_CR1_CEN_Msk, TIM_CR1_UDIS, TIM_CR1_OPM, TIM_CR1_CMS_Pos};
volatile TIM_TypeDef* tim = TIM_TABLE[static_cast<uint8_t>(key)];
res.reg = &tim->CR1;
return res;
}
static inline SHAL_TIM_DMA_Interrupt_Enable_Register getTimerDMAInterruptEnableRegister(Timer_Key key){
SHAL_TIM_DMA_Interrupt_Enable_Register res = {nullptr, TIM_DIER_UIE};
volatile TIM_TypeDef* tim = TIM_TABLE[static_cast<uint8_t>(key)];
res.reg = &tim->DIER;
return res;
}
static inline SHAL_TIM_Event_Generation_Register getTimerEventGenerationRegister(Timer_Key key){
SHAL_TIM_Event_Generation_Register res = {nullptr, TIM_EGR_UG};
volatile TIM_TypeDef* tim = TIM_TABLE[static_cast<uint8_t>(key)];
res.reg = &tim->EGR;
return res;
}
static inline SHAL_TIM_Prescaler_Register getTimerPrescalerRegister(Timer_Key key){
SHAL_TIM_Prescaler_Register res = {nullptr, 1UL << 15};
volatile TIM_TypeDef* tim = TIM_TABLE[static_cast<uint8_t>(key)];
res.reg = &tim->PSC;
return res;
}
static inline SHAL_TIM_Auto_Reload_Register getTimerAutoReloadRegister(Timer_Key key){
SHAL_TIM_Auto_Reload_Register res = {nullptr, 1UL << 15};
volatile TIM_TypeDef* tim = TIM_TABLE[static_cast<uint8_t>(key)];
res.reg = &tim->ARR;
return res;
}
//Get TIMER_KEY peripheral struct including bus register, enable mask, TIMER_KEY mask
static inline SHAL_TIM_RCC_Register getTimerRCC(Timer_Key t) {
switch(t) {
case Timer_Key::S_TIM1: return {&RCC->APB2ENR, RCC_APB2ENR_TIM1EN};
case Timer_Key::S_TIM2: return {&RCC->APB1ENR1, RCC_APB1ENR1_TIM2EN};
case Timer_Key::S_TIM6: return {&RCC->APB1ENR1, RCC_APB1ENR1_TIM6EN};
case Timer_Key::S_TIM7: return {&RCC->APB1ENR1, RCC_APB1ENR1_TIM7EN};
case Timer_Key::S_TIM15: return {&RCC->APB2ENR, RCC_APB2ENR_TIM15EN};
case Timer_Key::S_TIM16: return {&RCC->APB2ENR, RCC_APB2ENR_TIM16EN};
case Timer_Key::NUM_TIMERS:
case Timer_Key::S_TIM_INVALID:
assert(false);
}
__builtin_unreachable();
}
//Get timer IRQN from lookup table
static inline IRQn_Type getTimerIRQn(Timer_Key t) {
return IRQN_TABLE[static_cast<uint8_t>(t)];
}
#endif

View File

@@ -9,7 +9,7 @@
#ifndef SHAL_TIM_H #ifndef SHAL_TIM_H
#define SHAL_TIM_H #define SHAL_TIM_H
#include "SHAL_TIM_REG_F072xB.h" #include "SHAL_TIM_REG.h"
#include "SHAL_TIM_CALLBACK.h" #include "SHAL_TIM_CALLBACK.h"
#include <array> #include <array>
@@ -18,7 +18,7 @@ class Timer {
friend class TimerManager; friend class TimerManager;
public: public:
/// /// Initializes a timer
/// \param prescaler The amount of times the base clock has to cycle before the timer adds one to the count /// \param prescaler The amount of times the base clock has to cycle before the timer adds one to the count
/// \param autoReload The number of timer counts before the count is reset and IRQ is called /// \param autoReload The number of timer counts before the count is reset and IRQ is called
void init(uint32_t prescaler, uint32_t autoReload); void init(uint32_t prescaler, uint32_t autoReload);
@@ -40,7 +40,7 @@ public:
//Set TIMER_KEY IRQ callback function //Set TIMER_KEY IRQ callback function
void setCallbackFunc(TimerCallback callback){ void setCallbackFunc(TimerCallback callback){
registerTimerCallback(TIMER_KEY, callback); registerTimerCallback(m_key, callback);
} }
private: private:
@@ -48,7 +48,7 @@ private:
explicit Timer(Timer_Key t); explicit Timer(Timer_Key t);
Timer(); Timer();
Timer_Key TIMER_KEY; Timer_Key m_key;
}; };

View File

@@ -13,11 +13,12 @@
#include "SHAL_CORE.h" #include "SHAL_CORE.h"
#include "SHAL_TIM_REG.h" #include "SHAL_TIM_REG.h"
#define DEFINE_TIMER_IRQ(key, irq_handler) \ #define DEFINE_TIMER_IRQ(key, irq_handler) \
extern "C" void irq_handler(void) { \ extern "C" void irq_handler(void) { \
auto tim_reg = getTimerRegister(key); \ auto tim_status_reg = getTimerStatusRegister(key); \
if (tim_reg->SR & TIM_SR_UIF) { \ if (*tim_status_reg.reg & tim_status_reg.update_interrupt_flag_mask) { \
tim_reg->SR &= ~TIM_SR_UIF; /* clear flag */ \ SHAL_clear_bitmask(tim_status_reg.reg,tim_status_reg.update_interrupt_flag_mask); /* clear flag */ \
auto cb = timer_callbacks[static_cast<int>(key)]; \ auto cb = timer_callbacks[static_cast<int>(key)]; \
if (cb) cb(); \ if (cb) cb(); \
}; \ }; \

View File

@@ -2,8 +2,8 @@
// Created by Luca on 9/7/2025. // Created by Luca on 9/7/2025.
// //
#ifndef SHMINGO_HAL_SHAL_TIM_REG_H #ifndef SHAL_TIM_REG_H
#define SHMINGO_HAL_SHAL_TIM_REG_H #define SHAL_TIM_REG_H
#if defined(STM32F030x6) #if defined(STM32F030x6)
#include "stm32f030x6.h" #include "stm32f030x6.h"
@@ -46,7 +46,7 @@
#elif defined(STM32L431xx) #elif defined(STM32L431xx)
#include "stm32l431xx.h" #include "stm32l431xx.h"
#elif defined(STM32L432xx) #elif defined(STM32L432xx)
#include "stm32l432xx.h" #include "SHAL_TIM_REG_L432KC.h"
#elif defined(STM32L433xx) #elif defined(STM32L433xx)
#include "stm32l433xx.h" #include "stm32l433xx.h"
#elif defined(STM32L442xx) #elif defined(STM32L442xx)
@@ -92,4 +92,4 @@
#error "Please select first the target STM32F0xx device used in your application (in stm32f0xx.h file)" #error "Please select first the target STM32F0xx device used in your application (in stm32f0xx.h file)"
#endif #endif
#endif //SHMINGO_HAL_SHAL_TIM_REG_H #endif //SHAL_TIM_REG_H

View File

@@ -2,13 +2,46 @@
// Created by Luca on 9/7/2025. // Created by Luca on 9/7/2025.
// //
#ifndef SHMINGO_HAL_SHAL_TIM_TYPES_H #ifndef SHAL_TIM_TYPES_H
#define SHMINGO_HAL_SHAL_TIM_TYPES_H #define SHAL_TIM_TYPES_H
#include "SHAL_CORE.h" #include "SHAL_CORE.h"
struct TIM_RCC_Enable{ struct SHAL_TIM_RCC_Register{
volatile uint32_t* busEnableReg; volatile uint32_t* reg;
uint32_t enable_mask;
};
struct SHAL_TIM_Control_Register_1 {
volatile uint32_t* reg;
uint32_t counter_enable_mask;
uint32_t update_disable_mask;
uint32_t one_pulse_mode_mask;
uint32_t center_align_mode_offset;
};
struct SHAL_TIM_DMA_Interrupt_Enable_Register {
volatile uint32_t* reg;
uint32_t update_interrupt_enable_mask;
};
struct SHAL_TIM_Status_Register {
volatile uint32_t* reg;
uint32_t update_interrupt_flag_mask;
};
struct SHAL_TIM_Event_Generation_Register {
volatile uint32_t* reg;
uint32_t update_generation_mask;
};
struct SHAL_TIM_Prescaler_Register {
volatile uint32_t* reg;
uint32_t offset;
};
struct SHAL_TIM_Auto_Reload_Register {
volatile uint32_t* reg;
uint32_t offset; uint32_t offset;
}; };

View File

@@ -18,7 +18,7 @@
#define SHAL_UART4 UART(4) #define SHAL_UART4 UART(4)
//Valid usart Tx and Rx pairings for STM32F072 //Valid usart Tx and Rx pairings for STM32F072
enum class UART_Pair : uint8_t{ enum class UART_Pair_Key : uint8_t{
//UART1 //UART1
Tx1A9_Rx1A10, Tx1A9_Rx1A10,
Tx1B6_Rx1B7, Tx1B6_Rx1B7,
@@ -41,65 +41,65 @@ enum class UART_Pair : uint8_t{
}; };
constexpr SHAL_UART_Pair getUARTPair(const UART_Pair pair){ constexpr SHAL_UART_Pair getUARTPair(const UART_Pair_Key pair){
switch(pair){ switch(pair){
case UART_Pair::Tx1A9_Rx1A10: return {USART1, GPIO_Key::A9, GPIO_Key::A10, GPIO_Alternate_Function::AF1, GPIO_Alternate_Function::AF1}; case UART_Pair_Key::Tx1A9_Rx1A10: return {USART1, GPIO_Key::A9, GPIO_Key::A10, GPIO_Alternate_Function::AF1, GPIO_Alternate_Function::AF1};
case UART_Pair::Tx1B6_Rx1B7: return {USART1, GPIO_Key::B6, GPIO_Key::B7, GPIO_Alternate_Function::AF0, GPIO_Alternate_Function::AF0}; case UART_Pair_Key::Tx1B6_Rx1B7: return {USART1, GPIO_Key::B6, GPIO_Key::B7, GPIO_Alternate_Function::AF0, GPIO_Alternate_Function::AF0};
case UART_Pair::Tx2A2_Rx2A3: return {USART2, GPIO_Key::A2, GPIO_Key::A3, GPIO_Alternate_Function::AF1, GPIO_Alternate_Function::AF1}; case UART_Pair_Key::Tx2A2_Rx2A3: return {USART2, GPIO_Key::A2, GPIO_Key::A3, GPIO_Alternate_Function::AF1, GPIO_Alternate_Function::AF1};
case UART_Pair::Tx2A14_Rx2A15: return {USART2, GPIO_Key::A14, GPIO_Key::A15, GPIO_Alternate_Function::AF1, GPIO_Alternate_Function::AF1}; case UART_Pair_Key::Tx2A14_Rx2A15: return {USART2, GPIO_Key::A14, GPIO_Key::A15, GPIO_Alternate_Function::AF1, GPIO_Alternate_Function::AF1};
case UART_Pair::Tx3B10_Rx3B11: return {USART3, GPIO_Key::B10, GPIO_Key::B11, GPIO_Alternate_Function::AF4, GPIO_Alternate_Function::AF4}; case UART_Pair_Key::Tx3B10_Rx3B11: return {USART3, GPIO_Key::B10, GPIO_Key::B11, GPIO_Alternate_Function::AF4, GPIO_Alternate_Function::AF4};
case UART_Pair::Tx3C4_Rx3C5: return {USART3, GPIO_Key::C4, GPIO_Key::C5, GPIO_Alternate_Function::AF1, GPIO_Alternate_Function::AF1}; case UART_Pair_Key::Tx3C4_Rx3C5: return {USART3, GPIO_Key::C4, GPIO_Key::C5, GPIO_Alternate_Function::AF1, GPIO_Alternate_Function::AF1};
case UART_Pair::Tx3C10_Rx3C11: return {USART3, GPIO_Key::C10, GPIO_Key::C11, GPIO_Alternate_Function::AF1, GPIO_Alternate_Function::AF1}; case UART_Pair_Key::Tx3C10_Rx3C11: return {USART3, GPIO_Key::C10, GPIO_Key::C11, GPIO_Alternate_Function::AF1, GPIO_Alternate_Function::AF1};
case UART_Pair::Tx4A0_Rx4A1: return {USART4, GPIO_Key::A0, GPIO_Key::A1, GPIO_Alternate_Function::AF4, GPIO_Alternate_Function::AF4}; case UART_Pair_Key::Tx4A0_Rx4A1: return {USART4, GPIO_Key::A0, GPIO_Key::A1, GPIO_Alternate_Function::AF4, GPIO_Alternate_Function::AF4};
case UART_Pair::Tx4C10_Rx4C11: return {USART4, GPIO_Key::C10, GPIO_Key::C11, GPIO_Alternate_Function::AF0, GPIO_Alternate_Function::AF0}; case UART_Pair_Key::Tx4C10_Rx4C11: return {USART4, GPIO_Key::C10, GPIO_Key::C11, GPIO_Alternate_Function::AF0, GPIO_Alternate_Function::AF0};
case UART_Pair::NUM_PAIRS: case UART_Pair_Key::NUM_PAIRS:
case UART_Pair::INVALID: case UART_Pair_Key::INVALID:
assert(false); assert(false);
return {nullptr, GPIO_Key::INVALID, GPIO_Key::INVALID, GPIO_Alternate_Function::AF0, GPIO_Alternate_Function::AF0}; return {nullptr, GPIO_Key::INVALID, GPIO_Key::INVALID, GPIO_Alternate_Function::AF0, GPIO_Alternate_Function::AF0};
} }
__builtin_unreachable(); __builtin_unreachable();
} }
constexpr uint8_t getUARTChannel(const UART_Pair pair){ constexpr uint8_t getUARTChannel(const UART_Pair_Key pair){
switch(pair){ switch(pair){
case UART_Pair::Tx1A9_Rx1A10: case UART_Pair_Key::Tx1A9_Rx1A10:
case UART_Pair::Tx1B6_Rx1B7: case UART_Pair_Key::Tx1B6_Rx1B7:
return 0; return 0;
case UART_Pair::Tx2A2_Rx2A3: case UART_Pair_Key::Tx2A2_Rx2A3:
case UART_Pair::Tx2A14_Rx2A15: case UART_Pair_Key::Tx2A14_Rx2A15:
return 1; return 1;
case UART_Pair::Tx3B10_Rx3B11: case UART_Pair_Key::Tx3B10_Rx3B11:
case UART_Pair::Tx3C4_Rx3C5: case UART_Pair_Key::Tx3C4_Rx3C5:
case UART_Pair::Tx3C10_Rx3C11: case UART_Pair_Key::Tx3C10_Rx3C11:
return 2; return 2;
case UART_Pair::Tx4A0_Rx4A1: case UART_Pair_Key::Tx4A0_Rx4A1:
case UART_Pair::Tx4C10_Rx4C11: case UART_Pair_Key::Tx4C10_Rx4C11:
return 3; return 3;
case UART_Pair::NUM_PAIRS: case UART_Pair_Key::NUM_PAIRS:
case UART_Pair::INVALID: case UART_Pair_Key::INVALID:
assert(false); assert(false);
return 0; return 0;
} }
__builtin_unreachable(); __builtin_unreachable();
} }
constexpr SHAL_UART_ENABLE_REG getUARTEnableReg(const UART_Pair pair){ constexpr SHAL_UART_Enable_Register getUARTEnableReg(const UART_Pair_Key pair){
switch(pair){ switch(pair){
case UART_Pair::Tx1A9_Rx1A10: case UART_Pair_Key::Tx1A9_Rx1A10:
case UART_Pair::Tx1B6_Rx1B7: case UART_Pair_Key::Tx1B6_Rx1B7:
return {&RCC->APB2ENR,RCC_APB2ENR_USART1EN}; return {&RCC->APB2ENR,RCC_APB2ENR_USART1EN};
case UART_Pair::Tx2A2_Rx2A3: case UART_Pair_Key::Tx2A2_Rx2A3:
case UART_Pair::Tx2A14_Rx2A15: case UART_Pair_Key::Tx2A14_Rx2A15:
return {&RCC->APB1ENR,RCC_APB1ENR_USART2EN}; return {&RCC->APB1ENR,RCC_APB1ENR_USART2EN};
case UART_Pair::Tx3B10_Rx3B11: case UART_Pair_Key::Tx3B10_Rx3B11:
case UART_Pair::Tx3C4_Rx3C5: case UART_Pair_Key::Tx3C4_Rx3C5:
case UART_Pair::Tx3C10_Rx3C11: case UART_Pair_Key::Tx3C10_Rx3C11:
return {&RCC->APB1ENR,RCC_APB1ENR_USART3EN}; return {&RCC->APB1ENR,RCC_APB1ENR_USART3EN};
case UART_Pair::Tx4A0_Rx4A1: case UART_Pair_Key::Tx4A0_Rx4A1:
case UART_Pair::Tx4C10_Rx4C11: case UART_Pair_Key::Tx4C10_Rx4C11:
return {&RCC->APB1ENR,RCC_APB1ENR_USART4EN}; return {&RCC->APB1ENR,RCC_APB1ENR_USART4EN};
case UART_Pair::NUM_PAIRS: case UART_Pair_Key::NUM_PAIRS:
case UART_Pair::INVALID: case UART_Pair_Key::INVALID:
assert(false); assert(false);
return {nullptr, 0}; return {nullptr, 0};
} }

View File

@@ -0,0 +1,104 @@
//
// Created by Luca on 9/7/2025.
//
#ifndef SHAL_UART_REG_L432KC_H
#define SHAL_UART_REG_L432KC_H
#include <stm32l432xx.h>
#include <cassert>
#include "SHAL_UART_TYPES.h"
#define NUM_USART_LINES 4
#define SHAL_UART1 UART(1)
#define SHAL_UART2 UART(2)
//Valid usart Tx and Rx pairings for STM32L432KC
enum class UART_Pair_Key : uint8_t{
//UART1
Tx1A9_Rx1A10,
Tx1B6_Rx1B7,
//UART2
Tx2A2_Rx2A3,
NUM_PAIRS,
INVALID
};
static inline SHAL_UART_Pair getUARTPair(const UART_Pair_Key pair){
switch(pair){
case UART_Pair_Key::Tx1A9_Rx1A10: return {USART1, GPIO_Key::A9, GPIO_Key::A10, GPIO_Alternate_Function::AF7, GPIO_Alternate_Function::AF7};
case UART_Pair_Key::Tx1B6_Rx1B7: return {USART1, GPIO_Key::B6, GPIO_Key::B7, GPIO_Alternate_Function::AF7, GPIO_Alternate_Function::AF7};
case UART_Pair_Key::Tx2A2_Rx2A3: return {USART2, GPIO_Key::A2, GPIO_Key::A3, GPIO_Alternate_Function::AF7, GPIO_Alternate_Function::AF7};
case UART_Pair_Key::NUM_PAIRS:
case UART_Pair_Key::INVALID:
__builtin_unreachable();
}
__builtin_unreachable();
}
static inline uint8_t getUARTChannel(const UART_Pair_Key pair){ //TODO remove?
switch(pair){
case UART_Pair_Key::Tx1A9_Rx1A10:
case UART_Pair_Key::Tx1B6_Rx1B7:
return 0;
case UART_Pair_Key::Tx2A2_Rx2A3:
return 1;
case UART_Pair_Key::NUM_PAIRS:
case UART_Pair_Key::INVALID:
assert(false);
return 0;
}
__builtin_unreachable();
}
constexpr SHAL_UART_Enable_Register getUARTEnableReg(const UART_Pair_Key pair){
switch(pair){
case UART_Pair_Key::Tx1A9_Rx1A10:
case UART_Pair_Key::Tx1B6_Rx1B7:
return {&RCC->APB2ENR,RCC_APB2ENR_USART1EN};
case UART_Pair_Key::Tx2A2_Rx2A3:
return {&RCC->APB1ENR1,RCC_APB1ENR1_USART2EN};
case UART_Pair_Key::NUM_PAIRS:
case UART_Pair_Key::INVALID:
assert(false);
return {nullptr, 0};
}
__builtin_unreachable();
}
static inline SHAL_UART_Control_Register_1 getUARTControlRegister1(UART_Pair_Key key){
SHAL_UART_Control_Register_1 res = {nullptr, USART_CR1_UE, USART_CR1_TE, USART_CR1_RE};
res.reg = &getUARTPair(key).USARTReg->CR1;
return res;
};
static inline SHAL_UART_Baud_Rate_Generation_Register getUARTBaudRateGenerationRegister(UART_Pair_Key key){
SHAL_UART_Baud_Rate_Generation_Register res = {nullptr, 1UL << 15}; //TODO un-hardcode if other devices have wider baud rate allowances
res.reg = &getUARTPair(key).USARTReg->BRR;
return res;
};
static inline SHAL_UART_Transmit_Data_Register getUARTTransmitDataRegister(UART_Pair_Key key){
SHAL_UART_Transmit_Data_Register res = {nullptr, 1UL << 15}; //TODO un-hardcode if other devices have wider baud rate allowances
res.reg = &getUARTPair(key).USARTReg->TDR;
return res;
};
static inline SHAL_UART_ISR_FIFO_Disabled getUARTISRFifoDisabled(UART_Pair_Key key){
SHAL_UART_ISR_FIFO_Disabled res = {nullptr, USART_ISR_TXE};
res.reg = &getUARTPair(key).USARTReg->ISR;
return res;
};
#endif //SHAL_UART_REG_F072XB_H

View File

@@ -10,13 +10,14 @@
#define SHMINGO_HAL_SHAL_UART_H #define SHMINGO_HAL_SHAL_UART_H
#include "SHAL_UART_REG.h" #include "SHAL_UART_REG.h"
#include "SHAL_UART_TYPES.h"
class SHAL_UART{ class SHAL_UART{
friend class UARTManager; friend class UARTManager;
public: public:
void init(UART_Pair pair); void init(UART_Pair_Key pair);
//begins Tx and Usart TODO either modify this function or add a new one that supports Rx //begins Tx and Usart TODO either modify this function or add a new one that supports Rx
void begin(uint32_t baudRate) volatile; void begin(uint32_t baudRate) volatile;
@@ -33,7 +34,7 @@ private:
//Creates a SHAL_UART based on a pair of two valid U(S)ART pins //Creates a SHAL_UART based on a pair of two valid U(S)ART pins
UART_Pair m_UARTPair = UART_Pair::INVALID; UART_Pair_Key m_key = UART_Pair_Key::INVALID;
}; };

View File

@@ -47,7 +47,7 @@
#elif defined(STM32L431xx) #elif defined(STM32L431xx)
#include "stm32l431xx.h" #include "stm32l431xx.h"
#elif defined(STM32L432xx) #elif defined(STM32L432xx)
#include "stm32l432xx.h" #include "SHAL_UART_REG_L432KC.h"
#elif defined(STM32L433xx) #elif defined(STM32L433xx)
#include "stm32l433xx.h" #include "stm32l433xx.h"
#elif defined(STM32L442xx) #elif defined(STM32L442xx)

View File

@@ -19,9 +19,33 @@ struct SHAL_UART_Pair{
GPIO_Alternate_Function RxAlternateFunctionMask; GPIO_Alternate_Function RxAlternateFunctionMask;
}; };
struct SHAL_UART_ENABLE_REG{ struct SHAL_UART_Enable_Register{
volatile uint32_t* reg; volatile uint32_t* reg;
uint32_t mask; uint32_t mask;
}; };
struct SHAL_UART_Control_Register_1 {
volatile uint32_t* reg;
uint32_t usart_enable_mask;
uint32_t transmit_enable_mask;
uint32_t receive_enable_mask;
};
struct SHAL_UART_Baud_Rate_Generation_Register {
volatile uint32_t* reg;
uint32_t offset;
};
struct SHAL_UART_Transmit_Data_Register {
volatile uint16_t* reg;
uint16_t offset;
};
struct SHAL_UART_ISR_FIFO_Disabled {
volatile uint32_t* reg;
uint32_t transmit_data_register_empty_mask;
};
#endif //SHMINGO_HAL_SHAL_UART_TYPES_H #endif //SHMINGO_HAL_SHAL_UART_TYPES_H

View File

@@ -11,7 +11,6 @@
#include "SHAL_TIM.h" #include "SHAL_TIM.h"
#include "SHAL_GPIO.h" #include "SHAL_GPIO.h"
#include "SHAL_UART.h" #include "SHAL_UART.h"
#include "SHAL_I2C.h"
#include "SHAL_ADC.h" #include "SHAL_ADC.h"

View File

@@ -64,7 +64,7 @@ SHAL_Result SHAL_ADC::calibrate() {
return SHAL_Result::OKAY; return SHAL_Result::OKAY;
} }
uint16_t SHAL_ADC::singleConvertSingle(SHAL_ADC_Channel channel, ADC_SampleTime time) { uint16_t SHAL_ADC::singleConvertSingle(SHAL_ADC_Channel channel, SHAL_ADC_SampleTime time) {
ADC_TypeDef* ADC_reg = getADCRegister(m_ADCKey); ADC_TypeDef* ADC_reg = getADCRegister(m_ADCKey);
@@ -81,7 +81,7 @@ uint16_t SHAL_ADC::singleConvertSingle(SHAL_ADC_Channel channel, ADC_SampleTime
return result; return result;
} }
void SHAL_ADC::multiConvertSingle(SHAL_ADC_Channel* channels, const int numChannels, uint16_t* result, ADC_SampleTime time) { void SHAL_ADC::multiConvertSingle(SHAL_ADC_Channel* channels, const int numChannels, uint16_t* result, SHAL_ADC_SampleTime time) {
ADC_TypeDef* ADC_reg = getADCRegister(m_ADCKey); ADC_TypeDef* ADC_reg = getADCRegister(m_ADCKey);
ADC->CCR |= ADC_CCR_VREFEN | ADC_CCR_TSEN; //Enable VREFINT and Temp sensor in global ADC struct ADC->CCR |= ADC_CCR_VREFEN | ADC_CCR_TSEN; //Enable VREFINT and Temp sensor in global ADC struct

View File

@@ -107,7 +107,7 @@ void SHAL_GPIO::useAsExternalInterrupt(TriggerMode mode, EXTICallback callback)
__enable_irq(); //Enable IRQ just in case __enable_irq(); //Enable IRQ just in case
} }
uint16_t SHAL_GPIO::analogRead(ADC_SampleTime sampleTime) { uint16_t SHAL_GPIO::analogRead(SHAL_ADC_SampleTime sampleTime) {
SHAL_ADC_Channel channel = getGPIOPortInfo(m_GPIO_KEY).ADCChannel; SHAL_ADC_Channel channel = getGPIOPortInfo(m_GPIO_KEY).ADCChannel;

View File

@@ -10,7 +10,7 @@
#include "SHAL_UART.h" #include "SHAL_UART.h"
#include "SHAL_GPIO.h" #include "SHAL_GPIO.h"
void SHAL_UART::init(const UART_Pair pair){ void SHAL_UART::init(const UART_Pair_Key pair){
m_UARTPair = pair; m_UARTPair = pair;
@@ -26,7 +26,7 @@ void SHAL_UART::init(const UART_Pair pair){
GET_GPIO(Tx_Key).setAlternateFunction(uart_pair.TxAlternateFunctionMask); GET_GPIO(Tx_Key).setAlternateFunction(uart_pair.TxAlternateFunctionMask);
GET_GPIO(Rx_Key).setAlternateFunction(uart_pair.RxAlternateFunctionMask); GET_GPIO(Rx_Key).setAlternateFunction(uart_pair.RxAlternateFunctionMask);
SHAL_UART_ENABLE_REG pairUARTEnable = getUARTEnableReg(pair); //Register and mask to enable the SHAL_UART channel SHAL_UART_Enable_Register pairUARTEnable = getUARTEnableReg(pair); //Register and mask to enable the SHAL_UART channel
*pairUARTEnable.reg |= pairUARTEnable.mask; //Enable SHAL_UART line *pairUARTEnable.reg |= pairUARTEnable.mask; //Enable SHAL_UART line

View File

@@ -9,7 +9,13 @@
#elif defined(STM32L422xx) #elif defined(STM32L422xx)
#elif defined(STM32L431xx) #elif defined(STM32L431xx)
#elif defined(STM32L432xx) #elif defined(STM32L432xx)
DEFINE_EXTI_IRQ() DEFINE_EXTI_IRQ(0);
DEFINE_EXTI_IRQ(1);
DEFINE_EXTI_IRQ(2);
DEFINE_EXTI_IRQ(3);
DEFINE_EXTI_IRQ(4);
DEFINE_MULTI_EXTI_IRQ(5,9);
DEFINE_MULTI_EXTI_IRQ(10,15);
#elif defined(STM32L433xx) #elif defined(STM32L433xx)
#elif defined(STM32L442xx) #elif defined(STM32L442xx)
#elif defined(STM32L443xx) #elif defined(STM32L443xx)

View File

@@ -11,8 +11,6 @@ SHAL_Result SHAL_ADC::init() {
return SHAL_Result::ERROR; return SHAL_Result::ERROR;
} }
ADC_TypeDef* ADC_reg = getADCRegister(m_ADCKey);
SHAL_ADC_RCC_Enable_Reg clock_reg = getADCRCCEnableRegister(m_ADCKey); //Clock enable SHAL_ADC_RCC_Enable_Reg clock_reg = getADCRCCEnableRegister(m_ADCKey); //Clock enable
*clock_reg.reg |= clock_reg.mask; *clock_reg.reg |= clock_reg.mask;
@@ -55,43 +53,84 @@ SHAL_Result SHAL_ADC::calibrate() {
return SHAL_Result::OKAY; return SHAL_Result::OKAY;
} }
uint16_t SHAL_ADC::singleConvertSingle(SHAL_ADC_Channel channel, ADC_SampleTime time) { uint16_t SHAL_ADC::singleConvertSingle(SHAL_ADC_Channel channel, SHAL_ADC_SampleTime time) {
ADC_TypeDef* ADC_reg = getADCRegister(m_ADCKey); auto data_reg = getADCDataReg(m_ADCKey); //Where our output will be stored
auto sampleTimeReg = getADCChannelSamplingTimeRegister(m_ADCKey,channel);
ADC->CCR |= ADC_CCR_VREFEN | ADC_CCR_TSEN; //Enable VREFINT and Temp sensor in global ADC struct SHAL_set_bits(sampleTimeReg.reg,3,static_cast<uint8_t>(time),sampleTimeReg.channel_offset); //Set sample time register TODO un-hardcode bit width?
ADC_reg->CHSELR = static_cast<uint32_t>(channel); //Enable channel for conversion addADCChannelToSequence(channel,0); //Use index 0 to convert channel
ADC_reg->SMPR |= static_cast<uint32_t>(time); //Set sampling time setADCSequenceAmount(1); //Since we're using single convert, convert 1 channel
if(!SHAL_WAIT_FOR_CONDITION_US(((ADC_reg->ISR & ADC_ISR_EOC) != 0),500)){ //Wait for conversion if(enable() != SHAL_Result::OKAY){
return 0;
}
startConversion(); //Start ADC conversion
auto ISR_reg = getADCISRReg(m_ADCKey);
if(!SHAL_WAIT_FOR_CONDITION_US(((*ISR_reg.reg & ISR_reg.end_of_conversion_mask) != 0),500)){ //Wait for conversion
return 0; //Failed return 0; //Failed
} }
uint16_t result = ADC_reg->DR; return *data_reg.reg;
return result;
} }
void SHAL_ADC::multiConvertSingle(SHAL_ADC_Channel* channels, const int numChannels, uint16_t* result, ADC_SampleTime time) { SHAL_Result SHAL_ADC::multiConvertSingle(SHAL_ADC_Channel* channels, const int numChannels, uint16_t* result, SHAL_ADC_SampleTime time) {
ADC_TypeDef* ADC_reg = getADCRegister(m_ADCKey); auto data_reg = getADCDataReg(m_ADCKey); //Where our output will be stored
ADC->CCR |= ADC_CCR_VREFEN | ADC_CCR_TSEN; //Enable VREFINT and Temp sensor in global ADC struct
for(int i = 0; i < numChannels; i++){ //Enable all channels
ADC_reg->CHSELR = static_cast<uint32_t>(channels[i]);
}
ADC_reg->SMPR |= static_cast<uint32_t>(time); //Set sampling time
setADCSequenceAmount(numChannels); //Convert the correct amount of channels
for(int i = 0; i < numChannels; i++){ for(int i = 0; i < numChannels; i++){
if(!SHAL_WAIT_FOR_CONDITION_US(((ADC_reg->ISR & ADC_ISR_EOC) != 0),500)){ //Wait for conversion auto channel = channels[i];
continue; //Failed
}
result[i] = ADC_reg->DR; auto sampleTimeReg = getADCChannelSamplingTimeRegister(m_ADCKey,channel);
SHAL_set_bits(sampleTimeReg.reg,3,static_cast<uint8_t>(time),sampleTimeReg.channel_offset); //Set sample time register TODO un-hardcode bit width?
addADCChannelToSequence(channel,i); //Use index 0 to convert channel
if(enable() != SHAL_Result::OKAY){
return SHAL_Result::ERROR;
}
} }
startConversion(); //Start ADC conversion
auto ISR_reg = getADCISRReg(m_ADCKey);
for(int i = 0; i < numChannels; i++) {
if (!SHAL_WAIT_FOR_CONDITION_US(((*ISR_reg.reg & ISR_reg.end_of_conversion_mask) != 0),500)) { //Wait for conversion
return SHAL_Result::ERROR; //Failed conversion
}
result[i] = *data_reg.reg;
}
if (!SHAL_WAIT_FOR_CONDITION_US(((*ISR_reg.reg & ISR_reg.end_of_sequence_mask) != 0),500)) { //Wait for conversion
return SHAL_Result::ERROR; //Failed sequence
}
return SHAL_Result::OKAY;
}
SHAL_Result SHAL_ADC::enable() {
if(!isValid()){
return SHAL_Result::ERROR;
}
SHAL_ADC_Control_Reg control_reg = getADCControlReg(m_ADCKey);
SHAL_ADC_ISR_Reg ISR_reg = getADCISRReg(m_ADCKey);
*control_reg.reg |= control_reg.enable_mask; //Enable
if(!SHAL_WAIT_FOR_CONDITION_MS((*ISR_reg.reg & ISR_reg.ready_mask) != 0, 100)){
return SHAL_Result::ERROR;
}
return SHAL_Result::OKAY;
} }
SHAL_Result SHAL_ADC::disable() { SHAL_Result SHAL_ADC::disable() {
@@ -113,6 +152,14 @@ SHAL_Result SHAL_ADC::disable() {
return SHAL_Result::OKAY; return SHAL_Result::OKAY;
} }
SHAL_Result SHAL_ADC::startConversion() {
auto control_reg = getADCControlReg(m_ADCKey);
SHAL_apply_bitmask(control_reg.reg,control_reg.start_mask);
return SHAL_Result::OKAY;
}
bool SHAL_ADC::isValid() { bool SHAL_ADC::isValid() {
if(m_ADCKey == ADC_Key::INVALID || m_ADCKey == ADC_Key::NUM_ADC){ if(m_ADCKey == ADC_Key::INVALID || m_ADCKey == ADC_Key::NUM_ADC){
return false; return false;
@@ -145,6 +192,37 @@ SHAL_Result SHAL_ADC::configureAlignment(SHAL_ADC_Alignment alignment) {
return SHAL_Result::OKAY; return SHAL_Result::OKAY;
} }
SHAL_Result SHAL_ADC::setADCSequenceAmount(uint32_t amount) {
if(!isValid()){return SHAL_Result::ERROR;}
if(amount == 0){
return SHAL_Result::ERROR;
}
SHAL_ADC_Sequence_Amount_Reg sequence_amount_reg = getADCSequenceAmountRegister(m_ADCKey);
SHAL_set_bits(sequence_amount_reg.reg, 4, amount - 1, sequence_amount_reg.offset);
return SHAL_Result::OKAY;
}
SHAL_Result SHAL_ADC::addADCChannelToSequence(SHAL_ADC_Channel channel, uint32_t index) {
if(!isValid()){return SHAL_Result::ERROR;}
auto sequenceRegisters = getADCSequenceRegisters(m_ADCKey);
auto channelNum = static_cast<uint8_t>(channel);
uint32_t bitSection = (index + 1) % 5; //Need a new variable since SQR1 has its data bits shifted up by one section to make room for the L section
uint32_t sequenceRegNumber = (index + 1) / 5;
volatile uint32_t* sequenceReg = sequenceRegisters.regs[sequenceRegNumber];
uint32_t bitSectionOffset = sequenceRegisters.offsets[bitSection];
SHAL_set_bits(sequenceReg,5,channelNum,bitSectionOffset);
}
SHAL_ADC &ADCManager::get(ADC_Key key) { SHAL_ADC &ADCManager::get(ADC_Key key) {
return m_ADCs[static_cast<uint8_t>(key)]; return m_ADCs[static_cast<uint8_t>(key)];
} }

View File

@@ -74,32 +74,27 @@ void SHAL_GPIO::useAsExternalInterrupt(TriggerMode mode, EXTICallback callback)
setPinMode(PinMode::INPUT_MODE); //Explicitly set mode to input setPinMode(PinMode::INPUT_MODE); //Explicitly set mode to input
RCC->APB2ENR |= RCC_APB2ENR_SYSCFGCOMPEN; //Enable EXT, TODO check if this is different across STM32 models RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN; //Enable EXT, TODO Add this to a global SHAL_GLOBAL_TYPES.h file
NVIC_EnableIRQ(getGPIOEXTICR(m_GPIO_KEY).IRQN); //Enable IRQN for pin NVIC_EnableIRQ(getGPIOEXTICR(m_GPIO_KEY).IRQN); //Enable IRQN for pin
EXTI->IMR |= (1 << gpioPin); //Enable correct EXTI line
SHAL_EXTIO_Register EXTILineEnable = getGPIOEXTICR(m_GPIO_KEY); auto ext_imr = getEXTIInterruptMaskRegister(gpioPin);
SHAL_set_bits(ext_imr.reg,1,1,gpioPin);
SHAL_GPIO_EXTI_Register EXTILineEnable = getGPIOEXTICR(m_GPIO_KEY);
*EXTILineEnable.EXT_ICR |= EXTILineEnable.mask; //Set bits to enable correct port on correct line TODO Find way to clear bits before *EXTILineEnable.EXT_ICR |= EXTILineEnable.mask; //Set bits to enable correct port on correct line TODO Find way to clear bits before
uint32_t rising_mask = 0x00; uint32_t rising_mask = 0x00;
uint32_t falling_mask = 0x00; uint32_t falling_mask = 0x00;
//Set rising and falling edge triggers based on pin offset (enabled EXTI line) if(mode == TriggerMode::RISING_EDGE || mode == TriggerMode::RISING_FALLING_EDGE) {
switch(mode){ auto rising_trigger_selection_reg = getEXTIRisingTriggerSelectionRegister(gpioPin);
case TriggerMode::RISING_EDGE: SHAL_set_bits(rising_trigger_selection_reg.reg, 1, 1, gpioPin);
rising_mask = 1 << gpioPin;
break;
case TriggerMode::FALLING_EDGE:
falling_mask = 1 << gpioPin;
break;
case TriggerMode::RISING_FALLING_EDGE:
falling_mask = 1 << gpioPin;
falling_mask = 1 << gpioPin;
} }
//Set triggers if(mode == TriggerMode::FALLING_EDGE || mode == TriggerMode::RISING_FALLING_EDGE) {
EXTI->RTSR |= rising_mask; auto falling_trigger_selection_reg = getEXTIFallingTriggerSelectionRegister(gpioPin);
EXTI->FTSR |= falling_mask; SHAL_set_bits(falling_trigger_selection_reg.reg,1,1,gpioPin);
}
//Set callback //Set callback
registerEXTICallback(m_GPIO_KEY,callback); registerEXTICallback(m_GPIO_KEY,callback);
@@ -107,7 +102,7 @@ void SHAL_GPIO::useAsExternalInterrupt(TriggerMode mode, EXTICallback callback)
__enable_irq(); //Enable IRQ just in case __enable_irq(); //Enable IRQ just in case
} }
uint16_t SHAL_GPIO::analogRead(ADC_SampleTime sampleTime) { uint16_t SHAL_GPIO::analogRead(SHAL_ADC_SampleTime sampleTime) {
SHAL_ADC_Channel channel = getGPIOPortInfo(m_GPIO_KEY).ADCChannel; SHAL_ADC_Channel channel = getGPIOPortInfo(m_GPIO_KEY).ADCChannel;

View File

@@ -5,40 +5,50 @@
#include "SHAL_TIM.h" #include "SHAL_TIM.h"
#include <cassert> #include <cassert>
Timer::Timer(Timer_Key t) : TIMER_KEY(t){ Timer::Timer(Timer_Key key) : m_key(key){
} }
Timer::Timer() : TIMER_KEY(Timer_Key::S_TIM_INVALID){ Timer::Timer() : m_key(Timer_Key::S_TIM_INVALID){
} }
void Timer::start() { void Timer::start() {
getTimerRegister(TIMER_KEY)->CR1 |= TIM_CR1_CEN;
getTimerRegister(TIMER_KEY)->EGR |= TIM_EGR_UG; //load prescaler reg and ARR auto control_reg = getTimerControlRegister1(m_key);
auto event_generation_reg = getTimerEventGenerationRegister(m_key);
SHAL_apply_bitmask(control_reg.reg, control_reg.counter_enable_mask); //Enable counter
SHAL_apply_bitmask(event_generation_reg.reg, event_generation_reg.update_generation_mask);
enableInterrupt(); enableInterrupt();
} }
void Timer::stop() { void Timer::stop() {
getTimerRegister(TIMER_KEY)->CR1 &= ~TIM_CR1_CEN; auto control_reg = getTimerControlRegister1(m_key);
SHAL_clear_bitmask(control_reg.reg, control_reg.counter_enable_mask); //Enable counter
} }
void Timer::setPrescaler(uint16_t presc) { void Timer::setPrescaler(uint16_t presc) {
getTimerRegister(TIMER_KEY)->PSC = presc; auto prescaler_reg = getTimerPrescalerRegister(m_key);
SHAL_set_bits(prescaler_reg.reg, 16, presc, prescaler_reg.offset);
} }
void Timer::setARR(uint16_t arr) { void Timer::setARR(uint16_t arr) {
getTimerRegister(TIMER_KEY)->ARR = arr; auto autoreload_reg = getTimerAutoReloadRegister(m_key);
SHAL_set_bits(autoreload_reg.reg, 16, arr, autoreload_reg.offset);
} }
void Timer::enableInterrupt() { void Timer::enableInterrupt() {
getTimerRegister(TIMER_KEY)->DIER |= TIM_DIER_UIE; auto dma_ier = getTimerDMAInterruptEnableRegister(m_key);
NVIC_EnableIRQ(getIRQn(TIMER_KEY)); SHAL_apply_bitmask(dma_ier.reg,dma_ier.update_interrupt_enable_mask);
NVIC_EnableIRQ(getTimerIRQn(m_key)); //Enable the IRQn in the NVIC
} }
void Timer::init(uint32_t prescaler, uint32_t autoReload) { void Timer::init(uint32_t prescaler, uint32_t autoReload) {
TIM_RCC_Enable rcc = getTimerRCC(TIMER_KEY); SHAL_TIM_RCC_Register rcc = getTimerRCC(m_key);
*rcc.busEnableReg |= (1 << rcc.offset); SHAL_apply_bitmask(rcc.reg,rcc.enable_mask);
setPrescaler(prescaler); setPrescaler(prescaler);
setARR(autoReload); setARR(autoReload);
@@ -53,11 +63,9 @@ Timer &TimerManager::get(Timer_Key timer_key) {
Timer& selected = timers[static_cast<int>(timer_key)]; Timer& selected = timers[static_cast<int>(timer_key)];
//Timer queried is not initialized yet (defaults to invalid) //Timer queried is not initialized yet (defaults to invalid)
if(selected.TIMER_KEY == Timer_Key::S_TIM_INVALID){ if(selected.m_key == Timer_Key::S_TIM_INVALID){
timers[static_cast<int>(timer_key)] = Timer(timer_key); //Initialize TIMER_KEY timers[static_cast<int>(timer_key)] = Timer(timer_key); //Initialize TIMER_KEY
} }
return timers[static_cast<int>(timer_key)]; return timers[static_cast<int>(timer_key)];
} }

View File

@@ -4,13 +4,12 @@
#include "SHAL_TIM_CALLBACK.h" #include "SHAL_TIM_CALLBACK.h"
DEFINE_TIMER_IRQ(Timer_Key::S_TIM1, TIM1_BRK_UP_TRG_COM_IRQHandler) DEFINE_TIMER_IRQ(Timer_Key::S_TIM1, TIM1_IRQHandler)
DEFINE_TIMER_IRQ(Timer_Key::S_TIM2, TIM2_IRQHandler) DEFINE_TIMER_IRQ(Timer_Key::S_TIM2, TIM2_IRQHandler)
DEFINE_TIMER_IRQ(Timer_Key::S_TIM3, TIM3_IRQHandler) DEFINE_TIMER_IRQ(Timer_Key::S_TIM6, TIM6_IRQHandler)
DEFINE_TIMER_IRQ(Timer_Key::S_TIM14, TIM14_IRQHandler) DEFINE_TIMER_IRQ(Timer_Key::S_TIM7, TIM7_IRQHandler)
DEFINE_TIMER_IRQ(Timer_Key::S_TIM15, TIM15_IRQHandler) DEFINE_TIMER_IRQ(Timer_Key::S_TIM15, TIM15_IRQHandler)
DEFINE_TIMER_IRQ(Timer_Key::S_TIM16, TIM16_IRQHandler) DEFINE_TIMER_IRQ(Timer_Key::S_TIM16, TIM16_IRQHandler)
DEFINE_TIMER_IRQ(Timer_Key::S_TIM17, TIM17_IRQHandler)
void registerTimerCallback(Timer_Key key, TimerCallback callback){ void registerTimerCallback(Timer_Key key, TimerCallback callback){
timer_callbacks[static_cast<int>(key)] = callback; timer_callbacks[static_cast<int>(key)] = callback;

View File

@@ -10,9 +10,9 @@
#include "SHAL_UART.h" #include "SHAL_UART.h"
#include "SHAL_GPIO.h" #include "SHAL_GPIO.h"
void SHAL_UART::init(const UART_Pair pair){ void SHAL_UART::init(UART_Pair_Key pair){
m_UARTPair = pair; m_key = pair;
SHAL_UART_Pair uart_pair = getUARTPair(pair); //Get the UART_PAIR information to be initialized SHAL_UART_Pair uart_pair = getUARTPair(pair); //Get the UART_PAIR information to be initialized
@@ -26,7 +26,7 @@ void SHAL_UART::init(const UART_Pair pair){
GET_GPIO(Tx_Key).setAlternateFunction(uart_pair.TxAlternateFunctionMask); GET_GPIO(Tx_Key).setAlternateFunction(uart_pair.TxAlternateFunctionMask);
GET_GPIO(Rx_Key).setAlternateFunction(uart_pair.RxAlternateFunctionMask); GET_GPIO(Rx_Key).setAlternateFunction(uart_pair.RxAlternateFunctionMask);
SHAL_UART_ENABLE_REG pairUARTEnable = getUARTEnableReg(pair); //Register and mask to enable the SHAL_UART channel SHAL_UART_Enable_Register pairUARTEnable = getUARTEnableReg(pair); //Register and mask to enable the SHAL_UART channel
*pairUARTEnable.reg |= pairUARTEnable.mask; //Enable SHAL_UART line *pairUARTEnable.reg |= pairUARTEnable.mask; //Enable SHAL_UART line
@@ -35,18 +35,23 @@ void SHAL_UART::init(const UART_Pair pair){
void SHAL_UART::begin(uint32_t baudRate) volatile { void SHAL_UART::begin(uint32_t baudRate) volatile {
USART_TypeDef* usart = getUARTPair(m_UARTPair).USARTReg; USART_TypeDef* usart = getUARTPair(m_key).USARTReg;
usart->CR1 &= ~USART_CR1_UE; //Disable USART auto control_reg = getUARTControlRegister1(m_key);
SHAL_clear_bitmask(control_reg.reg, control_reg.usart_enable_mask); //Clear enable bit (turn off usart)
usart->CR1 = 0; //Clear USART config usart->CR1 = 0; //Clear USART config
usart->CR1 = USART_CR1_TE | USART_CR1_RE; //Tx enable and Rx Enable SHAL_apply_bitmask(control_reg.reg, control_reg.transmit_enable_mask); //Enable Tx
SHAL_apply_bitmask(control_reg.reg, control_reg.receive_enable_mask); //Enable Rx
usart->BRR = 8000000 / baudRate; //MAKE SURE ANY FUNCTION THAT CHANGES CLOCK UPDATES THIS! //TODO DO NOT HARDCODE THIS SHIT auto baud_rate_reg = getUARTBaudRateGenerationRegister(m_key);
usart->CR1 |= USART_CR1_UE; unsigned long adjustedBaudRate = 8000000 / baudRate;
SHAL_set_bits(baud_rate_reg.reg,16,adjustedBaudRate,baud_rate_reg.offset); //MAKE SURE ANY FUNCTION THAT CHANGES CLOCK UPDATES THIS! //TODO DO NOT HARDCODE THIS SHIT
SHAL_apply_bitmask(control_reg.reg, control_reg.usart_enable_mask); //Clear enable bit (turn off usart)
} }
void SHAL_UART::sendString(const char *s) volatile { void SHAL_UART::sendString(const char *s) volatile {
@@ -55,11 +60,14 @@ void SHAL_UART::sendString(const char *s) volatile {
void SHAL_UART::sendChar(char c) volatile { void SHAL_UART::sendChar(char c) volatile {
USART_TypeDef* usart = getUARTPair(m_UARTPair).USARTReg; auto ISR_non_fifo = getUARTISRFifoDisabled(m_key);
while(!(usart->ISR & USART_ISR_TXE)); //Wait for usart to finish what it's doing if(!SHAL_WAIT_FOR_CONDITION_US((*ISR_non_fifo.reg & ISR_non_fifo.transmit_data_register_empty_mask) == 0, 500)){
return;
}
usart->TDR = c; //Send character auto transmit_reg = getUARTTransmitDataRegister(m_key);
SHAL_set_bits_16(transmit_reg.reg,16,static_cast<uint16_t>(c),transmit_reg.offset);
} }

View File

@@ -1,86 +1,9 @@
#include "SHAL.h" #include "SHAL.h"
#include "stm32f0xx.h"
#include <cstdlib> #include <cstdlib>
void c3Interrupt(){
SHAL_UART2.sendString("Begin\r\n");
uint8_t cmd[3] = {0xAC, 0x33, 0x00};
SHAL_I2C1.masterWrite(0x38, cmd, 3);
SHAL_delay_ms(100);
uint8_t dht_buf[7] = {0};
//Read 7 bytes (status + 5 data + CRC)
SHAL_I2C1.masterRead(0x38, dht_buf, 7);
//Parse humidity (20 bits)
uint32_t rawHumidity = ((uint32_t)dht_buf[1] << 12) |
((uint32_t)dht_buf[2] << 4) |
((uint32_t)dht_buf[3] >> 4);
uint32_t rawTemp = (((uint32_t)dht_buf[3] & 0x0F) << 16) |
((uint32_t)dht_buf[4] << 8) |
((uint32_t)dht_buf[5]);
// Use 64-bit intermediate to avoid overflow
uint32_t hum_hundredths = (uint32_t)(((uint64_t)rawHumidity * 10000ULL) >> 20);
int32_t temp_hundredths = (int32_t)((((uint64_t)rawTemp * 20000ULL) >> 20) - 5000);
char out[80];
sprintf(out, "rawH=0x%05lX rawT=0x%05lX\r\n",
(unsigned long)rawHumidity, (unsigned long)rawTemp);
SHAL_UART2.sendString(out);
// print as X.YY
sprintf(out, "Temp: %ld.%02ld C, Hum: %ld.%02ld %%\r\n",
(long)(temp_hundredths / 100), (long)(abs(temp_hundredths % 100)),
(long)(hum_hundredths / 100), (long)(hum_hundredths % 100));
SHAL_UART2.sendString(out);
}
void tim2Handler(){
PIN(A4).toggle();
}
int main() { int main() {
SHAL_init();
//Setup UART2 (used by nucleo devices for USB comms)
SHAL_UART2.init(UART_Pair::Tx2A2_Rx2A3);
SHAL_UART2.begin(115200);
SHAL_I2C1.init(I2C_Pair::SCL1B6_SDA1B7);
SHAL_I2C1.setClockConfig(0x2000090E);
//Use pin C3 to trigger a function on external interrupt
PIN(C3).useAsExternalInterrupt(TriggerMode::RISING_EDGE,c3Interrupt);
SHAL_TIM2.init(8000-1,1500-1);
SHAL_TIM2.setCallbackFunc(tim2Handler);
SHAL_TIM2.start();
PIN(A4).setPinMode(PinMode::OUTPUT_MODE);
PIN(A5).setPinMode(PinMode::OUTPUT_MODE);
SHAL_delay_ms(3000); //Wait 100 ms from datasheet
uint8_t cmd = 0x71;
uint8_t status = 0;
SHAL_I2C1.masterWriteRead(0x38, &cmd, 1, &status, 1);
char statusString[32];
sprintf(statusString, "Status = 0x%02X\r\n", status);
SHAL_UART2.sendString(statusString);
SHAL_delay_ms(10);
c3Interrupt();
//End setup //End setup
while (true) { while (true) {