diff --git a/SHAL/Include/Peripheral/I2C/Reg/SHAL_I2C_REG_F072xB.h b/SHAL/Include/Peripheral/I2C/Reg/SHAL_I2C_REG_F072xB.h index 4a9812c..3a70ed7 100644 --- a/SHAL/Include/Peripheral/I2C/Reg/SHAL_I2C_REG_F072xB.h +++ b/SHAL/Include/Peripheral/I2C/Reg/SHAL_I2C_REG_F072xB.h @@ -77,10 +77,10 @@ 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,4,23,4,19,4,15,8,7,0}; + return {&I2C1->TIMINGR,31,23,19,15,7}; case I2C_Pair::SCL2B10_SDA2B11: case I2C_Pair::SCL2B13_SDA2B14: - return {&I2C2->TIMINGR,31,4,23,4,19,4,15,8,7,0}; + return {&I2C2->TIMINGR,31,23,19,15,7}; case I2C_Pair::NUM_PAIRS: case I2C_Pair::INVALID: assert(false); diff --git a/SHAL/Include/Peripheral/I2C/Reg/SHAL_I2C_TYPES.h b/SHAL/Include/Peripheral/I2C/Reg/SHAL_I2C_TYPES.h index d0f0146..d83ff4d 100644 --- a/SHAL/Include/Peripheral/I2C/Reg/SHAL_I2C_TYPES.h +++ b/SHAL/Include/Peripheral/I2C/Reg/SHAL_I2C_TYPES.h @@ -31,15 +31,10 @@ struct SHAL_I2C_Reset_Reg{ struct SHAL_I2C_Timing_Reg{ volatile uint32_t* reg; uint8_t prescaler_offset; - uint8_t prescaler_width; uint8_t dataSetupTime_offset; - uint8_t dataSetupTime_width; uint8_t dataHoldTime_offset; - uint8_t dataHoldTime_width; uint8_t SCLHighPeriod_offset; - uint8_t SCLHighPeriod_width; uint8_t SCLLowPeriod_offset; - uint8_t SCLLowPeriod_width; }; #endif //SHMINGO_HAL_SHAL_I2C_TYPES_H diff --git a/SHAL/Include/Peripheral/I2C/SHAL_I2C.h b/SHAL/Include/Peripheral/I2C/SHAL_I2C.h index 9a9470c..eec5694 100644 --- a/SHAL/Include/Peripheral/I2C/SHAL_I2C.h +++ b/SHAL/Include/Peripheral/I2C/SHAL_I2C.h @@ -17,7 +17,16 @@ public: void init(I2C_Pair pair) volatile; - void masterTransmit(); + /// + /// \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); @@ -33,9 +42,7 @@ private: }; - - - +#define I2C(num) I2CManager::get(num) class I2CManager{ @@ -47,7 +54,7 @@ public: private: - inline static SHAL_I2C m_UARTs[NUM_I2C_BUSES] = {}; + inline static SHAL_I2C m_I2CBuses[NUM_I2C_BUSES] = {}; }; diff --git a/SHAL/Src/Peripheral/I2C/SHAL_I2C.cpp b/SHAL/Src/Peripheral/I2C/SHAL_I2C.cpp index c7f749c..4ae2440 100644 --- a/SHAL/Src/Peripheral/I2C/SHAL_I2C.cpp +++ b/SHAL/Src/Peripheral/I2C/SHAL_I2C.cpp @@ -3,8 +3,118 @@ // #include "SHAL_I2C.h" +#include "SHAL_GPIO.h" -void SHAL_I2C::init() volatile { +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]; +} diff --git a/SHAL/Src/Peripheral/UART/SHAL_UART.cpp b/SHAL/Src/Peripheral/UART/SHAL_UART.cpp index c8d1a52..237ea24 100644 --- a/SHAL/Src/Peripheral/UART/SHAL_UART.cpp +++ b/SHAL/Src/Peripheral/UART/SHAL_UART.cpp @@ -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]; }