diff --git a/SHAL/Include/Core/SHAL_CORE.h b/SHAL/Include/Core/SHAL_CORE.h index f668139..256d0cc 100644 --- a/SHAL/Include/Core/SHAL_CORE.h +++ b/SHAL/Include/Core/SHAL_CORE.h @@ -11,9 +11,24 @@ #include +//Overall init function for SHAL -------------------------- + +void SHAL_init(); + +//--------------------------------------------------------- + + + + //Universal structs and defines --------------------------- +//Currently configures systick to count down in microseconds +void systick_init(); +//Max of 16ms, use SHAL_delay_ms for longer delay +void SHAL_delay_us(uint32_t us); + +void SHAL_delay_ms(uint32_t ms); //--------------------------------------------------------- diff --git a/SHAL/Include/Peripheral/I2C/SHAL_I2C.h b/SHAL/Include/Peripheral/I2C/SHAL_I2C.h index eec5694..a37f656 100644 --- a/SHAL/Include/Peripheral/I2C/SHAL_I2C.h +++ b/SHAL/Include/Peripheral/I2C/SHAL_I2C.h @@ -5,6 +5,8 @@ #ifndef SHMINGO_HAL_SHAL_I2C_H #define SHMINGO_HAL_SHAL_I2C_H +#include + #include "SHAL_CORE.h" #include "SHAL_I2C_REG.h" @@ -17,16 +19,26 @@ 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); + /// General I2C function to send commands to a device, then read back any returned data if necessary + /// \param addr address of slave device + /// \param writeData pointer to array of write commands + /// \param writeLen number of write commands + /// \param readData pointer to buffer to write received data to + /// \param readLen number of bytes to be read + void masterWriteRead(uint8_t addr,const uint8_t* writeData, size_t writeLen, uint8_t* readData, size_t readLen); + + /// Function to write an array of commands to an I2C device + /// \param addr Address of slave device + /// \param writeData Pointer to array of commands + /// \param writeLen Number of commands + void masterWrite(uint8_t addr, const uint8_t* writeData, uint8_t writeLen); + + /// Function to read bytes from an I2C device + /// \param addr Address of slave device + /// \param readBuffer Pointer to buffer where data will be placed + /// \param bytesToRead Number of bytes to read + void masterRead(uint8_t addr, uint8_t* readBuffer, uint8_t bytesToRead); - /// - /// \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); diff --git a/SHAL/Include/SHAL.h b/SHAL/Include/SHAL.h index 9756334..2e6d6de 100644 --- a/SHAL/Include/SHAL.h +++ b/SHAL/Include/SHAL.h @@ -11,5 +11,6 @@ #include "SHAL_TIM.h" #include "SHAL_GPIO.h" #include "SHAL_UART.h" +#include "SHAL_I2C.h" #endif diff --git a/SHAL/Src/Core/SHAL_CORE.cpp b/SHAL/Src/Core/SHAL_CORE.cpp new file mode 100644 index 0000000..550c317 --- /dev/null +++ b/SHAL/Src/Core/SHAL_CORE.cpp @@ -0,0 +1,31 @@ +// +// Created by Luca on 9/15/2025. +// + +#include "SHAL_CORE.h" + +void SHAL_init(){ + systick_init(); //Just this for now +} + + +void systick_init(){ + SysTick->CTRL = 0; //disable first + SysTick->LOAD = 0xFFFFFF; //max 24-bit + SysTick->VAL = 0; //clear + SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | SysTick_CTRL_ENABLE_Msk; +} + +void SHAL_delay_us(uint32_t us){ + uint32_t start = SysTick->VAL; + uint32_t ticks = us * (SystemCoreClock / 1000000U); + + //handle wraparound with 24-bit mask + while (((start - SysTick->VAL) & 0x00FFFFFF) < ticks) { } +} + +void SHAL_delay_ms(uint32_t ms){ + while(ms-- > 0){ + SHAL_delay_us(1000); + } +} \ No newline at end of file diff --git a/SHAL/Src/Peripheral/I2C/SHAL_I2C.cpp b/SHAL/Src/Peripheral/I2C/SHAL_I2C.cpp index 4ae2440..62ec75c 100644 --- a/SHAL/Src/Peripheral/I2C/SHAL_I2C.cpp +++ b/SHAL/Src/Peripheral/I2C/SHAL_I2C.cpp @@ -54,59 +54,48 @@ 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) { - +void SHAL_I2C::masterWriteRead(uint8_t addr,const uint8_t* writeData, size_t writeLen, uint8_t* readData, size_t readLen) { volatile I2C_TypeDef* I2CPeripheral = getI2CPair(m_I2CPair).I2CReg; - //Wait until not busy + //Wait for I2C bus 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 + //Write phase + if (writeLen > 0) { + //Configure: NBYTES = wlen, write mode, START + I2CPeripheral->CR2 = (addr << 1) | + (writeLen << I2C_CR2_NBYTES_Pos) | + I2C_CR2_START; - //Wait until TX ready - while (!(I2CPeripheral->ISR & I2C_ISR_TXIS)); + for (size_t i = 0; i < writeLen; i++) { + while (!(I2CPeripheral->ISR & I2C_ISR_TXIS)); // TX ready + I2CPeripheral->TXDR = writeData[i]; + } - //Send register address - I2CPeripheral->TXDR = reg; + //Wait until transfer complete + while (!(I2CPeripheral->ISR & I2C_ISR_TC)); + } - //Wait until TX ready - while (!(I2CPeripheral->ISR & I2C_ISR_TXIS)); + //Read phase + if (readLen > 0) { + I2CPeripheral->CR2 = (addr << 1) | + I2C_CR2_RD_WRN | + (readLen << I2C_CR2_NBYTES_Pos) | + I2C_CR2_START | I2C_CR2_AUTOEND; - //Send data to write to register - I2CPeripheral->TXDR = data; + for (size_t i = 0; i < readLen; i++) { + while (!(I2CPeripheral->ISR & I2C_ISR_RXNE)); //RX ready + readData[i] = static_cast(I2CPeripheral->RXDR); + } + } } +void SHAL_I2C::masterWrite(uint8_t addr, const uint8_t *writeData, uint8_t writeLen) { + masterWriteRead(addr,writeData,writeLen,nullptr,0); +} -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; +void SHAL_I2C::masterRead(uint8_t addr, uint8_t *readBuffer, uint8_t bytesToRead) { + masterWriteRead(addr,nullptr,0,readBuffer,bytesToRead); } SHAL_I2C& I2CManager::get(uint8_t I2CBus) { diff --git a/SHAL/Src/main.cpp b/SHAL/Src/main.cpp index 0b50bcc..32c6754 100644 --- a/SHAL/Src/main.cpp +++ b/SHAL/Src/main.cpp @@ -13,10 +13,14 @@ void tim2Handler(){ int main() { + SHAL_init(); + //Setup UART2 (used by nucleo devices for USB comms) SHAL_UART2.init(UART_Pair::Tx2A2_Rx2A3); SHAL_UART2.begin(115200); + SHAL_I2C1.init(I2C_Pair::SCL1B6_SDA1B7); + //Use pin C3 to trigger a function on external interrupt PIN(C3).useAsExternalInterrupt(TriggerMode::RISING_EDGE,c3Interrupt); @@ -27,6 +31,12 @@ int main() { PIN(A4).setPinMode(PinMode::OUTPUT_MODE); PIN(A5).setPinMode(PinMode::OUTPUT_MODE); + c3Interrupt(); + + SHAL_delay_ms(3000); + + c3Interrupt(); //test + while (true) { __WFI(); }