找回密码
 立即注册

QQ登录

只需一步,快速开始

打印 上一主题 下一主题
开启左侧

M487的I2C硬件收发器用的库函数一直不通

[复制链接]
跳转到指定楼层
楼主
匿名  发表于 2022-8-31 11:12:53 |只看大图 回帖奖励 |倒序浏览 |阅读模式
我想用新唐的硬件I2C驱动OLED模块,之前在STM32上做的是可以的。现在换成相同功能的新唐的函数发现失败了,不知道是不是我哪儿没有配置正确。
  1. void OLED_Write_cmd(uint8_t cmd)
  2. {
  3. //        HAL_I2C_Mem_Write(&hi2c2, 0x78, 0x00, I2C_MEMADD_SIZE_8BIT, &cmd, 1, 0x100);
  4.         while(I2C_WriteByteOneReg(I2C0,OLED_ADDR,0x00,cmd));
  5. }
  6. void OLED_Write_data(uint8_t data)
  7. {
  8. //        HAL_I2C_Mem_Write(&hi2c2, 0x78, 0x40, I2C_MEMADD_SIZE_8BIT, &data, 1, 0x100);
  9.         while(I2C_WriteByteOneReg(I2C0,OLED_ADDR,0x40,data));
  10. }
复制代码
被注释掉的是原来STM32的库函数。下面是对应的新唐的BSP库函数。
初始化中跟I2C0时钟和管脚的配置为

  1.     /* Enable I2C0 peripheral clock */
  2.     CLK_EnableModuleClock(I2C0_MODULE);
  3.     /* Set I2C0 multi-function pins */
  4.         SYS->GPG_MFPL = SYS_GPG_MFPL_PG1MFP_I2C0_SDA | SYS_GPG_MFPL_PG0MFP_I2C0_SCL;
复制代码
不知道还要配置什么不,我看的几个例子中基本上也就配置这些。
然后在程序开始设置一下速度
  1. void I2C0_Init(void)
  2. {
  3.     /* Open I2C module and set bus clock */
  4.     I2C_Open(I2C0, 100000);

  5.     /* Get I2C0 Bus Clock */
  6.     printf("I2C clock %d Hz\n", I2C_GetBusClockFreq(I2C0));
  7. }
复制代码
不知道为何没法点亮屏幕。GPIO模拟的可以,麻烦版主帮忙试试啊。


分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 顶 踩
回复

使用道具

沙发
chrishu 发表于 2022-8-31 14:18:42 | 只看该作者
uint8_t I2C_WriteByteOneReg(I2C_T *i2c, uint8_t u8SlaveAddr, uint8_t u8DataAddr, uint8_t data)
这个函数的作用是往u8SlaveAddr指定地址的I2C从机的u8DataAddr数据地址里写入一个字节的数据data   
时序为START+u8SlaveAddr+w+ACK+DataAddr+ACK+data+NAK+STOP   
请检查时序是否吻合您的应用。两处ACK的地方如果收到的是NAK会停止发送。
可以debug看一下I2C处理那种状态,我们的I2C所有动作后会有状态指示。
回复 支持 反对

使用道具 举报

板凳
chrishu 发表于 2022-8-31 14:19:13 | 只看该作者

回复 支持 反对

使用道具 举报

地板
匿名  发表于 2022-8-31 18:45:50

是的,用法就是这样,我在STM32 那个里面也是相同功能的函数操作是可以的。你手上有没有I2C接口的那种OLED,你可以试试,我在网上还没找到谁有硬件的I2C操作成功的。我改成IO模拟的是可以的,好奇怪啊。
回复 支持 反对

使用道具

5#
admin 发表于 2022-9-1 09:42:39 | 只看该作者
游客 117.89.30.x 发表于 2022-8-31 10:45
是的,用法就是这样,我在STM32 那个里面也是相同功能的函数操作是可以的。你手上有没有I2C接口的那种OLE ...

您可以debug看一下I2C处理跑到哪个状态里,我们的I2C所有动作后会有状态指示,就知道错在哪里了。
牛卧堂
回复 支持 反对

使用道具 举报

6#
匿名  发表于 2022-9-3 18:08:11
admin 发表于 2022-9-1 09:42
您可以debug看一下I2C处理跑到哪个状态里,我们的I2C所有动作后会有状态指示,就知道错在哪里了。 ...

DEBUG模式没出现状态码0x18,直接就0x20了。。。
然后我看了你们官方的例子也没用那个库函数的,于是找到了采用分立函数的
  1. void OLED_Write_cmd(uint8_t cmd)
  2. {
  3. //        HAL_I2C_Mem_Write(&hi2c2, 0x78, 0x00, I2C_MEMADD_SIZE_8BIT, &cmd, 1, 0x100);
  4.     /* Send START */
  5.     I2C_START(I2C0);
  6.     I2C_WAIT_READY(I2C0);

  7.     /* Send device address */
  8.     I2C_SET_DATA(I2C0, 0x78);
  9.     I2C_SET_CONTROL_REG(I2C0, I2C_CTL_SI);
  10.     I2C_WAIT_READY(I2C0);

  11.     /* Send register number and MSB of data */
  12.     I2C_SET_DATA(I2C0, 0x00);
  13.     I2C_SET_CONTROL_REG(I2C0, I2C_CTL_SI);
  14.     I2C_WAIT_READY(I2C0);


  15.     /* Send data */
  16.     I2C_SET_DATA(I2C0, cmd);
  17.     I2C_SET_CONTROL_REG(I2C0, I2C_CTL_SI);
  18.     I2C_WAIT_READY(I2C0);

  19.     /* Send STOP */
  20.     I2C_STOP(I2C0);
  21.        
  22.        
  23. }
  24. void OLED_Write_data(uint8_t data)
  25. {
  26. //        HAL_I2C_Mem_Write(&hi2c2, 0x78, 0x40, I2C_MEMADD_SIZE_8BIT, &data, 1, 0x100);
  27.     /* Send START */
  28.     I2C_START(I2C0);
  29.     I2C_WAIT_READY(I2C0);

  30.     /* Send device address */
  31.     I2C_SET_DATA(I2C0, 0x78);
  32.     I2C_SET_CONTROL_REG(I2C0, I2C_CTL_SI);
  33.     I2C_WAIT_READY(I2C0);

  34.     /* Send register number and MSB of data */
  35.     I2C_SET_DATA(I2C0, 0x40);
  36.     I2C_SET_CONTROL_REG(I2C0, I2C_CTL_SI);
  37.     I2C_WAIT_READY(I2C0);

  38.        
  39.     /* Send data */
  40.     I2C_SET_DATA(I2C0, data);
  41.     I2C_SET_CONTROL_REG(I2C0, I2C_CTL_SI);
  42.     I2C_WAIT_READY(I2C0);

  43.     /* Send STOP */
  44.     I2C_STOP(I2C0);
  45.        
  46. }
复制代码
实现如上,竟然可以驱动了。奇了怪了。。。经过调试状态码出现了0x18,正常通信了,见鬼了。。。我要好好分析一下你们那个不能用的库函数到底哪儿的问题
回复 支持 反对

使用道具

7#
匿名  发表于 2022-9-3 18:45:10
问题终于找到了,在于设备的地址问题,I2C_WriteByteOneReg(I2C0,0x3C,0x00,cmd);
该函数内对地址进行了移位,因为考虑到了写入是7位地址,最后要发送个0,所以给移位了,而STM32的没考虑这个东东,所以一直没得到正确的响应,原来STM32下用cubeMX配置的,里面设置了这个地方,所以可以使用便宜后的地址0x78,而新唐的BSP是在函数内实现的,所以要用原版的地址。而我忽略了这一点。因为买OLED模块时候给的例子写的地址都是0x78,今天经过调试,发现了端倪,之前没注意这一点,建议库函数的这个位置给个警告注释,应该是很多人用的时候忽略了这里,而导致没法正常使用提供的库函数,而选择用IO模拟。。。
回复 支持 反对

使用道具

8#
匿名  发表于 2022-9-3 18:46:27
0x3C<<1,就是0x78
回复 支持 反对

使用道具

9#
匿名  发表于 2022-9-3 19:20:00
https://bbs.21ic.com/icview-3250674-1-1.html
我把这次问题的总结发到了21的新唐板块。希望能帮到遇到相同问题的人,应该很多人遇到过,却没好意思问,然后也没解决,所以网上很多都是用的IO模拟I2C时序。
回复 支持 反对

使用道具

10#
匿名  发表于 2022-9-3 19:21:25
我把这次问题的总结和解决方法,思路,原因。写成了一篇贴文发到了21ic.com的新唐板块
帖子名字:我终于玩转了新唐的I2C硬件收发器库函数驱动OLED
回复 支持 反对

使用道具

高级模式
B Color Image Link Quote Code Smilies |上传

本版积分规则

新唐MCU