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

STM32Cube_FW_F1_V1.7.0似乎存在bug!

[复制链接]
绿茵场上的舞者 提问时间:2019-3-29 13:46 /
本帖最后由 绿茵场上的舞者 于 2019-3-29 13:46 编辑

ST的官方工具STM32CubeMX是目前开发STM32的常用工具,之前在STM32F4和STM32L0使用过,感觉还可以。我用的都是LL库,不是HAL库系列。因为LL库比HAL效率更高,接近之前的标准库,当然是封装的层少,个人感觉。
今天手里有块STM32F103C8的开发板,用STM32CubeMX开发程序中,发现本来设定的LED灯都是常闭的,可是程序跑起来后,发现默认都是常亮的。自己一度怀疑是程序写的有问题或是J-link有问题。
后来,调试发现是ST官方的STM32Cube_FW_F1_V1.7.0存在bug。调试中发现通过设置GPIO port bit set/reset register (GPIOx_BSRR) (x = A..I/J/K)来设置GPIO port output data register (GPIOx_ODR) (x = A..I/J/K)寄存器,引脚对应的寄存器位正常被设置,
但是在随后的LL_GPIO_Init(GPIOA, &GPIO_InitStruct)函数中设置对应引脚上下拉时,对应的GPIOx_ODR (x = A..I/J/K)寄存器也会被设置。还有,我都是通过STM32CubeMX里边下载官方库,应该是最新的SMT32F1系列的HAL库,STM32F1版本:STM32Cube_FW_F1_V1.7.0,STM32F4版本:STM32Cube_FW_F4_V1.24.0,STM32L0版本:STM32Cube_FW_L0_V1.11.2。

以下是STM32CubeMX自动生成的GPIO初始化代码:官方生成的初始化代码都是先设置对应的引脚电平,然后再初始化设置引脚的模式,速率等。如果先初始化引脚的模式等,再设置引脚的电平不会出现这个问题。

/** Configure pins as
        * Analog
        * Input
        * Output
        * EVENT_OUT
        * EXTI
*/
void MX_GPIO_Init(void)
{
    LL_GPIO_InitTypeDef GPIO_InitStruct = {0};
    /* GPIO Ports Clock Enable */
    LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_GPIOD);
    LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_GPIOA);
    LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_GPIOB);
    /**/
    LL_GPIO_ResetOutputPin(GPIOA, LED0_Pin | POWER_MC20_Pin);
    LL_GPIO_SetOutputPin(GPIOA, LED0_Pin);
    LL_GPIO_SetOutputPin(GPIOA, LL_GPIO_PIN_0);     //设置对应的引脚默认为高电平,但是经过以下的LL_GPIO_Init(GPIOA, &GPIO_InitStruct)后,GPIOx_ODR会被设置为低电平。我设置的是GPIOA0引脚,换为GPIOB0和GPIOB1引脚还是存在这个问题。
    /**/
    LL_GPIO_SetOutputPin(GPIOB, LED1_Pin | LED2_Pin);
    /**/
    GPIO_InitStruct.Pin = LED0_Pin | POWER_MC20_Pin;
    GPIO_InitStruct.Mode = LL_GPIO_MODE_OUTPUT;
    GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_LOW;
    GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
    LL_GPIO_Init(GPIOA, &GPIO_InitStruct);
//    LL_GPIO_SetOutputPin(GPIOA, LED0_Pin);
    /**/
    GPIO_InitStruct.Pin = LED1_Pin | LED2_Pin;
    GPIO_InitStruct.Mode = LL_GPIO_MODE_OUTPUT;
    GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_LOW;
    GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
    LL_GPIO_Init(GPIOB, &GPIO_InitStruct);
//    LL_GPIO_SetOutputPin(GPIOB, LED1_Pin | LED2_Pin);
}

注释部分是我手动添加的,默认软件是先设置对应的引脚电平,然后在初始化的。可是,由于函数LL_GPIO_Init(GPIOA, &GPIO_InitStruct)中设置上下拉部分的作用会导致之前设置的高电平被清零掉。要想真正的起作用,必须在函数LL_GPIO_Init(GPIOA, &GPIO_InitStruct)后重新设置对应引脚的电平。

以下是官方HAL库中stm32f1xx_ll_gpio.c文件中函数LL_GPIO_Init()代码,加注释的地方应该存在bug。

/**
  * @brief  Initialize GPIO registers according to the specified parameters in GPIO_InitStruct.
  * @param  GPIOx GPIO Port
  * @param  GPIO_InitStruct: pointer to a @ref LL_GPIO_InitTypeDef structure
  *         that contains the configuration information for the specified GPIO peripheral.
  * @retval An ErrorStatus enumeration value:
  *          - SUCCESS: GPIO registers are initialized according to GPIO_InitStruct content
  *          - ERROR:   Not applicable
  */
ErrorStatus LL_GPIO_Init(GPIO_TypeDef *GPIOx, LL_GPIO_InitTypeDef *GPIO_InitStruct)
{
  uint32_t pinmask;
  uint32_t pinpos;
  uint32_t currentpin;

  /* Check the parameters */
  assert_param(IS_GPIO_ALL_INSTANCE(GPIOx));
  assert_param(IS_LL_GPIO_PIN(GPIO_InitStruct->Pin));

  /* ------------------------- Configure the port pins ---------------- */
  /* Initialize  pinpos on first pin set */

  pinmask = ((GPIO_InitStruct->Pin) << GPIO_PIN_MASK_POS) >> GPIO_PIN_NB;
  pinpos = POSITION_VAL(pinmask);

  /* Configure the port pins */
  while ((pinmask  >> pinpos) != 0U)
  {
    /* skip if bit is not set */
    if ((pinmask & (1U << pinpos)) != 0U)
    {
      /* Get current io position */
      if (pinpos < GPIO_PIN_MASK_POS)
      {
        currentpin = (0x00000101U << pinpos);
      }
      else
      {
        currentpin = ((0x00010001U << (pinpos - GPIO_PIN_MASK_POS)) | 0x04000000U);
      }

      /* Check Pin Mode and Pin Pull parameters */
      assert_param(IS_LL_GPIO_MODE(GPIO_InitStruct->Mode));
      assert_param(IS_LL_GPIO_PULL(GPIO_InitStruct->Pull));

      /* Pin Mode configuration */
      LL_GPIO_SetPinMode(GPIOx, currentpin, GPIO_InitStruct->Mode);

      /* Pull-up Pull-down resistor configuration*/
      LL_GPIO_SetPinPull(GPIOx, currentpin, GPIO_InitStruct->Pull);   //设置上下拉部分代码,就是这部分导致之前设置的GPIOx_ODR寄存器对应位会被清零掉。

      if ((GPIO_InitStruct->Mode == LL_GPIO_MODE_OUTPUT) || (GPIO_InitStruct->Mode == LL_GPIO_MODE_ALTERNATE))
      {
        /* Check speed and Output mode parameters */
        assert_param(IS_LL_GPIO_SPEED(GPIO_InitStruct->Speed));
        assert_param(IS_LL_GPIO_OUTPUT_TYPE(GPIO_InitStruct->OutputType));

        /* Speed mode configuration */
        LL_GPIO_SetPinSpeed(GPIOx, currentpin, GPIO_InitStruct->Speed);

        /* Output mode configuration*/
        LL_GPIO_SetPinOutputType(GPIOx, currentpin, GPIO_InitStruct->OutputType);
      }
    }
    pinpos++;
  }
  return (SUCCESS);
}

后来,测试STM32L0和STM32F4的LL库这部分,没有存在问题。看芯片的技术文档,发现:STM32L0和F4系列有专门的上下拉设置寄存器GPIO port pull-up/pull-down register (GPIOx_PUPDR),而STM32F1系列应该是没有这个配置的寄存器(也不是很确定,我看的RM0008 技术手册,对应 STM32F101xx, STM32F102xx, STM32F103xx, STM32F105xx and STM32F107xx advanced ARM®-based 32-bit MCUs,里面是没有提到有上下拉寄存器),所以同样的函数LL_GPIO_Init()代码处理是不一样的,在F4和L0系列中,LL_GPIO_Init()函数没有问题,在F1中存在这个问题。

以下是F1系列,F4系列,L0系列中设置上下拉函数LL_GPIO_SetPinPull()的代码:

F1系列:个人感觉既然F1系列中没有上下拉设置寄存器,这个函数显得有些鸡肋,虽然显得HAL库中接口统一了。

__STATIC_INLINE void LL_GPIO_SetPinPull(GPIO_TypeDef *GPIOx, uint32_t Pin, uint32_t Pull)
{
  MODIFY_REG(GPIOx->ODR, (Pin >> GPIO_PIN_MASK_POS), Pull << (POSITION_VAL(Pin >> GPIO_PIN_MASK_POS)));
}

F4系列:

__STATIC_INLINE void LL_GPIO_SetPinPull(GPIO_TypeDef *GPIOx, uint32_t Pin, uint32_t Pull)
{
  MODIFY_REG(GPIOx->PUPDR, (GPIO_PUPDR_PUPDR0 << (POSITION_VAL(Pin) * 2U)), (Pull << (POSITION_VAL(Pin) * 2U)));
}

L0系列:

__STATIC_INLINE void LL_GPIO_SetPinPull(GPIO_TypeDef *GPIOx, uint32_t Pin, uint32_t Pull)
{
  MODIFY_REG(GPIOx->PUPDR, ((Pin * Pin) * GPIO_PUPDR_PUPD0), ((Pin * Pin) * Pull));
}



希望大家测试下,是否真的有这个问题。还有,以上都是个人意见,如有不妥之处,希望大家见谅。




收藏 评论4 发布时间:2019-3-29 13:46

举报

4个回答
七哥 回答时间:2019-3-29 17:14:14
本帖最后由 toofree 于 2019-3-29 17:22 编辑

这个没问题。上拉下模式,配合输出寄存器来设置的,它们是相关的。
上拉模式,必然对应的输出寄存器为1;反之下拉模式,对应的输出寄存器值就是0。
aa.jpg

评分

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

查看全部评分

绿茵场上的舞者 回答时间:2019-3-29 17:42:21
toofree 发表于 2019-3-29 17:14
这个没问题。上拉下模式,配合输出寄存器来设置的,它们是相关的。
上拉模式,必然对应的输出寄存器为1;反 ...

我设置的输出引脚模式,另外,我的意思是使用STM32CubeMX官方软件自动生成的代码存在问题。
绿茵场上的舞者 回答时间:2019-3-29 17:43:35
toofree 发表于 2019-3-29 17:14
这个没问题。上拉下模式,配合输出寄存器来设置的,它们是相关的。
上拉模式,必然对应的输出寄存器为1;反 ...

另外就是,希望大家在F1xx系列的芯片上测试下,是不是有这个问题。大家一起谈论下,看看。
七哥 回答时间:2019-3-31 00:08:52
本帖最后由 toofree 于 2019-3-31 00:41 编辑
绿茵场上的舞者 发表于 2019-3-29 17:43
另外就是,希望大家在F1xx系列的芯片上测试下,是不是有这个问题。大家一起谈论下,看看。 ...

明白楼主说的了,经验证的确如此。LL库的确坑多多,谨慎使用,推荐使用HAL库。
用HAL库就不存在此类问题了

的HAL库的IO初始化子函数中,做了IO输入判断,只有在输入模式下,才会有上下拉一说。
00.png

再次,在初始化IO结构体赋值前已经加了上下拉选项。
01.png



所属标签

相似问题

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