WM8994软件IIC调试怪异问题

情到浓时终转凉″ 提交于 2020-02-15 05:47:40

 

使用官方demo,硬件IIC可以正常与WM8994通讯,而我这个使用了几年的软件IIC却无法正常通讯,表现为设备地址0x34能正常发送,能正确响应ACK,如果后续的16bit(2个字节)的地址与16bit(2个字节)的数据,BIT0,BIT8有一个1的话,就无法完成通讯。

比如发送0xFEFE是没问题的,如果是0xFFFF或者0x0001或者0x0100之类,只要BIT0或BIT8有1则不会收到ACK,时序确认了无数次,其它各种IIC芯片都能正常读写,唯独这个WM8994死活无法读取,已经折腾1个多星期了。

 

之前的软件IIC代码在这:https://blog.csdn.net/cp1300/article/details/75644988 已经用了好几年了。

然后我还重新编写了一个IIC的通讯接口,问题依旧。


//SDA-PH8  SCL-PH7
#define WM8994_SDA_OUT_MODE()		SYS_GPIOx_OneInit(GPIOH, 8, OUT_OD, SPEED_50M)			//SDA输出模式
#define WM8994_SDA_IN_MODE()		SYS_GPIOx_OneInit(GPIOH, 8, IN_IPU, IN_NONE)			//SDA输入模式
#define IIC_SDA_Set(x)				(PHout(8) =  x)
#define IIC_SCL_Set(x)				(PHout(7) = x)
#define IIC_SDA_Get()				(PHin(8))

//IIC启动序列(结果:SDA=0,SCL=0)
void IIC_Start(void)
{
	IIC_SDA_Set(1);
	IIC_SCL_Set(1);
	Delay_US(3);
	IIC_SDA_Set(0);
	Delay_US(3);
	IIC_SCL_Set(0);
}


//IIC结束序列(结果:SDA=1,SCL=1)
void IIC_Stop(void)
{
	Delay_US(1);
	IIC_SCL_Set(1);
	Delay_US(1);
	IIC_SDA_Set(0);
	Delay_US(1);
	IIC_SDA_Set(1);
	Delay_US(1);
}

//IIC结束序列(结果:SDA=x,SCL=0)
void IIC_SendByte(u8 data)
{
	u8 i;
	
	for(i = 0;i < 8;i ++)
	{
		IIC_SDA_Set((data & 0x80)?1:0);	//MSB
		data <<= 1;
		//产生时钟
		Delay_US(1);
		IIC_SCL_Set(1);		//上升沿
		Delay_US(2);
		IIC_SCL_Set(0);		//下降沿
		Delay_US(1);
	}
	
}

//等待ACK(结果:SDA=x,SCL=0)
bool IIC_WaitACK(void)
{
	u8 retry = 0;
	
	WM8994_SDA_IN_MODE();	//SDA设置为输入
	Delay_US(1);
	IIC_SCL_Set(1);			//上升沿
	Delay_US(2);
	while(IIC_SDA_Get())
	{
		retry++;
		if(retry>250)
		{
			IIC_SCL_Set(0);			//下降沿
			WM8994_SDA_OUT_MODE();	//SDA设置为输出
			IIC_Stop();
			return FALSE;
		}
	}
	Delay_US(1);
	IIC_SCL_Set(0);			//下降沿
	Delay_US(1);
	WM8994_SDA_OUT_MODE();	//SDA设置为输出
	return TRUE;
}

/*************************************************************************************************************************
*函数        	:	bool WM8994_WriteOneReg(WM8994_HANDLE *pHandle,u16 RegAddr,u8 data)
*功能        	:	WM8994写一个寄存器
*参数        	:	pHandle:句柄;RegAddr:寄存器地址;data:要写入的值
*返回        	:	无
*依赖			: 	底层宏定义
*作者       	:	cp1300@139.com
*时间     		:	2019-02-13
*最后修改时间	:	2019-02-13
*说明        	:	
*************************************************************************************************************************/
bool WM8994_WriteOneReg(WM8994_HANDLE *pHandle,u16 RegAddr,u16 data)
{
	u8 SlaveAddr = pHandle->SlaveAddr;
	
	IIC_Start();				//发送起始信号
	IIC_SendByte(SlaveAddr);	//发送一字节
	if(IIC_WaitACK() == FALSE)
	{
		DEBUG("[IIC写错误]:1\r\n");
		return FALSE;
	}
	IIC_SendByte(RegAddr>>8);	//发送一字节
	if(IIC_WaitACK() == FALSE)
	{
		DEBUG("[IIC写错误]:2\r\n");
		return FALSE;
	}
	
	IIC_SendByte(RegAddr);	//发送一字节
	if(IIC_WaitACK() == FALSE)
	{
		DEBUG("[IIC写错误]:3\r\n");
		return FALSE;
	}
	
	IIC_SendByte(data>>8);	//发送一字节
	if(IIC_WaitACK() == FALSE)
	{
		DEBUG("[IIC写错误]:4\r\n");
		return FALSE;
	}
	
	IIC_SendByte(data);	//发送一字节
	if(IIC_WaitACK() == FALSE)
	{
		DEBUG("[IIC写错误]:5\r\n");
		return FALSE;
	}
	
	IIC_Stop();
	
	return TRUE;
}


//测试代码
while(1)
	{
		if(WM8994_WriteOneReg(pHandle, 0, BIT6) == TRUE)
		{
			uart_printf("WM8994写入成功\r\n");
		}
		SYS_DelayMS(1);
		LED1 = PDin(6);
		SYS_DelayMS(500);
		
		WM8994_WriteOneReg(pHandle, 0xFEFF, BIT0|BIT6);
		SYS_DelayMS(1);
		LED1 = PDin(6);
		SYS_DelayMS(500);
		
		//temp = WM8994_ReadOneReg(pHandle, 1792);
		//uart_printf("reg%02d=0x%X\r\n",1792, temp);
}

 

//结果,只要BIT0或BIT8不为1就能正常写入,并且有正确的ACK响应

依旧不甘心,测试时在8个bit发送完成后,在SCL低电平期间将SDA设置为高电平,所有通讯都会故障,这个就解释不通了,理论上IIC在SCL为低电平时,SDA是可以变动的,但是这个1貌似会影响到之后的ACK低电平。

测试结果是所有通讯都异常了,没法接收ACK(已经测试过,后面无论延时多久都不会收到ACK,所以可以排除是时间导致的ACK错过,只要接收ACK之前SDA输出了1,就不会再收到ACK了,而且SDA的变化时在SCL=0时进行的,是符合IIC标准的,理论上不会影响后续数据)

全部返回错误1,也就是第一个字节发送出去就没有ACK了

 

而且与时间无关,就算延时1秒,依旧无法读取

从WM8994的手册中,看到时钟只限制了最大速度400K,并没有最低限制,同步通讯,理论上这个地方的延时都不会有影响,而且在SCL为低电平期间,是允许SDA变化的

 

 

同样的代码,读取FT5336,一次就成功了

/*************************************************************************************************************************
*函数        	:	u8 FT5336_ReadOneReg(FT5336_HANDLE *pHandle,u8 RegAddr)
*功能        	:	FT5336读取一个8bit寄存器
*参数        	:	pHandle:句柄;RegAddr:寄存器地址
*返回        	:	读取的寄存器值
*依赖			: 	底层宏定义
*作者       	:	cp1300@139.com
*时间     		:	2019-02-13
*最后修改时间	:	2019-02-13
*说明        	:	
*************************************************************************************************************************/
u8 FT5336_ReadOneReg(FT5336_HANDLE *pHandle,u8 RegAddr)
{
	u16 data;
	u8 SlaveAddr = pHandle->SlaveAddr;
	
	
	
	SIIC_Start(&pHandle->IIC_Handle);									//产生IIC起始信号
	if(SIIC_SendByte(&pHandle->IIC_Handle, SlaveAddr) == FALSE)			//发送设备地址+写信号
	{
		DEBUG("没有收到ACK-01\r\n");
	}
	if(SIIC_SendByte(&pHandle->IIC_Handle, RegAddr) == FALSE)			//发送寄存器地址
	{
		DEBUG("没有收到ACK-02\r\n");
	}
	SIIC_Start(&pHandle->IIC_Handle);									//产生IIC起始信号
	if(SIIC_SendByte(&pHandle->IIC_Handle, SlaveAddr|BIT0) == FALSE)	//发送设备地址+读信号
	{
		DEBUG("没有收到ACK-03\r\n");
	}
	
	data = SIIC_ReadByte(&pHandle->IIC_Handle, TRUE);					//SIIC读取一个字节-高位
	SIIC_Stop(&pHandle->IIC_Handle);									//产生IIC停止信号
	
	return data;
}



/*************************************************************************************************************************
*函数        	:	FT5336_Init(FT5336_HANDLE *pHandle, u8 SlaveAddr)
*功能        	:	FT5336初始化
*参数        	:	pHandle:句柄;SlaveAddr通讯地址;
*返回        	:	TRUE:初始化成功;FALSE:初始化失败
*依赖			: 	底层宏定义
*作者       	:	cp1300@139.com
*时间     		:	2019-01-30
*最后修改时间	:	2019-01-30
*说明        	:	需要先提前初始化IIC接口
*************************************************************************************************************************/
bool FT5336_Init(FT5336_HANDLE *pHandle, u8 SlaveAddr)
{
	u8 id;
	
	if(pHandle == NULL) return FALSE;
	pHandle->SlaveAddr = SlaveAddr;							//通讯地址

	while(1)
	{
		id = FT5336_ReadOneReg(pHandle, 0xA8);
		
		uart_printf("FT5336 id = 0x%X\r\n", id);

		SYS_DelayMS(1000);
	}
	
	
	return TRUE;
}


//软件IIC读取数据测试
	uart_printf("FT5336测试开始\r\n");
	{	
		//软件IIC初始化
		if(SIIC_Init(&g_SysGlobal.mFT5336_Handle.IIC_Handle, GPIOH, GPIOH, 8, 7, 5) == FALSE)	
		{
			DEBUG("软件IIC初始化失败!\r\n");
		}	
		FT5336_Init(&g_SysGlobal.mFT5336_Handle, 0x70);
		//OSTimeDlyHMSM(1,0,0,0);
	}

 

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!