Refactored timer for F0

This commit is contained in:
Ea-r-th
2026-03-06 21:12:09 -08:00
parent 3593d8cbd2
commit 43bdee4406
26 changed files with 1763 additions and 606 deletions

View File

@@ -3,15 +3,15 @@ cmake_minimum_required(VERSION 3.19)
project(shmingo-HAL) project(shmingo-HAL)
set(PROJECT_DIR ${CMAKE_CURRENT_SOURCE_DIR}) set(PROJECT_DIR ${CMAKE_CURRENT_SOURCE_DIR})
set(MCU_FAMILY "STM32L4xx" CACHE STRING "MCU family") set(MCU_FAMILY "STM32F0xx")
set(MCU_MODEL "STM32L432xx" CACHE STRING "MCU model") set(MCU_MODEL "STM32F072xB")
set(CPU_PARAMETERS set(CPU_PARAMETERS
-mcpu=cortex-m4 -mcpu=cortex-m0
-mthumb) -mthumb)
set(STARTUP_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/MX/L432KC/startup_stm32l432kcux.s) set(STARTUP_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/MX/F072RB/startup_stm32f072rbtx.s)
set(MCU_LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/MX/L432KC/STM32L432KCUX_FLASH.ld) set(MCU_LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/MX/F072RB/STM32F072RBTX_FLASH.ld)
set(EXECUTABLE ${CMAKE_PROJECT_NAME}) set(EXECUTABLE ${CMAKE_PROJECT_NAME})
enable_language(C CXX ASM) enable_language(C CXX ASM)
@@ -29,28 +29,37 @@ set(MX_INCLUDE_DIRECTORIES
set(PROJECT_INCLUDE_DIRECTORIES set(PROJECT_INCLUDE_DIRECTORIES
${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}
SHAL/Include/Core/
SHAL/Include/Peripheral/Timer #[[
SHAL/Include/Peripheral/Timer/Reg
SHAL/Include/Peripheral/GPIO
SHAL/Include/Peripheral/GPIO/Reg
SHAL/Include/Peripheral/UART SHAL/Include/Peripheral/UART
SHAL/Include/Peripheral/UART/Reg SHAL/Include/Peripheral/UART/Reg
SHAL/Include/Peripheral/I2C SHAL/Include/Peripheral/I2C
SHAL/Include/Peripheral/I2C/Reg SHAL/Include/Peripheral/I2C/Reg
SHAL/Include/Peripheral/ADC SHAL/Include/Peripheral/ADC
SHAL/Include/Peripheral/ADC/Reg SHAL/Include/Peripheral/ADC/Reg
SHAL/Include/Peripheral/EXT/ SHAL/Include/Peripheral/EXT
SHAL/Include/Peripheral/EXT/Reg SHAL/Include/Peripheral/EXT/Reg
]]#
SHAL/Include/Core/
SHAL/Include/Peripheral/GPIO
SHAL/Include/Peripheral/GPIO/Reg
SHAL/Include/Peripheral/Timer
SHAL/Include/Peripheral/Timer/Reg
${CMAKE_CURRENT_SOURCE_DIR}/SHAL/Include ${CMAKE_CURRENT_SOURCE_DIR}/SHAL/Include
) )
file(GLOB_RECURSE PROJECT_SOURCES file(GLOB_RECURSE PROJECT_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/SHAL/Src/${MCU_FAMILY}/*.c
${CMAKE_CURRENT_SOURCE_DIR}/SHAL/Src/${MCU_FAMILY}/*.cpp
${CMAKE_CURRENT_SOURCE_DIR}/SHAL/Src/Universal/*.c
${CMAKE_CURRENT_SOURCE_DIR}/SHAL/Src/Universal/*.cpp ${CMAKE_CURRENT_SOURCE_DIR}/SHAL/Src/Universal/*.cpp
${CMAKE_CURRENT_SOURCE_DIR}/SHAL/Src/Universal/*.c
${CMAKE_CURRENT_SOURCE_DIR}/SHAL/Src/${MCU_FAMILY}/*.c
#${CMAKE_CURRENT_SOURCE_DIR}/SHAL/Src/${MCU_FAMILY}/*.cpp
${CMAKE_CURRENT_SOURCE_DIR}/SHAL/Src/main.cpp ${CMAKE_CURRENT_SOURCE_DIR}/SHAL/Src/main.cpp
#Temporary manual method of including source files to avoid including broken code
${CMAKE_CURRENT_SOURCE_DIR}/SHAL/Src/${MCU_FAMILY}/Peripheral/GPIO/*.cpp
${CMAKE_CURRENT_SOURCE_DIR}/SHAL/Src/${MCU_FAMILY}/Peripheral/Timer/*.cpp
${CMAKE_CURRENT_SOURCE_DIR}/SHAL/Src/${MCU_FAMILY}/Core/*.cpp
) )
add_executable(${EXECUTABLE} add_executable(${EXECUTABLE}
@@ -73,8 +82,6 @@ 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>

View File

@@ -5,12 +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 ?= STM32F072xB
MCU_FAMILY ?= STM32L4xx MCU_FAMILY ?= STM32F0xx
# --- Default target --- # --- Default target ---
all: build all: build
@@ -23,8 +20,6 @@ ${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)

View File

@@ -1,3 +1,9 @@
# Shmingo-HAL Instructions to run
A custom HAL for STM32F0 MCUs A binary is provided (Shmingo-HAL, formats are bin,hex,elf)
Download STM32CubeProgrammer
point to the binary file
Program via SWD (on Nucleo devices, you can just plug into USB and connect via onboard USB to SWD adapter)
You can also use an external ST-Link to program with the dedicated SWD pins

View File

@@ -8,6 +8,30 @@
#include "SHAL_CORE.h" #include "SHAL_CORE.h"
#include "SHAL_ADC_TYPES.h" #include "SHAL_ADC_TYPES.h"
enum class SHAL_ADC_Channel : uint32_t { //TODO remove unused or non existing channels?
CH0 = 0,
CH1,
CH2,
CH3,
CH4,
CH5,
CH6,
CH7,
CH8,
CH9,
CH10,
CH11,
CH12,
CH13,
CH14,
CH15,
CH16,
CHTemp,
CHRef,
CHBat,
NO_ADC_MAPPING
};
#define SHAL_ADC1 SHAL_ADC(1) #define SHAL_ADC1 SHAL_ADC(1)
enum class ADC_Key : uint8_t{ enum class ADC_Key : uint8_t{

View File

@@ -29,66 +29,29 @@ enum class GPIO_Key : uint8_t {
INVALID INVALID
}; };
static volatile GPIO_TypeDef * GPIO_TABLE[3] = { //Lookup table for ADCs
GPIOA,
GPIOB,
GPIOC,
};
constexpr uint8_t getGPIOPinNumber(GPIO_Key key){
return static_cast<uint8_t>(key) % 16;
}
constexpr SHAL_GPIO_Peripheral getGPIORegister(const GPIO_Key g){ static inline uint32_t getGPIOPortNumber(const GPIO_Key g){
switch(g) { return (static_cast<uint8_t>(g) / 16);
case GPIO_Key::A0: return {GPIOA,0};
case GPIO_Key::A1: return {GPIOA,1};
case GPIO_Key::A2: return {GPIOA,2};
case GPIO_Key::A3: return {GPIOA,3};
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();
static inline SHAL_GPIO_RCC_Enable_Register getGPIORCCEnable(const GPIO_Key g){
volatile uint32_t* reg = &RCC->AHBENR; //register
uint32_t mask;
mask = RCC_AHBENR_GPIOAEN << getGPIOPortNumber(g); //Should shift to get each port number
return {reg,mask};
} }
constexpr SHAL_GPIO_EXTI_Register getGPIOEXTICR(const GPIO_Key g){ constexpr SHAL_GPIO_EXTI_Register getGPIOEXTICR(const GPIO_Key g){
switch(g) { switch(g) {
case GPIO_Key::A0: return {&SYSCFG->EXTICR[0],SYSCFG_EXTICR1_EXTI0_PA,EXTI0_1_IRQn}; case GPIO_Key::A0: return {&SYSCFG->EXTICR[0],SYSCFG_EXTICR1_EXTI0_PA,EXTI0_1_IRQn};
@@ -148,128 +111,55 @@ constexpr SHAL_GPIO_EXTI_Register getGPIOEXTICR(const GPIO_Key g){
__builtin_unreachable(); __builtin_unreachable();
} }
constexpr SHAL_Peripheral_Register getGPIORCCEnable(const GPIO_Key g){
switch(g) {
case GPIO_Key::A0: static inline SHAL_GPIO_Mode_Register getGPIOModeRegister(const GPIO_Key key){
case GPIO_Key::A1: volatile uint32_t* reg = &GPIO_TABLE[static_cast<uint8_t>(key) / 16]->MODER;
case GPIO_Key::A2: uint32_t offset = 2 * (static_cast<uint8_t>(key) % 16);
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->AHBENR, RCC_AHBENR_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->AHBENR, RCC_AHBENR_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->AHBENR, RCC_AHBENR_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){ static inline SHAL_GPIO_Pullup_Pulldown_Register getGPIOPUPDRegister(const GPIO_Key key){
switch(g) { volatile uint32_t* reg = &GPIO_TABLE[static_cast<uint8_t>(key) / 16]->PUPDR;
case GPIO_Key::A0: uint32_t offset = 2 * static_cast<uint8_t>(key) % 16;
case GPIO_Key::A1: return {reg,offset};
case GPIO_Key::A2:
case GPIO_Key::A3:
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 0;
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 1;
case GPIO_Key::C0:
case GPIO_Key::C1:
case GPIO_Key::C2:
case GPIO_Key::C3:
case GPIO_Key::C4:
case GPIO_Key::C5:
case GPIO_Key::C6:
case GPIO_Key::C7:
case GPIO_Key::C8:
case GPIO_Key::C9:
case GPIO_Key::C10:
case GPIO_Key::C11:
case GPIO_Key::C12:
case GPIO_Key::C13:
case GPIO_Key::C14:
case GPIO_Key::C15:
return 2;
case GPIO_Key::INVALID:
case GPIO_Key::NUM_GPIO:
assert(false);
return 0;
}
__builtin_unreachable();
} }
static inline SHAL_GPIO_Alternate_Function_Register getGPIOAlternateFunctionRegister(const GPIO_Key key){
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)
uint32_t afrIndex = pinNumber < 8 ? 0 : 1;
volatile uint32_t* reg = &GPIO_TABLE[static_cast<uint8_t>(key) / 16]->AFR[afrIndex];
uint32_t offset = (pinNumber % 8) * 4; //Increment in groups of four
return {reg,offset};
}
static inline SHAL_GPIO_Output_Speed_Register getGPIOOutputSpeedRegister(const GPIO_Key key){
volatile uint32_t* reg = &GPIO_TABLE[static_cast<uint8_t>(key) / 16]->OSPEEDR;
uint32_t offset = 2 * static_cast<uint8_t>(key) % 16;
return {reg,offset};
}
static inline SHAL_GPIO_Output_Type_Register getGPIOOutputTypeRegister(const GPIO_Key key){
volatile uint32_t* reg = &GPIO_TABLE[static_cast<uint8_t>(key) / 16]->OTYPER;
uint32_t offset = static_cast<uint8_t>(key) % 16;
return {reg,offset};
}
static inline SHAL_GPIO_Output_Data_Register getGPIOOutputDataRegister(const GPIO_Key key){
volatile uint32_t* reg = &GPIO_TABLE[static_cast<uint8_t>(key) / 16]->ODR;
uint32_t offset = (static_cast<uint8_t>(key) % 16);
return {reg,offset};
}
static inline SHAL_GPIO_Input_Data_Register getGPIOInputDataRegister(const GPIO_Key key){
volatile uint32_t* reg = &GPIO_TABLE[static_cast<uint8_t>(key) / 16]->IDR;
uint32_t offset = static_cast<uint8_t>(key) % 16;
return {reg,offset};
}
/* TODO reimplement
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:
@@ -343,6 +233,6 @@ constexpr SHAL_GPIO_Port_Info getGPIOPortInfo(GPIO_Key key){
__builtin_unreachable(); __builtin_unreachable();
} }
*/
#endif //SHMINGO_HAL_SHAL_GPIO_REG_F072XB_H #endif //SHMINGO_HAL_SHAL_GPIO_REG_F072XB_H

View File

@@ -113,7 +113,8 @@ constexpr SHAL_GPIO_EXTI_Register getGPIOEXTICR(const GPIO_Key g){
static inline SHAL_GPIO_RCC_Enable_Register getGPIORCCEnable(const GPIO_Key g){ static inline SHAL_GPIO_RCC_Enable_Register getGPIORCCEnable(const GPIO_Key g){
volatile uint32_t* reg = &RCC->AHB2ENR; //register volatile uint32_t* reg = &RCC->AHB2ENR; //register
uint32_t offset; uint32_t offset;
offset = (static_cast<uint8_t>(g) / 16) == 0 ? RCC_AHB2ENR_GPIOAEN_Pos : RCC_AHB2ENR_GPIOBEN_Pos;
offset = RCC_AHB2ENR_GPIOAEN << getGPIOPortNUmber(g); //Should shift to get each port number
return {reg,offset}; return {reg,offset};
} }

View File

@@ -9,8 +9,8 @@
#include <cassert> #include <cassert>
#include "SHAL_EXTI_CALLBACK.h" //#include "SHAL_EXTI_CALLBACK.h"
#include "SHAL_ADC.h" //#include "SHAL_ADC.h"
//Abstraction of SHAL_GPIO registers //Abstraction of SHAL_GPIO registers
@@ -27,12 +27,12 @@ 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(SHAL_ADC_SampleTime sampleTime = SHAL_ADC_SampleTime::C8); //uint16_t analogRead(SHAL_ADC_SampleTime sampleTime = SHAL_ADC_SampleTime::C8); TODO Reimplement
uint16_t digitalRead(); 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 setAlternateFunction(GPIO_Alternate_Function_Mapping AF) volatile; //TODO reimplement?
void setOutputType(PinType type) volatile; void setOutputType(PinType type) volatile;
@@ -40,7 +40,7 @@ public:
void setInternalResistor(InternalResistorType type) volatile; void setInternalResistor(InternalResistorType type) volatile;
void useAsExternalInterrupt(TriggerMode mode, EXTICallback callback); //void useAsExternalInterrupt(TriggerMode mode, EXTICallback callback); TODO reimplement
SHAL_Result setPinMode(PinMode mode) volatile; SHAL_Result setPinMode(PinMode mode) volatile;
@@ -65,7 +65,7 @@ private:
#define GET_GPIO(key) GPIOManager::get(key) #define GET_GPIO(key) GPIOManager::get(key)
#define SET_ANALOGREAD_ADC(x) GPIOManager::setGPIOADC(x) //#define SET_ANALOGREAD_ADC(x) GPIOManager::setGPIOADC(x) TODO reimplement
//Manages instances of SHAL_GPIO objects //Manages instances of SHAL_GPIO objects
@@ -75,9 +75,9 @@ public:
static SHAL_GPIO& get(GPIO_Key); static SHAL_GPIO& get(GPIO_Key);
static SHAL_ADC getGPIOADC(){ return m_GPIO_ADC;} //static SHAL_ADC getGPIOADC(){ return m_GPIO_ADC;} TODO Reimplement
static void setGPIOADC(SHAL_ADC adc){m_GPIO_ADC = adc;} //static void setGPIOADC(SHAL_ADC adc){m_GPIO_ADC = adc;} TODO Reimplement
GPIOManager() = delete; GPIOManager() = delete;
@@ -85,7 +85,7 @@ private:
inline static SHAL_GPIO m_gpios[AVAILABLE_PORTS][PINS_PER_PORT] = {{}}; inline static SHAL_GPIO m_gpios[AVAILABLE_PORTS][PINS_PER_PORT] = {{}};
inline static SHAL_ADC m_GPIO_ADC = SHAL_ADC(1); //inline static SHAL_ADC m_GPIO_ADC = SHAL_ADC(1); TODO Reimplement
}; };

View File

@@ -6,8 +6,8 @@
#define SHAL_GPIO_TYPES_H #define SHAL_GPIO_TYPES_H
#include "SHAL_CORE.h" #include "SHAL_CORE.h"
#include "SHAL_ADC.h" //#include "SHAL_ADC.h"
#include "SHAL_ADC_TYPES.h" //#include "SHAL_ADC_TYPES.h"
struct SHAL_GPIO_EXTI_Register{ struct SHAL_GPIO_EXTI_Register{
volatile uint32_t* EXT_ICR; //4 32 bit registers which say which GPIO a line is connected to volatile uint32_t* EXT_ICR; //4 32 bit registers which say which GPIO a line is connected to
@@ -17,7 +17,7 @@ struct SHAL_GPIO_EXTI_Register{
struct SHAL_GPIO_RCC_Enable_Register{ struct SHAL_GPIO_RCC_Enable_Register{
volatile uint32_t* reg; volatile uint32_t* reg;
uint32_t offset; uint32_t mask;
}; };
struct SHAL_GPIO_Mode_Register { struct SHAL_GPIO_Mode_Register {
@@ -55,11 +55,12 @@ struct SHAL_GPIO_Input_Data_Register {
uint32_t offset; uint32_t offset;
}; };
/* TODO reimplement and uncomment ADC references (Here and on GPIO.h)
struct SHAL_GPIO_Port_Info{ struct SHAL_GPIO_Port_Info{
uint8_t number; uint8_t number;
SHAL_ADC_Channel ADCChannel; SHAL_ADC_Channel ADCChannel;
}; };
*/
enum class PinMode : uint8_t{ enum class PinMode : uint8_t{
INPUT_MODE = 0x00, INPUT_MODE = 0x00,
OUTPUT_MODE = 0x01, OUTPUT_MODE = 0x01,

View File

@@ -16,9 +16,9 @@
#include "SHAL_TIM_TYPES.h" #include "SHAL_TIM_TYPES.h"
enum class Timer_Key : uint8_t { //For STM32F072 enum class Timer_Key : uint8_t { //For STM32F072
S_TIM1, S_TIM1 = 0,
S_TIM2, S_TIM2 = 1,
S_TIM3, S_TIM3 = 2,
S_TIM6, S_TIM6,
S_TIM7, S_TIM7,
S_TIM14, S_TIM14,
@@ -39,20 +39,40 @@ enum class Timer_Key : uint8_t { //For STM32F072
#define SHAL_TIM16 TimerManager::get(Timer_Key::S_TIM16) #define SHAL_TIM16 TimerManager::get(Timer_Key::S_TIM16)
#define SHAL_TIM17 TimerManager::get(Timer_Key::S_TIM17) #define SHAL_TIM17 TimerManager::get(Timer_Key::S_TIM17)
static SHAL_TIM_Info TIM_INFO_TABLE[9] = {
{TIM1,TIM1_BRK_UP_TRG_COM_IRQn,4},
{TIM2,TIM2_IRQn,4},
{TIM3,TIM3_IRQn,4},
{TIM6,TIM6_DAC_IRQn,0},
{TIM7,TIM7_IRQn,0},
{TIM14,TIM14_IRQn,1},
{TIM15,TIM15_IRQn,2},
{TIM16,TIM16_IRQn,1},
{TIM17,TIM17_IRQn,1},
};
//Get actual register value based on enum
static volatile TIM_TypeDef* getTimerRegister(Timer_Key t) {
return TIM_INFO_TABLE[static_cast<uint8_t>(t)].timer;
}
static IRQn_Type getIRQn(Timer_Key t) {
return TIM_INFO_TABLE[static_cast<uint8_t>(t)].IRQn;
}
//Get TIMER_KEY peripheral struct including bus register, enable mask, TIMER_KEY mask //Get TIMER_KEY peripheral struct including bus register, enable mask, TIMER_KEY mask
constexpr TIM_RCC_Enable getTimerRCC(Timer_Key t) { static SHAL_TIM_RCC_Register getTimerRCC(Timer_Key t) {
switch(t) { switch(t) {
case Timer_Key::S_TIM1: return {&RCC->APB2ENR, RCC_APB2ENR_TIM1EN_Pos}; case Timer_Key::S_TIM1: return {&RCC->APB2ENR, RCC_APB2ENR_TIM1EN};
case Timer_Key::S_TIM2: return {&RCC->APB1ENR, RCC_APB1ENR_TIM2EN_Pos}; case Timer_Key::S_TIM2: return {&RCC->APB1ENR, RCC_APB1ENR_TIM2EN};
case Timer_Key::S_TIM3: return {&RCC->APB1ENR, RCC_APB1ENR_TIM3EN_Pos}; case Timer_Key::S_TIM3: return {&RCC->APB1ENR, RCC_APB1ENR_TIM3EN};
case Timer_Key::S_TIM6: return {&RCC->APB1ENR, RCC_APB1ENR_TIM6EN_Pos}; case Timer_Key::S_TIM6: return {&RCC->APB1ENR, RCC_APB1ENR_TIM6EN};
case Timer_Key::S_TIM7: return {&RCC->APB1ENR, RCC_APB1ENR_TIM7EN_Pos}; case Timer_Key::S_TIM7: return {&RCC->APB1ENR, RCC_APB1ENR_TIM7EN};
case Timer_Key::S_TIM14: return {&RCC->APB1ENR, RCC_APB1ENR_TIM14EN_Pos}; case Timer_Key::S_TIM14: return {&RCC->APB1ENR, RCC_APB1ENR_TIM14EN};
case Timer_Key::S_TIM15: return {&RCC->APB2ENR, RCC_APB2ENR_TIM15EN_Pos}; case Timer_Key::S_TIM15: return {&RCC->APB2ENR, RCC_APB2ENR_TIM15EN};
case Timer_Key::S_TIM16: return {&RCC->APB2ENR, RCC_APB2ENR_TIM16EN_Pos}; case Timer_Key::S_TIM16: return {&RCC->APB2ENR, RCC_APB2ENR_TIM16EN};
case Timer_Key::S_TIM17: return {&RCC->APB2ENR, RCC_APB2ENR_TIM17EN_Pos}; case Timer_Key::S_TIM17: return {&RCC->APB2ENR, RCC_APB2ENR_TIM17EN};
case Timer_Key::NUM_TIMERS: case Timer_Key::NUM_TIMERS:
case Timer_Key::S_TIM_INVALID: case Timer_Key::S_TIM_INVALID:
assert(false); assert(false);
@@ -62,43 +82,161 @@ constexpr TIM_RCC_Enable getTimerRCC(Timer_Key t) {
__builtin_unreachable(); __builtin_unreachable();
} }
//Get actual register value based on enum
constexpr volatile TIM_TypeDef* getTimerRegister(Timer_Key t) { static inline SHAL_TIM_Status_Register getTimerStatusRegister(Timer_Key key){
switch(t) {
case Timer_Key::S_TIM1: return TIM1; SHAL_TIM_Status_Register res = {nullptr, TIM_SR_UIF};
case Timer_Key::S_TIM2: return TIM2;
case Timer_Key::S_TIM3: return TIM3; volatile TIM_TypeDef* tim = TIM_INFO_TABLE[static_cast<uint8_t>(key)].timer;
case Timer_Key::S_TIM6: return TIM6;
case Timer_Key::S_TIM7: return TIM7; res.reg = &tim->SR;
case Timer_Key::S_TIM14: return TIM14; return res;
case Timer_Key::S_TIM15: return TIM15;
case Timer_Key::S_TIM16: return TIM16;
case Timer_Key::S_TIM17: return TIM17;
case Timer_Key::NUM_TIMERS:
case Timer_Key::S_TIM_INVALID:
assert(false);
return nullptr; //Unreachable
}
__builtin_unreachable();
} }
constexpr IRQn_Type getIRQn(Timer_Key t) { static inline SHAL_TIM_Control_Register_1 getTimerControlRegister1(Timer_Key key){
switch(t) {
case Timer_Key::S_TIM1: return TIM1_BRK_UP_TRG_COM_IRQn; SHAL_TIM_Control_Register_1 res = {nullptr, TIM_CR1_CEN_Msk,
case Timer_Key::S_TIM2: return TIM2_IRQn; TIM_CR1_UDIS,
case Timer_Key::S_TIM3: return TIM3_IRQn; TIM_CR1_OPM,
case Timer_Key::S_TIM6: return TIM6_DAC_IRQn; TIM_CR1_CMS_Pos,
case Timer_Key::S_TIM7: return TIM7_IRQn; TIM_CR1_ARPE};
case Timer_Key::S_TIM14: return TIM14_IRQn;
case Timer_Key::S_TIM15: return TIM15_IRQn; volatile TIM_TypeDef* tim = TIM_INFO_TABLE[static_cast<uint8_t>(key)].timer;
case Timer_Key::S_TIM16: return TIM16_IRQn;
case Timer_Key::S_TIM17: return TIM17_IRQn; res.reg = &tim->CR1;
case Timer_Key::NUM_TIMERS: return res;
case Timer_Key::S_TIM_INVALID:
assert(false);
return TIM1_BRK_UP_TRG_COM_IRQn; //Unreachable
} }
__builtin_unreachable();
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_INFO_TABLE[static_cast<uint8_t>(key)].timer;
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_INFO_TABLE[static_cast<uint8_t>(key)].timer;
res.reg = &tim->EGR;
return res;
}
static inline SHAL_TIM_Break_Dead_Time_Register getTimerBreakDeadTimeRegister(Timer_Key key) {
SHAL_TIM_Break_Dead_Time_Register res = {nullptr,
TIM_BDTR_DTG_Pos,
TIM_BDTR_LOCK_Pos,
TIM_BDTR_OSSI,
TIM_BDTR_OSSR,
TIM_BDTR_BKE,
TIM_BDTR_BKP,
TIM_BDTR_AOE,
TIM_BDTR_MOE};
volatile TIM_TypeDef* tim = TIM_INFO_TABLE[static_cast<uint8_t>(key)].timer;
res.reg = &tim->BDTR;
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_INFO_TABLE[static_cast<uint8_t>(key)].timer;
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_INFO_TABLE[static_cast<uint8_t>(key)].timer;
res.reg = &tim->ARR;
return res;
}
static inline SHAL_TIM_Capture_Compare_Register getTimerCaptureCompareRegister(Timer_Key key, SHAL_Timer_Channel channel){
auto channel_num = static_cast<uint8_t>(channel);
volatile TIM_TypeDef* tim = TIM_INFO_TABLE[static_cast<uint8_t>(key)].timer;
assert(channel_num <= TIM_INFO_TABLE[static_cast<uint8_t>(key)].numChannels);
switch(channel){
case SHAL_Timer_Channel::CH1: return {&tim->CCR1,0};
case SHAL_Timer_Channel::CH2: return {&tim->CCR2,0};
case SHAL_Timer_Channel::CH3: return {&tim->CCR3,0};
case SHAL_Timer_Channel::CH4: return {&tim->CCR4,0};
}
}
static inline SHAL_TIM_Capture_Compare_Enable_Register getTimerCaptureCompareEnableRegister(Timer_Key key, SHAL_Timer_Channel channel){
uint8_t channel_stride = 3;
auto channel_num = static_cast<uint8_t>(channel);
auto output_enable = TIM_CCER_CC1E << (channel_stride * (channel_num - 1));
auto output_polarity = TIM_CCER_CC1P << (channel_stride * channel_num);
auto output_complimentary_enable = TIM_CCER_CC1NE << (channel_stride * channel_num);
auto output_complimentary_polarity = TIM_CCER_CC1NP << (channel_stride * channel_num);
SHAL_TIM_Capture_Compare_Enable_Register res = {nullptr,
output_enable,
output_polarity,
output_complimentary_enable,
output_complimentary_polarity,
};
volatile TIM_TypeDef* tim = TIM_INFO_TABLE[static_cast<uint8_t>(key)].timer;
res.reg = &tim->CCER;
return res;
}
static inline SHAL_TIM_Output_Capture_Compare_Mode_Register getTimerOutputCaptureCompareModeRegister(Timer_Key key, SHAL_Timer_Channel channel) {
SHAL_TIM_Output_Capture_Compare_Mode_Register res = {
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_INFO_TABLE[static_cast<uint8_t>(key)].timer;
uint8_t num_tim_channels = TIM_INFO_TABLE[static_cast<uint8_t>(key)].numChannels;
volatile uint32_t* reg = nullptr;
uint8_t channelNum = static_cast<uint32_t>(channel);
assert(num_tim_channels >= channelNum); //Assert that we don't access undefined memory trying to initialize a non-existent channel
if(channelNum >= 3){
reg = &tim->CCMR2;
}
else{
reg = &tim->CCMR1;
}
res.reg = reg;
return res;
} }

View File

@@ -38,7 +38,10 @@ 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); //Capture Compare Functions
void setCaptureCompareValue(SHAL_Timer_Channel channel, uint16_t value);
void enableChannel(SHAL_Timer_Channel channel, SHAL_Timer_Channel_Main_Output_Mode mainOutputMode, SHAL_Timer_Channel_Complimentary_Output_Mode complimentaryOutputMode);
void setOutputCompareMode(SHAL_Timer_Channel channel, SHAL_TIM_Output_Compare_Mode outputCompareMode);
/// Set the duty cycle for PWM /// Set the duty cycle for PWM
/// \param dutyCycle 10 * percentage (e.g. 500 = 50%) /// \param dutyCycle 10 * percentage (e.g. 500 = 50%)

View File

@@ -7,6 +7,12 @@
#include "SHAL_CORE.h" #include "SHAL_CORE.h"
struct SHAL_TIM_Info{
volatile TIM_TypeDef* timer;
IRQn_Type IRQn;
uint8_t numChannels;
};
struct SHAL_TIM_RCC_Register{ struct SHAL_TIM_RCC_Register{
volatile uint32_t* reg; volatile uint32_t* reg;
uint32_t enable_mask; uint32_t enable_mask;
@@ -47,7 +53,7 @@ struct SHAL_TIM_Auto_Reload_Register {
}; };
struct SHAL_TIM_Capture_Compare_Mode_Registers_Input { struct SHAL_TIM_Capture_Compare_Mode_Registers_Input {
volatile uint32_t* regs[2]; volatile uint32_t* regs;
uint32_t input_capture_1_filter_offset; uint32_t input_capture_1_filter_offset;
uint32_t input_capture_1_prescaler_offset; uint32_t input_capture_1_prescaler_offset;
uint32_t capture_compare_1_selection_offset; uint32_t capture_compare_1_selection_offset;
@@ -56,8 +62,8 @@ struct SHAL_TIM_Capture_Compare_Mode_Registers_Input {
uint32_t capture_compare_2_selection_offset; uint32_t capture_compare_2_selection_offset;
}; };
struct SHAL_TIM_Capture_Compare_Mode_Registers_Output { struct SHAL_TIM_Output_Capture_Compare_Mode_Register {
volatile uint32_t* regs[2]; volatile uint32_t* reg;
uint32_t capture_compare_1_selection_offset; uint32_t capture_compare_1_selection_offset;
uint32_t output_compare_1_fast_enable_mask; uint32_t output_compare_1_fast_enable_mask;
uint32_t output_compare_1_preload_enable_mask; uint32_t output_compare_1_preload_enable_mask;
@@ -72,15 +78,27 @@ struct SHAL_TIM_Capture_Compare_Mode_Registers_Output {
struct SHAL_TIM_Break_Dead_Time_Register { struct SHAL_TIM_Break_Dead_Time_Register {
volatile uint32_t* reg; volatile uint32_t* reg;
uint32_t main_output_enable_mask; uint32_t dead_time_offset; // [7:0] DTG - Dead-time generator setup
uint32_t lock_configuration_offset; // [9:8] LOCK - Lock configuration
uint32_t off_state_selection_idle_mask; // [10] OSSI - Off-state selection for idle mode
uint32_t off_state_selection_run_mask; // [11] OSSR - Off-state selection for run mode
uint32_t break_enable_mask; // [12] BKE - Break enable
uint32_t break_polarity_mask; // [13] BKP - Break polarity
uint32_t automatic_output_enable_mask; // [14] AOE - Automatic output enable
uint32_t main_output_enable_mask; // [15] MOE - Main output enable
}; };
struct SHAL_TIM_Capture_Compare_Enable_Register { struct SHAL_TIM_Capture_Compare_Enable_Register {
volatile uint32_t* reg; volatile uint32_t* reg;
uint32_t cc_output_enable_offset;
uint32_t cc_output_polarity_offset;
uint32_t cc_complimentary_output_enable_offset;
uint32_t cc_complimentary_output_polarity_offset;
}; };
struct SHAL_TIM_Capture_Compare_Register { struct SHAL_TIM_Capture_Compare_Register {
volatile uint32_t* reg; volatile uint32_t* reg;
uint32_t offset;
}; };
@@ -102,12 +120,10 @@ enum class SHAL_TIM_Output_Compare_Preload : uint8_t {
}; };
enum class SHAL_Timer_Channel : uint8_t { //TODO change if other timers have fewer than 6 channels enum class SHAL_Timer_Channel : uint8_t { //TODO change if other timers have fewer than 6 channels
CH1 = 0, CH1 = 1,
CH2 = 1, CH2 = 2,
CH3 = 2, CH3 = 3,
CH4 = 3, CH4 = 4,
CH5 = 4,
CH6 = 5,
}; };
enum class SHAL_Timer_Channel_Main_Output_Mode : uint8_t { enum class SHAL_Timer_Channel_Main_Output_Mode : uint8_t {

View File

@@ -8,8 +8,6 @@
#include "SHAL_CORE.h" #include "SHAL_CORE.h"
#include "SHAL_GPIO_REG.h" #include "SHAL_GPIO_REG.h"
//Represents a pair of pins usable for USART Tx + Rx in combination, and their alternate function mapping //Represents a pair of pins usable for USART Tx + Rx in combination, and their alternate function mapping
struct SHAL_UART_Pair{ struct SHAL_UART_Pair{
USART_TypeDef* USARTReg; USART_TypeDef* USARTReg;

View File

@@ -10,8 +10,8 @@
#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_ADC.h" //#include "SHAL_ADC.h"

View File

@@ -5,7 +5,7 @@
#include "SHAL_ADC.h" #include "SHAL_ADC.h"
//Can hard code registers on F0 because all F0 devices have only one ADC, and use only one clock //Can hard code registers on F0 because all F0 devices have only one ADC, and use only one clock
SHAL_Result SHAL_ADC::init() { SHAL_Result SHAL_ADC::init(ADC_Key key) {
if(m_ADCKey == ADC_Key::INVALID || m_ADCKey == ADC_Key::NUM_ADC){ if(m_ADCKey == ADC_Key::INVALID || m_ADCKey == ADC_Key::NUM_ADC){
return SHAL_Result::ERROR; return SHAL_Result::ERROR;
@@ -81,7 +81,7 @@ uint16_t SHAL_ADC::singleConvertSingle(SHAL_ADC_Channel channel, SHAL_ADC_Sample
return result; return result;
} }
void SHAL_ADC::multiConvertSingle(SHAL_ADC_Channel* channels, const int numChannels, uint16_t* result, SHAL_ADC_SampleTime time) { SHAL_Result SHAL_ADC::multiConvertSingle(SHAL_ADC_Channel* channels, int numChannels, uint16_t* result, SHAL_ADC_SampleTime time) {
ADC_TypeDef* ADC_reg = getADCRegister(m_ADCKey); ADC_TypeDef* ADC_reg = getADCRegister(m_ADCKey);
ADC->CCR |= ADC_CCR_VREFEN | ADC_CCR_TSEN; //Enable VREFINT and Temp sensor in global ADC struct ADC->CCR |= ADC_CCR_VREFEN | ADC_CCR_TSEN; //Enable VREFINT and Temp sensor in global ADC struct

View File

@@ -3,7 +3,7 @@
// //
#include "SHAL_GPIO.h" #include "SHAL_GPIO.h"
#include "SHAL_EXTI_CALLBACK.h" //#include "SHAL_EXTI_CALLBACK.h"
@@ -13,10 +13,9 @@ SHAL_GPIO::SHAL_GPIO() : m_GPIO_KEY(GPIO_Key::INVALID){
SHAL_GPIO::SHAL_GPIO(GPIO_Key key) : m_GPIO_KEY(key) { SHAL_GPIO::SHAL_GPIO(GPIO_Key key) : m_GPIO_KEY(key) {
volatile unsigned long* gpioEnable = getGPIORCCEnable(key).reg; auto GPIORCCEnable = getGPIORCCEnable(key);
unsigned long gpioOffset = getGPIORCCEnable(key).offset;
*gpioEnable |= (1 << gpioOffset); //Set enable flag SHAL_set_register_value(GPIORCCEnable.reg,GPIORCCEnable.mask);
} }
void SHAL_GPIO::setLow() { void SHAL_GPIO::setLow() {
@@ -54,12 +53,23 @@ void SHAL_GPIO::setAlternateFunction(GPIO_Alternate_Function AF) volatile {
SHAL_set_bits(alternateFunctionReg.reg,4,static_cast<uint8_t>(AF),alternateFunctionReg.offset); SHAL_set_bits(alternateFunctionReg.reg,4,static_cast<uint8_t>(AF),alternateFunctionReg.offset);
} }
void SHAL_GPIO::setPinMode(PinMode mode) volatile { SHAL_Result SHAL_GPIO::setPinMode(PinMode mode) volatile {
SHAL_GPIO_Peripheral gpioPeripheral = getGPIORegister(m_GPIO_KEY); auto pinModeReg = getGPIOModeRegister(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 /*
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;
} }
/* TODO Fix implementation for STM32F072
void SHAL_GPIO::useAsExternalInterrupt(TriggerMode mode, EXTICallback callback) { void SHAL_GPIO::useAsExternalInterrupt(TriggerMode mode, EXTICallback callback) {
uint32_t gpioPin = getGPIORegister(m_GPIO_KEY).global_offset; //Use existing structs to get offset uint32_t gpioPin = getGPIORegister(m_GPIO_KEY).global_offset; //Use existing structs to get offset
@@ -98,19 +108,21 @@ void SHAL_GPIO::useAsExternalInterrupt(TriggerMode mode, EXTICallback callback)
__enable_irq(); //Enable IRQ just in case __enable_irq(); //Enable IRQ just in case
} }
*/
/* TODO reimplement
uint16_t SHAL_GPIO::analogRead(SHAL_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;
return GPIOManager::getGPIOADC().singleConvertSingle(channel,sampleTime); return GPIOManager::getGPIOADC().singleConvertSingle(channel,sampleTime);
} }
*/
SHAL_GPIO& GPIOManager::get(GPIO_Key key) { SHAL_GPIO& GPIOManager::get(GPIO_Key key) {
unsigned int gpioPort = getGPIOPortNumber(key); unsigned int gpioPort = getGPIOPortNumber(key);
unsigned long gpioPin = getGPIORegister(key).global_offset; //Use existing structs to get offset uint8_t gpioPin = getGPIOPinNumber(key);
if (m_gpios[gpioPort][gpioPin].m_GPIO_KEY == GPIO_Key::INVALID){ if (m_gpios[gpioPort][gpioPin].m_GPIO_KEY == GPIO_Key::INVALID){
m_gpios[gpioPort][gpioPin] = SHAL_GPIO(key); m_gpios[gpioPort][gpioPin] = SHAL_GPIO(key);

View File

@@ -95,8 +95,6 @@ void SHAL_I2C::masterWriteRead(uint8_t addr,const uint8_t* writeData, size_t wri
//Read phase //Read phase
if (readLen > 0) { if (readLen > 0) {
SHAL_UART2.sendString("Read initiated\r\n");
I2CPeripheral->CR2 &= ~(I2C_CR2_NBYTES | I2C_CR2_SADD | I2C_CR2_RD_WRN); I2CPeripheral->CR2 &= ~(I2C_CR2_NBYTES | I2C_CR2_SADD | I2C_CR2_RD_WRN);
I2CPeripheral->CR2 |= (addr << 1) | I2CPeripheral->CR2 |= (addr << 1) |
I2C_CR2_RD_WRN | I2C_CR2_RD_WRN |

View File

@@ -5,45 +5,96 @@
#include "SHAL_TIM.h" #include "SHAL_TIM.h"
#include <cassert> #include <cassert>
Timer::Timer(Timer_Key t) : TIMER_KEY(t){ Timer::Timer(Timer_Key t) : m_key(t){
} }
Timer::Timer() : TIMER_KEY(Timer_Key::S_TIM_INVALID){ Timer::Timer() : m_key(Timer_Key::S_TIM_INVALID){
} }
void Timer::start() { void Timer::start() {
getTimerRegister(TIMER_KEY)->CR1 |= TIM_CR1_CEN;
getTimerRegister(TIMER_KEY)->EGR |= TIM_EGR_UG; //load prescaler reg and ARR auto control_reg = getTimerControlRegister1(m_key);
auto event_generation_reg = getTimerEventGenerationRegister(m_key);
auto status_reg = getTimerStatusRegister(m_key);
auto break_time_dead_reg = getTimerBreakDeadTimeRegister(m_key);
auto rcc_reg = getTimerRCC(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);
SHAL_apply_bitmask(rcc_reg.reg,rcc_reg.enable_mask);
SHAL_apply_bitmask(break_time_dead_reg.reg,break_time_dead_reg.main_output_enable_mask);
enableInterrupt(); enableInterrupt();
} }
void Timer::stop() { void Timer::stop() {
getTimerRegister(TIMER_KEY)->CR1 &= ~TIM_CR1_CEN; auto rcc_reg = getTimerRCC(m_key);
SHAL_clear_bitmask(rcc_reg.reg,rcc_reg.enable_mask);
} }
void Timer::setPrescaler(uint16_t presc) { void Timer::setPrescaler(uint16_t presc) {
getTimerRegister(TIMER_KEY)->PSC = presc; getTimerRegister(m_key)->PSC = presc;
} }
void Timer::setARR(uint16_t arr) { void Timer::setARR(uint16_t arr) {
getTimerRegister(TIMER_KEY)->ARR = arr; getTimerRegister(m_key)->ARR = arr;
} }
void Timer::enableInterrupt() { void Timer::enableInterrupt() {
getTimerRegister(TIMER_KEY)->DIER |= TIM_DIER_UIE; getTimerRegister(m_key)->DIER |= TIM_DIER_UIE;
NVIC_EnableIRQ(getIRQn(TIMER_KEY)); NVIC_EnableIRQ(getIRQn(m_key));
} }
void Timer::init(uint32_t prescaler, uint32_t autoReload) { void Timer::init(uint16_t prescaler, uint16_t autoReload) {
TIM_RCC_Enable rcc = getTimerRCC(TIMER_KEY); SHAL_TIM_RCC_Register rcc = getTimerRCC(m_key);
*rcc.busEnableReg |= (1 << rcc.offset);
SHAL_apply_bitmask(rcc.reg,rcc.enable_mask);
setPrescaler(prescaler); setPrescaler(prescaler);
setARR(autoReload); setARR(autoReload);
} }
void Timer::setOutputCompareMode(SHAL_Timer_Channel channel, SHAL_TIM_Output_Compare_Mode outputCompareMode) {
auto channelNum = static_cast<uint8_t>(channel);
auto CCMR = getTimerOutputCaptureCompareModeRegister(m_key, channel);
uint32_t OCMR_Offset = channelNum % 2 == 1 ? CCMR.output_compare_1_mode_offset : CCMR.output_compare_2_mode_offset;
SHAL_set_bits(CCMR.reg,3,static_cast<uint8_t>(outputCompareMode),OCMR_Offset);
}
void Timer::enableChannel(SHAL_Timer_Channel channel, SHAL_Timer_Channel_Main_Output_Mode mainOutputMode,
SHAL_Timer_Channel_Complimentary_Output_Mode complimentaryOutputMode) {
SHAL_TIM_Capture_Compare_Enable_Register captureCompareEnableReg = getTimerCaptureCompareEnableRegister(m_key, channel);
uint16_t setValue = 0; //Value to set the register as
auto channelNum = static_cast<uint8_t>(channel);
uint8_t channelStride = 4; //4 bits per field
setValue |= (static_cast<uint8_t>(mainOutputMode) << ((channelNum - 1) * channelStride)); //xxBB shifted by c - 1
setValue |= (static_cast<uint8_t>(complimentaryOutputMode) << (((channelNum - 1) * channelStride) + 2)); //BBxx shifted by c - 1
SHAL_set_bits(captureCompareEnableReg.reg,16,setValue,0);
}
void Timer::setCaptureCompareValue(SHAL_Timer_Channel channel, uint16_t value) {
auto captureCompareReg = getTimerCaptureCompareRegister(m_key,channel);
SHAL_set_bits(captureCompareReg.reg,16,value,0);
}
Timer &TimerManager::get(Timer_Key timer_key) { Timer &TimerManager::get(Timer_Key timer_key) {
@@ -53,11 +104,9 @@ Timer &TimerManager::get(Timer_Key timer_key) {
Timer& selected = timers[static_cast<int>(timer_key)]; Timer& selected = timers[static_cast<int>(timer_key)];
//Timer queried is not initialized yet (defaults to invalid) //Timer queried is not initialized yet (defaults to invalid)
if(selected.TIMER_KEY == Timer_Key::S_TIM_INVALID){ if(selected.m_key == Timer_Key::S_TIM_INVALID){
timers[static_cast<int>(timer_key)] = Timer(timer_key); //Initialize TIMER_KEY timers[static_cast<int>(timer_key)] = Timer(timer_key); //Initialize TIMER_KEY
} }
return timers[static_cast<int>(timer_key)]; return timers[static_cast<int>(timer_key)];
} }

View File

@@ -112,7 +112,7 @@ uint16_t SHAL_ADC::singleConvertSingle(SHAL_ADC_Channel channel, SHAL_ADC_Sample
return result; return result;
} }
SHAL_Result SHAL_ADC::multiConvertSingle(SHAL_ADC_Channel* channels, const int numChannels, uint16_t* result, SHAL_ADC_SampleTime time) { SHAL_Result SHAL_ADC::multiConvertSingle(SHAL_ADC_Channel* channels, int numChannels, uint16_t* result, SHAL_ADC_SampleTime time) {
auto data_reg = getADCDataReg(m_ADCKey); //Where our output will be stored auto data_reg = getADCDataReg(m_ADCKey); //Where our output will be stored
setADCSequenceAmount(numChannels); //Convert the correct amount of channels setADCSequenceAmount(numChannels); //Convert the correct amount of channels

View File

@@ -79,7 +79,6 @@ void SHAL_I2C::masterWriteRead(uint8_t addr,const uint8_t* writeData, size_t wri
for (size_t i = 0; i < writeLen; i++) { for (size_t i = 0; i < writeLen; i++) {
if(!SHAL_WAIT_FOR_CONDITION_MS((I2CPeripheral->ISR & I2C_ISR_TXIS) != 0, 100)){ if(!SHAL_WAIT_FOR_CONDITION_MS((I2CPeripheral->ISR & I2C_ISR_TXIS) != 0, 100)){
SHAL_UART2.sendString("I2C timed out waiting for TX\r\n");
return; return;
} }
I2CPeripheral->TXDR = writeData[i]; I2CPeripheral->TXDR = writeData[i];

View File

@@ -1,264 +1,19 @@
#include <cstdio> #include <cstdio>
#include "SHAL.h" #include "SHAL.h"
#define NUM_CHANNELS 6
// Physical order on right-side header: A0, A1, A3, A4, A5, A6, A7
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,
};
bool isDeviceOn = false;
bool shouldToggleDeviceState = true;
bool shouldCheckSensorThresholds = true;
uint16_t vals[NUM_CHANNELS] = {0,0,0,0,0,0};
uint8_t currentSensor = 0;
bool isAlarmBeeping = false;
uint16_t sensorThresholds[NUM_CHANNELS] = {0,0,0,0,0,0};
int buzzer_beepCount = 0;
bool isBeepingForCalibration = false;
bool prevIsCalibrateButtonHigh = false;
int cyclesPerPrint = 2;
int currentCycle = 0;
bool areSensorRequirementsMetCurrent = false;
bool areSensorRequirementsMetPrevious = false;
void getSensorData(){
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 startBeeping(){
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();
//SHAL_UART2.init(UART_Pair_Key::Tx2A2_Rx2A3); PIN(A8).setPinMode(PinMode::ALTERNATE_FUNCTION_MODE);
//SHAL_UART2.begin(115200);
PIN(A0).setPinMode(PinMode::ANALOG_MODE); PIN(A8).setAlternateFunction(GPIO_Alternate_Function::AF2);
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);
PIN(B6).setPinMode(PinMode::INPUT_MODE); RCC->APB2ENR |= RCC_APB2ENR_TIM1EN;
PIN(A9).setPinMode(PinMode::OUTPUT_MODE);
PIN(B0).setAlternateFunction(GPIO_Alternate_Function_Mapping::B0_TIM1CH2N);
PIN(A8).setPinMode(PinMode::OUTPUT_MODE); SHAL_TIM1.init(48,100);
PIN(A8).setInternalResistor(InternalResistorType::NO_PULL); SHAL_TIM1.setOutputCompareMode(SHAL_Timer_Channel::CH1,SHAL_TIM_Output_Compare_Mode::PWMMode1);
SHAL_TIM1.enableChannel(SHAL_Timer_Channel::CH1,SHAL_Timer_Channel_Main_Output_Mode::Polarity_Reversed,SHAL_Timer_Channel_Complimentary_Output_Mode::Disabled);
SHAL_TIM2.init(4000,200); SHAL_TIM1.setCaptureCompareValue(SHAL_Timer_Channel::CH1, 5);
SHAL_TIM1.start();
SHAL_TIM2.setCallbackFunc(getSensorData);
SHAL_TIM2.enableInterrupt();
SHAL_TIM2.start();
SHAL_TIM1.init(0,2400); //PWM signal
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_TIM6.init(4000,500); //PWM switcher
SHAL_TIM6.setCallbackFunc(PWMToggle);
SHAL_TIM6.enableInterrupt();
SHAL_TIM7.init(4000,3000); //Calibrate timer
SHAL_TIM7.setCallbackFunc(buttonHoldCallback);
SHAL_TIM7.enableInterrupt();
SHAL_TIM15.init(4000,5000); //5 seconds
SHAL_TIM15.setCallbackFunc(startBeeping);
SHAL_TIM15.enableInterrupt();
SHAL_UART2.sendString("Hello3\r\n");
while (true) { //TODO set to use button for simulating off sensor, uncomment for real functionality
if(PIN(B6).digitalRead() != 1){
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();
}
}
} }

View File

@@ -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-m4 -mthumb -fdata-sections -ffunction-sections") set(COMMON_FLAGS "-mcpu=cortex-m0 -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")

BIN
shmingo-HAL.bin Normal file

Binary file not shown.

BIN
shmingo-HAL.elf Normal file

Binary file not shown.

1265
shmingo-HAL.hex Normal file

File diff suppressed because it is too large Load Diff