EFM32 硬件I2C通讯案例

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/qq_36075612/article/details/88658605

最近项目上用到了EFM32HG222F64G芯片中的硬件通讯,i2c通讯不稳定问题,导致花了很长时间去解决,走了不少弯路,最终还是解决了。在此写一下,做个记录,也方便给后面做产品的攻城狮,少走一些弯路吧!好了 ^_^! 进入正题。

来个直接点,直接上代码:

需要创建两个文件,I2C.c与I2C.h

I2C.h

#ifndef I2C_H
#define	I2C_H

#include "em_i2c.h"


void initI2c(void);
I2C_TransferReturn_TypeDef i2c_writeData(uint8_t wrStAddr, uint8_t* txData, uint8_t writeLen);
I2C_TransferReturn_TypeDef i2c_readData(uint8_t srAddr, uint8_t *rxData, uint8_t readLen);


#endif

I2C.c

#include "em_i2c.h"
#include "em_emu.h"
#include "i2c.h"
#include "em_cmu.h"
#include "lee_log.h"

#define I2C_ADDRESS                     0xD0
#define TIME_OUTT 100


I2C_TransferReturn_TypeDef I2C_Status;
/*----------------------------------------------------------------------------*/
//@Breif Description:Initialize the i2c module
/*----------------------------------------------------------------------------*/
void initI2c(void)
{
	I2C_Init_TypeDef init_I2C = 
	{
		.enable = true,
		.clhr = i2cClockHLRStandard,
		.freq = I2C_FREQ_STANDARD_MAX,
		.master = true,
		.refFreq = 0
	};
	
	/* Enabling clock to the I2C, GPIO*/
	CMU_ClockEnable(cmuClock_HFPER, true);
	CMU_ClockEnable(cmuClock_I2C0, true);
	CMU_ClockEnable(cmuClock_GPIO, true);
	
	/* Starting LFXO and waiting until it is stable */
	CMU_OscillatorEnable(cmuOsc_LFRCO, true, true);
	/* Routing the LFXO clock to the RTC */
	CMU_ClockSelectSet(cmuClock_LFA, cmuSelect_LFRCO);
	
	//GPIO_DriveModeSet(gpioPortA, gpioDriveModeHigh);
	
	/* Using PA0 (SDA) and PA1 (SCL) */
	GPIO_PinModeSet(gpioPortA, 1, gpioModeWiredAndPullUpFilter, 1);
	GPIO_PinModeSet(gpioPortA, 0, gpioModeWiredAndPullUpFilter, 1);
	/* Configure interrupt pin*/
	GPIO_PinModeSet(gpioPortC, 4, gpioModeInput, 0);

	
	//I2C0->ROUTE |= I2C_ROUTE_LOCATION_LOC2 + I2C_ROUTE_SCLPEN + I2C_ROUTE_SDAPEN;
	I2C0->ROUTE = I2C_ROUTE_SDAPEN
	| I2C_ROUTE_SCLPEN
	| (0 << _I2C_ROUTE_LOCATION_SHIFT);
	I2C_Init(I2C0, &init_I2C);
	I2C0->CTRL |= I2C_CTRL_AUTOSN;						    //一个字节的读取,这里需要更改
	//I2C0->CTRL |= I2C_CTRL_AUTOACK | I2C_CTRL_AUTOSN;		//两个字节的读取,这里需要更改
	//NVIC_EnableIRQ(I2C0_IRQn);
}
/*----------------------------------------------------------------------------*/
//@Breif Description:	write data to BMI160
/*----------------------------------------------------------------------------*/
I2C_TransferReturn_TypeDef i2c_writeData(uint8_t wrStAddr, uint8_t* txData, uint8_t writeLen)
{
	uint32_t loop = TIME_OUTT;
	I2C_TransferSeq_TypeDef tx_Init = 
	{
		.addr = I2C_ADDRESS,
		.buf[0].data = &wrStAddr,
		.buf[0].len = 1,
		.buf[1].data = txData,
		.buf[1].len = writeLen,
		.flags = I2C_FLAG_WRITE_WRITE,
	};
	
	I2C_Status = I2C_TransferInit(I2C0, &tx_Init);
	while ((I2C_Status == i2cTransferInProgress) && loop--)
	{
		I2C_Status = I2C_Transfer(I2C0);
		//EMU_EnterEM1();
	}	
	if (loop == TIME_OUTT) {
		LEE_LOG(LOG_INFO,"i2c_write loop fail.\n");
	}
	return(I2C_Status);
}

/*----------------------------------------------------------------------------*/
//@Breif Description:read data from BMI160
/*----------------------------------------------------------------------------*/
I2C_TransferReturn_TypeDef i2c_readData(uint8_t srAddr, uint8_t *rxData, uint8_t readLen)
{
	uint32_t loop = TIME_OUTT;
	I2C_TransferSeq_TypeDef rx_Init = 
	{
		.addr = I2C_ADDRESS,
		.buf[0].data = &srAddr,
		.buf[0].len = 1,
		.buf[1].data = rxData,
		.buf[1].len = readLen,
		.flags = I2C_FLAG_WRITE_READ,
	};
	/* Do a polled transfer */
	I2C_Status = I2C_TransferInit(I2C0, &rx_Init);
	while ((I2C_Status == i2cTransferInProgress) && (loop--))
	{
		/* Enter EM1 while waiting for I2C interrupt */
		I2C_Status = I2C_Transfer(I2C0);
		//EMU_EnterEM1();
		/* Could do a timeout function here. */
	}
	if (loop == TIME_OUTT) {
		LEE_LOG(LOG_INFO,"i2c_read loop fail.\n");
	}
	return(I2C_Status);
}

/*----------------------------------------------------------------------------*/
//@Breif Description:the interrupt service function
/*----------------------------------------------------------------------------*/
//void I2C0_IRQHandler(void)
//{
//	I2C_Status = I2C_Transfer(I2C0);
//}


在这说明一下,我出现过的问题,在I2C初始化的时候,按照实例代码配置

I2C0->CTRL |= I2C_CTRL_AUTOACK | I2C_CTRL_AUTOSN;       

我明明写的读取按照单字节来读取的,但是使用逻辑分析仪抓到的波形而双字节的波形(现在项目上是使用BMI160出现这种情况,不知道跟其他产品是否有类似的问题)

逻辑分析仪抓的波形如下:

write:

read:

使用下面的配置的话,是可以读取单字节的数据(项目上是使用BMI160与EFM32通讯)

I2C0->CTRL |= I2C_CTRL_AUTOSN;                            //一个字节的读取,这里需要更改

write:

read:

在main(),使用

int main(void)
{
   uint8_t data_wr[]={0};
   uint8_t reg_data = 0;
   
   initI2c();
   bmi160_init(0xd0);  

   while (1) {     
        data_wr[0] = 0x15;
        i2c_writeData(0x40,data_wr,1);
        LED_Delay_ms(1000);
        i2c_readData(0x40, &reg_data,1);       
        LEE_LOG(LOG_INFO," acc_data40 = %X \r\n", reg_data);
        LEE_LOG(LOG_INFO,"**************************** \r\n");
   }

只需要调用读、写方法即可

i2c_writeData(0x40,data_wr,1);

i2c_readData(0x40, &reg_data,1);       

以上的代码已经在项目上使用,测试过没什么问题。谢谢各位看官。

还有一个问题就是在初始化时。下面这两个要配合使用,不能单独配置一个,不然,不起作用。

.freq = I2C_FREQ_FASTPLUS_MAX;

CMU_ClockEnable(cmuClock_HFPER, true);

猜你喜欢

转载自blog.csdn.net/qq_36075612/article/details/88658605
今日推荐