你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

HAL库I2C使用DMA发送数据的问题

[复制链接]
ldptest 提问时间:2018-1-17 14:19 /
大家好:
我用STM32F10C8T6 连接IIC 接口的OLED。
STM32cubeMX进行初始化设置,以及修改了一下DMA发送函数,发现不能显示
接口驱动是没问题的,以前用3.5库(没使用DMA)是能正常显示的。
使用板上的LED灯检查卡在哪,发现卡在第二次发送上。
下面是精简后的程序,还请大神指导一下。

int main(void)
{
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_DMA_Init();
  MX_I2C1_Init();
  OLED_Init();
  while (1)
  {
  }
}
void I2C_Master_Transmit_DMA(uint16_t DevAddress, uint8_t *pData, uint16_t Size)
{
  while (HAL_I2C_Master_Transmit_DMA(&hi2c1,DevAddress,pData,Size)!= HAL_OK)
  {
    if (HAL_I2C_GetError(&hi2c1)!= HAL_I2C_ERROR_AF)
    {
      Error_Handler();
    }
  }
}
void OLED_WR_Byte(uint8_t Byte,uint8_t DC)
{
      uint8_t SendBuff[2];
      SendBuff[0] = DC;
      SendBuff[1] = Byte;
      I2C_Master_Transmit_DMA(OLED_ADDRESS,SendBuff,2);
}
void OLED_Init(void)
{  
  delay_ms(200);              //
OLED_WR_Byte(0xAE,OLED_CMD);//--display off关闭显示
OLED_WR_Byte(0x00,OLED_CMD);//---set low column address 设置开始低列地址为SEG0
   /*************目的测试卡在哪*********************/
        HAL_GPIO_WritePin(LED_GPIO_Port,LED_Pin,GPIO_PIN_SET);
OLED_WR_Byte(0x10,OLED_CMD);//---set high column address设置高列地址为0000b
OLED_WR_Byte(0x40,OLED_CMD);//--set start line address  设置开始行地址
OLED_WR_Byte(0xB0,OLED_CMD);//--set page address        设置开始页地址PAGE0
OLED_WR_Byte(0x81,OLED_CMD); // contrast control对比度控制,双字节命令
OLED_WR_Byte(0xFF,OLED_CMD);//--对比度为256
OLED_WR_Byte(0xA1,OLED_CMD);//set segment remap SEG0列地址为127
OLED_WR_Byte(0xA6,OLED_CMD);//--设置为正常显示(正常 / 反相显示)
OLED_WR_Byte(0xA8,OLED_CMD);//--set multiplex ratio(1 to 64)设置驱动路数
OLED_WR_Byte(0x3F,OLED_CMD);//--驱动路数为1/32 duty占空比
OLED_WR_Byte(0xC8,OLED_CMD);//Com scan direction: Scan from COM[N-1] to COM0
OLED_WR_Byte(0xD3,OLED_CMD);//-set display offset
OLED_WR_Byte(0x00,OLED_CMD);//
OLED_WR_Byte(0xD5,OLED_CMD);//set osc division
OLED_WR_Byte(0x80,OLED_CMD);//
OLED_WR_Byte(0xD8,OLED_CMD);//set area color mode off
OLED_WR_Byte(0x05,OLED_CMD);//
OLED_WR_Byte(0xD9,OLED_CMD);//Set Pre-Charge Period
OLED_WR_Byte(0xF1,OLED_CMD);//
OLED_WR_Byte(0xDA,OLED_CMD);//set com pin configuartion
OLED_WR_Byte(0x12,OLED_CMD);//
OLED_WR_Byte(0xDB,OLED_CMD);//set Vcomh设置电压
OLED_WR_Byte(0x30,OLED_CMD);//
OLED_WR_Byte(0x8D,OLED_CMD);//set charge pump enable设置电荷泵
OLED_WR_Byte(0x14,OLED_CMD);//开电荷泵
OLED_WR_Byte(0xAF,OLED_CMD);//--turn on oled panel,开始显示
}
收藏 1 评论17 发布时间:2018-1-17 14:19

举报

17个回答
ldptest 回答时间:2018-1-23 12:53:28
的确是两次发送去DMA时间过短导致。为了解决问题,我有两个方案。
方法一:加延时,固定延时,程序效率比较低,代码如下
void OLED_WR_Byte(uint8_t Byte,uint8_t DC)
{
      uint8_t SendBuff[2];
      SendBuff[0] = DC;
      SendBuff[1] = Byte;
      I2C_Master_Transmit_DMA(OLED_ADDRESS,SendBuff,2);
      HAL_Delay(1);
}

方法二:加I2C总线状态判断,程序不卡,但没显示,不知什么原因?
void I2C_Master_Transmit_DMA(uint16_t DevAddress, uint8_t *pData, uint16_t Size)
{
  while (HAL_I2C_GetState(&hi2c1)!=HAL_I2C_STATE_READY)  {}
  while (HAL_I2C_Master_Transmit_DMA(&hi2c1,DevAddress,pData,Size)!= HAL_OK)
  {
    if (HAL_I2C_GetError(&hi2c1)!= HAL_I2C_ERROR_AF)
    {
      Error_Handler();
    }
  }
}
ldptest 回答时间:2018-1-17 21:04:28
问题应该出在启动了DMA或I2C后,没有把它停掉。
何时怎样停掉?
ldptest 回答时间:2018-1-18 23:30:46
我遇到的问题应该与这里描述的一样
http://community.st.com/thread/3 ... p-in-hali2cgetstate
ldptest 回答时间:2018-1-20 22:06:13
为了调试,我换成I2C2口输出。
使用仿真,卡在了
HAL_Init();——  HAL_MspInit(); —— __HAL_AFIO_REMAP_SWJ_DISABLE();
无薪税绵 回答时间:2018-1-23 10:19:06
SW调试口都闭关了,当然会卡死了。
看看是驱动接口是否开启了功能复用。

评分

参与人数 1蝴蝶豆 +3 收起 理由
zero99 + 3

查看全部评分

nyszx 回答时间:2018-1-23 10:30:33
我想问一下楼主为啥要用DMA呀,看你函数
  1. void OLED_WR_Byte(uint8_t Byte,uint8_t DC)
  2. {
  3.       uint8_t SendBuff[2];
  4.       SendBuff[0] = DC;
  5.       SendBuff[1] = Byte;
  6.       I2C_Master_Transmit_DMA(OLED_ADDRESS,SendBuff,2);
  7. }
复制代码

就发送两个uint8_t的数据,数据量太少了,估计还不如直接发送来的快。
不知道楼主有没有检测到DMA传输完成中断?还有就是楼主说卡在了__HAL_AFIO_REMAP_SWJ_DISABLE();吗?怎么会卡在这里?楼主可以把STM32cubeMX进行初始化设置截图贴出来,便于分析

评分

参与人数 1蝴蝶豆 +4 收起 理由
zero99 + 4

查看全部评分

toofree 回答时间:2018-1-23 10:39:47
刚上手STM32的时候,项目中用STM32F10CBT6控制过EEPROM AT24C02。
刚开始使用硬件I2C,在开发板上试是好的,项目中的板子就不行,所不同的是一个是Microchip的24LCXX系列片子,一个是AT24CXX系列片子,对比了数据资料,参数没发现有明显不同。
调试跟踪,发现死在了一个while中,ST的固件库中是死等标志。后来的做法是,把while循环做了超时退出,实际操作是成功了,但就是标志没置过来。(有人说这种现象是ST I2C的Bug)。
单步调试是好的。后来调试的时候,在两个写操作之前加了一条Printf打印信息,想用来定位程序跑到什么地方出错的。神奇的事情发生了,竟然一路通畅跑过去了。一删Printf,就容易出错。
仔细看EEPROM手册,发现有一个时间非常关键,是前一个“停止”到下一个“起始”之前的延时最大需要5ms,即Twr。见下图时序参数表: 傲游截图20180123102422.jpg

时序波形示意:
傲游截图20180123102443.jpg

后来我在程序中增加了Twr这个延时,保证不少于5ms,后来I2C再没有挂过,产品也持续生产使用了五六年了。



个人猜想,在一个I2C写周期后,硬件I2C立即去读取标志,造成了硬件I2C内部某些机制紊乱。或许与外部I2C器件逻辑及管脚状态也有一定关系。


以上个人经验体会,仅供参考。




评分

参与人数 1蝴蝶豆 +5 收起 理由
zero99 + 5

查看全部评分

toofree 回答时间:2018-1-23 11:00:43
下面这个或许可以参考一下。本人英语不行,就不翻译了。


http://community.st.com/thread/4 ... ith-dma-not-working
傲游截图20180123105942.jpg

http://community.st.com/thread/27652
傲游截图20180123105951.jpg

ldptest 回答时间:2018-1-23 12:11:20
无薪税绵 发表于 2018-1-23 10:19
SW调试口都闭关了,当然会卡死了。
看看是驱动接口是否开启了功能复用。

这个问题已解决了,原来不知怎样在cubemx中设置SWD接口

评分

参与人数 1蝴蝶豆 +2 收起 理由
zero99 + 2 结贴奖励

查看全部评分

ldptest 回答时间:2018-1-23 12:15:50
nyszx 发表于 2018-1-23 10:30
我想问一下楼主为啥要用DMA呀,看你函数
就发送两个uint8_t的数据,数据量太少了,估计还不如直接发送来的 ...

1、为了学习研究,所以使用DMA
2、初始化时的确使用率比较低,两个数据。但用于显示时会使用一次传输显示整个字符(英文6字节数据,中文16字节数据)。
3、__HAL_AFIO_REMAP_SWJ_DISABLE();问题已解决了。
12下一页

所属标签

相似问题

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
微信公众号二维码 微信公众号
手机版二维码 手机版