Changes from v2.7.7 to v2.7.8:
[feat]:upgrade patch tool to v3.8 [opt]:opt code generate process display [opt]:opt login logic [opt]:opt ghs support [opt]:add MC03 ghs supportae455856-9c93-4b7f-8810-b5a8bbd6a1c7-image.png
将 SCL 对地短路后 Debug 查看 I2C 寄存器,MSTS -> BUSY 位置 1,I2c_MasterHwStatePtr = I2C_CHN_BUSY_STATUS。065b8965-524f-4213-b792-5e0d178ac1bb-image.png
I2C 发送 API CddI2c_SyncModeTransfer 函数里会判断 I2c 状态,此时 TempChannelStatus = I2C_CHN_ERROR_PRESENT 的情况下 API 是不会调用底层发送,所以 SCL 对地短路恢复后,I2C 总线通讯依旧无法恢复。bd6e1fae-6a40-4279-9308-63f6c49d95c2-image.png
2.1.1 排查方向一 推测是 I2C TOCFG Register 对 SCL 和 SDA 的常低检测导致的 SCL 对地短路恢复后总线通讯失败。但 TOCFG -> SDA 位为 0 的时候只检测 SCL 低电平超时时间,TOCFG -> SCL 位为 1 的时候检测 SCL 和 SDA 低电平超时时间,因此 SCL 低电平超时检测是无法关闭的ae41bf8d-ee9f-4927-98f3-d28b9f3928d7-image.png
在 I2C_Lld_MasterConfig 函数里将 I2C_Lld_MasterFeatureConfig 注释掉后,TOCFG -> SDA 位就不会被置 1,SDA 的低电平超时将不会被打开,此时使用逻辑分析仪抓取 I2C 设备的失联恢复的波形60fdd1ee-8b6d-49f6-9738-b4590b8b8dba-image.png
将 SDA 对地短路后进行测试。SDA 对地短路后 SDA 电平呈现常低,SCL 电平呈现常高,松开 SDA 对地短路后 SCL/SDA 电平均为常高,但 I2C 总线通讯失败,此时 SDA 常低检测处于未打开的情况,所以可以排除低电平超时导致的 I2C 总线发送失败的推断243b7060-38c5-4440-809b-ce9d8ea37e8e-image.png
2.1.2 排查方向二 推测是总线死锁导致的 SCL 对地短路恢复后总线通讯失败。参考 SDK 总线死锁的解决方案“https://forum.ytmicro.com/topic/603/i2c%E6%80%BB%E7%BA%BF%E6%AD%BB%E9%94%81%E9%97%AE%E9%A2%98%E4%BB%8B%E7%BB%8D”943959a4-8371-4b4f-a1e4-d6f367d98502-image.png
按照死锁的方式处理,SCL 对地短路恢复后,MCU 将 SCL配置为 GPIO,并输出 9 个 CLK 信号。实际测试也无法回复 I2C 总线通讯。 3. 解决方案 方案一: 检测 I2C 状态为 I2C_CHN_ERROR_PRESENT 的情况下,先反初始化 I2C 后,再重新初始化 I2C 即可恢复efd0d3dd-3ad2-43e1-bc0b-5afe70d7c8e2-image.png
方案二: CDDI2C MCAL 配置里 I2cBusIdleTimeout 配置是超时的配置,默认是 0(不开启),但当前版本测试开启后不生效。当前驱动没有检查这种情况的一个处理,后续 MCAL 版本更新后会修复88c1d22c-5a8b-4f02-a759-380049a8adb7-image.png
3a4a6966-d46a-478d-962e-483d51af2aba-image.png
对 PTD4 的 IO 反转操作只在中断回调函 I2C_SLAVE_EVENT_STOP Case 里操作4eecfcb4-3268-489c-b593-83364142c0e0-image.png
2. 问题分析 根据 I2C 驱动可以确认 I2C_SLAVE_EVENT_STOP 有三种条件会进入:① 重复接收起始位; ② 收到到错误 ;③ 总线上有 stop bit。也确认客户 restart 指令属于 重复接收起使位(repeat start ) 2.1 重复接收起始位 I2C_DRV_SlaveIRQHandler 函数中 repeatStartDetect 就是对 重复接收起始位 情况的判断。当 repeatStartDetect 置 1,会执行 I2C_DRV_SlaveEndTransferHandler 函数,然后通过回调函数进入 I2C_SLAVE_EVENT_STOP Case642f4da7-2bed-45cc-a3df-70f6b6f7a83a-image.png
6baa01ba-aae4-476e-8140-7dd5b467bae0-image.png
2.2 收到到错误 I2C_DRV_SlaveIRQHandler 函数中会判断 BitError 和 FIFOError。当 I2C 从机出现错误的情况下会执行 I2C_DRV_SlaveEndTransferHandler 函数,然后通过回调函数进入 I2C_SLAVE_EVENT_STOP Case5dbae1b4-3f09-45bf-a233-8af26c301a8e-image.png
2.3 总线上有 stop bit I2C_DRV_SlaveIRQHandler 函数中 stopDetect 就是对 总线上有 stop bit 情况的判断。当 stopDetect 置 1,会执行 I2C_DRV_SlaveEndTransferHandler 函数,然后通过回调函数进入 I2C_SLAVE_EVENT_STOP Case0ed833cd-cca7-45c8-94b8-2cc167162aaa-image.png
3. 解决方案 3.1 Plan A 如果不需要使用 重复接收起始位 进 I2C_SLAVE_EVENT_STOP,并且 I2C 不是使用 DMA,并且使能了监听的情况下,可以直接把 I2C_DRV_SlaveIRQHandler 函数里 repeatStartDetect 的 I2C_DRV_SlaveEndTransferHandler 函数直接注释即可66ffd82f-a1b2-460c-bc53-86a759950397-image.png
关于 I2C 产生 error 也进入 I2C_SLAVE_EVENT_STOP,可以在回调函数 I2C_SLAVE_EVENT_STOP Case 里调用 I2C_DRV_SlaveGetTransferStatus 函数获取 i2c 状态,如果产生 error 函数的返回值是 STATUS_ERROR,因此可以通过返回值去判断是否发产生 error6f2c71f9-2cfa-41cc-903b-9b3e83494c2c-image.png
注意事项: 此方案对 SDK I2C 驱动修改程度最小 此方案会导致主机发送主机写并且不发停止位情况下,无法获取主机写命令什么时候接收完成 3.2 Plan B 在 I2C_DRV_SlaveIRQHandler 函数里调用 I2C_DRV_SlaveEndTransferHandler 函数的位置加 log92ea1753-181c-4b3c-bf95-8fc343c93fef-image.png
然后在回调函数 I2C_SLAVE_EVENT_STOP case 里去判断对应的 log,然后做相应的处理0784d907-3432-4663-952b-19180284adff-image.png
注意事项: 此方案对 SDK I2C 驱动修改程度较大9ee02551-35ae-4b04-9bba-81aa137f1b7a-image.png
时钟为 8M,LOW 值为 0xFFF,根据公式计算,(4096 * 256)* (1 / 8M) = 131ms,而实际拉低时间是 800ms,确实触发超时,MSTS -> TOIF 标志位置 1,理论与实践现象一致。375c9480-42ca-4ca5-91f6-b53a79ea1109-image.png
2.2 HardFault 原因分析 使用 I2c_Master_Demo 例程,模仿客户代码调用方式对问题进行复现1039cc8a-d408-45fd-ae82-0f45fba727b3-image.png
实际 Debug 确定可以看到,当出现 HardFault 时,I2C 未接收完成6efa2f84-3a91-463d-b83e-072daf4ae7d9-image.png
1c1d7221-a043-49f3-b655-ac9467f5b130-image.png
当更改 RXBUFF 为静态局部变量后,就不会出现 HardFault ,其 I2C 通讯波形是完整的,有起始位和停止位。0692b417-fdf7-40f1-b3e2-b9ee7fae7f2c-image.png
3e2712aa-bfb1-41e7-bbde-6d5e7037e0cb-image.png
出现 HardFault 后观察栈空间以及修改栈空间大小均无效果,可以推断堆栈未出现溢出。RXBUFF 数组仅修改变量存储位置,即可避免 HardFault 出现,推测跟变量的存储位置及生命周期有关系,由于局部变量在函数执行结束后就释放了,可能是 i2c_Read 函数已经执行结束了,将 RXBUFF 数组释放了,但由于 I2C 接收还未完成,但接收 BUFF 已经被释放了,但此时还在给 RXBUFF 收数据,所以触发了 HardFault 。 在 i2c_Read 函数里和函数执行完成后分别设一个标志位,当出现 HardFault 的情况时 asd[1] 已经置 1 了,此时 i2c_Read 函数执行完毕 RXBUFF 数组已经被释放了,但此时 I2C 通讯还未结束,还在给 FIFO 写数据,所以触发了 HardFault 。614f878d-7414-44e1-9f1a-c6217d339793-image.png
3. 问题总结 使用 I2C_DRV_MasterReceiveData 函数时,必须使用 I2C_DRV_MasterGetTransferStatus 获取 I2C 状态,同时记得 I2C_DRV_MasterGetTransferStatus + while 等待的时候记得加上超时机制。9187f2f8-2da6-43e5-ae5b-a780d563a5d0-image.png
也可以将 RXBUFF 设置为全局变量或静态变量。I2c_Slave_Demo.zip 硬件:MD14 EVB or 客户板子 问题表述: I2C 从机模式时,客户想在回调函数里做处理,但不清楚回调函数里 Case 的使用情况。 2. Case 说明 I2C0_SlaveRxCpltCallback 函数 /* 伪 C 语言代码,直接编译会报错 */ void I2C0_SlaveRxCpltCallback(i2c_slave_event_t event, void *userData) { /* Get the instance number from userData */ uint32_t instance = 0; (void)userData; /* Depending on the event received, set the buffers or abort the transfer */ switch (event) { case I2C_SLAVE_EVENT_RX_REQ: /* * If the bus master requests data, then set the destination RX buffer * and accepted transfer size */ I2C_DRV_SlaveSetRxBuffer(instance, slaveRxBuffer, BUFF_SIZE); break; case I2C_SLAVE_EVENT_TX_REQ: /* * If the bus master sends data, then set the source TX buffer * and accepted transfer size */ I2C_DRV_SlaveSetTxBuffer(instance, slaveTxBuffer, BUFF_SIZE); break; case I2C_SLAVE_EVENT_TX_EMPTY: /* * If the TX buffer is empty. Because the example does not handle * this case there is no action taken. */ case I2C_SLAVE_EVENT_RX_FULL: /* * If the RX buffer is full, check the slave receive buffer is correct */ break; case I2C_SLAVE_EVENT_STOP: /* * This case is used when a stop condition is on the bus. Because * the example does not handle this case there is no action taken. */ break; } }
0b7d3fa6-05ae-4356-8070-568980a9a476-image.png
3. 获取接收 Data 的个数 使用 I2C_DRV_SlaveGetTransferStatus 函数可以获取 Data 接收的个数,I2C_DRV_SlaveSetTxBuffer 函数的第三个参数是当前 rxSize 的剩余长度,接收长度(已知) - bytesRemaining 得到当前接收了多少字节9dfa6e82-5e74-4d8f-8b15-13ddddb62ded-image.png
一、背景:
使用MCAL开发,版本为2.3.0
目前SPI配置为一个Sequence里面有一个Job,一个Job里面有两个Channel
调用顺序为先调用Spi_SetupEB再Spi_SyncTransmit
二、问题点:
①一个Job下配置了两个Channel ,在发送的时候片选信号未持续拉低
69022cf2-5c81-4eaa-8a64-28ad4ff7ee99-f86bbafeb72020994888d59a8261902d.png
②SPI channel的默认值,只有第一个字节生效(发送数据指针为空),并且Channel实际是要发送8个字节
0994ad48-a7ff-4b93-8ecb-0638ae30b9ff-4dddab3168dfc71bc9c6e20afdbdb278.png
针对上面两个问题,是YCT上哪些配置设置的不对导致的吗?该怎么修改或者有其他建议呀? 谢谢答疑
-
Announcements
Announcements regarding our community
-
Discussion & Question
A place to talk about whatever you want or ask a question
-
Blogs
Blog posts from individual members
快速上手云途开发生态
发帖前请查看
帮助改进和优化YT CONFIG TOOL,有机会抽取YTM32B1ME0 EVB哦...