STM32 HAL_I2C_Slave 从模式 为什么SCL会莫名拉低
本帖最后由 vrxiaochouyu 于 2018-9-11 15:18 编辑现象:
1,有时有应答,有时没有应答。(具体情况是,开机第一次显示未应答,然后报超时错误。第二次直接卡死,如图所示。等了15分钟之后报了遇忙错误。第三次,就真的卡死了。SLC一直为低,程序一点反应都没有)
2,有应答时,写入时时钟不见了。把主设备复位之后,SCL还是低的。为什么会把SCL拉低呢?
i2c即当主又当从。
做主的时候是给E2写数据,已经实现了,没出问题,可以排除硬件问题。
做从的时候是从芯片(另外一个芯片,该设备没有从模式)接收数据。难道是主从需要切换设置(轮巡代码里有设置模式啊)?还是因为STM32自身I2C BUG所致(从网上找了修改HAL_I2C_MspInit函数BUG的代码,然并卵)?
(更新)已从下面这篇文章解决卡死问题(并未根除,还偶尔卡死,但是概率低了很多)。但是还是没有应答。
解决STM32 I2C接口死锁在BUSY状态的方法讨论
然后波形是这样(PS:超时改为1,如果超时为100,依然是卡死)
如果超时改为0,会是这样。这个后边的两个脉冲是怎么来的,难道是强制结束?
我又使了地址全为0,还是一样。
(更新)已解决地址问题,原因是I2C信号太快了。读的信号是从第二个脉冲才开始的,所以永远都是错的。但还是有卡死问题。经常SCL就莫名的拉低了。貌似是和最开始差不多。最后截止的时候不应该给应答信号。但是应该如何解决呢?
“6,当Master速度过快Slave端来不及处理时,Slave设备可以拉低SCL不放(SCL=0将发生“线与”)以阻止Master发送更多的数据。此时Master将视情况减慢或结束数据传送。”难道和这个有关?
(更新)已解决,但是很崩溃。STM32一直在发应答。不发停止。如果size小于主机发的数量,就会卡死。只有遇到主机发停止,才会停止。自己不会停止。收不到停止就一直等啊等,就卡死了。
static void MX_I2C2_Init(void)
{
hi2c2.Instance = I2C2;
hi2c2.Init.ClockSpeed = 100000;
hi2c2.Init.DutyCycle = I2C_DUTYCYCLE_2;
hi2c2.Init.OwnAddress1 = 0xa0;//地址是A0
hi2c2.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
hi2c2.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
hi2c2.Init.OwnAddress2 = 0;//这里应该如何设置?
hi2c2.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
hi2c2.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
if (HAL_I2C_Init(&hi2c2) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
}
temp=UserRxBufferFS;//USB接收指令
HAL_UART_Transmit(&huart2,(uint8_t *)&temp,1,1000);//UART发送指令
if( HAL_I2C_Slave_Receive(&hi2c2, i2cdata, 10, 100)== HAL_OK); //i2c接收数据
while( CDC_Transmit_FS(i2cdata,10) != USBD_OK );//USB返回数据
我自己又写了一个模拟的I2C从设备。有时报地址错误(a0变为4B),有时地址对了,但是没有给应答信号(报09错误,即没有收到第10个SLC)。求大神指正。int I2C_slave()
{
GPIO_InitTypeDef GPIO_InitStruct;
uint32_t i,j=0;
uint8_t data, temp,stop;
//I2C_SDA_1; //释放SDA
//SDA设为输入
GPIO_InitStruct.Pin = GPIO_PIN_5|GPIO_PIN_7;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
i=0;
while (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_7)==1)
{ i++; if (i >=0xffff) {i=0;return 3;};};//start
for( i=0; i<8; i++ )
{
while(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_5)==1)
{ i++;if (i >=0xffff) {i=0;return 4;}; };
while(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_5)==0)
{i++;if (i >=0xffff) {i=0;return 5;};};
temp=HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_7);
data=data<<1;
data=data|temp;
}
if( data!=0xa0)
{if (data==0)return 15;
else
{
return data;//ID
}
};
GPIO_InitStruct.Pin = GPIO_PIN_7; //SDA设为输出
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
while(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_5)==1)
{ i++;if (i >=0xffff) {i=0;return 6;}; };
I2C_SDA_0;//ack
while(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_5)==0)
{i++;if (i >=0xffff) {i=0;return 7;};};
while(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_5)==1)
{ i++;if (i >=0xffff) {i=0;return 8;}; };
GPIO_InitStruct.Pin =GPIO_PIN_7;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
// GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
while(1)
{
while(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_5)==0)
{i++;if (i >=0xffff) {i=0;return 9;};};
temp=HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_7);
if (temp==0)
{
while(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_5)==1)
{i++;if (i >=0xffff) {i=0;return 10;};};
stop=HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_7);
if (stop==1){return 0;}//stop
}
data=data<<1;
data=data|temp;
for( i=0; i<7; i++ )
{
while(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_5)==0)
{i++;if (i >=0xffff) {i=0;return 11;};};
temp=HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_7);
data=data<<1;
data=data|temp;
while(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_5)==1)
{ i++;if (i >=0xffff) {i=0;return 12;}; };
}
i2cdata =data;
j++;
if(j>63)return 2;//over
GPIO_InitStruct.Pin = GPIO_PIN_7; //SDA设为输出
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
I2C_SDA_0; //ack
while(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_5)==0)
{i++;if (i >=0xffff) {i=0;return 13;};};
while(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_5)==1)
{ i++;if (i >=0xffff) {i=0;return 14;}; };
GPIO_InitStruct.Pin =GPIO_PIN_7;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
// GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}
}
这个I2C口,又当主又当从,主的时候是给E2烧写。从的时候是被动接收芯片给发的数据。 IIC从设备的时钟由主设备提供 楼上说的完全OK,从机只有被动,时钟都是主发起的!!! wenyangzeng 发表于 2018-9-10 12:54
IIC从设备的时钟由主设备提供
问题有歧义,稍作了更改。问题应该是,时钟后来怎么没了。写地址的时候还在,为什么写数据的时候就没了。 MrJiu 发表于 2018-9-10 13:44
楼上说的完全OK,从机只有被动,时钟都是主发起的!!!
问题的重点不在于谁发的时钟,而在于时钟怎么自己没了。SCL被强制拉低了。程序卡死了。 vrxiaochouyu 发表于 2018-9-10 14:03
问题的重点不在于谁发的时钟,而在于时钟怎么自己没了。SCL被强制拉低了。程序卡死了。 ...
SCL被强制拉低,有可能是从机。。。因为从机的scl的IO口配置必须是高阻态输入,也就是说,不能拉低。。。否则主机也没法输出高电平!!! MrJiu 发表于 2018-9-10 14:41
SCL被强制拉低,有可能是从机。。。因为从机的scl的IO口配置必须是高阻态输入,也就是说,不能拉低。。。 ...
那么是代码哪里的问题,如何解决呢?用的是CUBE生成的代码呢 vrxiaochouyu 发表于 2018-9-10 14:02
问题有歧义,稍作了更改。问题应该是,时钟后来怎么没了。写地址的时候还在,为什么写数据的时候就没了。 ...
那应该是从设备的应答信号失败,主设备接收不到应答信号,自然没有读操作,时钟消失。 vrxiaochouyu 发表于 2018-9-10 14:44
那么是代码哪里的问题,如何解决呢?用的是CUBE生成的代码呢
我一般不用ST的硬I2C。。。也没搞过I2C从机模式!!!如果是用Cube生成的代码,应该说配置是没问题的。。。
页:
[1]
2