- 2.驱动C文件
- /******************************************************************************************
- * 文 件 名: drv_i2c_slave.c
- * 文件描述: i2c从机驱动程序文件
- * 文件版本: V1.0
- * 日 期: 2020/12/14
- * 作 者: 何江
- * 版本记录
- * 2020/12/14: 第一次发布
- *
- ******************************************************************************************/
- /******************************************************************************************
- 头文件包含
- *******************************************************************************************/
- #include "drv_i2c_slave.h"
- #include <rthw.h>
- #include <rtthread.h>
- /******************************************************************************************
- 宏定义
- *******************************************************************************************/
- /******************************************************************************************
- 功能函数
- *******************************************************************************************/
- /******************************************************************************************
- I2C从机GPIO初始化
- *******************************************************************************************/
- #if (USING_I2C1)
- i2c_slave_t i2c1_slave_dev;
- static void I2C1_Configuration(void)
- {
- GPIO_InitTypeDef GPIO_InitStruct;
- NVIC_InitTypeDef NVIC_InitStructure;
- /* Enable GPIOA clock */
- RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);
- //复用功能选择
- GPIO_PinAFConfig( GPIOA ,GPIO_PinSource11, GPIO_AF_5);
- GPIO_PinAFConfig( GPIOA ,GPIO_PinSource12, GPIO_AF_5);
- //GPIO配置
- GPIO_InitStruct.GPIO_Pin = GPIO_Pin_12;
- GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_OD;
- GPIO_InitStruct.GPIO_Speed = GPIO_Speed_10MHz;
- GPIO_Init(GPIOA , &GPIO_InitStruct);
-
- GPIO_InitStruct.GPIO_Pin = GPIO_Pin_11;
- GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_OD;
- GPIO_InitStruct.GPIO_Speed = GPIO_Speed_10MHz;
- GPIO_Init(GPIOA , &GPIO_InitStruct);
-
- //配置i2c中断
- NVIC_InitStructure.NVIC_IRQChannel = I2C1_IRQn;
- NVIC_InitStructure.NVIC_IRQChannelPriority = 1;
- NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
- NVIC_Init(&NVIC_InitStructure);
- }
- #endif
- /******************************************************************************************
- I2C_SendSlaveAddress 设置从机模式的本机地址
- *******************************************************************************************/
- static void I2C_SendSlaveAddress(I2C_TypeDef* i2c, u8 addr)
- {
- WRITE_REG(i2c->IC_SAR, addr >> 1);
- }
- /******************************************************************************************
- 函数名称: i2c_slave_init
- 功能描述: I2C 从机初始化配置
- 输 入: pdev 从机设备
- numb i2c外设号,有的mcu支持2路
- 输 出: 无
- *******************************************************************************************/
- void i2c_slave_init(i2c_slave_t *pdev,int8u_t numb)
- {
- I2C_TypeDef *pi2c;
- I2C_InitTypeDef I2C_InitStruct;
- if(numb == 1){
- #if (USING_I2C1)
- pi2c = I2C1;
- I2C1_Configuration();
- #endif
- }else if(numb == 2){
- #if (USING_I2C2)
- pI2C = I2C2;
- I2C2_Configuration();
- #endif
- }else{
- return ;
- }
- pdev->device = pi2c;
- RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1 , ENABLE);
-
- I2C_StructInit(&I2C_InitStruct);
- /* I2C configuration */
- I2C_InitStruct.I2C_Mode = I2C_Mode_SLAVE;
- I2C_InitStruct.I2C_OwnAddress = 0;
- I2C_InitStruct.I2C_Speed = I2C_Speed_STANDARD;
- I2C_InitStruct.I2C_ClockSpeed = 100000;
- I2C_Init(pi2c, &I2C_InitStruct);
- I2C_ITConfig(pi2c,I2C_IT_RD_REQ|I2C_IT_STOP_DET,ENABLE);
- I2C_ITConfig(pi2c,I2C_IT_RX_FULL,ENABLE);
- //记得打开SLAVE使能标志
- pi2c->IC_CON &= (~IC_SLAVE_DISABLE);
- I2C_Cmd(pi2c, ENABLE);
- //从机匹配地址
- I2C_SendSlaveAddress(pi2c,I2C_SLAVE_WADDR);
- pdev->status = I2C_IDLE;
- pdev->ptran_buf = pdev->tran_buffer;
- pdev->precv_buf = pdev->recv_buffer;
- pdev->tran_count = I2C_SLAVE_TX_BUF_SIZE;
- pdev->recv_count = 0;
- }
- /*******************************************************************************************
- 函数名称: i2c_slave_read_recv_data
- 功能描述: 从I2C缓冲区中读取所有数据,并清除接收数据计数器
- 输 入: pdev i2c结构
- pd 保存数据的缓冲区
- 输 出: 实际接收到的数据个数
- *******************************************************************************************/
- int16s_t i2c_slave_read_recv_data(i2c_slave_t *pdev,int8u_t *pd)
- {
- int16s_t count;
- rt_base_t level;
- if(pd == _NULL || pdev == _NULL)
- return -1;
- if(pdev->status == I2C_IDLE){
- level = rt_hw_interrupt_disable();
- for(count = 0; count < pdev->recv_count; count++){
- pd[count] = pdev->recv_buffer[count];
- }
- pdev->recv_count = 0;
- pdev->precv_buf = pdev->recv_buffer;
- rt_hw_interrupt_enable(level);
- }else{
- count = 0;
- }
- return count;
- }
- /*******************************************************************************************
- 函数名称: i2c_slave_write_txbuffer_nbyte
- 功能描述: 设置修改I2C发送缓冲区中数据,并更新发送数量
- 输 入: pdev i2c结构
- index 缓冲区数组索引
- pd 要写入数据的缓冲区
- count 要写入数据的个数
- 输 出: 实际写入的数据个数
- *******************************************************************************************/
- int16s_t i2c_slave_write_txbuffer_nbyte(i2c_slave_t *pdev,int16s_t index,int8u_t *pd,int16s_t count)
- {
- int16s_t i;
- rt_base_t level;
- if(pd == _NULL || pdev == _NULL || ((index + count) >= I2C_SLAVE_TX_BUF_SIZE))
- return -1;
- //写入缓冲区完成之前不允许被i2c主机来读取
- //__disable_irq();
- level = rt_hw_interrupt_disable();
- for(i = index; i < (index + count); i++){
- pdev->tran_buffer[i] = pd[i];
- }
- //__enable_irq();
- //设置i2c发送缓冲区的数量
- pdev->tran_count = index + count;
- rt_hw_interrupt_enable(level);
- return i;
- }
- /*******************************************************************************************
- 函数名称: i2c_slave_read_txbuffer_nbyte
- 功能描述: 读取I2C发送缓冲区中数据,一般用来与应用程序中作比较用
- 输 入: pdev i2c结构
- index 缓冲区数组索引
- pd 要写入数据的缓冲区
- count 要写入数据的个数
- 输 出: 实际读取的数据个数
- *******************************************************************************************/
- int16s_t i2c_slave_read_txbuffer_nbyte(i2c_slave_t *pdev,int16s_t index,int8u_t *pd,int16s_t count)
- {
- int16s_t i;
- if(pd == _NULL || pdev == _NULL || ((index + count) >= I2C_SLAVE_TX_BUF_SIZE))
- return -1;
- for(i = 0; i < count; i++){
- pd[i] = pdev->tran_buffer[index];
- }
- return i;
- }
- /*******************************************************************************************
- 函数名称: i2c_slave_isr
- 功能描述: I2C中断函数
- 输 入: pdev i2c结构
-
- 输 出: 无
- *******************************************************************************************/
- void i2c_slave_isr(i2c_slave_t *pdev)
- {
- //主机写,直接存入缓冲区
- if(I2C_GetITStatus(pdev->device, I2C_IT_RX_FULL)){
- pdev->status = I2C_RECV_DATA;
- while(I2C_GetFlagStatus(pdev->device, I2C_STATUS_FLAG_RFNE)){
- if(pdev->recv_count < I2C_SLAVE_RX_BUF_SIZE){
- *pdev->precv_buf++ = I2C_ReceiveData(pdev->device);
- pdev->recv_count++;
- }else{
- //用于清除I2C_IT_RX_FULL中断
- I2C_ReceiveData(pdev->device);
- }
- }
- }
- //总线停止中断,STOP中断后i2c slave进入空闲状态
- if(I2C_GetITStatus(pdev->device, I2C_IT_STOP_DET)){
- I2C_ITConfig(pdev->device,I2C_IT_TX_EMPTY,DISABLE);
- I2C_ClearITPendingBit(pdev->device, I2C_IT_TX_EMPTY);
- I2C_ClearITPendingBit(pdev->device, I2C_IT_STOP_DET);
- I2C_ClearFlag(pdev->device, I2C_IT_TX_EMPTY);
- I2C_ClearFlag(pdev->device, I2C_IT_TX_ABRT);
- pdev->status = I2C_IDLE;
- }
- //主机请求读,只会进一次
- if(I2C_GetITStatus(pdev->device, I2C_IT_RD_REQ)){
- I2C_ClearITPendingBit(pdev->device, I2C_IT_RD_REQ);
- //打开发送寄存器空中断
- I2C_ITConfig(pdev->device,I2C_IT_TX_EMPTY,ENABLE);
- //复位发送缓冲区指针
- pdev->ptran_buf = pdev->tran_buffer;
- pdev->tran_count = I2C_SLAVE_TX_BUF_SIZE;
- pdev->status = I2C_TRAN_DATA;
- }
- switch(pdev->status){
- case I2C_IDLE:
- if(I2C_GetITStatus(pdev->device, I2C_IT_TX_EMPTY)){
- I2C_ITConfig(pdev->device,I2C_IT_TX_EMPTY,DISABLE);
- I2C_ClearITPendingBit(pdev->device, I2C_IT_TX_EMPTY);
- }
- break;
- case I2C_RECV_DATA:
- break;
- case I2C_TRAN_DATA:
- if(I2C_GetITStatus(pdev->device, I2C_IT_TX_EMPTY)){
- I2C_ClearITPendingBit(pdev->device, I2C_IT_TX_EMPTY);
- if(pdev->tran_count > 0){
- I2C_SendData(pdev->device,*pdev->ptran_buf++);
- pdev->tran_count--;
- //缓冲区数据发送完毕,退出发送
- if(pdev->tran_count == 0){
- pdev->ptran_buf = pdev->tran_buffer;
- pdev->tran_count = I2C_SLAVE_TX_BUF_SIZE;
- //中止发送
- I2C_GenerateSTOP(I2C1, ENABLE);
- pdev->status = I2C_IDLE;
- break;
- }
- }else{
- //复位发送缓冲区指针
- pdev->ptran_buf = pdev->tran_buffer;
- pdev->tran_count = I2C_SLAVE_TX_BUF_SIZE;
- //中止发送
- I2C_GenerateSTOP(I2C1, ENABLE);
- pdev->status = I2C_IDLE;
- }
- }
- break;
- default:
- break;
- }
- }
- /*******************************************************************************
- * Function Name : I2C1_IRQHandler
- * Description : This function handles I2C1 global interrupt request.
- * Input : None
- * Output : None
- * Return : None
- *******************************************************************************/
- void I2C1_IRQHandler(void)
- {
- #if (USING_I2C1)
- i2c_slave_isr(&i2c1_slave_dev);
- #endif
- }
- /******************************************************************************************
- endfile
- *******************************************************************************************/