天天看點

09----GD32E103RBT6----I2C測試代碼[測試不通過]

bsp_i2c.h

#ifndef __BSP_I2C_H
#define __BSP_I2C_H

#include "gd32e10x.h"

//SCL
#define    EEPROM_I2C_SCL_GPIO_CLK   RCU_GPIOB
#define    EEPROM_I2C_SCL_PORT       GPIOB   
#define    EEPROM_I2C_SCL_PIN        GPIO_PIN_10

//SDA
#define    EEPROM_I2C_SDA_GPIO_CLK   RCU_GPIOB
#define    EEPROM_I2C_SDA_PORT       GPIOB   
#define    EEPROM_I2C_SDA_PIN        GPIO_PIN_11

//控制闆子上另一個紅燈亮滅
#define LED_RED_ANOTHER_ON     PCout(13)=0
#define LED_RED_ANOTHER_OFF    PCout(13)=1


//I2C  
#define    EEPROM_I2Cx    I2C1
#define    EEPROM_I2C_CLK    RCU_I2C1
#define    EEPROM_I2Cx_SPPED   100000
/* 下面兩個位址都是取高7位作為7位的位址*/
/* 這個位址隻要與STM32外挂的I2C器件位址不一樣即可 */
#define    I2Cx_OWN_ADDRESS7      0X0A
#define    EEPROM_ADDRESS    0xA0

#define    EEPROM_I2Cx_FLAG_TIMEOUT    ((uint32_t)0xFFFFFFFF)


void SCL_GPIO_Config(void);
void SDA_GPIO_Config(void);
void LED_RED_ANOTHER_GPIO_Config(void);
void TP1_GPIO_Config(void);
void EEPROM_I2C_Config(void);
uint8_t I2C_EE_ByteWrite(uint8_t* sBuffer, uint8_t WriteAddr);
void Wait_EEPROMStandbyState(void);
uint8_t Wait_I2CBus_IdleState(uint32_t wait_delay);
uint8_t I2C_EE_Random_Read(uint8_t* pBuffer, uint8_t ReadAddr, uint8_t NumByteToRead);

#endif
           

bsp_i2c.c

#include "bsp_i2c.h"
#include "bsp_gpio.h"

void SCL_GPIO_Config(void)
{
	rcu_periph_clock_enable(EEPROM_I2C_SCL_GPIO_CLK);
	gpio_init(EEPROM_I2C_SCL_PORT, GPIO_MODE_AF_OD, GPIO_OSPEED_50MHZ, EEPROM_I2C_SCL_PIN);
}




void SDA_GPIO_Config(void)
{
	rcu_periph_clock_enable(EEPROM_I2C_SDA_GPIO_CLK);
	gpio_init(EEPROM_I2C_SDA_PORT, GPIO_MODE_AF_OD, GPIO_OSPEED_50MHZ, EEPROM_I2C_SDA_PIN);
}


void LED_RED_ANOTHER_GPIO_Config(void)
{
	rcu_periph_clock_enable(RCU_GPIOC);
	gpio_init(GPIOC, GPIO_MODE_OUT_OD, GPIO_OSPEED_50MHZ, GPIO_PIN_13);
}

void TP1_GPIO_Config(void)
{
	rcu_periph_clock_enable(RCU_GPIOC);
	gpio_init(GPIOC, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_14);
}



/*!
    \brief      I2C1工作參數配置
    \param[in]  none
    \param[out] none
    \retval     none
*/
void EEPROM_I2C_Config(void)
{

	
	rcu_periph_clock_enable(EEPROM_I2C_CLK);
//	rcu_periph_clock_enable(RCU_AF);
	
	/* 模式選I2C 模式,位址選擇7位位址,最後設定從機位址 */ 
  i2c_mode_addr_config(EEPROM_I2Cx, I2C_I2CMODE_ENABLE, I2C_ADDFORMAT_7BITS, EEPROM_ADDRESS); 
	/* I2C時鐘速率設為400KHz,占空比選擇 T_low/T_high=2 */ 
	i2c_clock_config(EEPROM_I2Cx, EEPROM_I2Cx_SPPED, I2C_DTCY_2); 
	i2c_ack_config(EEPROM_I2Cx, I2C_ACK_ENABLE); 
//	i2c_ackpos_config(EEPROM_I2Cx,I2C_ACKPOS_CURRENT);
	
	/* 使能EEPROM_I2Cx*/ 
  i2c_enable(EEPROM_I2Cx); 
}


/*!
    \brief      用I2C外設對EEPROM某個位址寫入一個位元組的資料,詳細過程嚴格按照《使用者手冊》
                第416頁介紹的主機發送模式下的軟體流程
    \param[in]  sBuffer:緩沖區指針
    \param[in]  WriteAddr:被寫入的位址
    \param[out] none
    \retval     傳回的數字表示錯誤發生的地方
*/
uint8_t I2C_EE_ByteWrite(uint8_t* sBuffer, uint8_t WriteAddr)
{
	uint32_t I2C_Timeout; 
	
	
	
	//發送起始位
	i2c_start_on_bus(EEPROM_I2Cx);
	I2C_Timeout = EEPROM_I2Cx_FLAG_TIMEOUT; 
	while(i2c_flag_get(EEPROM_I2Cx,I2C_FLAG_SBSEND)==0)
	{
		if((I2C_Timeout--) == 0)
			return 1;
	}
//	//《使用者手冊》第416頁第3條說了隻要往I2C_DATA寄存器寫入位址就能硬體清除ADDSEND位
//	i2c_flag_clear(EEPROM_I2Cx,I2C_FLAG_SBSEND );
	
	
	
	
	//發送EEPROM位址
	i2c_master_addressing(EEPROM_I2Cx,EEPROM_ADDRESS,I2C_TRANSMITTER);
	I2C_Timeout = EEPROM_I2Cx_FLAG_TIMEOUT; 
	//《使用者手冊》第416頁第4條說了通過讀I2C_STAT0寄存器然後讀I2C_STAT1寄存器
	// 就能硬體清除ADDSEND位,但是我親自實驗後發現,就算讀取了這兩個寄存器的值也不能
	// 清除ADDSEND位,是以我放棄讀取I2C_STAT0、I2C_STAT1這兩個寄存器,隻讀取I2C_STAT0
	// 這一個寄存器
//	while((i2c_flag_get(EEPROM_I2Cx,I2C_FLAG_ADDSEND)==0)&&(i2c_flag_get(EEPROM_I2Cx,I2C_FLAG_TRS)==0))
	while(i2c_flag_get(EEPROM_I2Cx,I2C_FLAG_ADDSEND)==0)
	{
		if((I2C_Timeout--) == 0)
			return 2;
	}
	//用軟體清除ADDSEND位
	i2c_flag_clear(EEPROM_I2Cx,I2C_FLAG_ADDSEND );
	
	
	

	//發送EEPROM内部的位址
	i2c_data_transmit(EEPROM_I2Cx,WriteAddr);
	I2C_Timeout = EEPROM_I2Cx_FLAG_TIMEOUT; 
	while(i2c_flag_get(EEPROM_I2Cx,I2C_FLAG_TBE)==0)
	{
		if((I2C_Timeout--) == 0)
			return 3;
	}
//	//《使用者手冊》第416頁第6條說了當寫第二個位元組到I2C_DATA,此時TBE會被硬體清零
//	i2c_flag_clear(EEPROM_I2Cx,I2C_FLAG_TBE );
	
	
	
	
	//發送一個位元組的資料,發送結束後不需要對标志位清0,因為在發出停止位硬體會對這位進行清0
	i2c_data_transmit(EEPROM_I2Cx,*sBuffer);
	I2C_Timeout = EEPROM_I2Cx_FLAG_TIMEOUT; 
	while(i2c_flag_get(EEPROM_I2Cx,I2C_FLAG_TBE)==0)
	{
		if((I2C_Timeout--) == 0)
			return 4;
	}
//	//《使用者手冊》第416頁第6條說了當寫第二個位元組到I2C_DATA,此時TBE會被硬體清零
//	i2c_flag_clear(EEPROM_I2Cx,I2C_FLAG_TBE );
	
	
	i2c_stop_on_bus(EEPROM_I2Cx);
	
	
	return 0;
}



/*!
    \brief      等待EEPROM内部資料擦寫完畢,如果擦寫完畢,就能産生ACK
    \param[in]  none
    \param[out] none
    \retval     none
*/
void Wait_EEPROMStandbyState(void)
{
	//ADDSEND是I2C_STAT0寄存器的值,但是變量名中不能帶數字,
	//是以沒有用I2C0_STAT_ADDSEND作為變量名
	uint8_t I2C_STAT_ADDSEND = 0;
 
  do
  {
    /* Send START condition */
    i2c_start_on_bus(EEPROM_I2Cx);
    /* 讀I2C1 SR1寄存器的ADDR位 */
    I2C_STAT_ADDSEND = i2c_flag_get(EEPROM_I2Cx,I2C_FLAG_ADDSEND);
    /* Send EEPROM address for write */
    i2c_master_addressing(EEPROM_I2Cx,EEPROM_ADDRESS,I2C_TRANSMITTER);
  }while(!I2C_STAT_ADDSEND);
	
  /* Clear  AERR flag */
  i2c_flag_clear(EEPROM_I2Cx,I2C_FLAG_AERR );
  /* STOP condition */    
  i2c_stop_on_bus(EEPROM_I2Cx);

}


/*!
    \brief      等待到總線沒有I2C通訊
    \param[in]  wait_delay:超過這個延時時間就報警
    \param[out] none
    \retval     錯誤碼
*/
uint8_t Wait_I2CBus_IdleState(uint32_t wait_delay)
{
	uint32_t Wait_Time=wait_delay;	
  while(i2c_flag_get(EEPROM_I2Cx,I2C_FLAG_I2CBSY))
  {
    if((Wait_Time--) == 0) return 1;
   }
  return 0;

}



/*!
    \brief      利用《使用者手冊》中第417頁介紹的A方案來接收資料
    \param[in]  NumByteToRead:被讀取的資料個數
    \param[in]  WriteAddr:EEPROM的讀取位址
    \param[out] pBuffer:緩沖區指針
    \retval     傳回的數字表示錯誤發生的地方
*/
uint8_t I2C_EE_Random_Read(uint8_t* pBuffer, uint8_t ReadAddr, uint8_t NumByteToRead)
{
	uint32_t I2C_Timeout; 
	
	//發送起始位
	i2c_start_on_bus(EEPROM_I2Cx);
	I2C_Timeout = EEPROM_I2Cx_FLAG_TIMEOUT; 
	while(i2c_flag_get(EEPROM_I2Cx,I2C_FLAG_SBSEND)==0)
	{
		if((I2C_Timeout--) == 0)
			return 1;
	}
//	//《使用者手冊》第417頁第3條說了隻要往I2C_DATA寄存器寫入位址就能硬體清除SBSEND位
//	i2c_flag_clear(EEPROM_I2Cx,I2C_FLAG_SBSEND );
	
	
	
	
	
	//發送EEPROM位址,第一次方向是發送資料
	i2c_master_addressing(EEPROM_I2Cx,EEPROM_ADDRESS,I2C_TRANSMITTER);
	I2C_Timeout = EEPROM_I2Cx_FLAG_TIMEOUT; 
	while(i2c_flag_get(EEPROM_I2Cx,I2C_FLAG_ADDSEND)==0)
	{
		if((I2C_Timeout--) == 0)
			return 2;
	}
	//《使用者手冊》第418頁第4條說了可以硬體清除ADDSEND位
	i2c_flag_clear(EEPROM_I2Cx,I2C_FLAG_ADDSEND );
	
	
	
	
	
	
		//發送EEPROM内部的位址
	i2c_data_transmit(EEPROM_I2Cx,ReadAddr);
	I2C_Timeout = EEPROM_I2Cx_FLAG_TIMEOUT; 
	while(i2c_flag_get(EEPROM_I2Cx,I2C_FLAG_TBE)==0)
	{
		if((I2C_Timeout--) == 0)
			return 3;
	}
	//《使用者手冊》第416頁第6條說了當寫第二個位元組到I2C_DATA,此時TBE會被硬體清零
	// 但是下個操作沒有寫第二個位元組到I2C_DATA的程式,是以用軟體對這個标志位清0
	i2c_flag_clear(EEPROM_I2Cx,I2C_FLAG_TBE );
	
	
	

		//發送起始位
	i2c_start_on_bus(EEPROM_I2Cx);
	I2C_Timeout = EEPROM_I2Cx_FLAG_TIMEOUT; 
	while(i2c_flag_get(EEPROM_I2Cx,I2C_FLAG_SBSEND)==0)
	{
		if((I2C_Timeout--) == 0)
			return 4;
	}
//	//《使用者手冊》第417頁第3條說了隻要往I2C_DATA寄存器寫入位址就能硬體清除ADDSEND位
//	i2c_flag_clear(EEPROM_I2Cx,I2C_FLAG_SBSEND );
	
	
	
	
	
		//發送EEPROM位址,第二次方向是接收資料
	i2c_master_addressing(EEPROM_I2Cx,EEPROM_ADDRESS,I2C_RECEIVER);
	I2C_Timeout = EEPROM_I2Cx_FLAG_TIMEOUT; 
	while(i2c_flag_get(EEPROM_I2Cx,I2C_FLAG_ADDSEND)==0)
	{
		if((I2C_Timeout--) == 0)
			return 5;
	}
	i2c_flag_clear(EEPROM_I2Cx,I2C_FLAG_ADDSEND );
	
	
	
	/*讀取NumByteToRead個位元組的資料*/
  while(NumByteToRead)  
  { 
    I2C_Timeout = EEPROM_I2Cx_FLAG_TIMEOUT; 
    while(i2c_flag_get(EEPROM_I2Cx,I2C_FLAG_RBNE)==0)
	  {
			if((I2C_Timeout--) == 0) 
				return 6;
	  } 
	/* Read a byte from the EEPROM */
    *pBuffer = i2c_data_receive(EEPROM_I2Cx);
    pBuffer++; 
		NumByteToRead--;
  }
	
	
	return 0;
	

	
}


           

main.c

uint8_t sBuffer[5]={0x4E,0x01,0x32,0x11,0x9A};
uint8_t dBuffer[5];
uint32_t Write_Error_Type=0;
uint32_t Read_Error_Type=0;
//需要讀多少位元組的資料
uint8_t NumByteToRead=1;
uint8_t i=0;
//存儲晶片儲存資料的首位址
uint8_t Data_Write_BaseAddress=0;
//需要存多少位元組的資料
uint8_t NumByteToWrite=2;



void test_i2c(void)
{
	LED_RED_GPIO_Config();
	LED_RED_OFF;
	LED_GREEN_GPIO_Config();
	LED_GREEN_OFF;
	LED_RED_ANOTHER_GPIO_Config();
	LED_RED_ANOTHER_OFF;
	/*如果不注釋掉這兩句,那麼執行下面代碼時會一直卡在Wait_EEPROMStandbyState()處,
	這是GD32E103RBT6的BUG*/
//	TP1_GPIO_Config();
//	PCout(14)=0;
	SCL_GPIO_Config();
	SDA_GPIO_Config();
	EEPROM_I2C_Config();
	
	/****************************寫入資料***************************/
	for(i=0;i<NumByteToWrite;i++)
	{
//		PCout(14)^=1;		
		//先寫入一個位元組的資料,寫入失敗的話讓紅燈亮
	  Write_Error_Type=I2C_EE_ByteWrite(sBuffer+i,Data_Write_BaseAddress+i);
	  if(Write_Error_Type!=0)
	  {
		LED_RED_ANOTHER_ON;
		while(1);
	  }

	  //等待總線通訊結束
	  Wait_EEPROMStandbyState();

	  if(Wait_I2CBus_IdleState(0xFFFFFFFF)!=0)
	  {
		  LED_RED_ANOTHER_ON;
		  while(1);
	  }
	}
  

	
	
//	/****************************讀取資料***************************************/
//	//讀取一個位元組的資料,讀取錯誤讓紅燈亮
//	Read_Error_Type=I2C_EE_Random_Read(dBuffer,Data_Write_BaseAddress,NumByteToRead);
//	if(Read_Error_Type!=0)
//	{
//		LED_RED_ON;
//		while(1);
//	}
//	
//	
//	//	  //等待總線通訊結束
//	  Wait_EEPROMStandbyState();
//	  if(Wait_I2CBus_IdleState(0xFFFFFF)!=0)
//	  {
//		  LED_RED_ANOTHER_ON;
//		  while(1);
//	  }
//	
//	
//	
//		//讀取一個位元組的資料,讀取錯誤讓紅燈亮
//	Read_Error_Type=I2C_EE_Random_Read(dBuffer+1,Data_Write_BaseAddress+1,NumByteToRead);
//	if(Read_Error_Type!=0)
//	{
//		LED_RED_ON;
//		while(1);
//	}
	
	//綠燈亮代表代碼執行到這一步
	LED_GREEN_ON;
	
	
	while(1);


}