IIC从机有响应,但是从机的寄存器内容读写有问题的可能原因

最近在调试一款,IIC芯片,用的是软件模拟的IIC,发现芯片的配置寄存器,写入的内容是有响应的,数据线(SDA)ack为零,一般这样是认为写入成功的。然后去读那个配置寄存器,发现这个寄存器返回的内容一直在变化,从机也一直是有响应的,ack也一直是零。因为这个软件IIC驱动很多其他IIC芯片是成功,所以怀疑到了芯片有问题… 但芯片有问题的概率还是比较小的,后面用硬件IIC成功访问到了这个芯片,配置寄存器的内容,返回也是正确的,不会变来变去。
我使用的模拟IIC是快速模式,硬件IIC的标准模式和快速模式都成功驱动了这个芯片,所以就是发现我使用的模拟IIC延时不匹配这个芯片。IIC标准模式和快速模式的时间需求如下。

在这里插入图片描述
后续是将快速模拟的IIC换成了标准速度的模拟IIC驱动成功了芯片,如果需要IIC来驱动显示屏这种,或者需要快速模式的IIC,建议还是用硬件IIC,软件IIC就用标准速度就好了。下面附上,标准速度的模拟IIC驱动。stm32的。延时是参考别的大佬写的,要修改成,自己时钟主频大小,单位M。

#define CPU_FREQUENCY_MHZ  40
/**
  * @brief delay_us
  * @param uint32_t nTime us
  * @retval None
  */
void delay_us(uint32_t nTime)
{
    int old_val,new_val,val;
 
    if(nTime > 900)
    {
        for(old_val = 0; old_val < nTime/900; old_val++)
        {
            delay_us(900);
        }
        nTime = nTime%900;
    }
 
    old_val = SysTick->VAL;
    new_val = old_val - CPU_FREQUENCY_MHZ*nTime;
    if(new_val >= 0)
    {
        do
        {
            val = SysTick->VAL;
        }
        while((val < old_val)&&(val >= new_val));
    }
    else
    {
        new_val +=CPU_FREQUENCY_MHZ*1000;
        do
        {
            val = SysTick->VAL;
        }
        while((val <= old_val)||(val > new_val));
    }
}

#include  "bsp_SimulateI2C.h"
/*
*********************************************************************************************************
* function    : bsp_SimuI2C_read_nBytes_ack api
* Description : read date
* Argument(s) : pSimuI2cPort: point to struct SimuI2cPortType, data: data to write
* Return(s)   : ack
*********************************************************************************************************
*/
uint32_t bsp_SimuI2C_read_nBytes_ack(
    struct SimuI2cPortType *pSimuI2cPort,
    uint8_t device_addr,
    uint8_t RegAddr, 
    uint8_t *pValue, 
    uint8_t Cnt)
{   
    uint32_t i, ack=0;
	
	//write dev addr
	bsp_SimuI2C_start(pSimuI2cPort);
	bsp_SimuI2C_write_byte(pSimuI2cPort, (device_addr&0xFE));//chip-addr
	ack = bsp_SimuI2C_ReadAck(pSimuI2cPort);//read ack
	//write reg addr
	bsp_SimuI2C_write_byte(pSimuI2cPort, RegAddr);//reg-addr
	ack += bsp_SimuI2C_ReadAck(pSimuI2cPort);//read ack
	//write dev addr
	bsp_SimuI2C_start(pSimuI2cPort);//restart
	bsp_SimuI2C_write_byte(pSimuI2cPort, (device_addr|0x01));//chip-addr
	ack += bsp_SimuI2C_ReadAck(pSimuI2cPort);//read ack
	//read N datas
	for(i=0; i<Cnt; i++){
		pValue[i] = bsp_SimuI2C_read_byte(pSimuI2cPort);//read data
		if((Cnt-1) == i){
			bsp_SimuI2C_SandNack(pSimuI2cPort);//send nack
		}else{
			bsp_SimuI2C_SandAck(pSimuI2cPort);//send ack
		}
	}
	bsp_SimuI2C_stop(pSimuI2cPort);
	
	return ack;
}

/*
*********************************************************************************************************
* function    : bsp_SimuI2C_write_nBytes_noAck api
* Description : write date
* Argument(s) : pSimuI2cPort: point to struct SimuI2cPortType, data: data to write
* Return(s)   : ack
*********************************************************************************************************
*/
uint32_t bsp_SimuI2C_write_nBytes_noAck(
    struct SimuI2cPortType *pSimuI2cPort,
    uint8_t device_addr,
    uint8_t RegAddr, 
    uint8_t *pValue, 
    uint8_t Cnt)
{
	uint32_t  ack=0;
	uint16_t i=0;
    
	bsp_SimuI2C_start(pSimuI2cPort);
	bsp_SimuI2C_write_byte(pSimuI2cPort, (device_addr&0xFE));//chip-addr
	ack = bsp_SimuI2C_ReadAck(pSimuI2cPort);//read ack
    
	bsp_SimuI2C_write_byte(pSimuI2cPort, RegAddr);//reg-addr
	ack += bsp_SimuI2C_ReadAck(pSimuI2cPort);//read ack
	//write N datas
	for(i=0; i<Cnt; i++){
		bsp_SimuI2C_write_byte(pSimuI2cPort, pValue[i]);//data
		ack += bsp_SimuI2C_ReadAck(pSimuI2cPort);//read ack
	}
	bsp_SimuI2C_stop(pSimuI2cPort);
	
	return ack;
} 

/*
*********************************************************************************************************
* function    : config_sda_in
* Description : config SDA GPIO for input
* Argument(s) : point to struct SimuI2cPortType
* Return(s)   : none
*********************************************************************************************************
*/

static void config_sda_in(struct SimuI2cPortType *pSimuI2cPort)
{
	uint32_t position = 0x00;
	while(((pSimuI2cPort->SDAPin) >> position) != 0){
		position++;
	}
	position--;
	pSimuI2cPort->SDAPort->MODER &= ~(3<<(position*2));
	pSimuI2cPort->SDAPort->MODER |= 0<<(position*2);
}

/*
*********************************************************************************************************
* function    : config_sda_out
* Description : config SDA GPIO for output
* Argument(s) : point to struct SimuI2cPortType
* Return(s)   : none
*********************************************************************************************************
*/
static void config_sda_out(struct SimuI2cPortType *pSimuI2cPort)
{
	uint32_t position = 0x00;
	while(((pSimuI2cPort->SDAPin) >> position) != 0){
		position++;
	}
	position--;
	pSimuI2cPort->SDAPort->MODER &= ~(3<<(position*2));
	pSimuI2cPort->SDAPort->MODER |= 1<<(position*2);
}

/*
*********************************************************************************************************
* function    : bsp_SimuI2C_start
* Description : generate a i2c start or restart
* Argument(s) : point to struct SimuI2cPortType
* Return(s)   : none
*********************************************************************************************************
*/
void bsp_SimuI2C_start(struct SimuI2cPortType *pSimuI2cPort)
{
	//config sda pin output
	config_sda_out(pSimuI2cPort);
	SIMUI2C_SDA_SET;
	SIMUI2C_SCL_SET;
	delay_us(5);//确保开始前高保持4.7us以上	
	SIMUI2C_SDA_CLR;
	delay_us(4);
	SIMUI2C_SCL_CLR;
	delay_us(4);
}

/*
*********************************************************************************************************
* function    : bsp_SimuI2C_stop
* Description : generate a i2c stop
* Argument(s) : point to struct SimuI2cPortType
* Return(s)   : none
*********************************************************************************************************
*/
void bsp_SimuI2C_stop(struct SimuI2cPortType *pSimuI2cPort)
{
	//config sda pin output
	config_sda_out(pSimuI2cPort);
	
	SIMUI2C_SCL_CLR;
	SIMUI2C_SDA_CLR;
	delay_us(4);
	SIMUI2C_SCL_SET;
	delay_us(4);//时钟线先拉高4us以上
	SIMUI2C_SDA_SET;
	
}

/*
*********************************************************************************************************
* function    : bsp_SimuI2C_SandAck
* Description : generate a i2c ack to slave
* Argument(s) : point to struct SimuI2cPortType
* Return(s)   : none
*********************************************************************************************************
*/
void bsp_SimuI2C_SandAck(struct SimuI2cPortType *pSimuI2cPort)
{
	SIMUI2C_SCL_CLR;
	config_sda_out(pSimuI2cPort);
		
	SIMUI2C_SDA_CLR;
	delay_us(2);
	SIMUI2C_SCL_SET;
	delay_us(2);
	SIMUI2C_SCL_CLR;
}

/*
*********************************************************************************************************
* function    : bsp_SimuI2C_SandNack
* Description : generate a i2c notack to slave
* Argument(s) : point to struct SimuI2cPortType
* Return(s)   : none
*********************************************************************************************************
*/
void bsp_SimuI2C_SandNack(struct SimuI2cPortType *pSimuI2cPort)
{
	SIMUI2C_SCL_CLR;
	config_sda_out(pSimuI2cPort);
	SIMUI2C_SDA_SET;
	delay_us(2);
	SIMUI2C_SCL_SET;
	delay_us(2);
	SIMUI2C_SCL_CLR;
}

/*
*********************************************************************************************************
* function    : bsp_SimuI2C_ReadAck
* Description : check i2c ack from slave
* Argument(s) : point to struct SimuI2cPortType
* Return(s)   : 0: ack, 1: nack
*********************************************************************************************************
*/
uint32_t bsp_SimuI2C_ReadAck(struct SimuI2cPortType *pSimuI2cPort)
{
	uint8_t ack,ucErrTime=0;
	config_sda_in(pSimuI2cPort);
		
	SIMUI2C_SCL_SET;
	delay_us(2);
	while(SIMUI2C_SDA_IN)
	{
		if(++ucErrTime>250)
		{
			bsp_SimuI2C_stop(pSimuI2cPort);
			return 1;		
		}
	}
	SIMUI2C_SCL_CLR;
	return 0;
}

/*
*********************************************************************************************************
* function    : bsp_SimuI2C_read_byte
* Description : read a byte from i2c slave
* Argument(s) : point to struct SimuI2cPortType
* Return(s)   : the read data
*********************************************************************************************************
*/
uint8_t bsp_SimuI2C_read_byte(struct SimuI2cPortType *pSimuI2cPort)
{
	uint32_t i;
	uint8_t  data = 0;
	config_sda_in(pSimuI2cPort);
	for(i=0; i<8; i++) {	
		SIMUI2C_SCL_CLR;
		delay_us(5);
		SIMUI2C_SCL_SET;	
		//read data in
		data<<=1;
		if(SIMUI2C_SDA_IN)	data |= 0x01;		
		delay_us(5);
	}
	return data;
}

/*
*********************************************************************************************************
* function    : bsp_SimuI2C_write_byte
* Description : write a byte to i2c slave
* Argument(s) : pSimuI2cPort: point to struct SimuI2cPortType, data: data to write
* Return(s)   : none
*********************************************************************************************************
*/
void bsp_SimuI2C_write_byte(struct SimuI2cPortType *pSimuI2cPort, uint8_t data)
{
	uint32_t i;
	config_sda_out(pSimuI2cPort);	
	SIMUI2C_SCL_CLR;
	for(i=0; i<8; ++i) {
		if(data & 0x80)
			SIMUI2C_SDA_SET;
		else
			SIMUI2C_SDA_CLR;
		data <<= 1;
		delay_us(5);
		SIMUI2C_SCL_SET;	
		delay_us(5);
		SIMUI2C_SCL_CLR;
	}
}
#ifndef  __BSP_SIMULATE_I2C__
#define  __BSP_SIMULATE_I2C__

#include  "stm32l4xx_hal.h"
#include  "stdio.h"
//Simulate I2C Port struct define
struct SimuI2cPortType{
	GPIO_TypeDef 	*SCLPort;//GPIO PORT
	uint32_t 		SCLPin;  //GPIO PIN
	GPIO_TypeDef 	*SDAPort;//GPIO PORT
	uint32_t 		SDAPin;  //GPIO PIN
};

//SCL output hardware operate
#define SIMUI2C_SCL_SET		HAL_GPIO_WritePin(pSimuI2cPort->SCLPort, pSimuI2cPort->SCLPin, GPIO_PIN_SET)
#define SIMUI2C_SCL_CLR		HAL_GPIO_WritePin(pSimuI2cPort->SCLPort, pSimuI2cPort->SCLPin, GPIO_PIN_RESET)
//SDA output hardware operate
#define SIMUI2C_SDA_SET		HAL_GPIO_WritePin(pSimuI2cPort->SDAPort, pSimuI2cPort->SDAPin, GPIO_PIN_SET)
#define SIMUI2C_SDA_CLR		HAL_GPIO_WritePin(pSimuI2cPort->SDAPort, pSimuI2cPort->SDAPin, GPIO_PIN_RESET)
//SDA input hardware operate
#define SIMUI2C_SDA_IN		HAL_GPIO_ReadPin(pSimuI2cPort->SDAPort, pSimuI2cPort->SDAPin)


//simulate i2c APIS
void bsp_SimuI2C_start(struct SimuI2cPortType *pSimuI2cPort);
void bsp_SimuI2C_stop(struct SimuI2cPortType *pSimuI2cPort);
void bsp_SimuI2C_SandAck(struct SimuI2cPortType *pSimuI2cPort);
void bsp_SimuI2C_SandNack(struct SimuI2cPortType *pSimuI2cPort);
uint32_t bsp_SimuI2C_ReadAck(struct SimuI2cPortType *pSimuI2cPort);
uint8_t bsp_SimuI2C_read_byte(struct SimuI2cPortType *pSimuI2cPort);
void bsp_SimuI2C_write_byte(struct SimuI2cPortType *pSimuI2cPort, uint8_t data);

uint32_t bsp_SimuI2C_read_nBytes_ack(
    struct SimuI2cPortType *pSimuI2cPort,
    uint8_t device_addr,
    uint8_t RegAddr, 
    uint8_t *pValue, 
    uint8_t Cnt);
		
uint32_t bsp_SimuI2C_write_nBytes_noAck(
struct SimuI2cPortType *pSimuI2cPort,
uint8_t device_addr,
uint8_t RegAddr, 
uint8_t *pValue, 
uint8_t Cnt); 


#endif /* End of module include */

下面是应用举例。要定一个结构体,赋值GPIO口。

struct SimuI2cPortType  xx_IIC_Ctrl_str;
void bsp_iic1_init(void)
{
	GPIO_InitTypeDef  GPIO_InitStruct;
	//SCL-PB8, SDA-PB9
	GPIO_InitStruct.Pin = GPIO_PIN_8 | GPIO_PIN_9;
	GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
	GPIO_InitStruct.Pull = GPIO_NOPULL;
	GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
	HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
	//将IIC端口和引脚,赋值给定义的结构体,就可以调用读写API了。
	xx_IIC_Ctrl_str.SCLPort = GPIOB;
	xx_IIC_Ctrl_str.SCLPin  = GPIO_PIN_8;
	xx_IIC_Ctrl_str.SDAPort = GPIOB;
	xx_IIC_Ctrl_str.SDAPin  = GPIO_PIN_9;	
}
//读n个字节举例
uint8_t rdata[2],ret = 0;
//0x20从机地址,0x08从机寄存器地址,读一个字节放到rdata[0],ret不是0,说明从机没有响应,读取失败。
ret =  bsp_SimuI2C_read_nBytes_ack(&xx_IIC_Ctrl,0x20,0x08,rdata,1);
//写n个字节举例
uint8_t data[2] = {0x21,0x00};	
		ret = bsp_SimuI2C_write_nBytes_noAck(&xx_IIC_Ctrl,0x20,0x00,data,2);
//如果只是访问从机芯片,然后直接写数据,不需要访问从机的寄存器,可以自己找最底层读写、ack、开始、结束去组合使用。(根据芯片时序要求)
  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值