From 8e27f8818e73314594a902b90e00b4b57a65a639 Mon Sep 17 00:00:00 2001 From: unicod Date: Tue, 24 Feb 2026 20:57:19 +0100 Subject: [PATCH] Added i2c_master.* - I2C_Write - I2C_Read - I2C_ReadReg --- Core/Inc/i2c_master.h | 13 ++++ Core/Src/i2c_master.c | 134 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 147 insertions(+) create mode 100644 Core/Inc/i2c_master.h create mode 100644 Core/Src/i2c_master.c diff --git a/Core/Inc/i2c_master.h b/Core/Inc/i2c_master.h new file mode 100644 index 0000000..8e75f98 --- /dev/null +++ b/Core/Inc/i2c_master.h @@ -0,0 +1,13 @@ +#ifndef __I2C_MASTER_H__ +#define __I2C_MASTER_H__ + +#include +#include + + +extern int I2C_Write(I2C_TypeDef* I2Cx, uint8_t addr, const uint8_t* data, uint16_t len); +extern int I2C_Read(I2C_TypeDef* I2Cx, uint8_t addr, uint8_t* data, uint16_t len); +extern int I2C_ReadReg(I2C_TypeDef* I2Cx, uint8_t addr, const uint8_t* reg, uint16_t reglen, uint8_t* data, uint16_t datalen); + + +#endif diff --git a/Core/Src/i2c_master.c b/Core/Src/i2c_master.c new file mode 100644 index 0000000..3d3f002 --- /dev/null +++ b/Core/Src/i2c_master.c @@ -0,0 +1,134 @@ +/***************************************************************************//** +* @file i2c_master.c +* @brief I2C master functions for STM32H5 using LL library +*//****************************************************************************/ + +//------------------------------C library--------------------------------------- +#include +//----------------------------user includes------------------------------------- +#include "i2c_master.h" +#include "main.h" +//------------------------------------------------------------------------------ + + +/* Private macros ------------------------------------------------------------*/ +#define I2C_TIMEOUT_US 5000 + + +// SOFTEND in the write section prevents STOP --> Restart possible +// AUTOEND in the read section generates correct STOP +// TXIS/RXNE polling is mandatory for H5 +// STOP-flag-clear is necessary, otherwise the next transaction will hang. + + +/* Functions -----------------------------------------------------------------*/ + +static int I2C_Tout(I2C_TypeDef* I2Cx, int val) { + LL_I2C_GenerateStopCondition(I2Cx); + LL_I2C_Disable(I2Cx); + LL_I2C_Enable(I2Cx); + LL_I2C_ClearFlag_NACK(I2Cx); + LL_I2C_ClearFlag_STOP(I2Cx); + LL_I2C_ClearFlag_ADDR(I2Cx); + return val; +} + +/***************************************************************************//** +* @brief Write data to I2C slave device +* @param I2Cx: I2C peripheral (e.g. I2C1) +* @param addr: 7-bit I2C slave address, left-aligned +* @param data: pointer to data buffer to write +* @param len: number of bytes to write +* @return 0 on success, -1 on TXIS timeout, -2 on STOP timeout +*//****************************************************************************/ +int I2C_Write(I2C_TypeDef* I2Cx, uint8_t addr, const uint8_t* data, uint16_t len) { + LL_I2C_HandleTransfer(I2Cx, addr, LL_I2C_ADDRSLAVE_7BIT, len, LL_I2C_MODE_AUTOEND, LL_I2C_GENERATE_START_WRITE); + for (uint16_t i = 0; i < len; i++) { + uint32_t tref = usTimerGetAbs(); + while (!LL_I2C_IsActiveFlag_TXIS(I2Cx)) { + if (usTimerGetRel(tref) > I2C_TIMEOUT_US) { // timeout expired + return I2C_Tout(I2Cx, -1); // error: TXIS timeout + } + } + LL_I2C_TransmitData8(I2Cx, data[i]); // send data + } + uint32_t tref = usTimerGetAbs(); + while (!LL_I2C_IsActiveFlag_STOP(I2Cx)) { + if (usTimerGetRel(tref) > I2C_TIMEOUT_US) { // timeout expired + return I2C_Tout(I2Cx, -2); // error: STOP timeout + } + } + LL_I2C_ClearFlag_STOP(I2Cx); + return 0; +} + +/***************************************************************************//** +* @brief Read data from I2C slave device +* @param I2Cx: I2C peripheral (e.g. I2C1) +* @param addr: 7-bit I2C slave address, left-aligned +* @param data: pointer to data buffer to store read data +* @param len: number of bytes to read +* @return 0 on success, -1 on RXNE timeout, -2 on STOP timeout +*//****************************************************************************/ +int I2C_Read(I2C_TypeDef* I2Cx, uint8_t addr, uint8_t* data, uint16_t len) { + LL_I2C_HandleTransfer(I2Cx, addr, LL_I2C_ADDRSLAVE_7BIT, len, LL_I2C_MODE_AUTOEND, LL_I2C_GENERATE_START_READ); + for (uint16_t i = 0; i < len; i++) { + uint32_t tref = usTimerGetAbs(); + while (!LL_I2C_IsActiveFlag_RXNE(I2Cx)) { + if (usTimerGetRel(tref) > I2C_TIMEOUT_US) { // timeout expired + return I2C_Tout(I2Cx, -1); // error: RXNE timeout + } + } + data[i] = LL_I2C_ReceiveData8(I2Cx); // read data + } + uint32_t tref = usTimerGetAbs(); + while (!LL_I2C_IsActiveFlag_STOP(I2Cx)) { + if (usTimerGetRel(tref) > I2C_TIMEOUT_US) { // timeout expired + return I2C_Tout(I2Cx, -2); // error: STOP timeout + } + } + LL_I2C_ClearFlag_STOP(I2Cx); + return 0; +} + +/***************************************************************************//** +* @brief Read data from I2C slave device register +* @param I2Cx: I2C peripheral (e.g. I2C1) +* @param addr: 7-bit I2C slave address, left-aligned +* @param reg: pointer to register address buffer (1-2 bytes) +* @param reglen: number of bytes in register address (1 or 2) +* @param data: pointer to data buffer to store read data +* @param datalen: number of bytes to read +* @return 0 on success, -1 on TXIS timeout, -2 on RXNE timeout, -3 on STOP timeout +*//****************************************************************************/ +int I2C_ReadReg(I2C_TypeDef* I2Cx, uint8_t addr, const uint8_t* reg, uint16_t reglen, uint8_t* data, uint16_t datalen) { + LL_I2C_HandleTransfer(I2Cx, addr, LL_I2C_ADDRSLAVE_7BIT, reglen, LL_I2C_MODE_SOFTEND, LL_I2C_GENERATE_START_WRITE); + for (uint16_t i = 0; i < reglen; i++) { + uint32_t tref = usTimerGetAbs(); + while (!LL_I2C_IsActiveFlag_TXIS(I2Cx)) { + if (usTimerGetRel(tref) > I2C_TIMEOUT_US) { // timeout expired + return I2C_Tout(I2Cx, -1); // error: TXIS timeout + } + } + LL_I2C_TransmitData8(I2Cx, reg[i]); // send register address + } + LL_I2C_HandleTransfer(I2Cx, addr, LL_I2C_ADDRSLAVE_7BIT, datalen, LL_I2C_MODE_AUTOEND, LL_I2C_GENERATE_RESTART_7BIT_READ); + for (uint16_t i = 0; i < datalen; i++) { + uint32_t tref = usTimerGetAbs(); + while (!LL_I2C_IsActiveFlag_RXNE(I2Cx)) { + if (usTimerGetRel(tref) > I2C_TIMEOUT_US) { // timeout expired + return I2C_Tout(I2Cx, -2); // error: RXNE timeout + } + } + data[i] = LL_I2C_ReceiveData8(I2Cx); // read data + } + uint32_t tref = usTimerGetAbs(); + while (!LL_I2C_IsActiveFlag_STOP(I2Cx)) { + if (usTimerGetRel(tref) > I2C_TIMEOUT_US) { // timeout expired + return I2C_Tout(I2Cx, -3); // error: STOP timeout + } + } + LL_I2C_ClearFlag_STOP(I2Cx); + return 0; +} +