zhiyaormb 2024-03-26 14:21 采纳率: 23.1%
浏览 166
已结题

STM32F4,HAL库SPI接收出问题

用了3块ADC芯片,均采用SPI口Receive Only Master模式进行读操作
其中SPI1的初始化部分(另外两个相同):

  hspi1.Instance = SPI1;
  hspi1.Init.Mode = SPI_MODE_MASTER;
  hspi1.Init.Direction = SPI_DIRECTION_2LINES_RXONLY;
  hspi1.Init.DataSize = SPI_DATASIZE_16BIT;
  hspi1.Init.CLKPolarity = SPI_POLARITY_HIGH;
  hspi1.Init.CLKPhase = SPI_PHASE_2EDGE;
  hspi1.Init.NSS = SPI_NSS_SOFT;
  hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_32;
  hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
  hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
  hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
  hspi1.Init.CRCPolynomial = 10;
  if (HAL_SPI_Init(&hspi1) != HAL_OK)
  {
    Error_Handler();
  }

    __HAL_RCC_SPI1_CLK_ENABLE();

    __HAL_RCC_GPIOA_CLK_ENABLE();
    /**SPI1 GPIO Configuration
    PA5     ------> SPI1_SCK
    PA6     ------> SPI1_MISO
    */
    GPIO_InitStruct.Pin = GPIO_PIN_5|GPIO_PIN_6;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF5_SPI1;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    /* SPI1 interrupt Init */
    HAL_NVIC_SetPriority(SPI1_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(SPI1_IRQn);

然后通过HAL_SPI_Receive_IT读数据。

img


用逻辑分析仪就发现了这样的波形:

信号1:ADC的convst指令,这个指令是在SPI的接收完成回调函数HAL_SPI_RxCpltCallback里面操作的,这个时间点显然接收还没完成,居然进了接收回调。
信号2:SPI的时钟,注意,这个结尾部分,短暂的空闲时间居然被拉低了。
信号3:ADC片选,这个是软件控制的,低有效。
信号4:ADC转换的busy信号,高有效。
现在的问题是:
1 接收数据未完成的时候居然会提前进入接收callback;
2 时钟在接收完成之后短暂被拉低。
由于这两个问题,导致读取数据的错位

  • 写回答

19条回答 默认 最新

  • 专家-赤兔[在线] 全栈领域优质创作者 2024-03-26 14:29
    关注
    获得0.60元问题酬金

    引自免费微信小程序:皆我百晓生

    针对您遇到的STM32F4 HAL库SPI接收问题,我们逐一分析并提出解决方案:

    1. 提前进入接收回调: 在HAL_SPI_Receive_IT中触发中断后,提前进入接收完成回调函数HAL_SPI_RxCpltCallback可能是由于SPI中断配置不当或SPI传输过程中存在异常。确保在调用HAL_SPI_TransmitReceive_ITHAL_SPI_Receive_IT之前正确清除中断标志,并且在回调函数内部处理好数据的同时重新启动接收(如果需要连续接收)。

      您可以在回调函数开始处加入对SPI状态的检查,确保数据接收完毕后再进行后续操作,例如:

      void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi)
      {
          // 确保数据接收完成
          if ((__HAL_SPI_GET_FLAG(hspi, SPI_FLAG_RXNE)) == RESET)
          {
              // 此处执行错误处理逻辑,比如打印错误信息等
              return;
          }
      
          // ...此处进行正常的数据处理...
      
          // 如果需要连续接收,则重新启动接收
          HAL_SPI_Receive_IT(&hspi1, rxBuffer, bufferLength);
      }
      
    2. SPI时钟在接收完成之后短暂被拉低: 这种现象可能与SPI总线管理不善有关,特别是在数据接收完成后没有及时停止SPI时钟输出。您可以通过调整SPI的NSS(片选)信号来解决这个问题,确保在每次数据接收完成后及时释放从设备(ADC),从而停止SPI时钟输出。

      修改您的主函数或相关处理函数,在数据接收完成后立即设置NSS为高电平(对于低有效的片选信号):

      void DataReceiveComplete()
      {
          // 处理接收到的数据...
      
          // 结束SPI事务,取消片选
          HAL_GPIO_WritePin(NSS_GPIO_Port, NSS_Pin, GPIO_PIN_SET);
      }
      

    同时,也请检查硬件连接和SPI外设配置,确保它们符合ADC芯片的数据手册要求,尤其是时钟极性和相位以及数据帧格式。另外,如果SPI控制器支持,可以尝试启用DMA接收模式替代中断接收,这样能更稳定地接收数据,减少中断处理过程中的干扰。

    综上所述,上述建议旨在帮助您定位并解决SPI通信中的问题。请根据实际情况对代码进行相应调整,并仔细检查SPI及ADC的工作模式、时序要求等关键参数是否匹配。

    评论 编辑记录

报告相同问题?

问题事件

  • 系统已结题 4月3日
  • 修改了问题 3月26日
  • 赞助了问题酬金15元 3月26日
  • 修改了问题 3月26日
  • 展开全部

悬赏问题

  • ¥30 关于#java#的问题,请各位专家解答!
  • ¥30 vue+element根据数据循环生成多个table,如何实现最后一列 平均分合并
  • ¥20 pcf8563时钟芯片不启振
  • ¥20 pip2.40更新pip2.43时报错
  • ¥15 换yum源但仍然用不了httpd
  • ¥50 C# 使用DEVMOD设置打印机首选项
  • ¥15 麒麟V10 arm安装gdal
  • ¥20 OPENVPN连接问题
  • ¥15 flask实现搜索框访问数据库
  • ¥15 mrk3399刷完安卓11后投屏调试只能显示一个设备