基于STM32CubeMx 实现STM32 IIC Slave功能
懒,直接上代码
暂时只实现slave功能,后续有时间再增加master
H文件
typedef enum
{
eMaster,
eSlave,
}eIICMode;
typedef enum
{
eCmd0,
eCmd1,
eCmd2,
eCmd3,
eCmd4,
eCmd5,
//...
}IIC_CMD;
typedef uint8_t (*I2C_Read)(void);
typedef uint8_t (*I2C_Write)(uint8_t data);
C文件
/*
本实验是基于stm32cubemx生成的HAL IIC库文件,
通过IIC中断和库文件实现IIC master和slave(重点)功能
*/
#include "stm32iic.h"
HAL_StatusTypeDef HAL_I2C_Slave_Start(I2C_HandleTypeDef *hi2c);
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/** @defgroup I2C_Private_Define I2C Private Define
* @{
*/
#define TIMING_CLEAR_MASK (0xF0FFFFFFU) /*!< I2C TIMING clear register Mask */
#define I2C_TIMEOUT_ADDR (10000U) /*!< 10 s */
#define I2C_TIMEOUT_BUSY (25U) /*!< 25 ms */
#define I2C_TIMEOUT_DIR (25U) /*!< 25 ms */
#define I2C_TIMEOUT_RXNE (25U) /*!< 25 ms */
#define I2C_TIMEOUT_STOPF (25U) /*!< 25 ms */
#define I2C_TIMEOUT_TC (25U) /*!< 25 ms */
#define I2C_TIMEOUT_TCR (25U) /*!< 25 ms */
#define I2C_TIMEOUT_TXIS (25U) /*!< 25 ms */
#define I2C_TIMEOUT_FLAG (25U) /*!< 25 ms */
#define MAX_NBYTE_SIZE 255U
#define SlaveAddr_SHIFT 7U
#define SlaveAddr_MSK 0x06U
/* Private define for @ref PreviousState usage */
#define I2C_STATE_MSK ((uint32_t)((uint32_t)((uint32_t)HAL_I2C_STATE_BUSY_TX | (uint32_t)HAL_I2C_STATE_BUSY_RX) & (uint32_t)(~((uint32_t)HAL_I2C_STATE_READY)))) /*!< Mask State define, keep only RX and TX bits */
#define I2C_STATE_NONE ((uint32_t)(HAL_I2C_MODE_NONE)) /*!< Default Value */
#define I2C_STATE_MASTER_BUSY_TX ((uint32_t)(((uint32_t)HAL_I2C_STATE_BUSY_TX & I2C_STATE_MSK) | (uint32_t)HAL_I2C_MODE_MASTER)) /*!< Master Busy TX, combinaison of State LSB and Mode enum */
#define I2C_STATE_MASTER_BUSY_RX ((uint32_t)(((uint32_t)HAL_I2C_STATE_BUSY_RX & I2C_STATE_MSK) | (uint32_t)HAL_I2C_MODE_MASTER)) /*!< Master Busy RX, combinaison of State LSB and Mode enum */
#define I2C_STATE_SLAVE_BUSY_TX ((uint32_t)(((uint32_t)HAL_I2C_STATE_BUSY_TX & I2C_STATE_MSK) | (uint32_t)HAL_I2C_MODE_SLAVE)) /*!< Slave Busy TX, combinaison of State LSB and Mode enum */
#define I2C_STATE_SLAVE_BUSY_RX ((uint32_t)(((uint32_t)HAL_I2C_STATE_BUSY_RX & I2C_STATE_MSK) | (uint32_t)HAL_I2C_MODE_SLAVE)) /*!< Slave Busy RX, combinaison of State LSB and Mode enum */
#define I2C_STATE_MEM_BUSY_TX ((uint32_t)(((uint32_t)HAL_I2C_STATE_BUSY_TX & I2C_STATE_MSK) | (uint32_t)HAL_I2C_MODE_MEM)) /*!< Memory Busy TX, combinaison of State LSB and Mode enum */
#define I2C_STATE_MEM_BUSY_RX ((uint32_t)(((uint32_t)HAL_I2C_STATE_BUSY_RX & I2C_STATE_MSK) | (uint32_t)HAL_I2C_MODE_MEM)) /*!< Memory Busy RX, combinaison of State LSB and Mode enum */
/* Private define to centralize the enable/disable of Interrupts */
#define I2C_XFER_TX_IT (uint16_t)(0x0001U) /* Bit field can be combinated with @ref I2C_XFER_LISTEN_IT */
#define I2C_XFER_RX_IT (uint16_t)(0x0002U) /* Bit field can be combinated with @ref I2C_XFER_LISTEN_IT */
#define I2C_XFER_LISTEN_IT (uint16_t)(0x8000U) /* Bit field can be combinated with @ref I2C_XFER_TX_IT and @ref I2C_XFER_RX_IT */
#define I2C_XFER_ERROR_IT (uint16_t)(0x0010U) /* Bit definition to manage addition of global Error and NACK treatment */
#define I2C_XFER_CPLT_IT (uint16_t)(0x0020U) /* Bit definition to manage only STOP evenement */
#define I2C_XFER_RELOAD_IT (uint16_t)(0x0040U) /* Bit definition to manage only Reload of NBYTE */
/* Private define Sequential Transfer Options default/reset value */
#define I2C_NO_OPTION_FRAME (0xFFFF0000U)
typedef struct _iic
{
uint16_t RW;
uint8_t Cmd;
uint8_t isTrigCmd;
uint8_t *ptr;
uint8_t size;
eIICMode mode;
}iic_struct_t;
iic_struct_t iictype =
{
.RW = 0,
.Cmd = 0,
.isTrigCmd = 0,
.ptr = 0,
.size = 0,
.mode = eSlave,
};
uint8_t I2C_Slave_Read_Cmd0(void)
{
return 0x11;
}
uint8_t I2C_Slave_Read_Cmd1(void)
{
return 0xF2;
}
I2C_Read pI2CSlaveReadFunctionbuf[]=
{
I2C_Slave_Read_Cmd0,
I2C_Slave_Read_Cmd1,
};
uint8_t I2C_Slave_Write_Cmd0(uint8_t data)
{
(void)data;
return 0;
}
uint8_t I2C_Slave_Write_Cmd1(uint8_t data)
{
(void)data;
return 0;
}
I2C_Write pI2CSlaveWriteFunctionbuf[]=
{
I2C_Slave_Write_Cmd0,
I2C_Slave_Write_Cmd1,
};
/*
重写IIC从机中断,系统启动时,需设置从机Enable ERR, TC, STOP, NACK, TXI interrupt
*/
HAL_StatusTypeDef HAL_I2C_SlaveIT(struct __I2C_HandleTypeDef *hi2c)
{
/* Process locked */
__HAL_LOCK(hi2c);
if (hi2c->Instance->ISR & I2C_FLAG_ADDR)
{
//trig slave address
__HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_ADDR);
iictype.RW = I2C_GET_DIR(hi2c);
if ((iictype.RW == 1) && (iictype.isTrigCmd == 0))
{
while(1);
}
}
else if (hi2c->Instance->ISR & I2C_FLAG_RXNE)
{
//rx is not empty
if (iictype.RW == 0)//write
{
if (iictype.isTrigCmd == 0)//cmd
{
iictype.Cmd = (uint8_t)hi2c->Instance->RXDR;
iictype.isTrigCmd = 1;
}
else
{
pI2CSlaveWriteFunctionbuf[iictype.Cmd]((uint8_t)hi2c->Instance->RXDR);
}
}
else
{
//error
while(1);
}
}
else if (hi2c->Instance->ISR & I2C_FLAG_TXIS)
{
//set tx data
if (iictype.isTrigCmd == 0)
{
//error
while(1);
}
else
{
if (iictype.RW == 0)
{
//error
while(1);
}
else
{
//tx
do
{
hi2c->Instance->TXDR = pI2CSlaveReadFunctionbuf[iictype.Cmd]();
}while(hi2c->Instance->ISR & I2C_FLAG_TXIS);
}
}
}
else if ((hi2c->Instance->ISR & I2C_FLAG_ARLO) || (hi2c->Instance->ISR & I2C_FLAG_STOPF)
|| (hi2c->Instance->ISR & I2C_FLAG_BERR) || (hi2c->Instance->ISR & I2C_ISR_NACKF))
{
__HAL_I2C_CLEAR_FLAG(hi2c, I2C_ISR_NACKF);
__HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_BERR);
__HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_ARLO);
__HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_STOPF);
/* If a pending TXIS flag is set */
/* Write a dummy data in TXDR to clear it */
if (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_TXIS) != RESET)
{
hi2c->Instance->TXDR = 0x00U;
}
/* Flush TX register if not empty */
if (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_TXE) == RESET)
{
__HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_TXE);
}
if (hi2c->Instance->ISR & 0xFFFE)
{
//has any error
hi2c->Instance->CR1 &= 0xFFFFFFFE;//clear PE
hi2c->Instance->CR1 |= 0x01;//set PE
}
//restart
HAL_I2C_Slave_Start(hi2c);
iictype.isTrigCmd = 0;
iictype.Cmd = 0;
iictype.RW = 0;
}
/* Process Unlocked */
__HAL_UNLOCK(hi2c);
return HAL_OK;
}
void HAL_I2C_MasterTxCpltCallback(I2C_HandleTypeDef *hi2c)
{
}
void HAL_I2C_MasterRxCpltCallback(I2C_HandleTypeDef *hi2c)
{
}
void HAL_I2C_SlaveTxCpltCallback(I2C_HandleTypeDef *hi2c)
{
}
void HAL_I2C_SlaveRxCpltCallback(I2C_HandleTypeDef *hi2c)
{
}
void HAL_I2C_ListenCpltCallback(I2C_HandleTypeDef *hi2c)
{
}
static void I2C_Enable_IRQ1(I2C_HandleTypeDef *hi2c, uint16_t InterruptRequest)
{
uint32_t tmpisr = 0U;
{
if ((InterruptRequest & I2C_XFER_LISTEN_IT) == I2C_XFER_LISTEN_IT)
{
/* Enable ERR, STOP, NACK, and ADDR interrupts */
tmpisr |= I2C_IT_ADDRI | I2C_IT_STOPI | I2C_IT_NACKI | I2C_IT_ERRI;
}
if ((InterruptRequest & I2C_XFER_TX_IT) == I2C_XFER_TX_IT)
{
/* Enable ERR, TC, STOP, NACK and RXI interrupts */
tmpisr |= I2C_IT_ERRI | I2C_IT_TCI | I2C_IT_STOPI | I2C_IT_NACKI | I2C_IT_TXI;
}
if ((InterruptRequest & I2C_XFER_RX_IT) == I2C_XFER_RX_IT)
{
/* Enable ERR, TC, STOP, NACK and TXI interrupts */
tmpisr |= I2C_IT_ERRI | I2C_IT_TCI | I2C_IT_STOPI | I2C_IT_NACKI | I2C_IT_RXI;
}
if (InterruptRequest == I2C_XFER_CPLT_IT)
{
/* Enable STOP interrupts */
tmpisr |= I2C_IT_STOPI;
}
}
/* Enable interrupts only at the end */
/* to avoid the risk of I2C interrupt handle execution before */
/* all interrupts requested done */
__HAL_I2C_ENABLE_IT(hi2c, tmpisr);
}
HAL_StatusTypeDef HAL_I2C_Slave_Start(I2C_HandleTypeDef *hi2c)
{
if (hi2c->State == HAL_I2C_STATE_READY)
{
/* Process Locked */
__HAL_LOCK(hi2c);
/* Enable Address Acknowledge */
hi2c->Instance->CR2 &= ~I2C_CR2_NACK;
/* Process Unlocked */
__HAL_UNLOCK(hi2c);
/* Note : The I2C interrupts must be enabled after unlocking current process
to avoid the risk of I2C interrupt handle execution before current
process unlock */
/* Enable ERR, TC, STOP, NACK, RXI interrupt */
/* possible to enable all of these */
/* I2C_IT_ERRI | I2C_IT_TCI| I2C_IT_STOPI| I2C_IT_NACKI | I2C_IT_ADDRI | I2C_IT_RXI | I2C_IT_TXI */
I2C_Enable_IRQ1(hi2c, I2C_XFER_TX_IT | I2C_XFER_RX_IT | I2C_XFER_LISTEN_IT | I2C_XFER_CPLT_IT);
return HAL_OK;
}
else
{
return HAL_BUSY;
}
}
使用方法
通过STM32CubeMx生成IIC,并将IIC中断打开,然后在main里面调用一次HAL_I2C_Slave_Start(hi2c);即可使能iic slave read/write功能
如何修改自己的read/write功能
read/write功能请查看pI2CSlaveReadFunctionbuf和pI2CSlaveWriteFunctionbuf这2个函数指针数组。每个数组对应一个cmd,cmd从0开始的。分别修改这2个函数指针数组里面的函数即可。