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

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

[复制链接]
网络孤客 提问时间: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 评论18 发布时间:2018-1-17 14:19

举报

18个回答
网络孤客 回答时间: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();
    }
  }
}
网络孤客 回答时间:2018-1-30 00:02:06
本帖最后由 ldptest 于 2018-1-30 00:03 编辑

1、发送控制命令没有使用DMA方式,直接采用HAL_I2C_Master_Transmit
2、发送显示内容采用以下方式
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();
    }
  }
}

void OLED_ShowChar(uint8_t chr)
{
        uint8_t c=0,i;
        c = chr - ' ';              //得到字库地址码
      uint8_t SendBuff[7];
      SendBuff[0] =  OLED_DATA;
      for(i=0;i<6;i++)
      {
        SendBuff[i+1] = F6x8[i + 5 * c];
      }
    I2C_Master_Transmit_DMA(OLED_ADDRESS,SendBuff,7);
}

结果:能显示,但连续显示字符时,第一个字符显示不出来,后续字符显示均正常,在第一个字符前加延时也不行。
七哥 回答时间: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

查看全部评分

网络孤客 回答时间:2018-1-17 21:04:28
问题应该出在启动了DMA或I2C后,没有把它停掉。
何时怎样停掉?
网络孤客 回答时间:2018-1-18 23:30:46
我遇到的问题应该与这里描述的一样
http://community.st.com/thread/3 ... p-in-hali2cgetstate
网络孤客 回答时间: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

查看全部评分

七哥 回答时间: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

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

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

评分

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

查看全部评分

网络孤客 回答时间: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();问题已解决了。
网络孤客 回答时间:2018-1-23 12:19:22
toofree 发表于 2018-1-23 10:39
刚上手STM32的时候,项目中用STM32F10CBT6控制过EEPROM AT24C02。
刚开始使用硬件I2C,在开发板上试是好的 ...

谢谢你的经验。
我的现象也是单步DEBUG能正常运行,一起执行就卡。
我查查相关手册看看有没有类似间隔问题。
网络孤客 回答时间:2018-1-23 12:20:08
toofree 发表于 2018-1-23 11:00
下面这个或许可以参考一下。本人英语不行,就不翻译了。

谢谢,我英文也不行,慢慢看ing
nyszx 回答时间:2018-1-23 16:51:20
学习了~看库代码,可以重写HAL_I2C_MasterTxCpltCallback(I2C_HandleTypeDef *hi2c),增加一个完成标记,检测完成标记在启动下一次DMA传输,比使用delay来延时好,楼主可以试试
网络孤客 回答时间:2018-1-23 20:40:16
nyszx 发表于 2018-1-23 16:51
学习了~看库代码,可以重写HAL_I2C_MasterTxCpltCallback(I2C_HandleTypeDef *hi2c),增加一个完成标记,检 ...

我在发送前增加检查DMA是否完成,结果还是一样的卡
void I2C_Master_Transmit_DMA(uint16_t DevAddress, uint8_t *pData, uint16_t Size)
{
  while ((HAL_DMA_GetState(&hdma_i2c2_tx) != HAL_DMA_STATE_READY) && (HAL_DMA_GetState(&hdma_i2c2_rx) != HAL_DMA_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();
    }
  }
}
12下一页

所属标签

相似问题

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32Cube扩展软件包
意法半导体边缘AI套件
ST - 理想汽车豪华SUV案例
ST意法半导体智能家居案例
STM32 ARM Cortex 32位微控制器
关注我们
st-img 微信公众号
st-img 手机版