Compare commits
17 Commits
3561879c24
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 3593d8cbd2 | |||
|
|
7a9cd2f70e | ||
|
|
ec0fea608b | ||
|
|
b50e7c25f6 | ||
|
|
7a24078e18 | ||
|
|
63fab62727 | ||
|
|
a1458de235 | ||
|
|
12aedf1ff9 | ||
|
|
aa7a041946 | ||
|
|
0b4a6ef584 | ||
|
|
e41cf30c87 | ||
|
|
2c5592c2d3 | ||
|
|
e822b8d9ec | ||
|
|
04f79cc543 | ||
|
|
d846897296 | ||
|
|
6c8fa459f8 | ||
|
|
af21480aff |
@@ -7,11 +7,11 @@ set(MCU_FAMILY "STM32L4xx" CACHE STRING "MCU family")
|
|||||||
set(MCU_MODEL "STM32L432xx" CACHE STRING "MCU model")
|
set(MCU_MODEL "STM32L432xx" CACHE STRING "MCU model")
|
||||||
|
|
||||||
set(CPU_PARAMETERS
|
set(CPU_PARAMETERS
|
||||||
-mcpu=cortex-m0
|
-mcpu=cortex-m4
|
||||||
-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
|
||||||
)
|
)
|
||||||
@@ -45,8 +45,8 @@
|
|||||||
* @brief Configuration of the Cortex-M4 Processor and Core Peripherals
|
* @brief Configuration of the Cortex-M4 Processor and Core Peripherals
|
||||||
*/
|
*/
|
||||||
#define __CM4_REV 0x0001U /*!< Cortex-M4 revision r0p1 */
|
#define __CM4_REV 0x0001U /*!< Cortex-M4 revision r0p1 */
|
||||||
#define __MPU_PRESENT 1U /*!< STM32L4XX provides an MPU */
|
#define __MPU_PRESENT 1U /*!< STM32L4xx provides an MPU */
|
||||||
#define __NVIC_PRIO_BITS 4U /*!< STM32L4XX uses 4 Bits for the Priority Levels */
|
#define __NVIC_PRIO_BITS 4U /*!< STM32L4xx uses 4 Bits for the Priority Levels */
|
||||||
#define __Vendor_SysTickConfig 0U /*!< Set to 1 if different SysTick Config is used */
|
#define __Vendor_SysTickConfig 0U /*!< Set to 1 if different SysTick Config is used */
|
||||||
#define __FPU_PRESENT 1U /*!< FPU present */
|
#define __FPU_PRESENT 1U /*!< FPU present */
|
||||||
|
|
||||||
@@ -59,7 +59,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief STM32L4XX Interrupt Number Definition, according to the selected device
|
* @brief STM32L4xx Interrupt Number Definition, according to the selected device
|
||||||
* in @ref Library_configuration_section
|
* in @ref Library_configuration_section
|
||||||
*/
|
*/
|
||||||
typedef enum
|
typedef enum
|
||||||
|
|||||||
5
Makefile
5
Makefile
@@ -5,6 +5,9 @@ BUILD_DIR := build
|
|||||||
BUILD_TYPE ?= Debug
|
BUILD_TYPE ?= Debug
|
||||||
TOOLCHAIN := gcc-arm-none-eabi.cmake
|
TOOLCHAIN := gcc-arm-none-eabi.cmake
|
||||||
|
|
||||||
|
CFLAGS_DEBUG ?= -g3 -O0
|
||||||
|
CXXFLAGS_DEBUG ?= -g3 -O0
|
||||||
|
|
||||||
# MCU target (override on command line: make build MCU_MODEL=STM32F051x8)
|
# MCU target (override on command line: make build MCU_MODEL=STM32F051x8)
|
||||||
MCU_MODEL ?= STM32L432xx
|
MCU_MODEL ?= STM32L432xx
|
||||||
MCU_FAMILY ?= STM32L4xx
|
MCU_FAMILY ?= STM32L4xx
|
||||||
@@ -20,6 +23,8 @@ ${BUILD_DIR}/build.ninja:
|
|||||||
-DCMAKE_BUILD_TYPE=${BUILD_TYPE} \
|
-DCMAKE_BUILD_TYPE=${BUILD_TYPE} \
|
||||||
-DCMAKE_TOOLCHAIN_FILE=${TOOLCHAIN} \
|
-DCMAKE_TOOLCHAIN_FILE=${TOOLCHAIN} \
|
||||||
-DCMAKE_EXPORT_COMPILE_COMMANDS=ON \
|
-DCMAKE_EXPORT_COMPILE_COMMANDS=ON \
|
||||||
|
-DCMAKE_C_FLAGS_DEBUG="${CFLAGS_DEBUG}" \
|
||||||
|
-DCMAKE_CXX_FLAGS_DEBUG="${CXXFLAGS_DEBUG}" \
|
||||||
-DMCU_MODEL=$(MCU_MODEL) \
|
-DMCU_MODEL=$(MCU_MODEL) \
|
||||||
-DMCU_FAMILY=$(MCU_FAMILY)
|
-DMCU_FAMILY=$(MCU_FAMILY)
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
#define SHMINGO_HAL_SHAL_CORE_H
|
#define SHMINGO_HAL_SHAL_CORE_H
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
#include <cstddef>
|
||||||
|
|
||||||
//Overall init function for SHAL --------------------------
|
//Overall init function for SHAL --------------------------
|
||||||
|
|
||||||
@@ -70,16 +71,59 @@ 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){
|
#define SHAL_set_bits(reg, size, bits, offset) \
|
||||||
uint32_t mask = (1 << (size)) - 1;
|
do { \
|
||||||
*reg &= ~(mask << offset);
|
if ((reg) != NULL) { \
|
||||||
*reg |= bits << offset;
|
uint32_t _mask = ((1U << (size)) - 1U); \
|
||||||
}
|
*(reg) &= ~((uint32_t)(_mask) << (offset)); \
|
||||||
|
*(reg) |= ((uint32_t)(bits) << (offset)); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
void SHAL_apply_bitmask(volatile uint32_t* reg, uint32_t mask){
|
#define SHAL_flip_bits(reg, size, offset) \
|
||||||
*reg &= ~(mask);
|
do { \
|
||||||
*reg |= mask;
|
if ((reg) != NULL) { \
|
||||||
}
|
uint32_t _mask = ((1U << (size)) - 1U); \
|
||||||
|
*(reg) ^= (_mask << (offset)); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define SHAL_set_bits_16(reg, size, bits, offset) \
|
||||||
|
do { \
|
||||||
|
if ((reg) != NULL) { \
|
||||||
|
uint16_t _mask = (uint16_t)((1U << (size)) - 1U); \
|
||||||
|
*(reg) &= (uint16_t)~((uint16_t)(_mask) << (offset)); \
|
||||||
|
*(reg) |= (uint16_t)((uint16_t)(bits) << (offset)); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define SHAL_clear_bitmask(reg, mask) \
|
||||||
|
do { \
|
||||||
|
*(reg) &= ~(mask); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define SHAL_apply_bitmask(reg, mask) \
|
||||||
|
do { \
|
||||||
|
SHAL_clear_bitmask((reg), (mask)); \
|
||||||
|
*(reg) |= (mask); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define SHAL_set_register_value(reg, value) \
|
||||||
|
do { \
|
||||||
|
if ((reg) != NULL) { \
|
||||||
|
*(reg) = (uint32_t)(value); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define SHAL_set_register_value_16(reg, value) \
|
||||||
|
do { \
|
||||||
|
if ((reg) != NULL) { \
|
||||||
|
*(reg) = (uint16_t)(value); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
|
||||||
|
void SHAL_print_register(const volatile uint32_t* reg);
|
||||||
|
|
||||||
//---------------------------------------------------------
|
//---------------------------------------------------------
|
||||||
|
|
||||||
|
|||||||
@@ -11,99 +11,151 @@
|
|||||||
#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 = 0,
|
||||||
|
CH1,
|
||||||
|
CH2,
|
||||||
|
CH3,
|
||||||
|
CH4,
|
||||||
|
CH5,
|
||||||
|
CH6,
|
||||||
|
CH7,
|
||||||
|
CH8,
|
||||||
|
CH9,
|
||||||
|
CH10,
|
||||||
|
CH11,
|
||||||
|
CH12,
|
||||||
|
CH13,
|
||||||
|
CH14,
|
||||||
|
CH15,
|
||||||
|
CH16,
|
||||||
|
CHTemp,
|
||||||
|
CHRef,
|
||||||
|
CHBat,
|
||||||
|
NO_ADC_MAPPING
|
||||||
|
};
|
||||||
|
|
||||||
enum class ADC_Key : uint8_t{
|
enum class ADC_Key : uint8_t{
|
||||||
S_ADC1 = 0,
|
S_ADC1 = 0,
|
||||||
NUM_ADC = 1,
|
NUM_ADC = 1,
|
||||||
INVALID = 255
|
INVALID = 255
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class ADC_Clock_Source : uint8_t {
|
enum class ADC_Clock_Source : uint32_t {
|
||||||
SHAL_SYSCLK,
|
SHAL_NO_CLOCK = 0x00,
|
||||||
SHAL_PLLSAI1,
|
SHAL_PLLSAI1 = 0x01,
|
||||||
SHAL_PLL,
|
SHAL_PLLSYS = 0x02,
|
||||||
SHAL_MSI
|
SHAL_SYSCLK = 0x03,
|
||||||
};
|
};
|
||||||
|
|
||||||
static volatile ADC_TypeDef* ADC_TABLE[1] = { //Lookup table for ADCs
|
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 = {&RCC->AHB2ENR, RCC_AHB2ENR_ADCEN};
|
||||||
|
|
||||||
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_ADSTP,
|
||||||
|
ADC_CR_ADDIS,
|
||||||
|
ADC_CR_ADCAL,
|
||||||
|
ADC_CR_ADSTART,
|
||||||
|
ADC_CR_DEEPPWD,
|
||||||
|
ADC_CR_ADVREGEN,
|
||||||
|
ADC_CR_ADCALDIF};
|
||||||
|
|
||||||
res.reg = &(ADC_TABLE[static_cast<uint8_t>(key)]->CR);
|
res.reg = &(ADC_TABLE[static_cast<uint8_t>(key)]->CR);
|
||||||
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, ADC_CFGR_CONT_Msk};
|
||||||
|
|
||||||
res.reg = &(ADC_TABLE[static_cast<uint8_t>(key)]->CFGR);
|
res.reg = &(ADC_TABLE[static_cast<uint8_t>(key)]->CFGR);
|
||||||
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, ADC_ISR_OVR};
|
||||||
|
|
||||||
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() {
|
||||||
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_Pos}; //Position
|
||||||
|
|
||||||
switch(clockSource){
|
|
||||||
case ADC_Clock_Source::SHAL_PLLSAI1:
|
|
||||||
res.mask = 1U << RCC_CCIPR_ADCSEL_Pos;
|
|
||||||
case ADC_Clock_Source::SHAL_PLL:
|
|
||||||
res.mask = 2U << RCC_CCIPR_ADCSEL_Pos;
|
|
||||||
case ADC_Clock_Source::SHAL_SYSCLK:
|
|
||||||
res.mask = 3U << RCC_CCIPR_ADCSEL_Pos;
|
|
||||||
case ADC_Clock_Source::SHAL_MSI:
|
|
||||||
break; //TODO implement this
|
|
||||||
}
|
|
||||||
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);
|
||||||
|
|
||||||
if (channelNum <= 9) {
|
if (channelNum <= 9) {
|
||||||
SMPReg = &ADCReg->SQR1;
|
SMPReg = &ADCReg->SMPR1;
|
||||||
pos = (channelNum * 3);
|
pos = (channelNum * 3);
|
||||||
} else {
|
} else {
|
||||||
SMPReg = &ADCReg->SQR2;
|
SMPReg = &ADCReg->SMPR2;
|
||||||
pos = ((channelNum - 10) * 3);
|
pos = ((channelNum - 10) * 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
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},
|
||||||
|
{0,
|
||||||
|
6,
|
||||||
|
12,
|
||||||
|
18,
|
||||||
|
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:
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ class SHAL_ADC {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
SHAL_Result init();
|
SHAL_Result init(ADC_Key key);
|
||||||
|
|
||||||
SHAL_Result calibrate();
|
SHAL_Result calibrate();
|
||||||
|
|
||||||
@@ -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,31 @@ 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();
|
||||||
|
|
||||||
|
//Wake up ADC from initial deep sleep state
|
||||||
|
SHAL_Result wakeFromDeepSleep();
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -5,84 +5,90 @@
|
|||||||
#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;
|
||||||
|
uint32_t stop_mask;
|
||||||
uint32_t disable_mask;
|
uint32_t disable_mask;
|
||||||
uint32_t calibration_mask;
|
uint32_t calibration_mask;
|
||||||
uint32_t start_mask;
|
uint32_t start_mask;
|
||||||
|
uint32_t deep_power_down_mask;
|
||||||
|
uint32_t voltage_regulator_mask;
|
||||||
|
uint32_t differential_mode_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;
|
||||||
|
|
||||||
uint32_t resolution_offset;
|
uint32_t resolution_offset;
|
||||||
uint32_t alignment_offset;
|
uint32_t alignment_offset;
|
||||||
|
uint32_t continuous_mode_mask;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//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;
|
||||||
|
uint32_t overrun_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 offset;
|
||||||
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
|
||||||
|
|||||||
@@ -6,7 +6,32 @@
|
|||||||
#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_Control_Register getEXTIControlRegister(uint32_t line){
|
||||||
|
uint8_t maskOffset = line % 4; //Each register has four 4-bit wide fields
|
||||||
|
uint8_t registerOffset = line / 4; //Composed of four registers with 4 fields each
|
||||||
|
|
||||||
|
SHAL_EXTI_Control_Register res = {&SYSCFG->EXTICR[registerOffset], maskOffset};
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline SHAL_EXTI_Interrupt_Mask_Register getEXTIInterruptMaskRegister(uint32_t line){
|
||||||
|
volatile uint32_t* reg = line < 32 ? &EXTI->IMR1 : &EXTI->IMR2;
|
||||||
|
return {reg};;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline SHAL_EXTI_Rising_Trigger_Selection_Register getEXTIRisingTriggerSelectionRegister(uint32_t line){
|
||||||
|
volatile uint32_t* reg = line < 32 ? &EXTI->RTSR1 : &EXTI->RTSR2;
|
||||||
|
return {reg};
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline SHAL_EXTI_Falling_Trigger_Selection_Register getEXTIFallingTriggerSelectionRegister(uint32_t line){
|
||||||
|
volatile uint32_t* 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
|
||||||
|
|||||||
27
SHAL/Include/Peripheral/EXT/SHAL_EXTI_TYPES.h
Normal file
27
SHAL/Include/Peripheral/EXT/SHAL_EXTI_TYPES.h
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
//
|
||||||
|
// 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;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SHAL_EXTI_Control_Register {
|
||||||
|
volatile uint32_t* reg;
|
||||||
|
uint32_t offset;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //SHMINGO_HAL_SHAL_EXTI_TYPES_H
|
||||||
@@ -10,83 +10,69 @@
|
|||||||
|
|
||||||
#include "SHAL_GPIO_TYPES.h"
|
#include "SHAL_GPIO_TYPES.h"
|
||||||
|
|
||||||
#define AVAILABLE_PORTS 3
|
#define AVAILABLE_PORTS 2
|
||||||
#define PINS_PER_PORT 16
|
#define PINS_PER_PORT 16
|
||||||
#define NUM_EXTI_LINES 16
|
#define NUM_EXTI_LINES 16
|
||||||
|
|
||||||
#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(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(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
|
||||||
enum class GPIO_Key : uint8_t {
|
enum class GPIO_Key : uint8_t {
|
||||||
#define X(key) key,
|
A0 = 0,
|
||||||
AVAILABLE_GPIO
|
A1 = 1,
|
||||||
#undef X
|
A2 = 2,
|
||||||
|
A3 = 3,
|
||||||
|
A4 = 4,
|
||||||
|
A5 = 5,
|
||||||
|
A6 = 6,
|
||||||
|
A7 = 7,
|
||||||
|
A8 = 8,
|
||||||
|
A9,
|
||||||
|
A10,
|
||||||
|
A11,
|
||||||
|
A12,
|
||||||
|
A13,
|
||||||
|
A14,
|
||||||
|
A15,
|
||||||
|
B0,
|
||||||
|
B1,
|
||||||
|
B3 = 19, //Offset to compensate for lack of B2
|
||||||
|
B4,
|
||||||
|
B5,
|
||||||
|
B6,
|
||||||
|
B7,
|
||||||
NUM_GPIO,
|
NUM_GPIO,
|
||||||
INVALID
|
INVALID
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class GPIO_Alternate_Function_Mapping {
|
||||||
|
A0_TIM2CH1 = 0x01,
|
||||||
|
A1_TIM2CH2 = 0x01,
|
||||||
|
A2_TIM2CH3 = 0x01,
|
||||||
|
A3_TIM2CH4 = 0x01,
|
||||||
|
A5_TIM2CH1 = 0x01,
|
||||||
|
A6_TIM1BKIN = 0x01,
|
||||||
|
A7_TIM1CH1N = 0x01,
|
||||||
|
A8_TIM1CH1 = 0x01,
|
||||||
|
A9_TIM1CH2 = 0x01,
|
||||||
|
A10_TIM1CH3 = 0x01,
|
||||||
|
A11_TIM1CH4 = 0x01,
|
||||||
|
A12_TIM1ETR = 0x01,
|
||||||
|
A15_TIM2CH1 = 0x01,
|
||||||
|
B0_TIM1CH2N = 0x01,
|
||||||
|
B1_TIM1CH3N = 0x01,
|
||||||
|
};
|
||||||
|
|
||||||
|
static volatile GPIO_TypeDef * GPIO_TABLE[2] = { //Lookup table for ADCs
|
||||||
|
GPIOA,
|
||||||
|
GPIOB
|
||||||
|
};
|
||||||
|
|
||||||
constexpr SHAL_GPIO_Peripheral getGPIORegister(const GPIO_Key g){
|
constexpr uint8_t getGPIOPinNumber(GPIO_Key key){
|
||||||
switch(g) {
|
return static_cast<uint8_t>(key) % 16;
|
||||||
case GPIO_Key::A0: return {GPIOA,0};
|
}
|
||||||
case GPIO_Key::A1: return {GPIOA,1};
|
|
||||||
case GPIO_Key::A2: return {GPIOA,2};
|
constexpr uint8_t getGPIOPortNUmber(GPIO_Key key){
|
||||||
case GPIO_Key::A3: return {GPIOA,3};
|
return static_cast<uint8_t>(key) / 16;
|
||||||
case GPIO_Key::A4: return {GPIOA,4};
|
|
||||||
case GPIO_Key::A5: return {GPIOA,5};
|
|
||||||
case GPIO_Key::A6: return {GPIOA,6};
|
|
||||||
case GPIO_Key::A7: return {GPIOA,7};
|
|
||||||
case GPIO_Key::A8: return {GPIOA,8};
|
|
||||||
case GPIO_Key::A9: return {GPIOA,9};
|
|
||||||
case GPIO_Key::A10: return {GPIOA,10};
|
|
||||||
case GPIO_Key::A11: return {GPIOA,11};
|
|
||||||
case GPIO_Key::A12: return {GPIOA,12};
|
|
||||||
case GPIO_Key::A13: return {GPIOA,13};
|
|
||||||
case GPIO_Key::A14: return {GPIOA,14};
|
|
||||||
case GPIO_Key::A15: return {GPIOA,15};
|
|
||||||
case GPIO_Key::B0: return {GPIOB,0};
|
|
||||||
case GPIO_Key::B1: return {GPIOB,1};
|
|
||||||
case GPIO_Key::B2: return {GPIOB,2};
|
|
||||||
case GPIO_Key::B3: return {GPIOB,3};
|
|
||||||
case GPIO_Key::B4: return {GPIOB,4};
|
|
||||||
case GPIO_Key::B5: return {GPIOB,5};
|
|
||||||
case GPIO_Key::B6: return {GPIOB,6};
|
|
||||||
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::NUM_GPIO:
|
|
||||||
assert(false);
|
|
||||||
return SHAL_GPIO_Peripheral(nullptr,0); //Unreachable
|
|
||||||
}
|
|
||||||
__builtin_unreachable();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr SHAL_GPIO_EXTI_Register getGPIOEXTICR(const GPIO_Key g){
|
constexpr SHAL_GPIO_EXTI_Register getGPIOEXTICR(const GPIO_Key g){
|
||||||
@@ -114,8 +100,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:
|
||||||
@@ -125,201 +110,117 @@ constexpr SHAL_GPIO_EXTI_Register getGPIOEXTICR(const GPIO_Key g){
|
|||||||
__builtin_unreachable();
|
__builtin_unreachable();
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr SHAL_Peripheral_Register getGPIORCCEnable(const GPIO_Key g){
|
static inline SHAL_GPIO_RCC_Enable_Register getGPIORCCEnable(const GPIO_Key g){
|
||||||
switch(g) {
|
volatile uint32_t* reg = &RCC->AHB2ENR; //register
|
||||||
case GPIO_Key::A0:
|
uint32_t offset;
|
||||||
case GPIO_Key::A1:
|
offset = (static_cast<uint8_t>(g) / 16) == 0 ? RCC_AHB2ENR_GPIOAEN_Pos : RCC_AHB2ENR_GPIOBEN_Pos;
|
||||||
case GPIO_Key::A2:
|
|
||||||
case GPIO_Key::A3:
|
return {reg,offset};
|
||||||
case GPIO_Key::A4:
|
|
||||||
case GPIO_Key::A5:
|
|
||||||
case GPIO_Key::A6:
|
|
||||||
case GPIO_Key::A7:
|
|
||||||
case GPIO_Key::A8:
|
|
||||||
case GPIO_Key::A9:
|
|
||||||
case GPIO_Key::A10:
|
|
||||||
case GPIO_Key::A11:
|
|
||||||
case GPIO_Key::A12:
|
|
||||||
case GPIO_Key::A13:
|
|
||||||
case GPIO_Key::A14:
|
|
||||||
case GPIO_Key::A15:
|
|
||||||
return {&RCC->AHB2ENR, RCC_AHB2ENR_GPIOAEN_Pos};
|
|
||||||
case GPIO_Key::B0:
|
|
||||||
case GPIO_Key::B1:
|
|
||||||
case GPIO_Key::B2:
|
|
||||||
case GPIO_Key::B3:
|
|
||||||
case GPIO_Key::B4:
|
|
||||||
case GPIO_Key::B5:
|
|
||||||
case GPIO_Key::B6:
|
|
||||||
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};
|
|
||||||
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::NUM_GPIO:
|
|
||||||
assert(false);
|
|
||||||
return SHAL_Peripheral_Register(nullptr,0); //Unreachable
|
|
||||||
}
|
|
||||||
__builtin_unreachable();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr uint32_t getGPIOPortNumber(const GPIO_Key g){
|
constexpr uint32_t getGPIOPortNumber(const GPIO_Key g){
|
||||||
switch(g) {
|
return (static_cast<uint8_t>(g) / 16);
|
||||||
case GPIO_Key::A0:
|
}
|
||||||
case GPIO_Key::A1:
|
|
||||||
case GPIO_Key::A2:
|
static inline SHAL_GPIO_Mode_Register getGPIOModeRegister(const GPIO_Key key){
|
||||||
case GPIO_Key::A3:
|
volatile uint32_t* reg = &GPIO_TABLE[static_cast<uint8_t>(key) / 16]->MODER;
|
||||||
case GPIO_Key::A4:
|
uint32_t offset = 2 * (static_cast<uint8_t>(key) % 16);
|
||||||
case GPIO_Key::A5:
|
return {reg,offset};
|
||||||
case GPIO_Key::A6:
|
}
|
||||||
case GPIO_Key::A7:
|
|
||||||
case GPIO_Key::A8:
|
static inline SHAL_GPIO_Pullup_Pulldown_Register getGPIOPUPDRegister(const GPIO_Key key){
|
||||||
case GPIO_Key::A9:
|
volatile uint32_t* reg = &GPIO_TABLE[static_cast<uint8_t>(key) / 16]->PUPDR;
|
||||||
case GPIO_Key::A10:
|
uint32_t offset = 2 * static_cast<uint8_t>(key) % 16;
|
||||||
case GPIO_Key::A11:
|
return {reg,offset};
|
||||||
case GPIO_Key::A12:
|
}
|
||||||
case GPIO_Key::A13:
|
|
||||||
case GPIO_Key::A14:
|
static inline SHAL_GPIO_Alternate_Function_Register getGPIOAlternateFunctionRegister(const GPIO_Key key){
|
||||||
case GPIO_Key::A15:
|
|
||||||
return 0;
|
uint32_t pinNumber = static_cast<uint8_t>(key) % 16; //Number of pin (We need 0-7 to be AFR 1 and 8-15 to be AFR 2)
|
||||||
case GPIO_Key::B0:
|
uint32_t afrIndex = pinNumber < 8 ? 0 : 1;
|
||||||
case GPIO_Key::B1:
|
|
||||||
case GPIO_Key::B2:
|
volatile uint32_t* reg = &GPIO_TABLE[static_cast<uint8_t>(key) / 16]->AFR[afrIndex];
|
||||||
case GPIO_Key::B3:
|
uint32_t offset = (pinNumber % 8) * 4; //Increment in groups of four
|
||||||
case GPIO_Key::B4:
|
return {reg,offset};
|
||||||
case GPIO_Key::B5:
|
}
|
||||||
case GPIO_Key::B6:
|
|
||||||
case GPIO_Key::B7:
|
static inline SHAL_GPIO_Output_Speed_Register getGPIOOutputSpeedRegister(const GPIO_Key key){
|
||||||
case GPIO_Key::B8:
|
volatile uint32_t* reg = &GPIO_TABLE[static_cast<uint8_t>(key) / 16]->OSPEEDR;
|
||||||
case GPIO_Key::B9:
|
uint32_t offset = 2 * static_cast<uint8_t>(key) % 16;
|
||||||
case GPIO_Key::B10:
|
return {reg,offset};
|
||||||
case GPIO_Key::B11:
|
}
|
||||||
case GPIO_Key::B12:
|
|
||||||
case GPIO_Key::B13:
|
static inline SHAL_GPIO_Output_Type_Register getGPIOOutputTypeRegister(const GPIO_Key key){
|
||||||
case GPIO_Key::B14:
|
volatile uint32_t* reg = &GPIO_TABLE[static_cast<uint8_t>(key) / 16]->OTYPER;
|
||||||
case GPIO_Key::B15:
|
uint32_t offset = static_cast<uint8_t>(key) % 16;
|
||||||
return 1;
|
return {reg,offset};
|
||||||
case GPIO_Key::C0:
|
}
|
||||||
case GPIO_Key::C1:
|
|
||||||
case GPIO_Key::C2:
|
static inline SHAL_GPIO_Output_Data_Register getGPIOOutputDataRegister(const GPIO_Key key){
|
||||||
case GPIO_Key::C3:
|
volatile uint32_t* reg = &GPIO_TABLE[static_cast<uint8_t>(key) / 16]->ODR;
|
||||||
case GPIO_Key::C4:
|
uint32_t offset = (static_cast<uint8_t>(key) % 16);
|
||||||
case GPIO_Key::C5:
|
return {reg,offset};
|
||||||
case GPIO_Key::C6:
|
}
|
||||||
case GPIO_Key::C7:
|
|
||||||
case GPIO_Key::C8:
|
static inline SHAL_GPIO_Input_Data_Register getGPIOInputDataRegister(const GPIO_Key key){
|
||||||
case GPIO_Key::C9:
|
volatile uint32_t* reg = &GPIO_TABLE[static_cast<uint8_t>(key) / 16]->IDR;
|
||||||
case GPIO_Key::C10:
|
uint32_t offset = static_cast<uint8_t>(key) % 16;
|
||||||
case GPIO_Key::C11:
|
return {reg,offset};
|
||||||
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::NUM_GPIO:
|
|
||||||
assert(false);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
__builtin_unreachable();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr SHAL_GPIO_Port_Info getGPIOPortInfo(GPIO_Key key){
|
constexpr SHAL_GPIO_Port_Info getGPIOPortInfo(GPIO_Key key){
|
||||||
switch(key){
|
switch(key){
|
||||||
case GPIO_Key::A0:
|
case GPIO_Key::A0:
|
||||||
|
return {0, SHAL_ADC_Channel::CH5};
|
||||||
case GPIO_Key::B0:
|
case GPIO_Key::B0:
|
||||||
case GPIO_Key::C0:
|
return {0, SHAL_ADC_Channel::CH15};
|
||||||
return {0, SHAL_ADC_Channel::CH0};
|
|
||||||
case GPIO_Key::A1:
|
case GPIO_Key::A1:
|
||||||
|
return {1, SHAL_ADC_Channel::CH6};
|
||||||
case GPIO_Key::B1:
|
case GPIO_Key::B1:
|
||||||
case GPIO_Key::C1:
|
return {1, SHAL_ADC_Channel::CH16};
|
||||||
return {1, SHAL_ADC_Channel::CH1};
|
|
||||||
case GPIO_Key::A2:
|
case GPIO_Key::A2:
|
||||||
case GPIO_Key::B2:
|
return {2, SHAL_ADC_Channel::CH7};
|
||||||
case GPIO_Key::C2:
|
|
||||||
return {2, SHAL_ADC_Channel::CH2};
|
|
||||||
case GPIO_Key::A3:
|
case GPIO_Key::A3:
|
||||||
|
return {3, SHAL_ADC_Channel::CH8};
|
||||||
case GPIO_Key::B3:
|
case GPIO_Key::B3:
|
||||||
case GPIO_Key::C3:
|
return {3, SHAL_ADC_Channel::NO_ADC_MAPPING};
|
||||||
return {3, SHAL_ADC_Channel::CH3};
|
|
||||||
case GPIO_Key::A4:
|
case GPIO_Key::A4:
|
||||||
|
return {4, SHAL_ADC_Channel::CH9};
|
||||||
case GPIO_Key::B4:
|
case GPIO_Key::B4:
|
||||||
case GPIO_Key::C4:
|
return {4, SHAL_ADC_Channel::NO_ADC_MAPPING};
|
||||||
return {4, SHAL_ADC_Channel::CH4};
|
|
||||||
case GPIO_Key::A5:
|
case GPIO_Key::A5:
|
||||||
|
return {5, SHAL_ADC_Channel::CH10};
|
||||||
case GPIO_Key::B5:
|
case GPIO_Key::B5:
|
||||||
case GPIO_Key::C5:
|
return {5, SHAL_ADC_Channel::NO_ADC_MAPPING};
|
||||||
return {5, SHAL_ADC_Channel::CH5};
|
|
||||||
case GPIO_Key::A6:
|
case GPIO_Key::A6:
|
||||||
|
return {6, SHAL_ADC_Channel::CH11};
|
||||||
case GPIO_Key::B6:
|
case GPIO_Key::B6:
|
||||||
case GPIO_Key::C6:
|
return {6, SHAL_ADC_Channel::NO_ADC_MAPPING};
|
||||||
return {6, SHAL_ADC_Channel::CH6};
|
|
||||||
case GPIO_Key::A7:
|
case GPIO_Key::A7:
|
||||||
|
return {7, SHAL_ADC_Channel::CH12};
|
||||||
case GPIO_Key::B7:
|
case GPIO_Key::B7:
|
||||||
case GPIO_Key::C7:
|
return {7, SHAL_ADC_Channel::NO_ADC_MAPPING};
|
||||||
return {7, SHAL_ADC_Channel::CH7};
|
|
||||||
case GPIO_Key::A8:
|
case GPIO_Key::A8:
|
||||||
case GPIO_Key::B8:
|
return {8, SHAL_ADC_Channel::NO_ADC_MAPPING};
|
||||||
case GPIO_Key::C8:
|
|
||||||
return {8, SHAL_ADC_Channel::CH8};
|
|
||||||
case GPIO_Key::A9:
|
case GPIO_Key::A9:
|
||||||
case GPIO_Key::B9:
|
return {9, SHAL_ADC_Channel::NO_ADC_MAPPING};
|
||||||
case GPIO_Key::C9:
|
|
||||||
return {9, SHAL_ADC_Channel::CH9};
|
|
||||||
case GPIO_Key::A10:
|
case GPIO_Key::A10:
|
||||||
case GPIO_Key::B10:
|
return {10, SHAL_ADC_Channel::NO_ADC_MAPPING};
|
||||||
case GPIO_Key::C10:
|
|
||||||
return {10, SHAL_ADC_Channel::CH10};
|
|
||||||
case GPIO_Key::A11:
|
case GPIO_Key::A11:
|
||||||
case GPIO_Key::B11:
|
return {11, SHAL_ADC_Channel::NO_ADC_MAPPING};
|
||||||
case GPIO_Key::C11:
|
|
||||||
return {11, SHAL_ADC_Channel::CH11};
|
|
||||||
case GPIO_Key::A12:
|
case GPIO_Key::A12:
|
||||||
case GPIO_Key::B12:
|
return {12, SHAL_ADC_Channel::NO_ADC_MAPPING};
|
||||||
case GPIO_Key::C12:
|
|
||||||
return {12, SHAL_ADC_Channel::CH12};
|
|
||||||
case GPIO_Key::A13:
|
case GPIO_Key::A13:
|
||||||
case GPIO_Key::B13:
|
return {13, SHAL_ADC_Channel::NO_ADC_MAPPING};
|
||||||
case GPIO_Key::C13:
|
|
||||||
return {13, SHAL_ADC_Channel::CH13};
|
|
||||||
case GPIO_Key::A14:
|
case GPIO_Key::A14:
|
||||||
case GPIO_Key::B14:
|
return {14, SHAL_ADC_Channel::NO_ADC_MAPPING};
|
||||||
case GPIO_Key::C14:
|
|
||||||
return {14, SHAL_ADC_Channel::CH14};
|
|
||||||
case GPIO_Key::A15:
|
case GPIO_Key::A15:
|
||||||
case GPIO_Key::B15:
|
return {15, SHAL_ADC_Channel::NO_ADC_MAPPING};
|
||||||
case GPIO_Key::C15:
|
|
||||||
return {15, SHAL_ADC_Channel::CH15};
|
|
||||||
case GPIO_Key::NUM_GPIO:
|
case GPIO_Key::NUM_GPIO:
|
||||||
case GPIO_Key::INVALID:
|
case GPIO_Key::INVALID:
|
||||||
return {0, SHAL_ADC_Channel::CH0};
|
return {0, SHAL_ADC_Channel::NO_ADC_MAPPING};
|
||||||
}
|
}
|
||||||
__builtin_unreachable();
|
__builtin_unreachable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif //SHAL_GPIO_REG_F072XB_H
|
||||||
|
|
||||||
#endif //SHAL_GPIO_REG_F072XB_H
|
|
||||||
@@ -27,22 +27,22 @@ 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;
|
uint16_t digitalRead();
|
||||||
|
|
||||||
void setAlternateFunction(GPIO_Alternate_Function AF) volatile;
|
void setAlternateFunction(GPIO_Alternate_Function AF) volatile;
|
||||||
|
void setAlternateFunction(GPIO_Alternate_Function_Mapping AF) volatile;
|
||||||
|
|
||||||
void setPinType(PinType type) volatile;
|
void setOutputType(PinType type) volatile;
|
||||||
|
|
||||||
void setOutputSpeed(OutputSpeed speed) volatile;
|
void setOutputSpeed(OutputSpeed speed) volatile;
|
||||||
|
|
||||||
void setInternalResistor(InternalResistorType type) volatile;
|
void setInternalResistor(InternalResistorType type) volatile;
|
||||||
|
|
||||||
|
|
||||||
void useAsExternalInterrupt(TriggerMode mode, EXTICallback callback);
|
void useAsExternalInterrupt(TriggerMode mode, EXTICallback callback);
|
||||||
|
|
||||||
|
SHAL_Result setPinMode(PinMode mode) volatile;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
@@ -67,6 +67,7 @@ private:
|
|||||||
|
|
||||||
#define SET_ANALOGREAD_ADC(x) GPIOManager::setGPIOADC(x)
|
#define SET_ANALOGREAD_ADC(x) GPIOManager::setGPIOADC(x)
|
||||||
|
|
||||||
|
|
||||||
//Manages instances of SHAL_GPIO objects
|
//Manages instances of SHAL_GPIO objects
|
||||||
class GPIOManager{
|
class GPIOManager{
|
||||||
|
|
||||||
|
|||||||
@@ -15,14 +15,44 @@ struct SHAL_GPIO_EXTI_Register{
|
|||||||
IRQn_Type IRQN; //IRQ number for enabling lines
|
IRQn_Type IRQN; //IRQ number for enabling lines
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SHAL_GPIO_Peripheral {
|
struct SHAL_GPIO_RCC_Enable_Register{
|
||||||
GPIO_TypeDef * reg;
|
volatile uint32_t* reg;
|
||||||
unsigned long global_offset;
|
uint32_t offset;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SHAL_Peripheral_Register {
|
struct SHAL_GPIO_Mode_Register {
|
||||||
volatile uint32_t* reg;
|
volatile uint32_t* reg;
|
||||||
unsigned long offset;
|
uint32_t offset;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SHAL_GPIO_Pullup_Pulldown_Register {
|
||||||
|
volatile uint32_t* reg;
|
||||||
|
uint32_t offset;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SHAL_GPIO_Alternate_Function_Register {
|
||||||
|
volatile uint32_t* reg;
|
||||||
|
uint32_t offset;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SHAL_GPIO_Output_Speed_Register{
|
||||||
|
volatile uint32_t* reg;
|
||||||
|
uint32_t offset;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SHAL_GPIO_Output_Type_Register {
|
||||||
|
volatile uint32_t* reg;
|
||||||
|
uint32_t offset;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SHAL_GPIO_Output_Data_Register {
|
||||||
|
volatile uint32_t* reg;
|
||||||
|
uint32_t offset;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SHAL_GPIO_Input_Data_Register {
|
||||||
|
volatile uint32_t* reg;
|
||||||
|
uint32_t offset;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SHAL_GPIO_Port_Info{
|
struct SHAL_GPIO_Port_Info{
|
||||||
|
|||||||
@@ -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){
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
205
SHAL/Include/Peripheral/Timer/Reg/SHAL_TIM_REG_L432KC.h
Normal file
205
SHAL/Include/Peripheral/Timer/Reg/SHAL_TIM_REG_L432KC.h
Normal file
@@ -0,0 +1,205 @@
|
|||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* @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,
|
||||||
|
TIM_CR1_ARPE};
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline SHAL_TIM_Capture_Compare_Mode_Registers_Input getTimerCaptureCompareModeRegisters(Timer_Key key){
|
||||||
|
SHAL_TIM_Capture_Compare_Mode_Registers_Input res = {{nullptr,
|
||||||
|
nullptr},
|
||||||
|
TIM_CCMR1_CC1S_Pos,
|
||||||
|
TIM_CCMR1_IC1PSC_Pos,
|
||||||
|
TIM_CCMR1_IC1F_Pos,
|
||||||
|
TIM_CCMR1_CC2S_Pos,
|
||||||
|
TIM_CCMR1_IC2PSC_Pos,
|
||||||
|
TIM_CCMR1_IC2F_Pos
|
||||||
|
};
|
||||||
|
|
||||||
|
volatile TIM_TypeDef* tim = TIM_TABLE[static_cast<uint8_t>(key)];
|
||||||
|
|
||||||
|
res.regs[0] = &tim->CCMR1;
|
||||||
|
res.regs[1] = &tim->CCMR2;
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline SHAL_TIM_Capture_Compare_Mode_Registers_Output
|
||||||
|
getTimerCaptureCompareModeRegistersOutput(Timer_Key key) {
|
||||||
|
SHAL_TIM_Capture_Compare_Mode_Registers_Output res = {
|
||||||
|
{nullptr, nullptr},
|
||||||
|
TIM_CCMR1_CC1S_Pos, //Channel 1 Capture/Compare selection
|
||||||
|
TIM_CCMR1_OC1FE, //Channel 1 Fast enable
|
||||||
|
TIM_CCMR1_OC1PE, //Channel 1 Preload enable
|
||||||
|
TIM_CCMR1_OC1M_Pos, //Channel 1 Mode (OC1M)
|
||||||
|
TIM_CCMR1_OC1CE, //Channel 1 Clear enable
|
||||||
|
TIM_CCMR1_CC2S_Pos, //Channel 2 Capture/Compare selection
|
||||||
|
TIM_CCMR1_OC2FE, //Channel 2 Fast enable
|
||||||
|
TIM_CCMR1_OC2PE, //Channel 2 Preload enable
|
||||||
|
TIM_CCMR1_OC2M_Pos, //Channel 2 Mode (OC2M)
|
||||||
|
TIM_CCMR1_OC2CE //Channel 2 Clear enable
|
||||||
|
};
|
||||||
|
|
||||||
|
volatile TIM_TypeDef* tim = TIM_TABLE[static_cast<uint8_t>(key)];
|
||||||
|
res.regs[0] = &tim->CCMR1;
|
||||||
|
res.regs[1] = &tim->CCMR2;
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline SHAL_TIM_Break_Dead_Time_Register getTimerBreakDeadTimeRegister(Timer_Key key){
|
||||||
|
|
||||||
|
SHAL_TIM_Break_Dead_Time_Register res = {nullptr, TIM_BDTR_MOE};
|
||||||
|
|
||||||
|
volatile TIM_TypeDef* tim = TIM_TABLE[static_cast<uint8_t>(key)];
|
||||||
|
|
||||||
|
res.reg = &tim->BDTR;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline SHAL_TIM_Capture_Compare_Enable_Register getTimerCaptureCompareEnableRegister(Timer_Key key){
|
||||||
|
volatile TIM_TypeDef* tim = TIM_TABLE[static_cast<uint8_t>(key)];
|
||||||
|
return {&tim->CCER};
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline SHAL_TIM_Capture_Compare_Register getTimerCaptureCompareRegister(Timer_Key key){
|
||||||
|
volatile TIM_TypeDef* tim = TIM_TABLE[static_cast<uint8_t>(key)];
|
||||||
|
return {&tim->CCR2};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//Get timer IRQN from lookup table
|
||||||
|
static inline IRQn_Type getTimerIRQn(Timer_Key t) {
|
||||||
|
return IRQN_TABLE[static_cast<uint8_t>(t)];
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -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,10 +18,10 @@ 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(uint16_t prescaler, uint16_t autoReload);
|
||||||
|
|
||||||
//Starts the counter
|
//Starts the counter
|
||||||
void start();
|
void start();
|
||||||
@@ -38,9 +38,15 @@ public:
|
|||||||
//Enable interrupts
|
//Enable interrupts
|
||||||
void enableInterrupt();
|
void enableInterrupt();
|
||||||
|
|
||||||
|
void setPWMMode(SHAL_Timer_Channel channel, SHAL_TIM_Output_Compare_Mode outputCompareMode, SHAL_Timer_Channel_Main_Output_Mode mainOutputMode, SHAL_Timer_Channel_Complimentary_Output_Mode complimentaryOutputMode);
|
||||||
|
|
||||||
|
/// Set the duty cycle for PWM
|
||||||
|
/// \param dutyCycle 10 * percentage (e.g. 500 = 50%)
|
||||||
|
void setPWMDutyCycle(uint32_t dutyCycle);
|
||||||
|
|
||||||
//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 +54,8 @@ private:
|
|||||||
explicit Timer(Timer_Key t);
|
explicit Timer(Timer_Key t);
|
||||||
Timer();
|
Timer();
|
||||||
|
|
||||||
Timer_Key TIMER_KEY;
|
Timer_Key m_key;
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -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(); \
|
||||||
}; \
|
}; \
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -2,14 +2,125 @@
|
|||||||
// 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;
|
||||||
|
uint32_t auto_reload_preload_enable_mask;
|
||||||
|
};
|
||||||
|
|
||||||
|
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;
|
uint32_t offset;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif //SHMINGO_HAL_SHAL_TIM_TYPES_H
|
struct SHAL_TIM_Auto_Reload_Register {
|
||||||
|
volatile uint32_t* reg;
|
||||||
|
uint32_t offset;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SHAL_TIM_Capture_Compare_Mode_Registers_Input {
|
||||||
|
volatile uint32_t* regs[2];
|
||||||
|
uint32_t input_capture_1_filter_offset;
|
||||||
|
uint32_t input_capture_1_prescaler_offset;
|
||||||
|
uint32_t capture_compare_1_selection_offset;
|
||||||
|
uint32_t input_capture_2_filter_offset;
|
||||||
|
uint32_t input_capture_2_prescaler_offset;
|
||||||
|
uint32_t capture_compare_2_selection_offset;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SHAL_TIM_Capture_Compare_Mode_Registers_Output {
|
||||||
|
volatile uint32_t* regs[2];
|
||||||
|
uint32_t capture_compare_1_selection_offset;
|
||||||
|
uint32_t output_compare_1_fast_enable_mask;
|
||||||
|
uint32_t output_compare_1_preload_enable_mask;
|
||||||
|
uint32_t output_compare_1_mode_offset;
|
||||||
|
uint32_t output_compare_1_clear_enable_mask;
|
||||||
|
uint32_t capture_compare_2_selection_offset;
|
||||||
|
uint32_t output_compare_2_fast_enable_mask;
|
||||||
|
uint32_t output_compare_2_preload_enable_mask;
|
||||||
|
uint32_t output_compare_2_mode_offset;
|
||||||
|
uint32_t output_compare_2_clear_enable_mask;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SHAL_TIM_Break_Dead_Time_Register {
|
||||||
|
volatile uint32_t* reg;
|
||||||
|
uint32_t main_output_enable_mask;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SHAL_TIM_Capture_Compare_Enable_Register {
|
||||||
|
volatile uint32_t* reg;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SHAL_TIM_Capture_Compare_Register {
|
||||||
|
volatile uint32_t* reg;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
enum class SHAL_TIM_Output_Compare_Mode : uint8_t {
|
||||||
|
Frozen = 0b000, //Output compare frozen
|
||||||
|
ActiveOnMatch = 0b001, //Set output to active level on match
|
||||||
|
InactiveOnMatch = 0b010, //Set output to inactive level on match
|
||||||
|
Toggle = 0b011, //Toggle output on match
|
||||||
|
ForceInactive = 0b100, //Force output to inactive
|
||||||
|
ForceActive = 0b101, //Force output to active
|
||||||
|
PWMMode1 = 0b110, //PWM mode 1 (active until compare match)
|
||||||
|
PWMMode2 = 0b111, //PWM mode 2 (inactive until compare match)
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class SHAL_TIM_Output_Compare_Preload : uint8_t {
|
||||||
|
Disabled = 0b0, //CCRx register is updated immediately
|
||||||
|
Enabled = 0b1, //CCRx register is buffered; updated on update event (UEV)
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class SHAL_Timer_Channel : uint8_t { //TODO change if other timers have fewer than 6 channels
|
||||||
|
CH1 = 0,
|
||||||
|
CH2 = 1,
|
||||||
|
CH3 = 2,
|
||||||
|
CH4 = 3,
|
||||||
|
CH5 = 4,
|
||||||
|
CH6 = 5,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class SHAL_Timer_Channel_Main_Output_Mode : uint8_t {
|
||||||
|
Disabled = 0b00,
|
||||||
|
Polarity_Normal = 0b01,
|
||||||
|
Polarity_Reversed = 0b11,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class SHAL_Timer_Channel_Complimentary_Output_Mode : uint8_t {
|
||||||
|
Disabled = 0b00,
|
||||||
|
Polarity_Normal = 0b01,
|
||||||
|
Polarity_Reversed = 0b11,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif //SHAL_TIM_TYPES_H
|
||||||
|
|||||||
@@ -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};
|
||||||
}
|
}
|
||||||
|
|||||||
104
SHAL/Include/Peripheral/UART/Reg/SHAL_UART_REG_L432KC.h
Normal file
104
SHAL/Include/Peripheral/UART/Reg/SHAL_UART_REG_L432KC.h
Normal 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}; //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}; //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
|
||||||
@@ -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;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -19,9 +19,31 @@ 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;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SHAL_UART_Transmit_Data_Register {
|
||||||
|
volatile uint16_t* reg;
|
||||||
|
};
|
||||||
|
|
||||||
|
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
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,128 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by Luca on 8/30/2025.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "SHAL_GPIO.h"
|
|
||||||
#include "SHAL_EXTI_CALLBACK.h"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
SHAL_GPIO::SHAL_GPIO() : m_GPIO_KEY(GPIO_Key::INVALID){
|
|
||||||
//Do not initialize anything
|
|
||||||
}
|
|
||||||
|
|
||||||
SHAL_GPIO::SHAL_GPIO(GPIO_Key key) : m_GPIO_KEY(key) {
|
|
||||||
|
|
||||||
volatile unsigned long* gpioEnable = getGPIORCCEnable(key).reg;
|
|
||||||
unsigned long gpioOffset = getGPIORCCEnable(key).offset;
|
|
||||||
|
|
||||||
*gpioEnable |= (1 << gpioOffset); //Set enable flag
|
|
||||||
}
|
|
||||||
|
|
||||||
void SHAL_GPIO::setLow() {
|
|
||||||
auto gpioPeripheral = getGPIORegister(m_GPIO_KEY);
|
|
||||||
gpioPeripheral.reg->ODR &= ~(1 << gpioPeripheral.global_offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SHAL_GPIO::setHigh() {
|
|
||||||
auto gpioPeripheral = getGPIORegister(m_GPIO_KEY);
|
|
||||||
gpioPeripheral.reg->ODR |= (1 << gpioPeripheral.global_offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SHAL_GPIO::toggle() volatile {
|
|
||||||
SHAL_GPIO_Peripheral gpioPeripheral = getGPIORegister(m_GPIO_KEY);
|
|
||||||
gpioPeripheral.reg->ODR ^= (1 << gpioPeripheral.global_offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void SHAL_GPIO::setPinType(PinType type) volatile {
|
|
||||||
SHAL_GPIO_Peripheral gpioPeripheral = getGPIORegister(m_GPIO_KEY);
|
|
||||||
gpioPeripheral.reg->OTYPER &= ~(1 << gpioPeripheral.global_offset);
|
|
||||||
gpioPeripheral.reg->OTYPER |= (static_cast<uint8_t>(type) << gpioPeripheral.global_offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SHAL_GPIO::setOutputSpeed(OutputSpeed speed) volatile {
|
|
||||||
SHAL_GPIO_Peripheral gpioPeripheral = getGPIORegister(m_GPIO_KEY);
|
|
||||||
gpioPeripheral.reg->OSPEEDR |= (static_cast<uint8_t>(speed) << (2 * gpioPeripheral.global_offset));
|
|
||||||
}
|
|
||||||
|
|
||||||
void SHAL_GPIO::setInternalResistor(InternalResistorType type) volatile {
|
|
||||||
SHAL_GPIO_Peripheral gpioPeripheral = getGPIORegister(m_GPIO_KEY);
|
|
||||||
gpioPeripheral.reg->PUPDR &= ~(0x03 << (2 * gpioPeripheral.global_offset));
|
|
||||||
gpioPeripheral.reg->PUPDR |= (static_cast<uint8_t>(type) << (2 * gpioPeripheral.global_offset));
|
|
||||||
}
|
|
||||||
|
|
||||||
void SHAL_GPIO::setAlternateFunction(GPIO_Alternate_Function AF) volatile {
|
|
||||||
SHAL_GPIO_Peripheral gpioPeripheral = getGPIORegister(m_GPIO_KEY);
|
|
||||||
|
|
||||||
int afrIndex = gpioPeripheral.global_offset < 8 ? 0 : 1; //Get index of AFR
|
|
||||||
|
|
||||||
gpioPeripheral.reg->AFR[afrIndex] &= ~(0xF << (gpioPeripheral.global_offset * 4));
|
|
||||||
gpioPeripheral.reg->AFR[afrIndex] |= (static_cast<int>(AF) << (gpioPeripheral.global_offset * 4));
|
|
||||||
}
|
|
||||||
|
|
||||||
void SHAL_GPIO::setPinMode(PinMode mode) volatile {
|
|
||||||
SHAL_GPIO_Peripheral gpioPeripheral = getGPIORegister(m_GPIO_KEY);
|
|
||||||
gpioPeripheral.reg->MODER &= ~(0x03 << (2 * gpioPeripheral.global_offset)); //Clear any previous mode
|
|
||||||
gpioPeripheral.reg->MODER |= (static_cast<uint8_t>(mode) << (2 * gpioPeripheral.global_offset)); //Set mode based on pinmode bit structure
|
|
||||||
}
|
|
||||||
|
|
||||||
void SHAL_GPIO::useAsExternalInterrupt(TriggerMode mode, EXTICallback callback) {
|
|
||||||
|
|
||||||
uint32_t gpioPin = getGPIORegister(m_GPIO_KEY).global_offset; //Use existing structs to get offset
|
|
||||||
|
|
||||||
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
|
|
||||||
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);
|
|
||||||
*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 falling_mask = 0x00;
|
|
||||||
|
|
||||||
//Set rising and falling edge triggers based on pin offset (enabled EXTI line)
|
|
||||||
switch(mode){
|
|
||||||
case TriggerMode::RISING_EDGE:
|
|
||||||
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
|
|
||||||
EXTI->RTSR |= rising_mask;
|
|
||||||
EXTI->FTSR |= falling_mask;
|
|
||||||
|
|
||||||
//Set callback
|
|
||||||
registerEXTICallback(m_GPIO_KEY,callback);
|
|
||||||
|
|
||||||
__enable_irq(); //Enable IRQ just in case
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t SHAL_GPIO::analogRead(ADC_SampleTime sampleTime) {
|
|
||||||
|
|
||||||
SHAL_ADC_Channel channel = getGPIOPortInfo(m_GPIO_KEY).ADCChannel;
|
|
||||||
|
|
||||||
return GPIOManager::getGPIOADC().singleConvertSingle(channel,sampleTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
SHAL_GPIO& GPIOManager::get(GPIO_Key key) {
|
|
||||||
|
|
||||||
unsigned int gpioPort = getGPIOPortNumber(key);
|
|
||||||
unsigned long gpioPin = getGPIORegister(key).global_offset; //Use existing structs to get offset
|
|
||||||
|
|
||||||
if (m_gpios[gpioPort][gpioPin].m_GPIO_KEY == GPIO_Key::INVALID){
|
|
||||||
m_gpios[gpioPort][gpioPin] = SHAL_GPIO(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
return m_gpios[gpioPort][gpioPin];
|
|
||||||
}
|
|
||||||
@@ -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
|
||||||
@@ -20,46 +20,38 @@ SHAL_GPIO::SHAL_GPIO(GPIO_Key key) : m_GPIO_KEY(key) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void SHAL_GPIO::setLow() {
|
void SHAL_GPIO::setLow() {
|
||||||
auto gpioPeripheral = getGPIORegister(m_GPIO_KEY);
|
auto outputDataReg = getGPIOOutputDataRegister(m_GPIO_KEY);
|
||||||
gpioPeripheral.reg->ODR &= ~(1 << gpioPeripheral.global_offset);
|
SHAL_set_bits(outputDataReg.reg,1,0,outputDataReg.offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SHAL_GPIO::setHigh() {
|
void SHAL_GPIO::setHigh() {
|
||||||
auto gpioPeripheral = getGPIORegister(m_GPIO_KEY);
|
auto outputDataReg = getGPIOOutputDataRegister(m_GPIO_KEY);
|
||||||
gpioPeripheral.reg->ODR |= (1 << gpioPeripheral.global_offset);
|
SHAL_set_bits(outputDataReg.reg,1,1,outputDataReg.offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SHAL_GPIO::toggle() volatile {
|
void SHAL_GPIO::toggle() volatile {
|
||||||
SHAL_GPIO_Peripheral gpioPeripheral = getGPIORegister(m_GPIO_KEY);
|
auto outputDataReg = getGPIOOutputDataRegister(m_GPIO_KEY);
|
||||||
gpioPeripheral.reg->ODR ^= (1 << gpioPeripheral.global_offset);
|
SHAL_flip_bits(outputDataReg.reg,1,outputDataReg.offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SHAL_GPIO::setOutputType(PinType type) volatile {
|
||||||
|
auto outputTypeReg = getGPIOOutputTypeRegister(m_GPIO_KEY);
|
||||||
void SHAL_GPIO::setPinType(PinType type) volatile {
|
SHAL_set_bits(outputTypeReg.reg,2,static_cast<uint8_t>(type),outputTypeReg.offset);
|
||||||
SHAL_GPIO_Peripheral gpioPeripheral = getGPIORegister(m_GPIO_KEY);
|
|
||||||
gpioPeripheral.reg->OTYPER &= ~(1 << gpioPeripheral.global_offset);
|
|
||||||
gpioPeripheral.reg->OTYPER |= (static_cast<uint8_t>(type) << gpioPeripheral.global_offset);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SHAL_GPIO::setOutputSpeed(OutputSpeed speed) volatile {
|
void SHAL_GPIO::setOutputSpeed(OutputSpeed speed) volatile {
|
||||||
SHAL_GPIO_Peripheral gpioPeripheral = getGPIORegister(m_GPIO_KEY);
|
auto outputSpeedReg = getGPIOOutputSpeedRegister(m_GPIO_KEY);
|
||||||
gpioPeripheral.reg->OSPEEDR |= (static_cast<uint8_t>(speed) << (2 * gpioPeripheral.global_offset));
|
SHAL_set_bits(outputSpeedReg.reg,2,static_cast<uint8_t>(speed),outputSpeedReg.offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SHAL_GPIO::setInternalResistor(InternalResistorType type) volatile {
|
void SHAL_GPIO::setInternalResistor(InternalResistorType type) volatile {
|
||||||
SHAL_GPIO_Peripheral gpioPeripheral = getGPIORegister(m_GPIO_KEY);
|
auto pupdreg = getGPIOPUPDRegister(m_GPIO_KEY);
|
||||||
gpioPeripheral.reg->PUPDR &= ~(0x03 << (2 * gpioPeripheral.global_offset));
|
SHAL_set_bits(pupdreg.reg,2,static_cast<uint8_t>(type),pupdreg.offset);
|
||||||
gpioPeripheral.reg->PUPDR |= (static_cast<uint8_t>(type) << (2 * gpioPeripheral.global_offset));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SHAL_GPIO::setAlternateFunction(GPIO_Alternate_Function AF) volatile {
|
void SHAL_GPIO::setAlternateFunction(GPIO_Alternate_Function AF) volatile {
|
||||||
SHAL_GPIO_Peripheral gpioPeripheral = getGPIORegister(m_GPIO_KEY);
|
auto alternateFunctionReg = getGPIOAlternateFunctionRegister(m_GPIO_KEY);
|
||||||
|
SHAL_set_bits(alternateFunctionReg.reg,4,static_cast<uint8_t>(AF),alternateFunctionReg.offset);
|
||||||
int afrIndex = gpioPeripheral.global_offset < 8 ? 0 : 1; //Get index of AFR
|
|
||||||
|
|
||||||
gpioPeripheral.reg->AFR[afrIndex] &= ~(0xF << (gpioPeripheral.global_offset * 4));
|
|
||||||
gpioPeripheral.reg->AFR[afrIndex] |= (static_cast<int>(AF) << (gpioPeripheral.global_offset * 4));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SHAL_GPIO::setPinMode(PinMode mode) volatile {
|
void SHAL_GPIO::setPinMode(PinMode mode) volatile {
|
||||||
@@ -107,7 +99,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;
|
||||||
|
|
||||||
@@ -27,8 +27,8 @@ void SHAL_I2C::init(I2C_Pair pair) volatile {
|
|||||||
GET_GPIO(SDA_Key).setAlternateFunction(I2CPair.SDA_Mask);
|
GET_GPIO(SDA_Key).setAlternateFunction(I2CPair.SDA_Mask);
|
||||||
|
|
||||||
//These may be abstracted further to support multiple I2C configurations
|
//These may be abstracted further to support multiple I2C configurations
|
||||||
GET_GPIO(SCL_Key).setPinType(PinType::OPEN_DRAIN);
|
GET_GPIO(SCL_Key).setOutputType(PinType::OPEN_DRAIN);
|
||||||
GET_GPIO(SDA_Key).setPinType(PinType::OPEN_DRAIN);
|
GET_GPIO(SDA_Key).setOutputType(PinType::OPEN_DRAIN);
|
||||||
|
|
||||||
GET_GPIO(SCL_Key).setOutputSpeed(OutputSpeed::HIGH_SPEED);
|
GET_GPIO(SCL_Key).setOutputSpeed(OutputSpeed::HIGH_SPEED);
|
||||||
GET_GPIO(SDA_Key).setOutputSpeed(OutputSpeed::HIGH_SPEED);
|
GET_GPIO(SDA_Key).setOutputSpeed(OutputSpeed::HIGH_SPEED);
|
||||||
@@ -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
|
||||||
|
|
||||||
@@ -1,158 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by Luca on 9/21/2025.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "SHAL_ADC.h"
|
|
||||||
|
|
||||||
//Can hard code registers on F0 because all F0 devices have only one ADC, and use only one clock
|
|
||||||
SHAL_Result SHAL_ADC::init() {
|
|
||||||
|
|
||||||
if(m_ADCKey == ADC_Key::INVALID || m_ADCKey == ADC_Key::NUM_ADC){
|
|
||||||
return SHAL_Result::ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
ADC_TypeDef* ADC_reg = getADCRegister(m_ADCKey);
|
|
||||||
|
|
||||||
SHAL_ADC_RCC_Enable_Reg clock_reg = getADCRCCEnableRegister(m_ADCKey); //Clock enable
|
|
||||||
|
|
||||||
*clock_reg.reg |= clock_reg.mask;
|
|
||||||
|
|
||||||
SHAL_ADC_Control_Reg control_reg = getADCControlReg(m_ADCKey);
|
|
||||||
|
|
||||||
if (*control_reg.reg & control_reg.enable_mask) {
|
|
||||||
//request disable: ADEN=1 -> set ADDIS to disable
|
|
||||||
*control_reg.reg |= control_reg.disable_mask;
|
|
||||||
//wait until ADEN cleared (ISR.ADREADY == 0)
|
|
||||||
if(!SHAL_WAIT_FOR_CONDITION_MS((*control_reg.reg & control_reg.enable_mask) == 0, 100)){
|
|
||||||
return SHAL_Result::ERROR;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(calibrate() != SHAL_Result::OKAY){ //Calibrate
|
|
||||||
return SHAL_Result::ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
configureAlignment(SHAL_ADC_Alignment::RIGHT);
|
|
||||||
configureResolution(SHAL_ADC_Resolution::B12);
|
|
||||||
|
|
||||||
return SHAL_Result::OKAY;
|
|
||||||
}
|
|
||||||
|
|
||||||
SHAL_Result SHAL_ADC::calibrate() {
|
|
||||||
|
|
||||||
if(disable() != SHAL_Result::OKAY){ //Disable the ADC
|
|
||||||
return SHAL_Result::ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
SHAL_ADC_Control_Reg control_reg = getADCControlReg(m_ADCKey);
|
|
||||||
|
|
||||||
*control_reg.reg |= control_reg.calibration_mask;
|
|
||||||
|
|
||||||
if(!SHAL_WAIT_FOR_CONDITION_US(((*control_reg.reg & control_reg.calibration_mask) == 0),500)){ //Wait for calibration
|
|
||||||
return SHAL_Result::ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
return SHAL_Result::OKAY;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t SHAL_ADC::singleConvertSingle(SHAL_ADC_Channel channel, ADC_SampleTime time) {
|
|
||||||
|
|
||||||
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_reg->CHSELR = static_cast<uint32_t>(channel); //Enable channel for conversion
|
|
||||||
ADC_reg->SMPR |= static_cast<uint32_t>(time); //Set sampling time
|
|
||||||
|
|
||||||
if(!SHAL_WAIT_FOR_CONDITION_US(((ADC_reg->ISR & ADC_ISR_EOC) != 0),500)){ //Wait for conversion
|
|
||||||
return 0; //Failed
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t result = ADC_reg->DR;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SHAL_ADC::multiConvertSingle(SHAL_ADC_Channel* channels, const int numChannels, uint16_t* result, ADC_SampleTime time) {
|
|
||||||
ADC_TypeDef* ADC_reg = getADCRegister(m_ADCKey);
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
|
|
||||||
for(int i = 0; i < numChannels; i++){
|
|
||||||
if(!SHAL_WAIT_FOR_CONDITION_US(((ADC_reg->ISR & ADC_ISR_EOC) != 0),500)){ //Wait for conversion
|
|
||||||
continue; //Failed
|
|
||||||
}
|
|
||||||
|
|
||||||
result[i] = ADC_reg->DR;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SHAL_Result SHAL_ADC::disable() {
|
|
||||||
|
|
||||||
if(!isValid()){
|
|
||||||
return SHAL_Result::ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
SHAL_ADC_Control_Reg control_reg = getADCControlReg(m_ADCKey);
|
|
||||||
if (*control_reg.reg & control_reg.enable_mask) {
|
|
||||||
//request disable: ADEN=1 -> set ADDIS to disable
|
|
||||||
*control_reg.reg |= control_reg.disable_mask;
|
|
||||||
//wait until ADEN cleared (ISR.ADREADY == 0)
|
|
||||||
if(!SHAL_WAIT_FOR_CONDITION_MS((*control_reg.reg & control_reg.enable_mask) == 0, 100)){
|
|
||||||
return SHAL_Result::ERROR;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return SHAL_Result::OKAY;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SHAL_ADC::isValid() {
|
|
||||||
if(m_ADCKey == ADC_Key::INVALID || m_ADCKey == ADC_Key::NUM_ADC){
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
SHAL_Result SHAL_ADC::configureResolution(SHAL_ADC_Resolution resolution) {
|
|
||||||
if(!isValid()){
|
|
||||||
return SHAL_Result::ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
SHAL_ADC_Config_Reg config_reg = getADCConfigReg(m_ADCKey);
|
|
||||||
|
|
||||||
SHAL_set_bits(config_reg.reg,2,static_cast<uint8_t>(resolution),config_reg.resolution_offset);
|
|
||||||
|
|
||||||
return SHAL_Result::OKAY;
|
|
||||||
}
|
|
||||||
|
|
||||||
SHAL_Result SHAL_ADC::configureAlignment(SHAL_ADC_Alignment alignment) {
|
|
||||||
if(!isValid()){
|
|
||||||
return SHAL_Result::ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
SHAL_ADC_Config_Reg config_reg = getADCConfigReg(m_ADCKey);
|
|
||||||
|
|
||||||
*config_reg.reg &= ~(0x1UL << config_reg.alignment_offset); //TODO check if this needs to be abstracted (Do other platforms have >2 resolution possibilities?
|
|
||||||
*config_reg.reg |= static_cast<uint8_t>(alignment) << config_reg.alignment_offset;
|
|
||||||
|
|
||||||
return SHAL_Result::OKAY;
|
|
||||||
}
|
|
||||||
|
|
||||||
SHAL_ADC &ADCManager::get(ADC_Key key) {
|
|
||||||
return m_ADCs[static_cast<uint8_t>(key)];
|
|
||||||
}
|
|
||||||
|
|
||||||
SHAL_ADC& ADCManager::getByIndex(int index) {
|
|
||||||
|
|
||||||
if(index < static_cast<int>(ADC_Key::NUM_ADC)){
|
|
||||||
return m_ADCs[index];
|
|
||||||
}
|
|
||||||
return m_ADCs[0];
|
|
||||||
}
|
|
||||||
@@ -1,63 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by Luca on 8/28/2025.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "SHAL_TIM.h"
|
|
||||||
#include <cassert>
|
|
||||||
|
|
||||||
Timer::Timer(Timer_Key t) : TIMER_KEY(t){
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
Timer::Timer() : TIMER_KEY(Timer_Key::S_TIM_INVALID){
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void Timer::start() {
|
|
||||||
getTimerRegister(TIMER_KEY)->CR1 |= TIM_CR1_CEN;
|
|
||||||
getTimerRegister(TIMER_KEY)->EGR |= TIM_EGR_UG; //load prescaler reg and ARR
|
|
||||||
enableInterrupt();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Timer::stop() {
|
|
||||||
getTimerRegister(TIMER_KEY)->CR1 &= ~TIM_CR1_CEN;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Timer::setPrescaler(uint16_t presc) {
|
|
||||||
getTimerRegister(TIMER_KEY)->PSC = presc;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Timer::setARR(uint16_t arr) {
|
|
||||||
getTimerRegister(TIMER_KEY)->ARR = arr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Timer::enableInterrupt() {
|
|
||||||
getTimerRegister(TIMER_KEY)->DIER |= TIM_DIER_UIE;
|
|
||||||
NVIC_EnableIRQ(getIRQn(TIMER_KEY));
|
|
||||||
}
|
|
||||||
|
|
||||||
void Timer::init(uint32_t prescaler, uint32_t autoReload) {
|
|
||||||
TIM_RCC_Enable rcc = getTimerRCC(TIMER_KEY);
|
|
||||||
*rcc.busEnableReg |= (1 << rcc.offset);
|
|
||||||
|
|
||||||
setPrescaler(prescaler);
|
|
||||||
setARR(autoReload);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Timer &TimerManager::get(Timer_Key timer_key) {
|
|
||||||
|
|
||||||
//Ensure that we don't try to get invalid timers
|
|
||||||
assert(timer_key != Timer_Key::S_TIM_INVALID && timer_key != Timer_Key::NUM_TIMERS);
|
|
||||||
|
|
||||||
Timer& selected = timers[static_cast<int>(timer_key)];
|
|
||||||
|
|
||||||
//Timer queried is not initialized yet (defaults to invalid)
|
|
||||||
if(selected.TIMER_KEY == Timer_Key::S_TIM_INVALID){
|
|
||||||
timers[static_cast<int>(timer_key)] = Timer(timer_key); //Initialize TIMER_KEY
|
|
||||||
}
|
|
||||||
|
|
||||||
return timers[static_cast<int>(timer_key)];
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by Luca on 8/28/2025.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "SHAL_TIM_CALLBACK.h"
|
|
||||||
|
|
||||||
DEFINE_TIMER_IRQ(Timer_Key::S_TIM1, TIM1_BRK_UP_TRG_COM_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_TIM14, TIM14_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_TIM17, TIM17_IRQHandler)
|
|
||||||
|
|
||||||
void registerTimerCallback(Timer_Key key, TimerCallback callback){
|
|
||||||
timer_callbacks[static_cast<int>(key)] = callback;
|
|
||||||
}
|
|
||||||
@@ -2,10 +2,25 @@
|
|||||||
// Created by Luca on 9/15/2025.
|
// Created by Luca on 9/15/2025.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
|
||||||
#include "SHAL_CORE.h"
|
#include "SHAL_CORE.h"
|
||||||
|
#include "SHAL_GPIO.h"
|
||||||
|
#include "SHAL_ADC.h"
|
||||||
|
#include "SHAL_UART.h"
|
||||||
|
|
||||||
void SHAL_init(){
|
void SHAL_init(){
|
||||||
systick_init(); //Just this for now
|
systick_init();
|
||||||
|
|
||||||
|
|
||||||
|
for(auto i = static_cast<uint8_t>(ADC_Key::S_ADC1); i < static_cast<uint8_t>(ADC_Key::NUM_ADC); i++){ //Init all ADCs
|
||||||
|
auto adc_key = static_cast<ADC_Key>(i);
|
||||||
|
|
||||||
|
ADCManager::getByIndex(i).init(adc_key);
|
||||||
|
}
|
||||||
|
|
||||||
|
SET_ANALOGREAD_ADC(SHAL_ADC1); //Default ADC1 for analogread calls
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -40,3 +55,9 @@ void SHAL_delay_ms(uint32_t ms){
|
|||||||
SHAL_delay_us(1000);
|
SHAL_delay_us(1000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SHAL_print_register(const volatile uint32_t* reg){
|
||||||
|
char buff[32];
|
||||||
|
sprintf(buff, "0x%08lX\r\n", (unsigned long)(*reg));
|
||||||
|
SHAL_UART2.sendString(buff);
|
||||||
|
}
|
||||||
@@ -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)
|
||||||
@@ -37,5 +43,5 @@ DEFINE_EXTI_IRQ()
|
|||||||
|
|
||||||
//Link function to EXTI line
|
//Link function to EXTI line
|
||||||
void registerEXTICallback(GPIO_Key key, EXTICallback callback){
|
void registerEXTICallback(GPIO_Key key, EXTICallback callback){
|
||||||
EXTI_callbacks[getGPIORegister(key).global_offset] = callback;
|
EXTI_callbacks[getGPIOPinNumber(key)] = callback;
|
||||||
}
|
}
|
||||||
308
SHAL/Src/STM32L4xx/Peripheral/ADC/SHAL_ADC.cpp
Normal file
308
SHAL/Src/STM32L4xx/Peripheral/ADC/SHAL_ADC.cpp
Normal file
@@ -0,0 +1,308 @@
|
|||||||
|
//
|
||||||
|
// Created by Luca on 9/21/2025.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "SHAL_ADC.h"
|
||||||
|
#include "SHAL_GPIO.h"
|
||||||
|
#include "SHAL_UART.h"
|
||||||
|
#include <cstdio>
|
||||||
|
|
||||||
|
SHAL_Result SHAL_ADC::init(ADC_Key key) {
|
||||||
|
|
||||||
|
m_ADCKey = key;
|
||||||
|
|
||||||
|
if(!isValid()){
|
||||||
|
SHAL_UART2.sendString("Not valid\r\n");
|
||||||
|
return SHAL_Result::ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
SHAL_ADC_RCC_Enable_Reg clock_reg = getADCRCCEnableRegister(m_ADCKey); //Clock enable
|
||||||
|
|
||||||
|
SHAL_apply_bitmask(clock_reg.reg,clock_reg.mask);
|
||||||
|
|
||||||
|
auto clock_select_register = getADCClockSelectRegister();
|
||||||
|
|
||||||
|
SHAL_set_bits(clock_select_register.reg, 2, static_cast<uint32_t>(ADC_Clock_Source::SHAL_SYSCLK),clock_select_register.offset); //Set ADC clock
|
||||||
|
|
||||||
|
wakeFromDeepSleep();
|
||||||
|
|
||||||
|
if(calibrate() != SHAL_Result::OKAY){ //Calibrate
|
||||||
|
SHAL_UART2.sendString("Calibration failed");
|
||||||
|
return SHAL_Result::ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(enable() != SHAL_Result::OKAY){
|
||||||
|
SHAL_UART2.sendString("Could not enable from init\r\n");
|
||||||
|
return SHAL_Result::ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
configureAlignment(SHAL_ADC_Alignment::RIGHT);
|
||||||
|
configureResolution(SHAL_ADC_Resolution::B12);
|
||||||
|
|
||||||
|
return SHAL_Result::OKAY;
|
||||||
|
}
|
||||||
|
|
||||||
|
SHAL_Result SHAL_ADC::calibrate() {
|
||||||
|
SHAL_ADC_Control_Reg control_reg = getADCControlReg(m_ADCKey);
|
||||||
|
|
||||||
|
if(disable() != SHAL_Result::OKAY){
|
||||||
|
return SHAL_Result::ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
SHAL_delay_us(1000);
|
||||||
|
|
||||||
|
if ((*control_reg.reg & (control_reg.enable_mask | control_reg.disable_mask)) != 0) {
|
||||||
|
return SHAL_Result::ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
SHAL_clear_bitmask(control_reg.reg, control_reg.differential_mode_mask);
|
||||||
|
|
||||||
|
SHAL_apply_bitmask(control_reg.reg, control_reg.calibration_mask);
|
||||||
|
|
||||||
|
if ((*control_reg.reg & control_reg.calibration_mask) == 0) {
|
||||||
|
return SHAL_Result::ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!SHAL_WAIT_FOR_CONDITION_US(((*control_reg.reg & control_reg.calibration_mask) != 0),500)) { //Wait for conversion
|
||||||
|
return SHAL_Result::ERROR; //Failed sequence
|
||||||
|
}
|
||||||
|
|
||||||
|
SHAL_UART2.sendString("Calibration OK\r\n");
|
||||||
|
return SHAL_Result::OKAY;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t SHAL_ADC::singleConvertSingle(SHAL_ADC_Channel channel, SHAL_ADC_SampleTime time) {
|
||||||
|
auto data_reg = getADCDataReg(m_ADCKey);
|
||||||
|
auto ISR_reg = getADCISRReg(m_ADCKey);
|
||||||
|
auto config_reg = getADCConfigReg(m_ADCKey);
|
||||||
|
|
||||||
|
SHAL_clear_bitmask(config_reg.reg, config_reg.continuous_mode_mask);
|
||||||
|
|
||||||
|
auto sampleTimeReg = getADCChannelSamplingTimeRegister(m_ADCKey, channel);
|
||||||
|
SHAL_set_bits(sampleTimeReg.reg, 3, static_cast<uint8_t>(time), sampleTimeReg.channel_offset);
|
||||||
|
|
||||||
|
addADCChannelToSequence(channel, 0);
|
||||||
|
if(setADCSequenceAmount(1) == SHAL_Result::ERROR) { return 0; }
|
||||||
|
|
||||||
|
if(enable() != SHAL_Result::OKAY) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// CRITICAL: Clear ALL relevant flags before starting
|
||||||
|
SHAL_apply_bitmask(ISR_reg.reg, ISR_reg.end_of_sequence_mask);
|
||||||
|
SHAL_apply_bitmask(ISR_reg.reg, ISR_reg.end_of_conversion_mask);
|
||||||
|
if(ISR_reg.overrun_mask) {
|
||||||
|
SHAL_apply_bitmask(ISR_reg.reg, ISR_reg.overrun_mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
volatile uint16_t dummy = *data_reg.reg;
|
||||||
|
(void)dummy;
|
||||||
|
|
||||||
|
startConversion();
|
||||||
|
|
||||||
|
if(!SHAL_WAIT_FOR_CONDITION_US(((*ISR_reg.reg & ISR_reg.end_of_conversion_mask) != 0), 2000)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t result = *data_reg.reg;
|
||||||
|
|
||||||
|
SHAL_apply_bitmask(ISR_reg.reg, ISR_reg.end_of_conversion_mask);
|
||||||
|
SHAL_apply_bitmask(ISR_reg.reg, ISR_reg.end_of_sequence_mask);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
SHAL_Result SHAL_ADC::multiConvertSingle(SHAL_ADC_Channel* channels, const int numChannels, uint16_t* result, SHAL_ADC_SampleTime time) {
|
||||||
|
auto data_reg = getADCDataReg(m_ADCKey); //Where our output will be stored
|
||||||
|
|
||||||
|
setADCSequenceAmount(numChannels); //Convert the correct amount of channels
|
||||||
|
|
||||||
|
for(int i = 0; i < numChannels; i++){
|
||||||
|
auto channel = channels[i];
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
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()){
|
||||||
|
SHAL_UART2.sendString("Enable failed: Invalid \r\n");
|
||||||
|
return SHAL_Result::ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
SHAL_ADC_Control_Reg control_reg = getADCControlReg(m_ADCKey);
|
||||||
|
SHAL_ADC_ISR_Reg ISR_reg = getADCISRReg(m_ADCKey);
|
||||||
|
|
||||||
|
if(!SHAL_WAIT_FOR_CONDITION_MS((*control_reg.reg & control_reg.calibration_mask) == 0, 100)) {
|
||||||
|
return SHAL_Result::ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*control_reg.reg & control_reg.enable_mask) {
|
||||||
|
return SHAL_Result::OKAY; //Not an error
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*control_reg.reg & control_reg.disable_mask) {
|
||||||
|
return SHAL_Result::ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Clear ADRDY flag by writing 1 to it
|
||||||
|
SHAL_apply_bitmask(ISR_reg.reg, ISR_reg.ready_mask);
|
||||||
|
|
||||||
|
//Enable the ADC by setting ADEN
|
||||||
|
SHAL_apply_bitmask(control_reg.reg, control_reg.enable_mask);
|
||||||
|
|
||||||
|
if(!SHAL_WAIT_FOR_CONDITION_MS((*ISR_reg.reg & ISR_reg.ready_mask) != 0, 100)) {
|
||||||
|
return SHAL_Result::ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Clear ADRDY again
|
||||||
|
SHAL_apply_bitmask(ISR_reg.reg, ISR_reg.ready_mask);
|
||||||
|
|
||||||
|
return SHAL_Result::OKAY;
|
||||||
|
}
|
||||||
|
|
||||||
|
SHAL_Result SHAL_ADC::wakeFromDeepSleep() {
|
||||||
|
SHAL_ADC_Control_Reg control_reg = getADCControlReg(m_ADCKey); //ADC Control register
|
||||||
|
|
||||||
|
SHAL_clear_bitmask(control_reg.reg,control_reg.deep_power_down_mask); //Wake ADC from sleep
|
||||||
|
|
||||||
|
SHAL_apply_bitmask(control_reg.reg,control_reg.voltage_regulator_mask);
|
||||||
|
|
||||||
|
SHAL_delay_us(50); //Wait for regulator to stabilize
|
||||||
|
|
||||||
|
return SHAL_Result::OKAY;
|
||||||
|
}
|
||||||
|
|
||||||
|
SHAL_Result SHAL_ADC::disable() {
|
||||||
|
if(!isValid()){
|
||||||
|
return SHAL_Result::ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto control_reg = getADCControlReg(m_ADCKey);
|
||||||
|
|
||||||
|
//Stop any ongoing conversion
|
||||||
|
if (*control_reg.reg & control_reg.start_mask) {
|
||||||
|
SHAL_apply_bitmask(control_reg.reg, control_reg.stop_mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Only disable if ADC is enabled otherwise it hangs
|
||||||
|
if (*control_reg.reg & control_reg.enable_mask) {
|
||||||
|
SHAL_apply_bitmask(control_reg.reg, control_reg.disable_mask);
|
||||||
|
|
||||||
|
if (!SHAL_WAIT_FOR_CONDITION_MS(((*control_reg.reg & (control_reg.enable_mask | control_reg.disable_mask)) == 0),500)){
|
||||||
|
return SHAL_Result::ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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() {
|
||||||
|
if(m_ADCKey == ADC_Key::INVALID || m_ADCKey == ADC_Key::NUM_ADC){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
SHAL_Result SHAL_ADC::configureResolution(SHAL_ADC_Resolution resolution) {
|
||||||
|
if(!isValid()){
|
||||||
|
return SHAL_Result::ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
SHAL_ADC_Config_Reg config_reg = getADCConfigReg(m_ADCKey);
|
||||||
|
|
||||||
|
SHAL_set_bits(config_reg.reg,2,static_cast<uint8_t>(resolution),config_reg.resolution_offset);
|
||||||
|
|
||||||
|
return SHAL_Result::OKAY;
|
||||||
|
}
|
||||||
|
|
||||||
|
SHAL_Result SHAL_ADC::configureAlignment(SHAL_ADC_Alignment alignment) {
|
||||||
|
if(!isValid()){
|
||||||
|
return SHAL_Result::ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
SHAL_ADC_Config_Reg config_reg = getADCConfigReg(m_ADCKey);
|
||||||
|
|
||||||
|
//TODO check if this needs to be abstracted (Do other platforms have >2 resolution possibilities?
|
||||||
|
SHAL_set_bits(config_reg.reg,1,static_cast<uint8_t>(alignment),config_reg.alignment_offset);
|
||||||
|
|
||||||
|
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;
|
||||||
|
uint32_t sequenceRegNumber = (index + 1) / 5;
|
||||||
|
|
||||||
|
volatile uint32_t* sequenceReg = sequenceRegisters.regs[sequenceRegNumber];
|
||||||
|
uint32_t bitSectionOffset = sequenceRegisters.offsets[bitSection];
|
||||||
|
|
||||||
|
// Clear only the specific 5 bits we're setting, not the entire register
|
||||||
|
uint32_t clearMask = ~(0x1F << bitSectionOffset);
|
||||||
|
*sequenceReg &= clearMask;
|
||||||
|
|
||||||
|
// Set the new channel number
|
||||||
|
*sequenceReg |= (channelNum << bitSectionOffset);
|
||||||
|
|
||||||
|
return SHAL_Result::OKAY;
|
||||||
|
}
|
||||||
|
|
||||||
|
SHAL_ADC &ADCManager::get(ADC_Key key) {
|
||||||
|
return m_ADCs[static_cast<uint8_t>(key)];
|
||||||
|
}
|
||||||
|
|
||||||
|
SHAL_ADC& ADCManager::getByIndex(int index) {
|
||||||
|
|
||||||
|
if(index < static_cast<int>(ADC_Key::NUM_ADC)){
|
||||||
|
return m_ADCs[index];
|
||||||
|
}
|
||||||
|
return m_ADCs[0];
|
||||||
|
}
|
||||||
126
SHAL/Src/STM32L4xx/Peripheral/GPIO/SHAL_GPIO.cpp
Normal file
126
SHAL/Src/STM32L4xx/Peripheral/GPIO/SHAL_GPIO.cpp
Normal file
@@ -0,0 +1,126 @@
|
|||||||
|
//
|
||||||
|
// Created by Luca on 8/30/2025.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
#include "SHAL_GPIO.h"
|
||||||
|
#include "SHAL_EXTI_CALLBACK.h"
|
||||||
|
|
||||||
|
#include "SHAL_UART.h"
|
||||||
|
|
||||||
|
SHAL_GPIO::SHAL_GPIO() : m_GPIO_KEY(GPIO_Key::INVALID){
|
||||||
|
//Do not initialize anything
|
||||||
|
}
|
||||||
|
|
||||||
|
SHAL_GPIO::SHAL_GPIO(GPIO_Key key) : m_GPIO_KEY(key) {
|
||||||
|
|
||||||
|
volatile unsigned long* gpioEnable = getGPIORCCEnable(key).reg;
|
||||||
|
unsigned long gpioOffset = getGPIORCCEnable(key).offset;
|
||||||
|
|
||||||
|
*gpioEnable |= (1 << gpioOffset); //Set enable flag
|
||||||
|
}
|
||||||
|
|
||||||
|
void SHAL_GPIO::setLow() {
|
||||||
|
auto outputDataReg = getGPIOOutputDataRegister(m_GPIO_KEY);
|
||||||
|
SHAL_set_bits(outputDataReg.reg,1,0,outputDataReg.offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SHAL_GPIO::setHigh() {
|
||||||
|
auto outputDataReg = getGPIOOutputDataRegister(m_GPIO_KEY);
|
||||||
|
SHAL_set_bits(outputDataReg.reg,1,1,outputDataReg.offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SHAL_GPIO::toggle() volatile {
|
||||||
|
auto outputDataReg = getGPIOOutputDataRegister(m_GPIO_KEY);
|
||||||
|
SHAL_flip_bits(outputDataReg.reg,1,outputDataReg.offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SHAL_GPIO::setOutputType(PinType type) volatile {
|
||||||
|
auto outputTypeReg = getGPIOOutputTypeRegister(m_GPIO_KEY);
|
||||||
|
SHAL_set_bits(outputTypeReg.reg,2,static_cast<uint8_t>(type),outputTypeReg.offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SHAL_GPIO::setOutputSpeed(OutputSpeed speed) volatile {
|
||||||
|
auto outputSpeedReg = getGPIOOutputSpeedRegister(m_GPIO_KEY);
|
||||||
|
SHAL_set_bits(outputSpeedReg.reg,2,static_cast<uint8_t>(speed),outputSpeedReg.offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SHAL_GPIO::setInternalResistor(InternalResistorType type) volatile {
|
||||||
|
auto pupdreg = getGPIOPUPDRegister(m_GPIO_KEY);
|
||||||
|
SHAL_set_bits(pupdreg.reg,2,static_cast<uint8_t>(type),pupdreg.offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SHAL_GPIO::setAlternateFunction(GPIO_Alternate_Function AF) volatile {
|
||||||
|
auto alternateFunctionReg = getGPIOAlternateFunctionRegister(m_GPIO_KEY);
|
||||||
|
SHAL_set_bits(alternateFunctionReg.reg,4,static_cast<uint8_t>(AF),alternateFunctionReg.offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
SHAL_Result SHAL_GPIO::setPinMode(PinMode mode) volatile {
|
||||||
|
auto pinModeReg = getGPIOModeRegister(m_GPIO_KEY);
|
||||||
|
|
||||||
|
if(mode == PinMode::ANALOG_MODE && getGPIOPortInfo(m_GPIO_KEY).ADCChannel == SHAL_ADC_Channel::NO_ADC_MAPPING){
|
||||||
|
char buff[100];
|
||||||
|
sprintf(buff, "Error: GPIO pin %d has no valid ADC mapping\r\n", static_cast<uint8_t>(m_GPIO_KEY));
|
||||||
|
SHAL_UART2.sendString(buff);
|
||||||
|
return SHAL_Result::ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
SHAL_set_bits(pinModeReg.reg,2,static_cast<uint8_t>(mode),pinModeReg.offset); //Set mode
|
||||||
|
|
||||||
|
return SHAL_Result::OKAY;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SHAL_GPIO::useAsExternalInterrupt(TriggerMode mode, EXTICallback callback) {
|
||||||
|
|
||||||
|
|
||||||
|
/* ---- Connect PB6 to EXTI6 via SYSCFG ---- */
|
||||||
|
uint32_t port_b_val = 1; // 0=A, 1=B, 2=C, 3=D, etc.
|
||||||
|
SYSCFG->EXTICR[1] &= ~(0xFUL << 8); // Clear EXTI6 bits (bits 8-11)
|
||||||
|
SYSCFG->EXTICR[1] |= (port_b_val << 8); // Set EXTI6 to PB6
|
||||||
|
|
||||||
|
/* ---- Configure EXTI line 6 ---- */
|
||||||
|
EXTI->IMR1 |= (1UL << 6); // Unmask line 6
|
||||||
|
EXTI->RTSR1 |= (1UL << 6); // Rising trigger enable
|
||||||
|
EXTI->FTSR1 &= ~(1UL << 6); // Falling trigger disable
|
||||||
|
|
||||||
|
/* ---- Enable NVIC interrupt for EXTI lines [9:5] ---- */
|
||||||
|
NVIC_SetPriority(EXTI9_5_IRQn, 2);
|
||||||
|
NVIC_EnableIRQ(EXTI9_5_IRQn);
|
||||||
|
|
||||||
|
__enable_irq(); //Enable IRQ just in case
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t SHAL_GPIO::analogRead(SHAL_ADC_SampleTime sampleTime) {
|
||||||
|
|
||||||
|
SHAL_ADC_Channel channel = getGPIOPortInfo(m_GPIO_KEY).ADCChannel;
|
||||||
|
|
||||||
|
return GPIOManager::getGPIOADC().singleConvertSingle(channel,sampleTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SHAL_GPIO::setAlternateFunction(GPIO_Alternate_Function_Mapping AF) volatile {
|
||||||
|
setPinMode(PinMode::ALTERNATE_FUNCTION_MODE);
|
||||||
|
auto alternateFunctionReg = getGPIOAlternateFunctionRegister(m_GPIO_KEY);
|
||||||
|
SHAL_set_bits(alternateFunctionReg.reg,4,static_cast<uint8_t>(AF),alternateFunctionReg.offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t SHAL_GPIO::digitalRead() {
|
||||||
|
auto inputDataReg = getGPIOInputDataRegister(m_GPIO_KEY);
|
||||||
|
|
||||||
|
if((*inputDataReg.reg & (1 << 6)) != 0){
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SHAL_GPIO& GPIOManager::get(GPIO_Key key) {
|
||||||
|
|
||||||
|
unsigned int gpioPort = getGPIOPortNumber(key);
|
||||||
|
uint8_t gpioPin = getGPIOPinNumber(key);
|
||||||
|
|
||||||
|
if (m_gpios[gpioPort][gpioPin].m_GPIO_KEY == GPIO_Key::INVALID){
|
||||||
|
m_gpios[gpioPort][gpioPin] = SHAL_GPIO(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
return m_gpios[gpioPort][gpioPin];
|
||||||
|
}
|
||||||
@@ -27,8 +27,8 @@ void SHAL_I2C::init(I2C_Pair pair) volatile {
|
|||||||
GET_GPIO(SDA_Key).setAlternateFunction(I2CPair.SDA_Mask);
|
GET_GPIO(SDA_Key).setAlternateFunction(I2CPair.SDA_Mask);
|
||||||
|
|
||||||
//These may be abstracted further to support multiple I2C configurations
|
//These may be abstracted further to support multiple I2C configurations
|
||||||
GET_GPIO(SCL_Key).setPinType(PinType::OPEN_DRAIN);
|
GET_GPIO(SCL_Key).setOutputType(PinType::OPEN_DRAIN);
|
||||||
GET_GPIO(SDA_Key).setPinType(PinType::OPEN_DRAIN);
|
GET_GPIO(SDA_Key).setOutputType(PinType::OPEN_DRAIN);
|
||||||
|
|
||||||
GET_GPIO(SCL_Key).setOutputSpeed(OutputSpeed::HIGH_SPEED);
|
GET_GPIO(SCL_Key).setOutputSpeed(OutputSpeed::HIGH_SPEED);
|
||||||
GET_GPIO(SDA_Key).setOutputSpeed(OutputSpeed::HIGH_SPEED);
|
GET_GPIO(SDA_Key).setOutputSpeed(OutputSpeed::HIGH_SPEED);
|
||||||
117
SHAL/Src/STM32L4xx/Peripheral/Timer/SHAL_TIM.cpp
Normal file
117
SHAL/Src/STM32L4xx/Peripheral/Timer/SHAL_TIM.cpp
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
//
|
||||||
|
// Created by Luca on 8/28/2025.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "SHAL_TIM.h"
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
Timer::Timer(Timer_Key key) : m_key(key){
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Timer::Timer() : m_key(Timer_Key::S_TIM_INVALID){
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void Timer::start() {
|
||||||
|
|
||||||
|
auto control_reg = getTimerControlRegister1(m_key);
|
||||||
|
auto event_generation_reg = getTimerEventGenerationRegister(m_key);
|
||||||
|
auto status_reg = getTimerStatusRegister(m_key);
|
||||||
|
|
||||||
|
SHAL_apply_bitmask(control_reg.reg, control_reg.counter_enable_mask); //Enable counter
|
||||||
|
SHAL_apply_bitmask(control_reg.reg, control_reg.auto_reload_preload_enable_mask); //Preload enable (buffer)
|
||||||
|
SHAL_apply_bitmask(event_generation_reg.reg, event_generation_reg.update_generation_mask);
|
||||||
|
|
||||||
|
SHAL_clear_bitmask(status_reg.reg,status_reg.update_interrupt_flag_mask);
|
||||||
|
|
||||||
|
enableInterrupt();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Timer::stop() {
|
||||||
|
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) {
|
||||||
|
auto prescaler_reg = getTimerPrescalerRegister(m_key);
|
||||||
|
SHAL_set_register_value(prescaler_reg.reg,presc);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Timer::setARR(uint16_t arr) {
|
||||||
|
auto autoreload_reg = getTimerAutoReloadRegister(m_key);
|
||||||
|
SHAL_set_register_value(autoreload_reg.reg,arr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Timer::enableInterrupt() {
|
||||||
|
auto dma_ier = getTimerDMAInterruptEnableRegister(m_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(uint16_t prescaler, uint16_t autoReload) {
|
||||||
|
SHAL_TIM_RCC_Register rcc = getTimerRCC(m_key);
|
||||||
|
SHAL_apply_bitmask(rcc.reg,rcc.enable_mask);
|
||||||
|
|
||||||
|
setPrescaler(prescaler);
|
||||||
|
setARR(autoReload);
|
||||||
|
|
||||||
|
*getTimerStatusRegister(m_key).reg = 0;
|
||||||
|
*getTimerDMAInterruptEnableRegister(m_key).reg = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Timer::setPWMMode(SHAL_Timer_Channel channel, SHAL_TIM_Output_Compare_Mode outputCompareMode, SHAL_Timer_Channel_Main_Output_Mode mainOutputMode,
|
||||||
|
SHAL_Timer_Channel_Complimentary_Output_Mode complimentaryOutputMode) {
|
||||||
|
|
||||||
|
auto ccer = getTimerCaptureCompareEnableRegister(m_key);
|
||||||
|
auto ccmr1 = getTimerCaptureCompareModeRegistersOutput(m_key);
|
||||||
|
auto bdtr = getTimerBreakDeadTimeRegister(m_key);
|
||||||
|
|
||||||
|
uint8_t fullChannelModeMask = static_cast<uint8_t>(mainOutputMode) | (static_cast<uint8_t>(complimentaryOutputMode) << 2);
|
||||||
|
uint8_t channelNum = static_cast<uint8_t>(channel);
|
||||||
|
|
||||||
|
if (channelNum <= 3) {
|
||||||
|
|
||||||
|
uint32_t regNum = channelNum / 2; //TODO change later for support for channels 5 and 6
|
||||||
|
|
||||||
|
if (channelNum % 2 == 1) {
|
||||||
|
SHAL_set_bits(ccmr1.regs[regNum], 4, static_cast<uint8_t>(outputCompareMode),
|
||||||
|
ccmr1.output_compare_2_mode_offset);
|
||||||
|
} else {
|
||||||
|
SHAL_set_bits(ccmr1.regs[regNum], 4, static_cast<uint8_t>(outputCompareMode),
|
||||||
|
ccmr1.output_compare_1_mode_offset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t offset = channelNum * 4;
|
||||||
|
|
||||||
|
if (static_cast<uint8_t>(m_key) > 3) {
|
||||||
|
fullChannelModeMask &= (0b0011); //Clear bits for complimentary output since channels 4,5,6 don't support it
|
||||||
|
}
|
||||||
|
|
||||||
|
SHAL_set_bits(ccer.reg, 4, fullChannelModeMask, offset);
|
||||||
|
SHAL_apply_bitmask(bdtr.reg, bdtr.main_output_enable_mask);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void Timer::setPWMDutyCycle(uint32_t dutyCycle) {
|
||||||
|
auto reg = getTimerCaptureCompareRegister(m_key);
|
||||||
|
SHAL_set_bits(reg.reg,16,dutyCycle,0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Timer &TimerManager::get(Timer_Key timer_key) {
|
||||||
|
|
||||||
|
//Ensure that we don't try to get invalid timers
|
||||||
|
assert(timer_key != Timer_Key::S_TIM_INVALID && timer_key != Timer_Key::NUM_TIMERS);
|
||||||
|
|
||||||
|
Timer& selected = timers[static_cast<int>(timer_key)];
|
||||||
|
|
||||||
|
//Timer queried is not initialized yet (defaults to invalid)
|
||||||
|
if(selected.m_key == Timer_Key::S_TIM_INVALID){
|
||||||
|
timers[static_cast<int>(timer_key)] = Timer(timer_key); //Initialize TIMER_KEY
|
||||||
|
}
|
||||||
|
|
||||||
|
return timers[static_cast<int>(timer_key)];
|
||||||
|
}
|
||||||
16
SHAL/Src/STM32L4xx/Peripheral/Timer/SHAL_TIM_CALLBACK.cpp
Normal file
16
SHAL/Src/STM32L4xx/Peripheral/Timer/SHAL_TIM_CALLBACK.cpp
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
//
|
||||||
|
// Created by Luca on 8/28/2025.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "SHAL_TIM_CALLBACK.h"
|
||||||
|
|
||||||
|
DEFINE_TIMER_IRQ(Timer_Key::S_TIM1, TIM1_IRQHandler)
|
||||||
|
DEFINE_TIMER_IRQ(Timer_Key::S_TIM2, TIM2_IRQHandler)
|
||||||
|
DEFINE_TIMER_IRQ(Timer_Key::S_TIM6, TIM6_IRQHandler)
|
||||||
|
DEFINE_TIMER_IRQ(Timer_Key::S_TIM7, TIM7_IRQHandler)
|
||||||
|
DEFINE_TIMER_IRQ(Timer_Key::S_TIM15, TIM1_BRK_TIM15_IRQHandler)
|
||||||
|
DEFINE_TIMER_IRQ(Timer_Key::S_TIM16, TIM1_UP_TIM16_IRQHandler)
|
||||||
|
|
||||||
|
void registerTimerCallback(Timer_Key key, TimerCallback callback){
|
||||||
|
timer_callbacks[static_cast<uint32_t>(key)] = callback;
|
||||||
|
}
|
||||||
@@ -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,31 +35,43 @@ 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;
|
uint32_t adjustedBaudRate = SystemCoreClock / baudRate;
|
||||||
|
|
||||||
|
SHAL_set_register_value(baud_rate_reg.reg,adjustedBaudRate);
|
||||||
|
|
||||||
|
SHAL_apply_bitmask(control_reg.reg, control_reg.usart_enable_mask); //Turn on usart
|
||||||
}
|
}
|
||||||
|
|
||||||
void SHAL_UART::sendString(const char *s) volatile {
|
void SHAL_UART::sendString(const char *s) volatile {
|
||||||
while (*s) sendChar(*s++); //Send chars while we haven't reached end of s
|
while (*s) {//Send chars while we haven't reached end of s
|
||||||
|
sendChar(*s++);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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_MS((*ISR_non_fifo.reg & ISR_non_fifo.transmit_data_register_empty_mask) != 0, 500)){
|
||||||
|
PIN(B3).setHigh();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
usart->TDR = c; //Send character
|
auto transmit_reg = getUARTTransmitDataRegister(m_key);
|
||||||
|
SHAL_set_register_value_16(transmit_reg.reg, static_cast<uint16_t>(c));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1,89 +1,264 @@
|
|||||||
|
#include <cstdio>
|
||||||
#include "SHAL.h"
|
#include "SHAL.h"
|
||||||
#include "stm32f0xx.h"
|
|
||||||
|
|
||||||
#include <cstdlib>
|
|
||||||
|
|
||||||
void c3Interrupt(){
|
#define NUM_CHANNELS 6
|
||||||
SHAL_UART2.sendString("Begin\r\n");
|
|
||||||
|
|
||||||
uint8_t cmd[3] = {0xAC, 0x33, 0x00};
|
// Physical order on right-side header: A0, A1, A3, A4, A5, A6, A7
|
||||||
SHAL_I2C1.masterWrite(0x38, cmd, 3);
|
SHAL_ADC_Channel channels[NUM_CHANNELS] = {
|
||||||
|
SHAL_ADC_Channel::CH5,
|
||||||
|
SHAL_ADC_Channel::CH6,
|
||||||
|
SHAL_ADC_Channel::CH8,
|
||||||
|
SHAL_ADC_Channel::CH9,
|
||||||
|
SHAL_ADC_Channel::CH10,
|
||||||
|
SHAL_ADC_Channel::CH12,
|
||||||
|
};
|
||||||
|
|
||||||
SHAL_delay_ms(100);
|
bool isDeviceOn = false;
|
||||||
|
bool shouldToggleDeviceState = true;
|
||||||
|
bool shouldCheckSensorThresholds = true;
|
||||||
|
|
||||||
uint8_t dht_buf[7] = {0};
|
uint16_t vals[NUM_CHANNELS] = {0,0,0,0,0,0};
|
||||||
|
uint8_t currentSensor = 0;
|
||||||
|
|
||||||
//Read 7 bytes (status + 5 data + CRC)
|
bool isAlarmBeeping = false;
|
||||||
SHAL_I2C1.masterRead(0x38, dht_buf, 7);
|
|
||||||
|
|
||||||
//Parse humidity (20 bits)
|
uint16_t sensorThresholds[NUM_CHANNELS] = {0,0,0,0,0,0};
|
||||||
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) |
|
int buzzer_beepCount = 0;
|
||||||
((uint32_t)dht_buf[4] << 8) |
|
bool isBeepingForCalibration = false;
|
||||||
((uint32_t)dht_buf[5]);
|
|
||||||
|
|
||||||
// Use 64-bit intermediate to avoid overflow
|
bool prevIsCalibrateButtonHigh = false;
|
||||||
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];
|
int cyclesPerPrint = 2;
|
||||||
sprintf(out, "rawH=0x%05lX rawT=0x%05lX\r\n",
|
int currentCycle = 0;
|
||||||
(unsigned long)rawHumidity, (unsigned long)rawTemp);
|
|
||||||
SHAL_UART2.sendString(out);
|
|
||||||
|
|
||||||
// print as X.YY
|
bool areSensorRequirementsMetCurrent = false;
|
||||||
sprintf(out, "Temp: %ld.%02ld C, Hum: %ld.%02ld %%\r\n",
|
bool areSensorRequirementsMetPrevious = false;
|
||||||
(long)(temp_hundredths / 100), (long)(abs(temp_hundredths % 100)),
|
|
||||||
(long)(hum_hundredths / 100), (long)(hum_hundredths % 100));
|
void getSensorData(){
|
||||||
SHAL_UART2.sendString(out);
|
|
||||||
|
vals[currentSensor] = SHAL_ADC1.singleConvertSingle(channels[currentSensor]);
|
||||||
|
|
||||||
|
if(currentSensor == (NUM_CHANNELS - 1) && currentCycle == cyclesPerPrint - 1){
|
||||||
|
char buff[125];
|
||||||
|
// Print in the same order as the channels[] array (physical order)
|
||||||
|
sprintf(buff, "A0:%u,A1:%u,A3:%u,A4:%u,A5:%u,A6:%u\r\n",
|
||||||
|
vals[0], vals[1], vals[2], vals[3], vals[4], vals[5]);
|
||||||
|
SHAL_UART2.sendString(buff);
|
||||||
|
}
|
||||||
|
|
||||||
|
currentSensor = (currentSensor + 1) % NUM_CHANNELS;
|
||||||
|
currentCycle = (currentCycle + 1) % cyclesPerPrint;
|
||||||
}
|
}
|
||||||
|
|
||||||
void tim2Handler(){
|
void startBeeping(){
|
||||||
PIN(A4).toggle();
|
|
||||||
|
SHAL_TIM6.setPrescaler(4000);
|
||||||
|
SHAL_TIM6.setARR(200);
|
||||||
|
|
||||||
|
SHAL_TIM6.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void stopBeeping(){
|
||||||
|
SHAL_TIM1.stop();
|
||||||
|
SHAL_TIM6.stop();
|
||||||
|
isAlarmBeeping = false;
|
||||||
|
isBeepingForCalibration = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void checkSensorThresholds(){
|
||||||
|
|
||||||
|
bool localFlag = true;
|
||||||
|
|
||||||
|
for(int i = 0; i < NUM_CHANNELS; i++){
|
||||||
|
if(vals[i] < sensorThresholds[i]){
|
||||||
|
areSensorRequirementsMetCurrent = false; //Conditions not met
|
||||||
|
localFlag = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(localFlag){
|
||||||
|
areSensorRequirementsMetCurrent = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(areSensorRequirementsMetCurrent){
|
||||||
|
if(!areSensorRequirementsMetPrevious){
|
||||||
|
SHAL_TIM1.stop();
|
||||||
|
SHAL_TIM6.stop();
|
||||||
|
SHAL_TIM15.stop();
|
||||||
|
PIN(A9).setLow();
|
||||||
|
stopBeeping();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
if(areSensorRequirementsMetPrevious){
|
||||||
|
SHAL_TIM15.start();
|
||||||
|
PIN(A9).setHigh();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
areSensorRequirementsMetPrevious = areSensorRequirementsMetCurrent;
|
||||||
|
}
|
||||||
|
|
||||||
|
void calibrateThresholds(){
|
||||||
|
|
||||||
|
// Read every channel once and set threshold to 80% of reading
|
||||||
|
for(int i = 0; i < NUM_CHANNELS; i++){
|
||||||
|
uint16_t sensorVal = (vals[i] * 3) / 5;
|
||||||
|
|
||||||
|
if(sensorVal < 50){
|
||||||
|
sensorVal = 0;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
sensorVal = sensorVal - 50;
|
||||||
|
}
|
||||||
|
sensorThresholds[i] = sensorVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
char buff[125];
|
||||||
|
// Print in the same order as the channels[] array (physical order)
|
||||||
|
sprintf(buff, "Thresholds calibrated to: A0:%u,A1:%u,A3:%u,A4:%u,A5:%u,A6:%u\r\n",
|
||||||
|
sensorThresholds[0], sensorThresholds[1], sensorThresholds[2], sensorThresholds[3], sensorThresholds[4], sensorThresholds[5]);
|
||||||
|
SHAL_UART2.sendString(buff);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PWMToggle(){
|
||||||
|
|
||||||
|
//Flash light
|
||||||
|
PIN(A9).toggle();
|
||||||
|
|
||||||
|
SHAL_TIM15.stop(); //Stop timer for allowed time off sensors
|
||||||
|
|
||||||
|
if(isBeepingForCalibration && buzzer_beepCount > 2){
|
||||||
|
isBeepingForCalibration = false;
|
||||||
|
buzzer_beepCount = 0;
|
||||||
|
SHAL_TIM6.stop(); //Reset timer 6
|
||||||
|
SHAL_TIM1.stop(); //Stop buzzer
|
||||||
|
|
||||||
|
SHAL_TIM6.setPrescaler(4000);
|
||||||
|
SHAL_TIM6.setARR(400);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!isAlarmBeeping){
|
||||||
|
SHAL_TIM1.start();
|
||||||
|
buzzer_beepCount++;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
SHAL_TIM1.stop();
|
||||||
|
}
|
||||||
|
isAlarmBeeping = !isAlarmBeeping;
|
||||||
|
}
|
||||||
|
|
||||||
|
void buttonHoldCallback(){
|
||||||
|
|
||||||
|
shouldCheckSensorThresholds = false; //Dont check sensor thresholds yet, ensure that calibration beep happens
|
||||||
|
|
||||||
|
SHAL_TIM7.stop(); //Stop this timer
|
||||||
|
|
||||||
|
SHAL_TIM2.stop(); //Stop reading from ADC
|
||||||
|
|
||||||
|
buzzer_beepCount = 0;
|
||||||
|
isBeepingForCalibration = true;
|
||||||
|
|
||||||
|
SHAL_TIM6.init(4000,50);
|
||||||
|
SHAL_TIM6.start();
|
||||||
|
|
||||||
|
calibrateThresholds();
|
||||||
|
SHAL_TIM1.start();
|
||||||
|
|
||||||
|
SHAL_TIM2.start(); //Restart value checks
|
||||||
|
|
||||||
|
shouldToggleDeviceState = false;
|
||||||
|
shouldCheckSensorThresholds = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
|
|
||||||
SHAL_init();
|
SHAL_init();
|
||||||
|
|
||||||
//Setup UART2 (used by nucleo devices for USB comms)
|
//SHAL_UART2.init(UART_Pair_Key::Tx2A2_Rx2A3);
|
||||||
SHAL_UART2.init(UART_Pair::Tx2A2_Rx2A3);
|
//SHAL_UART2.begin(115200);
|
||||||
SHAL_UART2.begin(115200);
|
|
||||||
|
|
||||||
SHAL_I2C1.init(I2C_Pair::SCL1B6_SDA1B7);
|
PIN(A0).setPinMode(PinMode::ANALOG_MODE);
|
||||||
SHAL_I2C1.setClockConfig(0x2000090E);
|
PIN(A1).setPinMode(PinMode::ANALOG_MODE);
|
||||||
|
PIN(A3).setPinMode(PinMode::ANALOG_MODE);
|
||||||
|
PIN(A4).setPinMode(PinMode::ANALOG_MODE);
|
||||||
|
PIN(A5).setPinMode(PinMode::ANALOG_MODE);
|
||||||
|
PIN(A6).setPinMode(PinMode::ANALOG_MODE);
|
||||||
|
PIN(A7).setPinMode(PinMode::ANALOG_MODE);
|
||||||
|
|
||||||
//Use pin C3 to trigger a function on external interrupt
|
PIN(B6).setPinMode(PinMode::INPUT_MODE);
|
||||||
PIN(C3).useAsExternalInterrupt(TriggerMode::RISING_EDGE,c3Interrupt);
|
PIN(A9).setPinMode(PinMode::OUTPUT_MODE);
|
||||||
|
PIN(B0).setAlternateFunction(GPIO_Alternate_Function_Mapping::B0_TIM1CH2N);
|
||||||
|
|
||||||
SHAL_TIM2.init(8000-1,1500-1);
|
PIN(A8).setPinMode(PinMode::OUTPUT_MODE);
|
||||||
SHAL_TIM2.setCallbackFunc(tim2Handler);
|
PIN(A8).setInternalResistor(InternalResistorType::NO_PULL);
|
||||||
|
|
||||||
|
SHAL_TIM2.init(4000,200);
|
||||||
|
|
||||||
|
SHAL_TIM2.setCallbackFunc(getSensorData);
|
||||||
|
SHAL_TIM2.enableInterrupt();
|
||||||
SHAL_TIM2.start();
|
SHAL_TIM2.start();
|
||||||
|
|
||||||
PIN(A4).setPinMode(PinMode::OUTPUT_MODE);
|
SHAL_TIM1.init(0,2400); //PWM signal
|
||||||
PIN(A5).setPinMode(PinMode::OUTPUT_MODE);
|
SHAL_TIM1.setPWMMode(SHAL_Timer_Channel::CH2,SHAL_TIM_Output_Compare_Mode::PWMMode1,SHAL_Timer_Channel_Main_Output_Mode::Polarity_Normal,SHAL_Timer_Channel_Complimentary_Output_Mode::Polarity_Reversed);
|
||||||
|
SHAL_TIM1.setPWMDutyCycle(900);
|
||||||
|
|
||||||
SHAL_delay_ms(3000); //Wait 100 ms from datasheet
|
SHAL_TIM6.init(4000,500); //PWM switcher
|
||||||
|
SHAL_TIM6.setCallbackFunc(PWMToggle);
|
||||||
|
SHAL_TIM6.enableInterrupt();
|
||||||
|
|
||||||
uint8_t cmd = 0x71;
|
SHAL_TIM7.init(4000,3000); //Calibrate timer
|
||||||
uint8_t status = 0;
|
SHAL_TIM7.setCallbackFunc(buttonHoldCallback);
|
||||||
|
SHAL_TIM7.enableInterrupt();
|
||||||
|
|
||||||
SHAL_I2C1.masterWriteRead(0x38, &cmd, 1, &status, 1);
|
SHAL_TIM15.init(4000,5000); //5 seconds
|
||||||
|
SHAL_TIM15.setCallbackFunc(startBeeping);
|
||||||
char statusString[32];
|
SHAL_TIM15.enableInterrupt();
|
||||||
sprintf(statusString, "Status = 0x%02X\r\n", status);
|
|
||||||
SHAL_UART2.sendString(statusString);
|
|
||||||
|
|
||||||
|
|
||||||
SHAL_delay_ms(10);
|
SHAL_UART2.sendString("Hello3\r\n");
|
||||||
|
|
||||||
c3Interrupt();
|
while (true) { //TODO set to use button for simulating off sensor, uncomment for real functionality
|
||||||
//End setup
|
|
||||||
|
|
||||||
while (true) {
|
if(PIN(B6).digitalRead() != 1){
|
||||||
__WFI();
|
|
||||||
|
if(prevIsCalibrateButtonHigh){
|
||||||
|
SHAL_TIM7.start();
|
||||||
|
}
|
||||||
|
prevIsCalibrateButtonHigh = false;
|
||||||
|
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
if(!prevIsCalibrateButtonHigh){
|
||||||
|
if(shouldToggleDeviceState){
|
||||||
|
if(!isDeviceOn){ //Turn device on
|
||||||
|
PIN(A8).setHigh();
|
||||||
|
isDeviceOn = true;
|
||||||
|
}
|
||||||
|
else{ //Turn device off
|
||||||
|
PIN(A8).setLow();
|
||||||
|
PIN(A9).setLow();
|
||||||
|
isDeviceOn = false;
|
||||||
|
|
||||||
|
areSensorRequirementsMetCurrent = true;
|
||||||
|
areSensorRequirementsMetPrevious = true;
|
||||||
|
|
||||||
|
SHAL_TIM15.stop();
|
||||||
|
stopBeeping();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
shouldToggleDeviceState = true;
|
||||||
|
|
||||||
|
SHAL_TIM7.stop();
|
||||||
|
}
|
||||||
|
prevIsCalibrateButtonHigh = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(isDeviceOn && shouldCheckSensorThresholds){
|
||||||
|
checkSensorThresholds();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ set(CMAKE_ASM_COMPILER ${TOOLCHAIN_PREFIX}gcc)
|
|||||||
set(CMAKE_OBJCOPY ${TOOLCHAIN_PREFIX}objcopy)
|
set(CMAKE_OBJCOPY ${TOOLCHAIN_PREFIX}objcopy)
|
||||||
set(CMAKE_SIZE ${TOOLCHAIN_PREFIX}size)
|
set(CMAKE_SIZE ${TOOLCHAIN_PREFIX}size)
|
||||||
|
|
||||||
set(COMMON_FLAGS "-mcpu=cortex-m0 -mthumb -fdata-sections -ffunction-sections")
|
set(COMMON_FLAGS "-mcpu=cortex-m4 -mthumb -fdata-sections -ffunction-sections")
|
||||||
set(CMAKE_C_FLAGS_INIT "${COMMON_FLAGS} --specs=nano.specs")
|
set(CMAKE_C_FLAGS_INIT "${COMMON_FLAGS} --specs=nano.specs")
|
||||||
set(CMAKE_CXX_FLAGS_INIT "${COMMON_FLAGS} -fno-rtti -fno-exceptions -fno-threadsafe-statics --specs=nano.specs")
|
set(CMAKE_CXX_FLAGS_INIT "${COMMON_FLAGS} -fno-rtti -fno-exceptions -fno-threadsafe-statics --specs=nano.specs")
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user