Compare commits
3 Commits
914fbf5a17
...
b2d10f5e5e
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b2d10f5e5e | ||
|
|
25b56f9fcd | ||
|
|
183be36c64 |
@@ -12,6 +12,8 @@
|
||||
|
||||
#define NUM_I2C_BUSES 2
|
||||
|
||||
#define SHAL_I2C1 I2C(1)
|
||||
#define SHAL_I2C2 I2C(2)
|
||||
|
||||
enum class I2C_Pair : uint8_t{
|
||||
//I2C_1
|
||||
@@ -40,7 +42,7 @@ constexpr SHAL_I2C_Pair getI2CPair(const I2C_Pair pair){
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
constexpr SHAL_I2C_Enable_REG getI2CEnableReg(const I2C_Pair pair){
|
||||
constexpr SHAL_I2C_Enable_Reg getI2CEnableReg(const I2C_Pair pair){
|
||||
switch(pair){
|
||||
case I2C_Pair::SCL1B6_SDA1B7:
|
||||
case I2C_Pair::SCL1B8_SDA1B9:
|
||||
@@ -56,4 +58,37 @@ constexpr SHAL_I2C_Enable_REG getI2CEnableReg(const I2C_Pair pair){
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
constexpr SHAL_I2C_Reset_Reg getI2CResetReg(const I2C_Pair pair){
|
||||
switch(pair){
|
||||
case I2C_Pair::SCL1B6_SDA1B7:
|
||||
case I2C_Pair::SCL1B8_SDA1B9:
|
||||
return {&RCC->APB1RSTR,RCC_APB1RSTR_I2C1RST};
|
||||
case I2C_Pair::SCL2B10_SDA2B11:
|
||||
case I2C_Pair::SCL2B13_SDA2B14:
|
||||
return {&RCC->APB1RSTR,RCC_APB1RSTR_I2C2RST};
|
||||
case I2C_Pair::NUM_PAIRS:
|
||||
case I2C_Pair::INVALID:
|
||||
assert(false);
|
||||
return {nullptr, 0};
|
||||
}
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
//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){
|
||||
switch(pair){
|
||||
case I2C_Pair::SCL1B6_SDA1B7:
|
||||
case I2C_Pair::SCL1B8_SDA1B9:
|
||||
return {&I2C1->TIMINGR,31,23,19,15,7};
|
||||
case I2C_Pair::SCL2B10_SDA2B11:
|
||||
case I2C_Pair::SCL2B13_SDA2B14:
|
||||
return {&I2C2->TIMINGR,31,23,19,15,7};
|
||||
case I2C_Pair::NUM_PAIRS:
|
||||
case I2C_Pair::INVALID:
|
||||
assert(false);
|
||||
__builtin_unreachable();
|
||||
}
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
#endif //SHAL_I2C_REG_F072XB_H
|
||||
|
||||
@@ -17,9 +17,24 @@ struct SHAL_I2C_Pair {
|
||||
GPIO_Alternate_Function SDA_Mask;
|
||||
};
|
||||
|
||||
struct SHAL_I2C_Enable_REG{
|
||||
struct SHAL_I2C_Enable_Reg{
|
||||
volatile uint32_t* reg;
|
||||
uint32_t mask;
|
||||
};
|
||||
|
||||
struct SHAL_I2C_Reset_Reg{
|
||||
volatile uint32_t* reg;
|
||||
uint32_t mask;
|
||||
};
|
||||
|
||||
//Manual values for I2C timer register
|
||||
struct SHAL_I2C_Timing_Reg{
|
||||
volatile uint32_t* reg;
|
||||
uint8_t prescaler_offset;
|
||||
uint8_t dataSetupTime_offset;
|
||||
uint8_t dataHoldTime_offset;
|
||||
uint8_t SCLHighPeriod_offset;
|
||||
uint8_t SCLLowPeriod_offset;
|
||||
};
|
||||
|
||||
#endif //SHMINGO_HAL_SHAL_I2C_TYPES_H
|
||||
|
||||
@@ -15,6 +15,25 @@ class SHAL_I2C{
|
||||
|
||||
public:
|
||||
|
||||
void init(I2C_Pair pair) volatile;
|
||||
|
||||
///
|
||||
/// \param addr I2C address of slave device
|
||||
/// \param reg Address of register in slave device to write to
|
||||
/// \param data Data to write to slave register
|
||||
void masterTransmit(uint8_t addr, uint8_t reg, uint8_t data);
|
||||
|
||||
///
|
||||
/// \param addr I2C address of slave device
|
||||
/// \param reg Register to read data from
|
||||
uint8_t masterReceive(uint8_t addr, uint8_t reg);
|
||||
|
||||
//Manually set the clock configuration. Refer to your MCU's reference manual for examples
|
||||
void setClockConfig(uint8_t prescaler, uint8_t dataSetupTime, uint8_t dataHoldTime, uint8_t SCLHighPeriod, uint8_t SCLLowPeriod);
|
||||
|
||||
//Set clock configuration based on a value calculated from STM32CubeMX, or other similar tools
|
||||
void setClockConfig(uint32_t configuration);
|
||||
|
||||
private:
|
||||
|
||||
SHAL_I2C() = default;
|
||||
@@ -23,9 +42,7 @@ private:
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
#define I2C(num) I2CManager::get(num)
|
||||
|
||||
class I2CManager{
|
||||
|
||||
@@ -37,7 +54,7 @@ public:
|
||||
|
||||
private:
|
||||
|
||||
inline static SHAL_I2C m_UARTs[NUM_I2C_BUSES] = {};
|
||||
inline static SHAL_I2C m_I2CBuses[NUM_I2C_BUSES] = {};
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -29,6 +29,17 @@ enum class Timer_Key : uint8_t { //For STM32F072
|
||||
S_TIM_INVALID
|
||||
};
|
||||
|
||||
#define SHAL_TIM1 TimerManager::get(Timer_Key::S_TIM1)
|
||||
#define SHAL_TIM2 TimerManager::get(Timer_Key::S_TIM2)
|
||||
#define SHAL_TIM3 TimerManager::get(Timer_Key::S_TIM3)
|
||||
#define SHAL_TIM6 TimerManager::get(Timer_Key::S_TIM6)
|
||||
#define SHAL_TIM7 TimerManager::get(Timer_Key::S_TIM7)
|
||||
#define SHAL_TIM14 TimerManager::get(Timer_Key::S_TIM14)
|
||||
#define SHAL_TIM15 TimerManager::get(Timer_Key::S_TIM15)
|
||||
#define SHAL_TIM16 TimerManager::get(Timer_Key::S_TIM16)
|
||||
#define SHAL_TIM17 TimerManager::get(Timer_Key::S_TIM17)
|
||||
|
||||
|
||||
|
||||
//Get TIMER_KEY peripheral struct including bus register, enable mask, TIMER_KEY mask
|
||||
constexpr TIM_RCC_Enable getTimerRCC(Timer_Key t) {
|
||||
|
||||
@@ -18,6 +18,11 @@ class Timer {
|
||||
friend class TimerManager;
|
||||
public:
|
||||
|
||||
///
|
||||
/// \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
|
||||
void init(uint32_t prescaler, uint32_t autoReload);
|
||||
|
||||
//Starts the counter
|
||||
void start();
|
||||
|
||||
@@ -49,12 +54,16 @@ private:
|
||||
|
||||
|
||||
#define getTimer(timer_key) TimerManager::get(timer_key)
|
||||
#define TIM(num) TimerManager::getTimerFromIndex(num)
|
||||
|
||||
//Manages all timers so user does not have to personally initialize
|
||||
class TimerManager{
|
||||
public:
|
||||
|
||||
static Timer& get(Timer_Key);
|
||||
|
||||
static Timer& getTimerFromIndex(uint8_t index){return timers[index];}
|
||||
|
||||
TimerManager() = delete;
|
||||
|
||||
private:
|
||||
|
||||
@@ -12,6 +12,11 @@
|
||||
|
||||
#define NUM_USART_LINES 4
|
||||
|
||||
#define SHAL_UART1 UART(1)
|
||||
#define SHAL_UART2 UART(2)
|
||||
#define SHAL_UART3 UART(3)
|
||||
#define SHAL_UART4 UART(4)
|
||||
|
||||
//Valid usart Tx and Rx pairings for STM32F072
|
||||
enum class UART_Pair : uint8_t{
|
||||
//UART1
|
||||
|
||||
@@ -2,3 +2,119 @@
|
||||
// Created by Luca on 9/9/2025.
|
||||
//
|
||||
|
||||
#include "SHAL_I2C.h"
|
||||
#include "SHAL_GPIO.h"
|
||||
|
||||
void SHAL_I2C::init(I2C_Pair pair) volatile {
|
||||
m_I2CPair = pair;
|
||||
|
||||
SHAL_I2C_Pair I2CPair = getI2CPair(pair); //Get the UART_PAIR information to be initialized
|
||||
|
||||
//Get the SHAL_GPIO pins for this SHAL_I2C setup
|
||||
GPIO_Key SCL_Key = I2CPair.SCL_Key; //SCL pin
|
||||
GPIO_Key SDA_Key = I2CPair.SDA_Key; //SDA pin
|
||||
|
||||
GET_GPIO(SCL_Key).setPinMode(PinMode::ALTERNATE_FUNCTION_MODE); //Implicitly initializes and enables GPIO bus
|
||||
GET_GPIO(SDA_Key).setPinMode(PinMode::ALTERNATE_FUNCTION_MODE);
|
||||
|
||||
GET_GPIO(SCL_Key).setAlternateFunction(I2CPair.SCL_Mask);
|
||||
GET_GPIO(SDA_Key).setAlternateFunction(I2CPair.SDA_Mask);
|
||||
|
||||
//These may be abstracted further to support multiple I2C configurations
|
||||
GET_GPIO(SCL_Key).setPinType(PinType::OPEN_DRAIN);
|
||||
GET_GPIO(SDA_Key).setPinType(PinType::OPEN_DRAIN);
|
||||
|
||||
GET_GPIO(SCL_Key).setOutputSpeed(OutputSpeed::HIGH_SPEED);
|
||||
GET_GPIO(SDA_Key).setOutputSpeed(OutputSpeed::HIGH_SPEED);
|
||||
|
||||
GET_GPIO(SCL_Key).setInternalResistor(InternalResistorType::PULLUP);
|
||||
GET_GPIO(SDA_Key).setInternalResistor(InternalResistorType::PULLUP);
|
||||
|
||||
SHAL_I2C_Enable_Reg pairI2CEnable = getI2CEnableReg(pair); //Register and mask to enable the I2C peripheral
|
||||
SHAL_I2C_Reset_Reg pairI2CReset = getI2CResetReg(pair);
|
||||
|
||||
*pairI2CReset.reg |= pairI2CReset.mask; //Reset peripheral
|
||||
*pairI2CEnable.reg |= pairI2CEnable.mask; //Enable I2C peripheral clock
|
||||
|
||||
I2CPair.I2CReg->CR1 |= I2C_CR1_PE; //Enable I2C peripheral
|
||||
}
|
||||
|
||||
void SHAL_I2C::setClockConfig(uint8_t prescaler, uint8_t dataSetupTime, uint8_t dataHoldTime, uint8_t SCLHighPeriod, uint8_t SCLLowPeriod) {
|
||||
|
||||
SHAL_I2C_Timing_Reg clockReg = getI2CTimerReg(m_I2CPair);
|
||||
|
||||
*clockReg.reg |= (prescaler << clockReg.prescaler_offset);
|
||||
*clockReg.reg |= (dataSetupTime << clockReg.dataSetupTime_offset);
|
||||
*clockReg.reg |= (dataHoldTime << clockReg.dataHoldTime_offset);
|
||||
*clockReg.reg |= (SCLHighPeriod << clockReg.SCLHighPeriod_offset);
|
||||
*clockReg.reg |= (SCLLowPeriod << clockReg.SCLLowPeriod_offset);
|
||||
}
|
||||
|
||||
void SHAL_I2C::setClockConfig(uint32_t configuration) {
|
||||
*getI2CTimerReg(m_I2CPair).reg = configuration;
|
||||
}
|
||||
|
||||
void SHAL_I2C::masterTransmit(uint8_t addr, uint8_t reg, uint8_t data) {
|
||||
|
||||
volatile I2C_TypeDef* I2CPeripheral = getI2CPair(m_I2CPair).I2CReg;
|
||||
|
||||
//Wait until not busy
|
||||
while (I2CPeripheral->ISR & I2C_ISR_BUSY);
|
||||
|
||||
//Send start + slave address
|
||||
I2CPeripheral->CR2 = (addr << 1) | (2 << I2C_CR2_NBYTES_Pos) | I2C_CR2_START | I2C_CR2_AUTOEND; //Pack bits in compliance with I2C format
|
||||
|
||||
//Wait until TX ready
|
||||
while (!(I2CPeripheral->ISR & I2C_ISR_TXIS));
|
||||
|
||||
//Send register address
|
||||
I2CPeripheral->TXDR = reg;
|
||||
|
||||
//Wait until TX ready
|
||||
while (!(I2CPeripheral->ISR & I2C_ISR_TXIS));
|
||||
|
||||
//Send data to write to register
|
||||
I2CPeripheral->TXDR = data;
|
||||
}
|
||||
|
||||
|
||||
uint8_t SHAL_I2C::masterReceive(uint8_t addr, uint8_t reg) {
|
||||
|
||||
volatile I2C_TypeDef* I2CPeripheral = getI2CPair(m_I2CPair).I2CReg;
|
||||
|
||||
//Send register address with write
|
||||
|
||||
//Wait for bus
|
||||
while (I2CPeripheral->ISR & I2C_ISR_BUSY);
|
||||
|
||||
//Send start with I2C config
|
||||
I2CPeripheral->CR2 = (addr << 1) | (1 << I2C_CR2_NBYTES_Pos) | I2C_CR2_START;
|
||||
|
||||
//Wait for transmit
|
||||
while (!(I2CPeripheral->ISR & I2C_ISR_TXIS));
|
||||
|
||||
//Set address to read from
|
||||
I2CPeripheral->TXDR = reg;
|
||||
|
||||
//Wait for transfer to complete
|
||||
while (!(I2CPeripheral->ISR & I2C_ISR_TC));
|
||||
|
||||
//Restart in read mode, auto end
|
||||
I2CPeripheral->CR2 = (addr << 1) | I2C_CR2_RD_WRN |
|
||||
(1 << I2C_CR2_NBYTES_Pos) |
|
||||
I2C_CR2_START | I2C_CR2_AUTOEND;
|
||||
|
||||
//Wait
|
||||
while (!(I2C1->ISR & I2C_ISR_RXNE));
|
||||
return (uint8_t)I2C1->RXDR;
|
||||
}
|
||||
|
||||
SHAL_I2C& I2CManager::get(uint8_t I2CBus) {
|
||||
|
||||
if(I2CBus > NUM_I2C_BUSES - 1){
|
||||
assert(false);
|
||||
//Memory fault
|
||||
}
|
||||
|
||||
return m_I2CBuses[I2CBus];
|
||||
}
|
||||
|
||||
@@ -6,8 +6,7 @@
|
||||
#include <cassert>
|
||||
|
||||
Timer::Timer(Timer_Key t) : TIMER_KEY(t){
|
||||
TIM_RCC_Enable rcc = getTimerRCC(TIMER_KEY);
|
||||
*rcc.busEnableReg |= (1 << rcc.offset);
|
||||
|
||||
}
|
||||
|
||||
Timer::Timer() : TIMER_KEY(Timer_Key::S_TIM_INVALID){
|
||||
@@ -37,6 +36,14 @@ void Timer::enableInterrupt() {
|
||||
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) {
|
||||
|
||||
@@ -52,3 +59,5 @@ Timer &TimerManager::get(Timer_Key timer_key) {
|
||||
|
||||
return timers[static_cast<int>(timer_key)];
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -29,6 +29,8 @@ void SHAL_UART::init(const UART_Pair pair){
|
||||
SHAL_UART_ENABLE_REG pairUARTEnable = getUARTEnableReg(pair); //Register and mask to enable the SHAL_UART channel
|
||||
|
||||
*pairUARTEnable.reg |= pairUARTEnable.mask; //Enable SHAL_UART line
|
||||
|
||||
|
||||
}
|
||||
|
||||
void SHAL_UART::begin(uint32_t baudRate) volatile {
|
||||
@@ -63,5 +65,11 @@ void SHAL_UART::sendChar(char c) volatile {
|
||||
|
||||
|
||||
SHAL_UART& UARTManager::get(uint8_t uart) {
|
||||
|
||||
if(uart > NUM_USART_LINES - 1){
|
||||
assert(false);
|
||||
//Memory fault
|
||||
}
|
||||
|
||||
return m_UARTs[uart];
|
||||
}
|
||||
|
||||
@@ -13,23 +13,20 @@ void tim2Handler(){
|
||||
|
||||
int main() {
|
||||
|
||||
//Setup UART2 (used by nucleo devices for USB comms)
|
||||
SHAL_UART2.init(UART_Pair::Tx2A2_Rx2A3);
|
||||
SHAL_UART2.begin(115200);
|
||||
|
||||
UART(2).init(UART_Pair::Tx2A2_Rx2A3);
|
||||
|
||||
UART(2).begin(115200);
|
||||
|
||||
//Use pin C3 to trigger a function on external interrupt
|
||||
PIN(C3).useAsExternalInterrupt(TriggerMode::RISING_EDGE,c3Interrupt);
|
||||
|
||||
Timer timer2 = getTimer(Timer_Key::S_TIM2);
|
||||
SHAL_TIM2.init(8000-1,1500-1);
|
||||
SHAL_TIM2.setCallbackFunc(tim2Handler);
|
||||
SHAL_TIM2.start();
|
||||
|
||||
PIN(A4).setPinMode(PinMode::OUTPUT_MODE);
|
||||
PIN(A5).setPinMode(PinMode::OUTPUT_MODE);
|
||||
|
||||
timer2.setPrescaler(8000 - 1);
|
||||
timer2.setARR(1500 - 1);
|
||||
timer2.setCallbackFunc(tim2Handler);
|
||||
timer2.start();
|
||||
|
||||
while (true) {
|
||||
__WFI();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user