1.1 硬件I2C介绍
在项目中遇见与MCU通信接口协议为I2C的设备时,可通过GPIO口软件模拟I2C和使用MCU自身的硬件I2C资源。两者各有优势,软件模拟可以不受GPIO口限制,也可以主控制器MCU的选择上降低成本,但也存在I2C设备对通信速率有特定的要求或者需要较高的传输速率时,会存在时序调试困难、start/stop/ack/noack/read/write等都需要软件实现、GPIO口翻转速率限制等原因导致软件模拟I2C通信速率有一定的限制。硬件I2C则不存在上述问题,I2C通信速率可配置100k/400k/1M(NXP芯片做到了3.4M),通信时序中的绝大部分都由硬件完成,我们只需要按照逻辑配置好相应的寄存器即可,但也存在受特定GPIO口限制、相应成本高等缺点。本文主要是基GD32MCU介绍硬件I2C的配置和注意的事项,关于I2C协议概念介绍只是简要提及。
1.2 GD32 mcu硬件I2C的主要特性
1、同一接口既可实现主机功能又可实现从机功能;
2、主从机之间的双向数据传输;
3、支持7位和10位的地址模式和广播寻址;
4、支持I2C多主机模式;
5、速率100k\400k\1M;
6、从机模式下可配置SCL主动拉低;
7、支持DMA模式;
8、支持SMBUS;
9、事件中断和错误中断;
10、支持PEC错误校验。
1.3 主机发送和接收实现(速率100k/400k/1M 地址10bit or 7bit)
//.h文件
#ifndef MAIN_H
#define MAIN_H
#include "gd32f3x0.h"
#define I2Cx_Pinx_AFx_BIT(gpiox,pinx,afx) (((uint32_t)gpiox)|((uint32_t)(pinx)<<4)|(uint32_t)(afx))
/*send_slaver address*/
typedef enum
{
Send_7Address=0x42,
Send_7Address_2=0x44,
send_gual=0x00,
Send_10Address=0x232
}Send_Address_Enum;
/*define pin speed enum*/
typedef enum
{
standard_speed=100000,
High_speed=400000,
More_HighSpeed=1000000
}I2Cx_Speed_enum;
/*define I2Cx SDA Pin enum*/
typedef enum
{
//define I2C0
I2C0_SDA_GPIOx1=I2Cx_Pinx_AFx_BIT(GPIOA,10,4),
I2C0_SDA_GPIOx2=I2Cx_Pinx_AFx_BIT(GPIOB,7,1),
I2C0_SDA_GPIOx3=I2Cx_Pinx_AFx_BIT(GPIOB,9,1),
//define I2C1
I2C1_SDA_GPIOx4=I2Cx_Pinx_AFx_BIT(GPIOA,1,4),
I2C1_SDA_GPIOx5=I2Cx_Pinx_AFx_BIT(GPIOB,11,1),
I2C1_SDA_GPIOx6=I2Cx_Pinx_AFx_BIT(GPIOF,7,0)
}I2Cx_PinSDA_Enum;
/*define I2Cx SCL Pin enum*/
typedef enum
{
//define I2C0
I2C0_SCL_GPIOy1=I2Cx_Pinx_AFx_BIT(GPIOA,9,4),
I2C0_SCL_GPIOy2=I2Cx_Pinx_AFx_BIT(GPIOB,6,1),
I2C1_SCL_GPIOy3=I2Cx_Pinx_AFx_BIT(GPIOB,8,1),
//define I2C1
I2C1_SCL_GPIOy4=I2Cx_Pinx_AFx_BIT(GPIOA,0,4),
I2C1_SCL_GPIOy5=I2Cx_Pinx_AFx_BIT(GPIOB,10,1),
I2C1_SCL_GPIOy6=I2Cx_Pinx_AFx_BIT(GPIOB,6,0)
}I2Cx_PinSCL_Enum;
/*define I2Cx address model*/
typedef enum
{
I2Cx_Address_7bit=I2C_ADDFORMAT_7BITS,
I2Cx_Address_10bit=I2C_ADDFORMAT_10BITS
}Address_Model_Enum;
/*define I2Cx slaver address*/
typedef enum
{
Slaver_7Address=0x40,
Slaver_10Address=0x230
}Slaver_Address_Enum;
/*define I2CX init param*/
typedef struct
{
uint32_t Memory_address;
I2Cx_PinSDA_Enum gpio_sdapin;
I2Cx_PinSCL_Enum gpio_sclpin;
rcu_periph_enum I2Cx_Periph;
I2Cx_Speed_enum I2c_speed;
Address_Model_Enum address_model;
Send_Address_Enum address;
Slaver_Address_Enum slaver_address;
}Param_Typedef;
/*I2C gpio init function*/
void I2Cx_Init(Param_Typedef* i2c_init);
/*I2C gpiopin enable*/
void I2Cx_Pin_ClockEnable(I2Cx_PinSDA_Enum gpio_sdapin,I2Cx_PinSCL_Enum gpio_sclpin);
/*I2C master send buffer 7 and 10 address*/
void Master_SendData_address(uint8_t* SendBuffer,uint8_t DataNum,Param_Typedef *i2c_init);
/*I2C master receive data 7 and 10 address*/
void Master_ReceiveData(uint8_t* ReceiveBuffer,uint8_t DataNum,Param_Typedef *i2c_init);
/*I2C 7 bit address prepare send*/
void Send_7Prepare(Param_Typedef *i2c_init);
/*I2C 10 bit address prepare send*/
void Send_10Prepare(Param_Typedef *i2c_init);
/*I2C 10 bit address prepare receive*/
void Receive_10Prepare(Param_Typedef *i2c_init);
/*Master receive 7 address prepare*/
void Receive_7Prepare(Param_Typedef *i2c_init);
#endif /* MAIN_H */
//.c文件
#include "gd32f3x0.h"
#include <stdio.h>
#include "gd32f350r_eval.h"
#include "main.h"
#include "systick.h"
#define I2C0_Measure
//#define I2C1_Measure
#define BufferNum 20
uint8_t write_buffer[BufferNum]={0};//send data buffer
uint8_t receive_buffer[BufferNum]={0};//receive data buffer
Param_Typedef I2Cx_Param;
/*define I2Cx Param struct array*/
static Param_Typedef Para_Aarry[]=
{
/*I2C0 param array*/
{I2C0,I2C0_SDA_GPIOx2,I2C0_SCL_GPIOy2,RCU_I2C0,standard_speed,I2Cx_Address_7bit,Send_7Address,Slaver_7Address},
{I2C0,I2C0_SDA_GPIOx2,I2C0_SCL_GPIOy2,RCU_I2C0,standard_speed,I2Cx_Address_10bit,Send_10Address,Slaver_10Address},
{I2C0,I2C0_SDA_GPIOx2,I2C0_SCL_GPIOy2,RCU_I2C0,High_speed,I2Cx_Address_7bit,Send_7Address,Slaver_7Address},
{I2C0,I2C0_SDA_GPIOx2,I2C0_SCL_GPIOy2,RCU_I2C0,High_speed,I2Cx_Address_10bit,Send_10Address,Slaver_10Address},
{I2C0,I2C0_SDA_GPIOx2,I2C0_SCL_GPIOy2,RCU_I2C0,More_HighSpeed,I2Cx_Address_7bit,Send_7Address,Slaver_7Address},
/*I2C1 param array*/
{I2C1,I2C1_SDA_GPIOx5,I2C1_SCL_GPIOy5,RCU_I2C1,standard_speed,I2Cx_Address_7bit,Send_7Address,Slaver_7Address},
{I2C1,I2C1_SDA_GPIOx5,I2C1_SCL_GPIOy5,RCU_I2C1,standard_speed,I2Cx_Address_10bit,Send_10Address,Slaver_10Address},
{I2C1,I2C1_SDA_GPIOx5,I2C1_SCL_GPIOy5,RCU_I2C1,High_speed,I2Cx_Address_7bit,Send_7Address,Slaver_7Address},
{I2C1,I2C1_SDA_GPIOx5,I2C1_SCL_GPIOy5,RCU_I2C1,High_speed,I2Cx_Address_10bit,Send_10Address,Slaver_10Address},
{I2C1,I2C1_SDA_GPIOx5,I2C1_SCL_GPIOy5,RCU_I2C1,More_HighSpeed,I2Cx_Address_7bit,Send_7Address,Slaver_7Address},
};
/*testing sequence enum*/
typedef enum
{
/*Measure I2C0*/
I2C0_Seven_Address_standard=0,
I2C0_Ten_Address_standard,
I2C0_Seven_Address_high,
I2C0_Ten_Address_high,
I2C0_Seven_Address_more_high,
/*Measure I2C1*/
I2C1_Seven_Address_standard,
I2C1_Ten_Address_standard,
I2C1_Seven_Address_high,
I2C1_Ten_Address_high,
I2C1_Seven_Address_more_high
}Test_Sequence_Enum;
/*Configure Param of I2Cx Send data*/
void Configure_I2CX_Send(Test_Sequence_Enum measure_sequence);
/*Configure Param of I2Cx receive data*/
void Configure_I2CX_Receive(Test_Sequence_Enum measure_sequence);
/*I2Cx param init*/
void Param_Init(Param_Typedef* i2c_param,Param_Typedef* Param_Array,Test_Sequence_Enum measure_sequence);
/*!
\brief main function
\param[in] none
\param[out] none
\retval none
*/
int main(void)
{
uint8_t num=0;
/*configure EVAL_COM1*/
gd_eval_com_init(EVAL_COM);
systick_config();
for(num=0;num<BufferNum;num++){
write_buffer[num]=num;
}
#ifdef I2C0_Measure
/*Test Sequence I2C0 send*/
Configure_I2CX_Send(I2C0_Seven_Address_standard);
Configure_I2CX_Send(I2C0_Ten_Address_standard);
Configure_I2CX_Send(I2C0_Seven_Address_high);
Configure_I2CX_Send(I2C0_Ten_Address_high);
Configure_I2CX_Send(I2C0_Seven_Address_more_high);
/*Test Sequence I2C0 receive*/
Configure_I2CX_Receive(I2C0_Seven_Address_standard);
Configure_I2CX_Receive(I2C0_Ten_Address_standard);
Configure_I2CX_Receive(I2C0_Seven_Address_high);
Configure_I2CX_Receive(I2C0_Ten_Address_high);
Configure_I2CX_Receive(I2C0_Seven_Address_more_high);
#elif defined I2C1_Measure
/*Test Sequence I2C1 send*/
Configure_I2CX_Send(I2C1_Seven_Address_standard);
Configure_I2CX_Send(I2C1_Ten_Address_standard);
Configure_I2CX_Send(I2C1_Seven_Address_high);
Configure_I2CX_Send(I2C1_Ten_Address_high);
Configure_I2CX_Send(I2C1_Seven_Address_more_high);
/*Test Sequence I2C1 receive*/
Configure_I2CX_Receive(I2C1_Seven_Address_standard);
Configure_I2CX_Receive(I2C1_Ten_Address_standard);
Configure_I2CX_Receive(I2C1_Seven_Address_high);
Configure_I2CX_Receive(I2C1_Ten_Address_high);
Configure_I2CX_Receive(I2C1_Seven_Address_more_high);
#endif
while(1){
}
}
/*!
\brief Configure Param of I2Cx I2Cx Send data
\param[in] Test_Sequence_Enum measure_sequence //test sequence
\param[out] none
\retval none
*/
void Configure_I2CX_Send(Test_Sequence_Enum measure_sequence)
{
switch(measure_sequence)
{
case I2C0_Seven_Address_standard:
Param_Init(&I2Cx_Param,Para_Aarry,I2C0_Seven_Address_standard);
I2Cx_Init(&I2Cx_Param);
delay_1ms(3000);//delay 3s wait slaver init success!
Master_SendData_address(write_buffer,BufferNum,&I2Cx_Param);
printf("I2C0 Seven Address standard send success\n");
break;
case I2C0_Ten_Address_standard:
Param_Init(&I2Cx_Param,Para_Aarry,I2C0_Ten_Address_standard);
I2Cx_Init(&I2Cx_Param);
delay_1ms(3000);//delay 3s wait slaver init success!
Master_SendData_address(write_buffer,BufferNum,&I2Cx_Param);
printf("I2C0_Ten_Address_standard send success\n");
break;
case I2C0_Seven_Address_high:
Param_Init(&I2Cx_Param,Para_Aarry,I2C0_Seven_Address_high);
I2Cx_Init(&I2Cx_Param);
delay_1ms(3000);//delay 3s wait slaver init success!
Master_SendData_address(write_buffer,BufferNum,&I2Cx_Param);
printf("I2C0_Seven_Address_high send success\n");
break;
case I2C0_Ten_Address_high:
Param_Init(&I2Cx_Param,Para_Aarry,I2C0_Ten_Address_high);
I2Cx_Init(&I2Cx_Param);
delay_1ms(3000);//delay 3s wait slaver init success!
Master_SendData_address(write_buffer,BufferNum,&I2Cx_Param);
printf("I2C0_Ten_Address_high send success\n");
break;
case I2C0_Seven_Address_more_high:
Param_Init(&I2Cx_Param,Para_Aarry,I2C0_Seven_Address_more_high);
I2Cx_Init(&I2Cx_Param);
delay_1ms(3000);//delay 3s wait slaver init success!
Master_SendData_address(write_buffer,BufferNum,&I2Cx_Param);
printf("I2C0_Seven_Address_more_high send success\n");
break;
case I2C1_Seven_Address_standard:
Param_Init(&I2Cx_Param,Para_Aarry,I2C1_Seven_Address_standard);
I2Cx_Init(&I2Cx_Param);
delay_1ms(3000);//delay 3s wait slaver init success!
Master_SendData_address(write_buffer,BufferNum,&I2Cx_Param);
printf("I2C1 Seven Address standard send success\n");
break;
case I2C1_Ten_Address_standard:
Param_Init(&I2Cx_Param,Para_Aarry,I2C1_Ten_Address_standard);
I2Cx_Init(&I2Cx_Param);
delay_1ms(3000);//delay 3s wait slaver init success!
Master_SendData_address(write_buffer,BufferNum,&I2Cx_Param);
printf("I2C1_Ten_Address_standard send success\n");
break;
case I2C1_Seven_Address_high:
Param_Init(&I2Cx_Param,Para_Aarry,I2C1_Seven_Address_high);
I2Cx_Init(&I2Cx_Param);
delay_1ms(3000);//delay 3s wait slaver init success!
Master_SendData_address(write_buffer,BufferNum,&I2Cx_Param);
printf("I2C1_Seven_Address_high send success\n");
break;
case I2C1_Ten_Address_high:
Param_Init(&I2Cx_Param,Para_Aarry,I2C1_Ten_Address_high);
I2Cx_Init(&I2Cx_Param);
delay_1ms(3000);//delay 3s wait slaver init success!
Master_SendData_address(write_buffer,BufferNum,&I2Cx_Param);
printf("I2C1_Ten_Address_high send success\n");
break;
case I2C1_Seven_Address_more_high:
Param_Init(&I2Cx_Param,Para_Aarry,I2C1_Seven_Address_more_high);
I2Cx_Init(&I2Cx_Param);
delay_1ms(3000);//delay 3s wait slaver init success!
Master_SendData_address(write_buffer,BufferNum,&I2Cx_Param);
printf("I2C1_Seven_Address_more_high send success\n");
break;
default:
break;
}
}
/*!
\brief Configure Param of receive data
\param[in] Test_Sequence_Enum measure_sequence //test sequence
\param[out] none
\retval none
*/
void Configure_I2CX_Receive(Test_Sequence_Enum measure_sequence)
{
switch(measure_sequence)
{
case I2C0_Seven_Address_standard:
Param_Init(&I2Cx_Param,Para_Aarry,I2C0_Seven_Address_standard);
I2Cx_Init(&I2Cx_Param);
delay_1ms(3000);//delay 3s wait slaver init success!
Master_ReceiveData(receive_buffer,BufferNum,&I2Cx_Param);
printf("I2C0_Seven_Address_standard receive data success!!\n");
break;
case I2C0_Ten_Address_standard:
Param_Init(&I2Cx_Param,Para_Aarry,I2C0_Ten_Address_standard);
I2Cx_Init(&I2Cx_Param);
delay_1ms(3000);//delay 3s wait slaver init success!
Master_ReceiveData(receive_buffer,BufferNum,&I2Cx_Param);
printf("I2C0_Ten_Address_standard receive data success!!\n");
break;
case I2C0_Seven_Address_high:
Param_Init(&I2Cx_Param,Para_Aarry,I2C0_Seven_Address_high);
I2Cx_Init(&I2Cx_Param);
delay_1ms(3000);//delay 3s wait slaver init success!
Master_ReceiveData(receive_buffer,BufferNum,&I2Cx_Param);
printf("I2C0_Seven_Address_high receive data success!!\n");
break;
case I2C0_Ten_Address_high:
Param_Init(&I2Cx_Param,Para_Aarry,I2C0_Ten_Address_high);
I2Cx_Init(&I2Cx_Param);
delay_1ms(3000);//delay 3s wait slaver init success!
Master_ReceiveData(receive_buffer,BufferNum,&I2Cx_Param);
printf("I2C0_Ten_Address_high receive data success!!\n");
break;
case I2C0_Seven_Address_more_high:
Param_Init(&I2Cx_Param,Para_Aarry,I2C0_Seven_Address_more_high);
I2Cx_Init(&I2Cx_Param);
delay_1ms(3000);//delay 3s wait slaver init success!
Master_ReceiveData(receive_buffer,BufferNum,&I2Cx_Param);
printf("I2C0_Ten_Address_high receive data success!!\n");
break;
case I2C1_Seven_Address_standard:
Param_Init(&I2Cx_Param,Para_Aarry,I2C1_Seven_Address_standard);
I2Cx_Init(&I2Cx_Param);
delay_1ms(3000);//delay 3s wait slaver init success!
Master_ReceiveData(receive_buffer,BufferNum,&I2Cx_Param);
printf("I2C1_Seven_Address_standard receive data success!!\n");
break;
case I2C1_Ten_Address_standard:
Param_Init(&I2Cx_Param,Para_Aarry,I2C1_Ten_Address_standard);
I2Cx_Init(&I2Cx_Param);
delay_1ms(3000);//delay 3s wait slaver init success!
Master_ReceiveData(receive_buffer,BufferNum,&I2Cx_Param);
printf("I2C1_Ten_Address_standard receive data success!!\n");
break;
case I2C1_Seven_Address_high:
Param_Init(&I2Cx_Param,Para_Aarry,I2C1_Seven_Address_high);
I2Cx_Init(&I2Cx_Param);
delay_1ms(3000);//delay 3s wait slaver init success!
Master_ReceiveData(receive_buffer,BufferNum,&I2Cx_Param);
printf("I2C1_Seven_Address_high receive data success!!\n");
break;
case I2C1_Ten_Address_high:
Param_Init(&I2Cx_Param,Para_Aarry,I2C1_Ten_Address_high);
I2Cx_Init(&I2Cx_Param);
delay_1ms(3000);//delay 3s wait slaver init success!
Master_ReceiveData(receive_buffer,BufferNum,&I2Cx_Param);
printf("I2C1_Ten_Address_high receive data success!!\n");
break;
case I2C1_Seven_Address_more_high:
Param_Init(&I2Cx_Param,Para_Aarry,I2C1_Seven_Address_more_high);
I2Cx_Init(&I2Cx_Param);
delay_1ms(3000);//delay 3s wait slaver init success!
Master_ReceiveData(receive_buffer,BufferNum,&I2Cx_Param);
printf("I2C1_Ten_Address_high receive data success!!\n");
break;
default:
break;
}
}
/*!
\brief Configure Param of I2Cx receive data
\param[in] Test_Sequence_Enum measure_sequence //test sequence
\param[out] none
\retval none
*/
void Param_Init(Param_Typedef* i2c_param,Param_Typedef* Param_Array,Test_Sequence_Enum measure_sequence)
{
i2c_param->Memory_address=Param_Array[measure_sequence].Memory_address;
i2c_param->gpio_sclpin=Param_Array[measure_sequence].gpio_sclpin;
i2c_param->gpio_sdapin=Param_Array[measure_sequence].gpio_sdapin;
i2c_param->address=Param_Array[measure_sequence].address;
i2c_param->address_model=Param_Array[measure_sequence].address_model;
i2c_param->I2Cx_Periph=Param_Array[measure_sequence].I2Cx_Periph;
i2c_param->I2c_speed=Param_Array[measure_sequence].I2c_speed;
i2c_param->slaver_address=Param_Array[measure_sequence].slaver_address;
}
/*!
\brief I2C init
\param[in] I2Cx_PinSDA_Enum SDA pin
I2Cx_PinSCL_Enum SCL pin
rcu_periph_enum I2C periph
I2Cx_Speed_enum check clock frequence
Address_Model_Enum 7 or 10 address check
Slaver_Address_Enum 7 or 10 address
\param[out] none
\retval none
*/
void I2Cx_Init(Param_Typedef *i2c_init)
{
uint32_t gpiox_sda,pinx_sda,afx_sda,gpiox_scl,pinx_scl,afx_scl;
I2Cx_Pin_ClockEnable(i2c_init->gpio_sdapin,i2c_init->gpio_sclpin);//SCL and SDA GPIO enable
/*GPIO sda configure*/
gpiox_sda=(uint32_t)((i2c_init->gpio_sdapin)& 0xffffff00);
pinx_sda=(0x01<<((i2c_init->gpio_sdapin & 0xf0) >> 4));
afx_sda=AF((i2c_init->gpio_sdapin & 0x0f));
I2Cx_Pin_ClockEnable(i2c_init->gpio_sdapin,i2c_init->gpio_sclpin);
gpio_af_set(gpiox_sda, afx_sda, pinx_sda);//IO口引脚复用功能
gpio_mode_set(gpiox_sda, GPIO_MODE_AF, GPIO_PUPD_PULLUP,pinx_sda);//GPIO口、备用功能、端口上拉模式、具体引脚
gpio_output_options_set(gpiox_sda, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ,pinx_sda);//GPIO口、推挽输出及开漏输出、输出速率、具体引脚
/*GPIO scl configure*/
gpiox_scl=(uint32_t)((i2c_init->gpio_sclpin)& 0xffffff00);
pinx_scl=(0x01<<((i2c_init->gpio_sclpin & 0xf0) >> 4));
afx_scl=AF((i2c_init->gpio_sclpin & 0x0f));
gpio_af_set(gpiox_scl, afx_scl,pinx_scl);//IO口引脚复用功能
gpio_mode_set(gpiox_scl, GPIO_MODE_AF, GPIO_PUPD_PULLUP,pinx_scl);//GPIO口、备用功能、端口上拉模式、具体引脚
/*--------------------------------I2C module initaial configure------------------------------------*/
/*enable I2C clock*/
rcu_periph_clock_enable(i2c_init->I2Cx_Periph);//使能I2C时钟
/*configure I2C clock*/
i2c_clock_config(i2c_init->Memory_address,i2c_init->I2c_speed,I2C_DTCY_2);//I2C的基地址、I2C数据传输速度、I2C的快速模式
/*configure I2C address*/
i2c_mode_addr_config(i2c_init->Memory_address,I2C_I2CMODE_ENABLE,i2c_init->address_model,i2c_init->slaver_address);//I2C基地址、I2C模式、7位地址模式、I2C从机地址
/*enable I2C0*/
i2c_enable(i2c_init->Memory_address);//I2C外设使能
/*enable acknowledge*/
i2c_ack_config(i2c_init->Memory_address,I2C_ACK_ENABLE);//选择是否发送应答信号
}
/*!
\brief I2C GPIO Clock enable
\param[in] I2Cx_PinSDA_Enum SDA pin
I2Cx_PinSCL_Enum SCL pin
\param[out] none
\retval none
*/
void I2Cx_Pin_ClockEnable(I2Cx_PinSDA_Enum gpio_sdapin,I2Cx_PinSCL_Enum gpio_sclpin)
{
uint32_t gpiox_sda,gpiox_scl;
gpiox_sda=(uint32_t)(gpio_sdapin & 0xffffff00);
gpiox_scl=(uint32_t)(gpio_sclpin & 0xffffff00);
/*SDA enable*/
if(gpiox_sda==GPIOB){
rcu_periph_clock_enable(RCU_GPIOB);
}else if(gpiox_sda==GPIOA){
rcu_periph_clock_enable(RCU_GPIOC);
}else if(gpiox_sda==GPIOF){
rcu_periph_clock_enable(RCU_GPIOF);
}
/*SCL enable*/
if(gpiox_scl==GPIOB){
rcu_periph_clock_enable(RCU_GPIOB);
}else if(gpiox_scl==GPIOA){
rcu_periph_clock_enable(RCU_GPIOA);
}
}
/*!
\brief Master send data 7 and 10 address
\param[in] SendBuffer send array
DataNum send data num
\param[out] none
\retval none
*/
void Master_SendData_address(uint8_t* SendBuffer,uint8_t DataNum,Param_Typedef *i2c_init)
{
uint8_t num;
/*wait until I2C bus is idle*/
while(i2c_flag_get(i2c_init->Memory_address,I2C_FLAG_I2CBSY)){
}
/*send a start condition to I2C bus*/
i2c_start_on_bus(i2c_init->Memory_address);//在I2C总线上产生一个开始信号
/*wait until SBSEND bit is set judge start whether send*/
while(!i2c_flag_get(i2c_init->Memory_address,I2C_FLAG_SBSEND)){
}
//I2C_STAT0(i2c_init->Memory_address);//read I2C_STAT0 to clear ADDSEND
if(i2c_init->address_model==I2Cx_Address_7bit){
Send_7Prepare(i2c_init);
}
else if(i2c_init->address_model==I2Cx_Address_10bit){
Send_10Prepare(i2c_init);
}
/*wait until the transmit data buffer is empty */
while(SET != i2c_flag_get(i2c_init->Memory_address,I2C_FLAG_TBE)){
}
for(num=0;num<DataNum;num++){
i2c_data_transmit(i2c_init->Memory_address,SendBuffer[num]);
while(!i2c_flag_get(i2c_init->Memory_address,I2C_FLAG_BTC)){
}
}
/*send a stop condition to I2C bus*/
i2c_stop_on_bus(i2c_init->Memory_address);//在总线上发送停止信号位
/*wait until the stop condition is finished*/
while(I2C_CTL0(i2c_init->Memory_address)&0x0200);//等待结束信号发送
//printf("master send data success");
}
/*!
\brief Master receive data
\param[in] ReceiveBuffer receive data array
DataNum receive data num
address slaver address
\param[out] none
\retval none
*/
void Master_ReceiveData(uint8_t* ReceiveBuffer,uint8_t DataNum,Param_Typedef *i2c_init)
{
/*wait until I2C bus is idle*/
while(i2c_flag_get(i2c_init->Memory_address,I2C_FLAG_I2CBSY));
/*send a start condition to I2C bus*/
i2c_start_on_bus(i2c_init->Memory_address);//在I2C总线上产生一个开始信号
/*wait until SBSEND bit is set judge start whether send*/
while(!i2c_flag_get(i2c_init->Memory_address,I2C_FLAG_SBSEND));
if(i2c_init->address==Send_7Address){
Receive_7Prepare(i2c_init);
}
else if(i2c_init->address==Send_10Address){
Receive_10Prepare(i2c_init);
}
if(DataNum==1){
/*disable acknowledge*/
i2c_ack_config(i2c_init->Memory_address,I2C_ACK_DISABLE);//选择是否发送应答信号
/*send a stop condition to I2C bus*/
i2c_stop_on_bus(i2c_init->Memory_address);//在总线上发送停止信号位
/*I2C_DATA is not empty*/
while(!i2c_flag_get(i2c_init->Memory_address,I2C_FLAG_RBNE));
*ReceiveBuffer=i2c_data_receive(i2c_init->Memory_address);//read data from I2C_DATA
}
while(DataNum){
if(DataNum==2){
while(!i2c_flag_get(i2c_init->Memory_address,I2C_FLAG_RBNE));
*ReceiveBuffer=i2c_data_receive(i2c_init->Memory_address);//read data from I2C_DATA
DataNum-=1;
ReceiveBuffer++;
/*disable acknowledge*/
i2c_ack_config(i2c_init->Memory_address,I2C_ACK_DISABLE);//选择是否发送应答信号
/*send a stop condition to I2C bus*/
i2c_stop_on_bus(i2c_init->Memory_address);//在总线上发送停止信号位
}
/*I2C_DATA is not empty*/
while(!i2c_flag_get(i2c_init->Memory_address,I2C_FLAG_RBNE));
*ReceiveBuffer=i2c_data_receive(i2c_init->Memory_address);//read data from I2C_DATA
DataNum-=1;
ReceiveBuffer++;
}
/*wait until the stop condition is finished*/
while(I2C_CTL0(i2c_init->Memory_address)&0x0200);//判断stop结束位已经发送
/*enable acknowledge*/
i2c_ack_config(i2c_init->Memory_address,I2C_ACK_ENABLE);//软件发送应答信号使能
i2c_ackpos_config(i2c_init->Memory_address,I2C_ACKPOS_CURRENT);//ACKEN位决定对当前正在接收的字节是否发送ACK/NACK;PECTRANS位表明PEC 是否处于移位寄存器中
//printf("master receive data success");
}
/*!
\brief Master send 7 address prepare
\param[in] none
\param[out] none
\retval none
*/
void Send_7Prepare(Param_Typedef *i2c_init)
{
/*send slave address to I2C bus*/
i2c_master_addressing(i2c_init->Memory_address,i2c_init->address,I2C_TRANSMITTER);//发送从机地址+写、清除SBSEND位、I2C设备发送方
/*wait until ADDSEND bit is set*/
while(!i2c_flag_get(i2c_init->Memory_address,I2C_FLAG_ADDSEND)){
}
/*read I2C_STAT0 and then read I2C_STAT1 to clear ADDSEND*/
i2c_flag_clear(i2c_init->Memory_address,I2C_FLAG_ADDSEND);//清除ADDSEND位
}
/*!
\brief Master receive 7 address prepare
\param[in] none
\param[out] none
\retval none
*/
void Receive_7Prepare(Param_Typedef *i2c_init)
{
/*send slave address to I2C bus */
i2c_master_addressing(i2c_init->Memory_address,i2c_init->address,I2C_RECEIVER);//发送从机地址+写、清除SBSEND位、I2C设备发送方
/* wait until ADDSEND bit is set */
while(!i2c_flag_get(i2c_init->Memory_address,I2C_FLAG_ADDSEND)){
}
/*read I2C_STAT0 and then read I2C_STAT1 to clear ADDSEND*/
i2c_flag_clear(i2c_init->Memory_address,I2C_FLAG_ADDSEND);//清除ADDSEND位
}
/*!
\brief Master send 10 address prepare
\param[in] none
\param[out] none
\retval none
*/
void Send_10Prepare(Param_Typedef *i2c_init)
{
uint32_t adrH10,adrL10;
adrH10=(((i2c_init->address & 0x300)>>7)|0xf0);//10位地址头(高2位)
adrL10=i2c_init->address & 0xff;//10位地址(低8位)
/*send slave address adr10 to I2C bus */
i2c_master_addressing(i2c_init->Memory_address,(uint8_t)adrH10, I2C_TRANSMITTER);
/* wait until ADDSEND bit is set */
while(!i2c_flag_get(i2c_init->Memory_address,I2C_FLAG_ADD10SEND));
i2c_data_transmit(i2c_init->Memory_address,adrL10);
/*wait until ADDSEND bit is set*/
while(!i2c_flag_get(i2c_init->Memory_address,I2C_FLAG_ADDSEND));
/*read I2C_STAT0 and then read I2C_STAT1 to clear ADDSEND*/
i2c_flag_clear(i2c_init->Memory_address,I2C_FLAG_ADDSEND);//清除ADDSEND位
}
/*!
\brief Master receive 10 address prepare
\param[in] none
\param[out] none
\retval none
*/
void Receive_10Prepare(Param_Typedef *i2c_init)
{
uint32_t adrH10,adrL10;
adrH10=(((i2c_init->address & 0x300)>>7)|0xf0);//10位地址头(高2位)
adrL10=i2c_init->address & 0xff;//10位地址(低8位)
/*send slave address to I2C bus*/
i2c_master_addressing(i2c_init->Memory_address,(uint8_t)adrH10, I2C_TRANSMITTER);//发送从机10地址头+写、清除SBSEND位、I2C设备发送方
/*wait until ADDSEND bit is set*/
while(!i2c_flag_get(i2c_init->Memory_address,I2C_FLAG_ADD10SEND));
i2c_data_transmit(i2c_init->Memory_address,adrL10);
/* wait until ADDSEND bit is set */
while(!i2c_flag_get(i2c_init->Memory_address,I2C_FLAG_ADDSEND));
/*read I2C_STAT0 and then read I2C_STAT1 to clear ADDSEND*/
i2c_flag_clear(i2c_init->Memory_address,I2C_FLAG_ADDSEND);//清除ADDSEND位
/*send a start condition to I2C bus*/
i2c_start_on_bus(i2c_init->Memory_address);//在I2C总线上产生一个开始信号
/*wait until SBSEND bit is set judge start whether send*/
while(!i2c_flag_get(i2c_init->Memory_address,I2C_FLAG_SBSEND));
i2c_master_addressing(i2c_init->Memory_address,(uint8_t)adrH10,I2C_RECEIVER);
while(!i2c_flag_get(i2c_init->Memory_address,I2C_FLAG_ADDSEND));//等待ADDSEND位置1 硬件置1
/*read I2C_STAT0 and then read I2C_STAT1 to clear ADDSEND*/
i2c_flag_clear(i2c_init->Memory_address,I2C_FLAG_ADDSEND);//清除ADDSEND位
}
/* retarget the C library printf function to the USART */
int fputc(int ch, FILE *f)
{
usart_data_transmit(EVAL_COM, (uint8_t)ch);
while(RESET == usart_flag_get(EVAL_COM, USART_FLAG_TBE));
return ch;
}
/*!
\brief this function handles SysTick exception
\param[in] none
\param[out] none
\retval none
*/
void SysTick_Handler(void)
{
delay_decrement();
}
上述程序实现了主机发送和接收,速率100k/400k/1M,发送从机地址10bit、7bit,程序方便移植,只需将对应的.c和.h添加到工程中即可。当I2C的通信速率为1M时,需配置I2C模块所挂载的pclk时钟为3的整数倍或者25的整数倍,否则主机的SCL实际的时钟会有一定的误差,大于或者小于1M,大于1M可能导致通信失败(GD mcu官方手册有提到)。I2C总线空闲时,默认为高电平,因为GPIO口内部自带的上拉驱动能力不够,配置为开漏输出,需外接上拉电阻,GPIO的输出速率要选择最大(代码中选择的是50M)增加GPIO口输出能力,否则通过示波器查看发现SCL时钟波形不是正规的波形,也可能造成通信失败。不同GPIO口输出速率下,SCL时钟输出波形如下图所示。
1.4 从机发送和接收(速率100k\400k\1M,地址10bit or 7bit)
I2C的从机的通信时钟由主机提供,故不需要配置时钟,I2C初始化后默认为从机模式,发送start信号后,由从机模式转换为主机模式。
#include "gd32f3x0.h"
#include <stdio.h>
#include "gd32f350r_eval.h"
#include "main.h"
#include "systick.h"
#define I2C0_Measure
//#define I2C1_Measure
#define BufferNum 20
uint8_t write_buffer[BufferNum]={0};//send data buffer
uint8_t receive_buffer[BufferNum]={0};//receive data buffer
Param_Typedef I2Cx_Param;
/*define I2Cx Param struct array*/
static Param_Typedef Para_Aarry[]=
{
/*I2C0 param array*/
{I2C0,I2C0_SDA_GPIOx2,I2C0_SCL_GPIOy2,RCU_I2C0,standard_speed,I2Cx_Address_7bit,Send_7Address,Slaver_7Address},
{I2C0,I2C0_SDA_GPIOx2,I2C0_SCL_GPIOy2,RCU_I2C0,standard_speed,I2Cx_Address_10bit,Send_10Address,Slaver_10Address},
{I2C0,I2C0_SDA_GPIOx2,I2C0_SCL_GPIOy2,RCU_I2C0,High_speed,I2Cx_Address_7bit,Send_7Address,Slaver_7Address},
{I2C0,I2C0_SDA_GPIOx2,I2C0_SCL_GPIOy2,RCU_I2C0,High_speed,I2Cx_Address_10bit,Send_10Address,Slaver_10Address},
{I2C0,I2C0_SDA_GPIOx2,I2C0_SCL_GPIOy2,RCU_I2C0,More_HighSpeed,I2Cx_Address_7bit,Send_7Address,Slaver_7Address},
/*I2C1 param array*/
{I2C1,I2C1_SDA_GPIOx5,I2C1_SCL_GPIOy5,RCU_I2C1,standard_speed,I2Cx_Address_7bit,Send_7Address,Slaver_7Address},
{I2C1,I2C1_SDA_GPIOx5,I2C1_SCL_GPIOy5,RCU_I2C1,standard_speed,I2Cx_Address_10bit,Send_10Address,Slaver_10Address},
{I2C1,I2C1_SDA_GPIOx5,I2C1_SCL_GPIOy5,RCU_I2C1,High_speed,I2Cx_Address_7bit,Send_7Address,Slaver_7Address},
{I2C1,I2C1_SDA_GPIOx5,I2C1_SCL_GPIOy5,RCU_I2C1,High_speed,I2Cx_Address_10bit,Send_10Address,Slaver_10Address},
{I2C1,I2C1_SDA_GPIOx5,I2C1_SCL_GPIOy5,RCU_I2C1,More_HighSpeed,I2Cx_Address_7bit,Send_7Address,Slaver_7Address},
};
/*testing sequence enum*/
typedef enum
{
/*Measure I2C0*/
I2C0_Seven_Address_standard=0,
I2C0_Ten_Address_standard,
I2C0_Seven_Address_high,
I2C0_Ten_Address_high,
I2C0_Seven_Address_more_high,
/*Measure I2C1*/
I2C1_Seven_Address_standard,
I2C1_Ten_Address_standard,
I2C1_Seven_Address_high,
I2C1_Ten_Address_high,
I2C1_Seven_Address_more_high
}Test_Sequence_Enum;
/*Configure Param of I2Cx Send data*/
void Configure_I2CX_Send(Test_Sequence_Enum measure_sequence);
/*Configure Param of I2Cx receive data*/
void Configure_I2CX_Receive(Test_Sequence_Enum measure_sequence);
/*I2Cx param init*/
void Param_Init(Param_Typedef* i2c_param,Param_Typedef* Param_Array,Test_Sequence_Enum measure_sequence);
/*!
\brief main function
\param[in] none
\param[out] none
\retval none
*/
int main(void)
{
uint8_t num=0;
for(num=0;num<BufferNum;num++){
write_buffer[num]=num;
}
//printf("I2C slaver measuring\n");
#ifdef I2C0_Measure
/*Test Sequence I2C0 receive*/
Configure_I2CX_Receive(I2C0_Seven_Address_standard);
Configure_I2CX_Receive(I2C0_Ten_Address_standard);
Configure_I2CX_Receive(I2C0_Seven_Address_high);
Configure_I2CX_Receive(I2C0_Ten_Address_high);
Configure_I2CX_Receive(I2C0_Seven_Address_more_high);
/*Test Sequence I2C0 send*/
Configure_I2CX_Send(I2C0_Seven_Address_standard);
Configure_I2CX_Send(I2C0_Ten_Address_standard);
Configure_I2CX_Send(I2C0_Seven_Address_high);
Configure_I2CX_Send(I2C0_Ten_Address_high);
Configure_I2CX_Send(I2C0_Seven_Address_more_high);
#elif defined I2C1_Measure
/*Test Sequence I2C1 receive*/
Configure_I2CX_Receive(I2C1_Seven_Address_standard);
Configure_I2CX_Receive(I2C1_Ten_Address_standard);
Configure_I2CX_Receive(I2C1_Seven_Address_high);
Configure_I2CX_Receive(I2C1_Ten_Address_high);
Configure_I2CX_Receive(I2C1_Seven_Address_more_high);
/*Test Sequence I2C1 send*/
Configure_I2CX_Send(I2C1_Seven_Address_standard);
Configure_I2CX_Send(I2C1_Ten_Address_standard);
Configure_I2CX_Send(I2C1_Seven_Address_high);
Configure_I2CX_Send(I2C1_Ten_Address_high);
Configure_I2CX_Send(I2C1_Seven_Address_more_high);
#endif
while(1){
}
}
/*!
\brief Configure Param of I2Cx I2Cx Send data
\param[in] Test_Sequence_Enum measure_sequence //test sequence
\param[out] none
\retval none
*/
void Configure_I2CX_Send(Test_Sequence_Enum measure_sequence)
{
switch(measure_sequence)
{
case I2C0_Seven_Address_standard:
Param_Init(&I2Cx_Param,Para_Aarry,I2C0_Seven_Address_standard);
I2Cx_Init(&I2Cx_Param);
Slaver_SendData_address(write_buffer,BufferNum,&I2Cx_Param);
printf("I2C0 Seven Address standard send success\n");
break;
case I2C0_Ten_Address_standard:
Param_Init(&I2Cx_Param,Para_Aarry,I2C0_Ten_Address_standard);
I2Cx_Init(&I2Cx_Param);
Slaver_SendData_address(write_buffer,BufferNum,&I2Cx_Param);
printf("I2C0_Ten_Address_standard send success\n");
break;
case I2C0_Seven_Address_high:
Param_Init(&I2Cx_Param,Para_Aarry,I2C0_Seven_Address_high);
I2Cx_Init(&I2Cx_Param);
Slaver_SendData_address(write_buffer,BufferNum,&I2Cx_Param);
printf("I2C0_Seven_Address_high send success\n");
break;
case I2C0_Ten_Address_high:
Param_Init(&I2Cx_Param,Para_Aarry,I2C0_Ten_Address_high);
I2Cx_Init(&I2Cx_Param);
Slaver_SendData_address(write_buffer,BufferNum,&I2Cx_Param);
printf("I2C0_Ten_Address_high send success\n");
break;
case I2C0_Seven_Address_more_high:
Param_Init(&I2Cx_Param,Para_Aarry,I2C0_Seven_Address_more_high);
I2Cx_Init(&I2Cx_Param);
Slaver_SendData_address(write_buffer,BufferNum,&I2Cx_Param);
printf("I2C0_Seven_Address_more_high send success\n");
break;
case I2C1_Seven_Address_standard:
Param_Init(&I2Cx_Param,Para_Aarry,I2C1_Seven_Address_standard);
I2Cx_Init(&I2Cx_Param);
Slaver_SendData_address(write_buffer,BufferNum,&I2Cx_Param);
printf("I2C1 Seven Address standard send success\n");
break;
case I2C1_Ten_Address_standard:
Param_Init(&I2Cx_Param,Para_Aarry,I2C1_Ten_Address_standard);
I2Cx_Init(&I2Cx_Param);
Slaver_SendData_address(write_buffer,BufferNum,&I2Cx_Param);
printf("I2C1_Ten_Address_standard send success\n");
break;
case I2C1_Seven_Address_high:
Param_Init(&I2Cx_Param,Para_Aarry,I2C1_Seven_Address_high);
I2Cx_Init(&I2Cx_Param);
Slaver_SendData_address(write_buffer,BufferNum,&I2Cx_Param);
printf("I2C1_Seven_Address_high send success\n");
break;
case I2C1_Ten_Address_high:
Param_Init(&I2Cx_Param,Para_Aarry,I2C1_Ten_Address_high);
I2Cx_Init(&I2Cx_Param);
Slaver_SendData_address(write_buffer,BufferNum,&I2Cx_Param);
printf("I2C1_Ten_Address_high send success\n");
break;
case I2C1_Seven_Address_more_high:
Param_Init(&I2Cx_Param,Para_Aarry,I2C1_Seven_Address_more_high);
I2Cx_Init(&I2Cx_Param);
Slaver_SendData_address(write_buffer,BufferNum,&I2Cx_Param);
printf("I2C1_Seven_Address_more_high send success\n");
break;
default:
break;
}
}
/*!
\brief Configure Param of receive data
\param[in] Test_Sequence_Enum measure_sequence //test sequence
\param[out] none
\retval none
*/
void Configure_I2CX_Receive(Test_Sequence_Enum measure_sequence)
{
switch(measure_sequence)
{
case I2C0_Seven_Address_standard:
Param_Init(&I2Cx_Param,Para_Aarry,I2C0_Seven_Address_standard);
I2Cx_Init(&I2Cx_Param);
Slaver_ReceiveData_address(receive_buffer,BufferNum,&I2Cx_Param);
printf("I2C0_Seven_Address_standard receive data success!!\n");
break;
case I2C0_Ten_Address_standard:
Param_Init(&I2Cx_Param,Para_Aarry,I2C0_Ten_Address_standard);
I2Cx_Init(&I2Cx_Param);
Slaver_ReceiveData_address(receive_buffer,BufferNum,&I2Cx_Param);
printf("I2C0_Ten_Address_standard receive data success!!\n");
break;
case I2C0_Seven_Address_high:
Param_Init(&I2Cx_Param,Para_Aarry,I2C0_Seven_Address_high);
I2Cx_Init(&I2Cx_Param);
Slaver_ReceiveData_address(receive_buffer,BufferNum,&I2Cx_Param);
printf("I2C0_Seven_Address_high receive data success!!\n");
break;
case I2C0_Ten_Address_high:
Param_Init(&I2Cx_Param,Para_Aarry,I2C0_Ten_Address_high);
I2Cx_Init(&I2Cx_Param);
Slaver_ReceiveData_address(receive_buffer,BufferNum,&I2Cx_Param);
printf("I2C0_Ten_Address_high receive data success!!\n");
break;
case I2C0_Seven_Address_more_high:
Param_Init(&I2Cx_Param,Para_Aarry,I2C0_Seven_Address_more_high);
I2Cx_Init(&I2Cx_Param);
Slaver_ReceiveData_address(receive_buffer,BufferNum,&I2Cx_Param);
printf("I2C0_Ten_Address_high receive data success!!\n");
break;
case I2C1_Seven_Address_standard:
Param_Init(&I2Cx_Param,Para_Aarry,I2C1_Seven_Address_standard);
I2Cx_Init(&I2Cx_Param);
Slaver_ReceiveData_address(receive_buffer,BufferNum,&I2Cx_Param);
printf("I2C1_Seven_Address_standard receive data success!!\n");
break;
case I2C1_Ten_Address_standard:
Param_Init(&I2Cx_Param,Para_Aarry,I2C1_Ten_Address_standard);
I2Cx_Init(&I2Cx_Param);
Slaver_ReceiveData_address(receive_buffer,BufferNum,&I2Cx_Param);
printf("I2C1_Ten_Address_standard receive data success!!\n");
break;
case I2C1_Seven_Address_high:
Param_Init(&I2Cx_Param,Para_Aarry,I2C1_Seven_Address_high);
I2Cx_Init(&I2Cx_Param);
Slaver_ReceiveData_address(receive_buffer,BufferNum,&I2Cx_Param);
printf("I2C1_Seven_Address_high receive data success!!\n");
break;
case I2C1_Ten_Address_high:
Param_Init(&I2Cx_Param,Para_Aarry,I2C1_Ten_Address_high);
I2Cx_Init(&I2Cx_Param);
Slaver_ReceiveData_address(receive_buffer,BufferNum,&I2Cx_Param);
printf("I2C1_Ten_Address_high receive data success!!\n");
break;
case I2C1_Seven_Address_more_high:
Param_Init(&I2Cx_Param,Para_Aarry,I2C1_Seven_Address_more_high);
I2Cx_Init(&I2Cx_Param);
Slaver_ReceiveData_address(receive_buffer,BufferNum,&I2Cx_Param);
printf("I2C1_Ten_Address_high receive data success!!\n");
break;
default:
break;
}
}
/*!
\brief Configure Param of I2Cx receive data
\param[in] Test_Sequence_Enum measure_sequence //test sequence
\param[out] none
\retval none
*/
void Param_Init(Param_Typedef* i2c_param,Param_Typedef* Param_Array,Test_Sequence_Enum measure_sequence)
{
i2c_param->Memory_address=Param_Array[measure_sequence].Memory_address;
i2c_param->gpio_sclpin=Param_Array[measure_sequence].gpio_sclpin;
i2c_param->gpio_sdapin=Param_Array[measure_sequence].gpio_sdapin;
i2c_param->address=Param_Array[measure_sequence].address;
i2c_param->address_model=Param_Array[measure_sequence].address_model;
i2c_param->I2Cx_Periph=Param_Array[measure_sequence].I2Cx_Periph;
i2c_param->I2c_speed=Param_Array[measure_sequence].I2c_speed;
i2c_param->slaver_address=Param_Array[measure_sequence].slaver_address;
}
/*!
\brief I2C init
\param[in] I2Cx_PinSDA_Enum SDA pin
I2Cx_PinSCL_Enum SCL pin
rcu_periph_enum I2C periph
I2Cx_Speed_enum check clock frequence
Address_Model_Enum 7 or 10 address check
Slaver_Address_Enum 7 or 10 address
\param[out] none
\retval none
*/
void I2Cx_Init(Param_Typedef *i2c_init)
{
uint32_t gpiox_sda,pinx_sda,afx_sda,gpiox_scl,pinx_scl,afx_scl;
I2Cx_Pin_ClockEnable(i2c_init->gpio_sdapin,i2c_init->gpio_sclpin);//SCL and SDA GPIO enable
/*GPIO sda configure*/
gpiox_sda=(uint32_t)((i2c_init->gpio_sdapin)& 0xffffff00);
pinx_sda=(0x01<<((i2c_init->gpio_sdapin & 0xf0) >> 4));
afx_sda=AF((i2c_init->gpio_sdapin & 0x0f));
I2Cx_Pin_ClockEnable(i2c_init->gpio_sdapin,i2c_init->gpio_sclpin);
gpio_af_set(gpiox_sda, afx_sda, pinx_sda);//IO口引脚复用功能
gpio_mode_set(gpiox_sda, GPIO_MODE_AF, GPIO_PUPD_PULLUP,pinx_sda);//GPIO口、备用功能、端口上拉模式、具体引脚
gpio_output_options_set(gpiox_sda, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ,pinx_sda);//GPIO口、推挽输出及开漏输出、输出速率、具体引脚
/*GPIO scl configure*/
gpiox_scl=(uint32_t)((i2c_init->gpio_sclpin)& 0xffffff00);
pinx_scl=(0x01<<((i2c_init->gpio_sclpin & 0xf0) >> 4));
afx_scl=AF((i2c_init->gpio_sclpin & 0x0f));
gpio_af_set(gpiox_scl, afx_scl,pinx_scl);//IO口引脚复用功能
gpio_mode_set(gpiox_scl, GPIO_MODE_AF, GPIO_PUPD_PULLUP,pinx_scl);//GPIO口、备用功能、端口上拉模式、具体引脚
gpio_output_options_set(gpiox_scl, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ,pinx_scl);//GPIO口、推挽输出及开漏输出、输出速率、具体引脚
/*--------------------------------I2C module initaial configure------------------------------------*/
/*enable I2C clock*/
rcu_periph_clock_enable(i2c_init->I2Cx_Periph);//使能I2C时钟
/*configure I2C clock*/
i2c_clock_config(i2c_init->Memory_address,i2c_init->I2c_speed,I2C_DTCY_2);//I2C的基地址、I2C数据传输速度、I2C的快速模式
/*configure I2C address*/
i2c_mode_addr_config(i2c_init->Memory_address,I2C_I2CMODE_ENABLE,i2c_init->address_model,i2c_init->slaver_address);//I2C基地址、I2C模式、7位地址模式、I2C从机地址
/*enable I2C0*/
i2c_enable(i2c_init->Memory_address);//I2C外设使能
/*enable acknowledge*/
i2c_ack_config(i2c_init->Memory_address,I2C_ACK_ENABLE);//选择是否发送应答信号
}
/*!
\brief I2C GPIO Clock enable
\param[in] I2Cx_PinSDA_Enum SDA pin
I2Cx_PinSCL_Enum SCL pin
\param[out] none
\retval none
*/
void I2Cx_Pin_ClockEnable(I2Cx_PinSDA_Enum gpio_sdapin,I2Cx_PinSCL_Enum gpio_sclpin)
{
uint32_t gpiox_sda,gpiox_scl;
gpiox_sda=(uint32_t)(gpio_sdapin & 0xffffff00);
gpiox_scl=(uint32_t)(gpio_sclpin & 0xffffff00);
/*SDA enable*/
if(gpiox_sda==GPIOB){
rcu_periph_clock_enable(RCU_GPIOB);
}else if(gpiox_sda==GPIOA){
rcu_periph_clock_enable(RCU_GPIOC);
}else if(gpiox_sda==GPIOF){
rcu_periph_clock_enable(RCU_GPIOF);
}
/*SCL enable*/
if(gpiox_scl==GPIOB){
rcu_periph_clock_enable(RCU_GPIOB);
}else if(gpiox_scl==GPIOA){
rcu_periph_clock_enable(RCU_GPIOA);
}
}
/*!
\brief Slaver receive data
\param[in] uint8_t* SendBuffer //receive buffer
uint8_t DataNum //receive data num
Param_Typedef *i2c_init //define I2CX init param
\param[out] none
\retval none
*/
void Slaver_ReceiveData_address(uint8_t* ReceiveBuffer,uint8_t DataNum,Param_Typedef *i2c_init)
{
/*waiting I2C_FLAG_ADDSEND is set 1*/
while(!i2c_flag_get(i2c_init->Memory_address,I2C_FLAG_ADDSEND));
/*read I2C_STAT0 and then read I2C_STAT1 to clear ADDSEND*/
i2c_flag_clear(i2c_init->Memory_address,I2C_FLAG_ADDSEND);//清除ADDSEND位
while(DataNum){
/*I2C_DATA is not empty*/
while(!i2c_flag_get(i2c_init->Memory_address,I2C_FLAG_RBNE));
*ReceiveBuffer=i2c_data_receive(i2c_init->Memory_address);//read data from I2C_DATA
ReceiveBuffer+=1;
DataNum-=1;
}
while(!i2c_flag_get(i2c_init->Memory_address,I2C_FLAG_STPDET));
/*clear STPDET flag*/
I2C_STAT0(i2c_init->Memory_address);
I2C_CTL0(i2c_init->Memory_address)=0x0000;
//printf("slaver receive data success!!\n");
}
/*!
\brief I2C slaver send buffer 7 and 10 address
\param[in] uint8_t* SendBuffer //receive buffer
uint8_t DataNum //receive data num
Param_Typedef *i2c_init //define I2CX init param
\param[out] none
\retval none
*/
void Slaver_SendData_address(uint8_t* SendBuffer,uint8_t DataNum,Param_Typedef *i2c_init)
{
uint8_t num;
/*waiting I2C_FLAG_ADDSEND is set 1*/
while(!i2c_flag_get(i2c_init->Memory_address,I2C_FLAG_ADDSEND));
/*read I2C_STAT0 and then read I2C_STAT1 to clear ADDSEND*/
i2c_flag_clear(i2c_init->Memory_address,I2C_FLAG_ADDSEND);//清除ADDSEND位
if(i2c_init->address_model==I2Cx_Address_10bit){
/*wait until ADDSEND bit is set*/
while(!i2c_flag_get(i2c_init->Memory_address,I2C_FLAG_ADDSEND));
/*read I2C_STAT0 and then read I2C_STAT1 to clear ADDSEND*/
i2c_flag_clear(i2c_init->Memory_address,I2C_FLAG_ADDSEND);//清除ADDSEND位
}
/*wait until the transmit data buffer is empty*/
while(SET != i2c_flag_get(i2c_init->Memory_address,I2C_FLAG_TBE));
//send one byte to I2C BUS
i2c_data_transmit(i2c_init->Memory_address,*SendBuffer);
SendBuffer+=1;
while(!i2c_flag_get(i2c_init->Memory_address,I2C_FLAG_BTC));
//send two byte to I2C BUS
i2c_data_transmit(i2c_init->Memory_address,*SendBuffer);
SendBuffer+=1;
for(num=0;num<(DataNum-2);num++){
/*I2C_DATA is not empty*/
while(!i2c_flag_get(i2c_init->Memory_address,I2C_FLAG_BTC));
i2c_data_transmit(i2c_init->Memory_address,*SendBuffer);
SendBuffer+=1;
}
/*wait until the transmit data buffer is empty*/
while(SET != i2c_flag_get(i2c_init->Memory_address,I2C_FLAG_AERR));
//clear I2C AERR flag
i2c_flag_clear(i2c_init->Memory_address,I2C_FLAG_AERR);
}
/* retarget the C library printf function to the USART */
int fputc(int ch, FILE *f)
{
usart_data_transmit(EVAL_COM, (uint8_t)ch);
while(RESET == usart_flag_get(EVAL_COM, USART_FLAG_TBE));
return ch;
}
/*!
\brief this function handles SysTick exception
\param[in] none
\param[out] none
\retval none
*/
void SysTick_Handler(void)
{
delay_decrement();
}
以上从机接收和发送代码和主机一一对应,两者可作为测试使用。I2C从机支持双地址、10bit地址和广播地址模式(0x00)。双地址模式:I2C从机设备可对两个地址响应。广播地址模式:所有I2C从机设备默认的响应地址。
//双地址模式
i2c_dualaddr_enable(I2C0,0x44);
//广播地址
i2c_slave_response_to_gcall_config(I2C0, I2C_GCEN_ENABLE);
1.5 主机中断接收发送程序
//主机中断发送
int main(void)
{
uint8_t num=0;
/*configure EVAL_COM1*/
gd_eval_com_init(EVAL_COM);
systick_config();
for(num=0;num<BufferNum;num++){
write_buffer[num]=num;
}
printf("I2C master send by interrupt measuring!!!");
Param_Init(&I2Cx_Param,Para_Aarry,I2C_Measuring);
I2Cx_Init(&I2Cx_Param);
nvic_irq_enable(I2Cx_EV_IRQn,0,0);/*!< I2C0 event interrupt priority and enable*/
nvic_irq_enable(I2Cx_ER_IRQn,0,1);/*!< I2C0 erro interrupt priority and enable*/
i2c_interrupt_enable(I2C_x,I2C_INT_ERR);//error interrupt enable
i2c_interrupt_enable(I2C_x,I2C_INT_EV);//event interrupt enable
i2c_interrupt_enable(I2C_x,I2C_INT_BUF);//buffer interrupt enable
delay_1ms(3000);
/*wait until I2C bus is idle*/
while(i2c_flag_get(I2C_x,I2C_FLAG_I2CBSY));
/*send a start condition to I2C bus*/
i2c_start_on_bus(I2C_x);//在I2C总线上产生一个开始信号
while(!Send_InterruptFlag);
/*wait until the stop condition is finished*/
while(I2C_CTL0(I2C_x)&0x0200);//等待结束信号发送
printf("I2C0 master interrupt send success!!");
while(1){
}
}
/*!
\brief this function handles I2C0 Event
\param[in] none
\param[out] none
\retval none
*/
void I2C0_EV_IRQHandler(void)
{
if(i2c_flag_get(I2C_x,I2C_FLAG_SBSEND)){
I2C_STAT0(I2C_x);
/*send slave address to I2C bus */
i2c_master_addressing(I2C_x,0x42,I2C_TRANSMITTER);//发送从机地址+写、清除SBSEND位、I2C设备发送方
}else if(i2c_flag_get(I2C_x,I2C_FLAG_ADDSEND)){
i2c_flag_clear(I2C_x,I2C_FLAG_ADDSEND);//清除ADDSEND位
}else if(i2c_flag_get(I2C_x,I2C_FLAG_TBE)){
if(Data<20){
i2c_data_transmit(I2C_x,write_buffer[Data]);
Data+=1;
}else{
i2c_stop_on_bus(I2C_x);//在总线上发送停止信号位
Send_InterruptFlag=1;
i2c_interrupt_disable(I2C_x,I2C_INT_ERR);//error interrupt enable
i2c_interrupt_disable(I2C_x,I2C_INT_EV);//event interrupt enable
i2c_interrupt_disable(I2C_x,I2C_INT_BUF);//buffer interrupt enable
}
}
}
/*!
\brief this function handles I2C0 Error
\param[in] none
\param[out] none
\retval none
*/
void I2C0_ER_IRQHandler(void)
{
//SMBus Alert status
if(i2c_flag_get(I2C_x,I2C_FLAG_SMBALT)){
i2c_flag_clear(I2C_x,I2C_FLAG_SMBALT);
}
//timeout signal in SMBus mode
if(i2c_flag_get(I2C_x,I2C_FLAG_SMBTO)){
i2c_flag_clear(I2C_x,I2C_FLAG_SMBTO);
}
//PEC error when receiving data
if(i2c_flag_get(I2C_x,I2C_FLAG_PECERR)){
i2c_flag_clear(I2C_x,I2C_FLAG_PECERR);
}
//over-run or under-run situation occurs in slave mode
if(i2c_flag_get(I2C_x,I2C_FLAG_OUERR)){
i2c_flag_clear(I2C_x,I2C_FLAG_OUERR);
}
//acknowledge error
if(i2c_flag_get(I2C_x,I2C_FLAG_AERR)){
i2c_flag_clear(I2C_x,I2C_FLAG_AERR);
}
//arbitration lost in master mode
if(i2c_flag_get(I2C_x,I2C_FLAG_LOSTARB)){
i2c_flag_clear(I2C_x,I2C_FLAG_LOSTARB);
}
//a bus error
if(i2c_flag_get(I2C_x,I2C_FLAG_BERR)){
i2c_flag_clear(I2C_x,I2C_FLAG_BERR);
}
}
//主机接收中断
/*!
\brief this function handles I2C0 Event
\param[in] none
\param[out] none
\retval none
*/
void I2C0_EV_IRQHandler(void)
{
if(i2c_flag_get(I2C_x,I2C_FLAG_SBSEND)){
I2C_STAT0(I2C_x);
/*send slave address to I2C bus */
i2c_master_addressing(I2C_x,0x42,I2C_RECEIVER);//发送从机地址+写、清除SBSEND位、I2C设备发送方
}
if(i2c_flag_get(I2C_x,I2C_FLAG_ADDSEND)){
i2c_flag_clear(I2C_x,I2C_FLAG_ADDSEND);//清除ADDSEND位
}
if(i2c_flag_get(I2C_x,I2C_FLAG_RBNE)){
if(Data==18){
receive_buffer[Data]=i2c_data_receive(I2C_x);
Data+=1;
/*disable acknowledge*/
i2c_ack_config(I2C_x,I2C_ACK_DISABLE);//选择是否发送应答信号
i2c_stop_on_bus(I2C_x);//在总线上发送停止信号位
}else if(Data<18){
receive_buffer[Data]=i2c_data_receive(I2C_x);
Data+=1;
}else if(Data==19)
{
receive_buffer[Data]=i2c_data_receive(I2C_x);
Receive_InterruptFlag=1;
i2c_interrupt_disable(I2C_x,I2C_INT_ERR);//error interrupt enable
i2c_interrupt_disable(I2C_x,I2C_INT_EV);//event interrupt enable
i2c_interrupt_disable(I2C_x,I2C_INT_BUF);//buffer interrupt enable
}
}
}
/*!
\brief this function handles I2C0 Error
\param[in] none
\param[out] none
\retval none
*/
void I2C0_ER_IRQHandle(void)
{
//SMBus Alert status
if(i2c_flag_get(I2C_x,I2C_FLAG_SMBALT)){
i2c_flag_clear(I2C_x,I2C_FLAG_SMBALT);
}
//timeout signal in SMBus mode
if(i2c_flag_get(I2C_x,I2C_FLAG_SMBTO)){
i2c_flag_clear(I2C_x,I2C_FLAG_SMBTO);
}
//PEC error when receiving data
if(i2c_flag_get(I2C_x,I2C_FLAG_PECERR)){
i2c_flag_clear(I2C_x,I2C_FLAG_PECERR);
}
//over-run or under-run situation occurs in slave mode
if(i2c_flag_get(I2C_x,I2C_FLAG_OUERR)){
i2c_flag_clear(I2C_x,I2C_FLAG_OUERR);
}
//acknowledge error
if(i2c_flag_get(I2C_x,I2C_FLAG_AERR)){
i2c_flag_clear(I2C_x,I2C_FLAG_AERR);
}
//arbitration lost in master mode
if(i2c_flag_get(I2C_x,I2C_FLAG_LOSTARB)){
i2c_flag_clear(I2C_x,I2C_FLAG_LOSTARB);
}
//a bus error
if(i2c_flag_get(I2C_x,I2C_FLAG_BERR)){
i2c_flag_clear(I2C_x,I2C_FLAG_BERR);
}
}
如果项目程序有多个中断,尽可能将I2C主机接收的中断优先级设为最高,否则会存在主机多接收一个数据,原因:当主机接收一个数据时,RBNE置1,在未读取DATA寄存器中的数据时,被更高的优先级任务打断,I2C总线上又接收一个数据到移位寄存器,此时BTC标志位置1。当中断恢复时,主机读取DATA寄存器中的数据。因为此时BTC已经置1,BTC清除的条件是需先读state状态寄存器,再读DATA寄存器,此时读DATA寄存器,无法清除BTC,使移位寄存器中的数据无法移到数据寄存器,I2C总线SCL被拉低,已阻止接收下一个数据,此时I2C还认为接收两个数据,会再次进中断读取DATA寄存器,BTC清零,移位寄存器数据移到Data寄存器,再次读取下一个数据,会造成接收的数据中有两个前后重复的数据。
1.6 从机中断接收和发送
//从机中断接收
/*!
\brief this function handles I2C0 Event
\param[in] none
\param[out] none
\retval none
*/
void I2C0_EV_IRQHandler(void)
{
if(i2c_interrupt_flag_get(I2C_x,I2C_INT_FLAG_ADDSEND)){
/*read I2C_STAT0 and then read I2C_STAT1 to clear ADDSEND*/
i2c_flag_clear(I2C_x,I2C_FLAG_ADDSEND);//清除ADDSEND位
}else if(i2c_interrupt_flag_get(I2C_x,I2C_INT_FLAG_TBE)){
if(Data<20){
i2c_data_transmit(I2C_x,writer_buffer[Data]);
Data+=1;
}else{
Send_InterruptFlag=1;
i2c_interrupt_disable(I2C_x,I2C_INT_ERR);
i2c_interrupt_disable(I2C_x,I2C_INT_EV);
i2c_interrupt_disable(I2C_x,I2C_INT_BUF);
}
}
}
/*!
\brief this function handles I2C0 Error
\param[in] none
\param[out] none
\retval none
*/
void I2C0_ER_IRQHandle(void)
{
//SMBus Alert status
if(i2c_flag_get(I2C_x,I2C_FLAG_SMBALT)){
i2c_flag_clear(I2C_x,I2C_FLAG_SMBALT);
}
//timeout signal in SMBus mode
if(i2c_flag_get(I2C_x,I2C_FLAG_SMBTO)){
i2c_flag_clear(I2C_x,I2C_FLAG_SMBTO);
}
//PEC error when receiving data
if(i2c_flag_get(I2C_x,I2C_FLAG_PECERR)){
i2c_flag_clear(I2C_x,I2C_FLAG_PECERR);
}
//over-run or under-run situation occurs in slave mode
if(i2c_flag_get(I2C_x,I2C_FLAG_OUERR)){
i2c_flag_clear(I2C_x,I2C_FLAG_OUERR);
}
//acknowledge error
if(i2c_flag_get(I2C_x,I2C_FLAG_AERR)){
i2c_flag_clear(I2C_x,I2C_FLAG_AERR);
}
//arbitration lost in master mode
if(i2c_flag_get(I2C_x,I2C_FLAG_LOSTARB)){
i2c_flag_clear(I2C_x,I2C_FLAG_LOSTARB);
}
//a bus error
if(i2c_flag_get(I2C_x,I2C_FLAG_BERR)){
i2c_flag_clear(I2C_x,I2C_FLAG_BERR);
}
}
//从机中断发送
/*!
\brief this function handles I2C0 Event
\param[in] none
\param[out] none
\retval none
*/
void I2C0_EV_IRQHandler(void)
{
if(i2c_interrupt_flag_get(I2C_x,I2C_INT_FLAG_ADDSEND)){
/*read I2C_STAT0 and then read I2C_STAT1 to clear ADDSEND*/
i2c_flag_clear(I2C_x,I2C_FLAG_ADDSEND);//清除ADDSEND位
}else if(i2c_interrupt_flag_get(I2C_x,I2C_INT_FLAG_TBE)){
if(Data<20){
i2c_data_transmit(I2C_x,writer_buffer[Data]);
Data+=1;
}else{
Send_InterruptFlag=1;
i2c_interrupt_disable(I2C_x,I2C_INT_ERR);
i2c_interrupt_disable(I2C_x,I2C_INT_EV);
i2c_interrupt_disable(I2C_x,I2C_INT_BUF);
}
}
}
/*!
\brief this function handles I2C0 Error
\param[in] none
\param[out] none
\retval none
*/
void I2C0_ER_IRQHandle(void)
{
//SMBus Alert status
if(i2c_flag_get(I2C_x,I2C_FLAG_SMBALT)){
i2c_flag_clear(I2C_x,I2C_FLAG_SMBALT);
}
//timeout signal in SMBus mode
if(i2c_flag_get(I2C_x,I2C_FLAG_SMBTO)){
i2c_flag_clear(I2C_x,I2C_FLAG_SMBTO);
}
//PEC error when receiving data
if(i2c_flag_get(I2C_x,I2C_FLAG_PECERR)){
i2c_flag_clear(I2C_x,I2C_FLAG_PECERR);
}
//over-run or under-run situation occurs in slave mode
if(i2c_flag_get(I2C_x,I2C_FLAG_OUERR)){
i2c_flag_clear(I2C_x,I2C_FLAG_OUERR);
}
//acknowledge error
if(i2c_flag_get(I2C_x,I2C_FLAG_AERR)){
i2c_flag_clear(I2C_x,I2C_FLAG_AERR);
}
//arbitration lost in master mode
if(i2c_flag_get(I2C_x,I2C_FLAG_LOSTARB)){
i2c_flag_clear(I2C_x,I2C_FLAG_LOSTARB);
}
//a bus error
if(i2c_flag_get(I2C_x,I2C_FLAG_BERR)){
i2c_flag_clear(I2C_x,I2C_FLAG_BERR);
}
}
主机发送每一个byte数据时,从机都需发送ACK信号,而从机发送数据时,当主机接收到最后一个字节的数据时,给从机发NACK信号,从机接收到NACK信号后,就知道主机要结束通信了。从机SCL拉低功能作用是:从机在接收数据时,由于需要处理其他事情,比如打印一些调试信息,可能没有及时读取DATA寄存器中的数据,这时从机会拉低SCL时钟线已阻止主机发送下一个字节数据,也就是再告诉主机“我正在忙啦!您稍等片刻”,I2C中对这个拉低时间没有具体要求,但是在SMBUS中,对SCL拉低的时间规定为25ms,如果25ms从机还在拉低SCL硬件就会强制发送stop信号结束此次通信(也就是说主机的忍耐是有限度的哈!!)。
这篇就先写这么多,I2C硬件的其他主要特性及代码实现在后面介绍。