[技术讨论] 【请教】关于 PCA9555 芯片 I2C 通讯挂死的奇怪问题

[复制链接]
5251|0
 楼主| villivateur 发表于 2021-7-10 16:54 | 显示全部楼层 |阅读模式
本帖最后由 villivateur 于 2021-7-10 17:13 编辑

最近的项目正在使用 STM32F103RC 和 PCA9555 芯片。
PCA9555 芯片的 port0 用于监控一个 4x4 的矩阵键盘(故 GPIO 低四位是输出模式,高四位是输入模式);port1 用于向外接并口显示屏写数据(故 GPIO 八位均为输出模式)。
STM32(使用 FreeRTOS) 通过 I2C 与 9555 通讯(使用了 STM32 的 I2C 控制器,非 GPIO 模拟),400kbps 速率。键盘监听和写显示屏是两个线程,通过信号量保证 I2C 读写不冲突。
问题出现了:程序运行后,I2C 必现 SDA 被拉低挂死,必须重置 PCA9555 才能恢复,但下次启动又会被挂死。
奇怪的现象是,如果我把 PCA9555 port1 的最高位初始化为输入模式,同样的代码,就不会出现任何问题。
同样的,删掉键盘监听线程(或者删掉监听线程里面读 I2C 的部分),也不会挂死;单独删掉显示屏线程,仍然会挂死。

我的代码:
1. 初始化键盘相关:
  1. void keyboard_gpio_init()
  2. {
  3.     PCA9555_WriteByte(PCA9555_OUTPUT_PORT0, 0x00);
  4.     PCA9555_WriteByte(PCA9555_CONF_PORT0, 0xF0); // port 0 is keyboard
  5. }
2. 初始化显示屏相关:
  1. void tmf_lcd_gpio_init()
  2. {
  3.     GPIO_InitTypeDef LCD_InitStructure;
  4.     RCC_APB2PeriphClockCmd(LCD_CLK, ENABLE);
  5.     LCD_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  6.     LCD_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  7.     LCD_InitStructure.GPIO_Pin = LCD_RS | LCD_RW | LCD_E | LCD_PSB | LCD_RST;

  8.     GPIO_Init(LCD_PORT, &LCD_InitStructure);

  9.     PCA9555_WriteByte(PCA9555_OUTPUT_PORT1, 0x00);
  10.     PCA9555_WriteByte(PCA9555_CONF_PORT1, 0x00); // port 1 is lcd
  11. }
注意,此处如果把最后一行的 0x00 改成 0x80 或者 0xF0 等等,故障均会消失。
3. 键盘监听的部分代码:
  1. <font color="#F00000"><font color="#000000">static inline uint8_t keyboard_get_col(void)
  2. {
  3.     uint8_t data = 0xff;
  4.     if (PCA9555_ReadByte(PCA9555_INPUT_PORT0, &data) != 0) {
  5.         return 0xff;
  6.     }
  7.     if (data & KEYBOARD_COL0) {
  8.         return 0x00;
  9.     }
  10.     if (data & KEYBOARD_COL1) {
  11.         return 0x01;
  12.     }
  13.     if (data & KEYBOARD_COL2) {
  14.         return 0x02;
  15.     }
  16.     if (data & KEYBOARD_COL3) {
  17.         return 0x03;
  18.     }
  19.     return 0xff;
  20. }

  21. TMF_CMD keyboard_get_pressed(void)
  22. {
  23.     uint8_t col;
  24.     TMF_CMD pressed;
  25.     uint8_t pressed_index;
  26.     uint8_t flag=0; // 四行扫描完成之后 是否有按键
  27.    
  28.    
  29.     if (PCA9555_WriteByte(PCA9555_OUTPUT_PORT0, KEYBOARD_ROW0) != 0) {
  30.         return TMF_CMD_NONE;
  31.     }
  32.     col = keyboard_get_col(); //<font color="#F00000"> 这一行可以成功执行,执行完后就挂死了</font>
  33.     if(col!=0xff){
  34.         pressed_index =  0x00+col;
  35.         flag = 1;
  36.     }
  37. </font></font>
  38. ......
4. PCA9555 驱动请见 https://drive.vvzero.com/s/X8CNkkSKNzYqMbX

请问,是我哪里没搞对吗?

您需要登录后才可以回帖 登录 | 注册

本版积分规则

1

主题

1

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部