硬件I2C学习(二)

本篇主要讲基于GD32 mcu硬件I2C主从机DMA模式收发、PEC错误校验、多主机仲裁功能程序例程。

1.1 主机DMA接收和发送

#include "gd32f3x0.h"
#include <stdio.h>
#include "gd32f350r_eval.h"
#include "main.h"
#include "systick.h"
#define  I2C0_Measure
//#define  I2C1_Measure
#if  defined I2C0_Measure
#define I2C_x             I2C0
#define DMACH_Tx  DMA_CH1
#define DMACH_Rx  DMA_CH2
#define I2C_Measuring     I2C0_Seven_Address_standard
#elif defined I2C1_Measure
#define  I2C_x             I2C1
#define  DMACH_Tx  DMA_CH3
#define  DMACH_Rx  DMA_CH4
#define  I2C_Measuring     I2C1_Seven_Address_standard
#endif
//#define Master_DMA_send
#define Master_DMA_receive
#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;
uint8_t Data=0,Send_InterruptFlag=0;
void I2C_DMA_init(void);
/*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 Master_DMA_send
	 /*--------DMA send measuring-----------------*/
	 Param_Init(&I2Cx_Param,Para_Aarry,I2C_Measuring);
	 I2Cx_Init(&I2Cx_Param);
	 I2C_DMA_init();
	 delay_1ms(3000);
	 Master_DMA_SendData(write_buffer,BufferNum,&I2Cx_Param);
   printf("I2C_DMA send data sucess!\n");	
	 #elif defined Master_DMA_receive
   /*--------DMA receive measuring-----------------*/
   Param_Init(&I2Cx_Param,Para_Aarry,I2C_Measuring);
	 I2Cx_Init(&I2Cx_Param);
   I2C_DMA_init();
   delay_1ms(3000);
   Master_DMA_ReceiveData(receive_buffer,BufferNum,&I2Cx_Param);
   printf("I2C_DMA receive data sucess!\n");	
   #endif	 
   while(1){
      
   }
}

void I2C_DMA_init()
{
	  dma_parameter_struct dma_init_struct;
	  /* enable DMA clock */
    rcu_periph_clock_enable(RCU_DMA);
	  /*deinitialize DMA TX*/
    dma_deinit(DMACH_Tx);
    dma_struct_para_init(&dma_init_struct);
    dma_init_struct.direction = DMA_MEMORY_TO_PERIPHERAL;
    dma_init_struct.memory_addr = (uint32_t)write_buffer;
    dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
    dma_init_struct.memory_width = DMA_MEMORY_WIDTH_8BIT;
    dma_init_struct.number = 20;
    dma_init_struct.periph_addr =  (uint32_t)&I2C_DATA(I2C_x);
    dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
    dma_init_struct.periph_width = DMA_PERIPHERAL_WIDTH_8BIT;
    dma_init_struct.priority = DMA_PRIORITY_ULTRA_HIGH;
    dma_init(DMACH_Tx,&dma_init_struct);
    /*configure DMA mode*/
    dma_circulation_disable(DMACH_Tx);
    dma_memory_to_memory_disable(DMACH_Tx);
	  dma_channel_enable(DMACH_Tx);
	
	  /*deinitialize DMA RX*/
    dma_deinit(DMACH_Rx);
    dma_init_struct.direction = DMA_PERIPHERAL_TO_MEMORY;
    dma_init_struct.memory_addr = (uint32_t)receive_buffer;
    dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
    dma_init_struct.memory_width = DMA_MEMORY_WIDTH_8BIT;
    dma_init_struct.number = 20;
    dma_init_struct.periph_addr =  (uint32_t)&I2C_DATA(I2C_x);
    dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
    dma_init_struct.periph_width = DMA_PERIPHERAL_WIDTH_8BIT;
    dma_init_struct.priority = DMA_PRIORITY_ULTRA_HIGH;
    dma_init(DMACH_Rx,&dma_init_struct); 
    /*configure DMA mode*/		
    dma_circulation_disable(DMACH_Rx);
    dma_memory_to_memory_disable(DMACH_Rx);	
		dma_channel_enable(DMACH_Rx);
}

/*!
    \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      I2C DMA send data
    \param[in]  Param_Typedef *i2c_init //I2C Param
                SendBuffer              //send array
		            DataNum send            //data num
    \param[out] none
    \retval     none
*/
void Master_DMA_SendData(uint8_t* SendBuffer,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){
	  Send_7Prepare(i2c_init);
	}
	else if(i2c_init->address==Send_10Address){
	  Send_10Prepare(i2c_init);
	}
	/*wait until the transmit data buffer is empty*/
  while(SET != i2c_flag_get(i2c_init->Memory_address,I2C_FLAG_TBE));//等待TBE寄存器置1
	/*deinitialize DMA0 channe7*/
	i2c_dma_enable(i2c_init->Memory_address,I2C_DMA_ON);
	 while(!dma_flag_get(DMACH_Tx, DMA_FLAG_FTF));//等待dma数据传输完成
	/*wait until BTC bit is set*/
  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("I2C DMA send data success");
}

/*!
    \brief      I2C DMA receive data
    \param[in]  Param_Typedef *i2c_init // I2C Param
                SendBuffer              // send array
		        DataNum send            //data num
    \param[out] none
    \retval     none
*/
void Master_DMA_ReceiveData(uint8_t* ReceiveBuffer,uint8_t DataNum,Param_Typedef *i2c_init)
{
	uint32_t adrH_10,adrL_10;
	if(DataNum>=2){
		i2c_dma_last_transfer_config(i2c_init->Memory_address,I2C_DMALST_ON);
	}else if(DataNum==1){
		i2c_ack_config(i2c_init->Memory_address,I2C_ACK_DISABLE);
	}
	/*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){
	  /*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位
	}
	else if(i2c_init->address==Send_10Address){
	  adrH_10=(((i2c_init->address & 0x300)>>7)|0xf0);//10位地址头(高2位)	
	  adrL_10=i2c_init->address & 0xff;//10位地址(低8位)
		/*send slave address to I2C bus */
    i2c_master_addressing(i2c_init->Memory_address,(uint8_t)adrH_10, 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,adrL_10);
	  /*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)adrH_10,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位
	}
	i2c_dma_last_transfer_config(i2c_init->Memory_address,I2C_DMALST_ON);//next DMA EOT is the last transfer
	i2c_dma_enable(i2c_init->Memory_address,I2C_DMA_ON);
	   while(!dma_flag_get(DMACH_Rx,DMA_FLAG_FTF));//等待dma数据传输完成
	i2c_stop_on_bus(i2c_init->Memory_address);
	/*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
}
/*!
    \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 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_master_addressing(i2c_init->Memory_address,(uint8_t)adrL10, I2C_TRANSMITTER);
	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位
}
/* 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();
}

DMA传输可以提高cpu传输效率,由DMA负责存储器和外设之间数据的搬运,注意这里的存储器指的是mcu内部自带的sram,外设指I2C DATA寄存器。当I2C发送时dma传输方向sram-data(存储器到外设),接收时为data-sram(外设到存储器),dma只是一个搬运工,也可以理解为mcu的一个助手小弟,帮mcu处理一些数据搬运的杂活,所以dma也叫直接存储器访问控制器。
1.2 从机DMA收发

  /*!
    \brief      main function
    \param[in]  none
    \param[out] none
    \retval     none
*/
int main(void)
{
	 uint8_t num=0;
	 //systick_config();
	 for(num=0;num<BufferNum;num++){
		 write_buffer[num]=num;
	 }
	 #ifdef slaver_DMA_send
	 /*--------DMA send measuring-----------------*/
	 Param_Init(&I2Cx_Param,Para_Aarry,I2C_Measuring);
	 I2Cx_Init(&I2Cx_Param);
	 I2C_DMA_init();
	 Slaver_DMA_ReceiveData(receive_buffer,BufferNum,&I2Cx_Param);
	 #elif defined slaver_DMA_receive
   /*--------DMA receive measuring-----------------*/
   Param_Init(&I2Cx_Param,Para_Aarry,I2C_Measuring);
	 I2Cx_Init(&I2Cx_Param);
   I2C_DMA_init();
	 Slaver_DMA_SendData(write_buffer,BufferNum,&I2Cx_Param);
	 #endif
   while(1){
      
   }
}
/*!
    \brief      I2C DMA send data
    \param[in]  Param_Typedef *i2c_init //I2C Param
                SendBuffer              //send array
		            DataNum send            //data num
    \param[out] none
    \retval     none
*/
void Slave_DMA_SendData(uint8_t* SendBuffer,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位	
	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位	
	}
	//delay_1ms(1);
	/*wait until the transmit data buffer is empty*/
  while(SET != i2c_flag_get(i2c_init->Memory_address,I2C_FLAG_TBE));//等待TBE寄存器置1
	/*deinitialize DMA0 channe7*/
	i2c_dma_enable(i2c_init->Memory_address,I2C_DMA_ON);
	 while(!dma_flag_get(DMACH_Tx, DMA_FLAG_FTF));//等待dma数据传输完成
  /*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);
	//printf("I2C DMA send data success");
}

/*!
    \brief      I2C DMA receive data
    \param[in]  Param_Typedef *i2c_init // I2C Param
                SendBuffer              // send array
		            DataNum send            //data num
    \param[out] none
    \retval     none
*/
void Slave_DMA_ReceiveData(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位	
	i2c_dma_enable(i2c_init->Memory_address,I2C_DMA_ON);
	 while(!dma_flag_get(DMACH_Rx, DMA_FLAG_FTF));//等待dma数据传输完成
	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;
}

主机dma使能位的打开在接收到从机的地址响应ack信号并清除ADDSEND标志位后,从机dma使能开关打开在接收到总线上主机发送的地址与自身地址匹配时,并清除ADDSEND标志位之后。
1.3 主从机数据发送PEC错误校验
当对数据传输的准确率要求比较高时,就需要用到CRC错误校验。pec发送:主从每发送一个byte数据时,其CRC寄存器便计算一次CRC校验值,当最后一个数据发送完时,硬件自动发送计算的CRC值。pec接收方:每接收一个字节,也计算一次CRC值,当接收到发送方发送的CRC值与自身计算的值相等时,则接收数据正确,反之则会产生PEC校验错误。如果我们需要测试硬件I2C PEC校验错误情况,可以使发送方关闭crc校验,接收方打开crc校验,在发送方发完最后一个字节数据时,随便再发送一个数据,接收方则会把最后一个字节数据作为crc计算值与自身计算的crc值比较,然后查看对应的pec错误校验位是否置位。

 //pec错误校验使能
  i2c_pec_enable(I2C_x,I2C_PEC_ENABLE);
//发送pec校验值
  i2c_pec_transfer_enable(I2C_x,I2C_PECTRANS_ENABLE);

1.4 I2C多主仲裁
我们都知道I2C总线可以同时挂载多个从设备(一主多从),那在某一时刻总线上同时有两个主机对同一个从机地址发起访问时,那如何规定哪一个主机赢得竞争权呢?I2C总线空闲时默认电平为高电平,同时SDA数据线和SCL时钟线都具有线与关系,则低电平优先原则。两个主机同时发送START信号、从机地址后,到发送数据阶段如果两者总线上发送的都为高电平,则继续传送数据,如果一个为高,一个为低,则发送低电平的I2C主机赢得总线竞争权,仲裁失败的主机则恢复从机模式。I2C模块每发送一个bit位时,都会判断总线上的电平与自己实际发送的是否一致,若不一致,则产生仲裁错误。
使用硬件I2C多主仲裁功能时,应注意在PCB板上两个主机对从设备的SCL线和SDA线要尽可能的等长,保证信号同时到达。

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
MSP432是德州仪器(Texas Instruments)推出的一款低功耗微控制器系列。在MSP432中,I2C是一种常用的通信协议,用于连接微控制器与其他外设。根据引用\[2\]和引用\[3\]中的代码片段,可以看出在MSP432上配置和初始化I2C1的步骤。首先,需要配置系统时钟为120 MHz,并使能GPIO Port G作为I2C的引脚。然后,使能I2C1模块,并使用系统时钟初始化I2C1为主设备。在I2C通信中,可以使用OLED_WR_Byte函数来写入数据或命令到I2C设备。该函数通过I2C总线将数据或命令发送给从设备。具体的I2C通信协议和数据传输细节可以参考引用\[2\]中的代码。 #### 引用[.reference_title] - *1* [MSP432P401R TI Drivers 库函数学习笔记(七)I2C驱动OLED屏幕](https://blog.csdn.net/weixin_44457994/article/details/119374411)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* *3* [MSP432E401YT硬件IIC驱动0.96OLED](https://blog.csdn.net/qq_26083903/article/details/130904595)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值