STM32
直播中

李春梅

7年用户 1771经验值
私信 关注
[问答]

如何解决显示图像时的闪烁延迟问题?

如何解决显示图像时的闪烁延迟问题?

回帖(1)

柴扉

2021-12-7 13:51:24
前言
在前两章节中已经讲述了串口的通常用法, 【STM32】CubeMX+HAL库之串口
以及串口DMA空闲中断不定长接收与发送, 【STM32】串口DMA空闲中断不定长收发配自定义装包与解包


在本章节我们将介绍DMA双缓冲这一技术。在很多时候数据的发送频率与数据接收使用频率并不一致,数据来的太快,接收者还没来得及对其进行处理,下一帧的数据就到了,并将其覆盖,致使信息的有效性大大减弱。这时我们增加一个缓冲区来存放来不及处理的数据,就能更好地完成任务。双缓冲还有一个重要的应用是在图像部分,可以更好的解决显示图像时的闪烁延迟问题。


所用工具:


开发板:野火挑战者STM32H743IIT6
STM32CubeMX
IDE: Keil-MDK
满足怎样的需求
利用DMA传输方式节约CPU资源
利用串口空闲中断来拉起处理函数
提供掉线重启DMA的能力,保证热插拔的稳定性
总述流程
在主函数中调用初始化函数
main.c
/* USER CODE BEGIN PFP */
extern void uartInit(UART_HandleTypeDef *huart);
/* USER CODE END PFP */

  /* USER CODE BEGIN 2 */
  uartInit(&huart1);
  /* USER CODE END 2 */


bsp_uart.c中的定义
uint8_t rx_buf[2][RX_BUFLEN]; //双缓冲Buffer


DMA_Stream_TypeDef *DMA_DBuf;


初始化函数实体
此部分初始化两个Buffer,与前部分的区别十分明显。
bsp_uart.c
void uartInit(UART_HandleTypeDef *huart)
{
        DMA_DBuf = huart->hdmarx->Instance;
        //enable the DMA transfer for the receiver request
  //使能DMA串口接收
  SET_BIT(huart->Instance->CR3, USART_CR3_DMAR);
  //enalbe idle interrupt
  //使能空闲中断
  __HAL_UART_ENABLE_IT(huart, UART_IT_IDLE);


  //disable DMA
  //失效DMA
  __HAL_DMA_DISABLE(huart->hdmarx);
  while(DMA_DBuf->CR & DMA_SxCR_EN)
  {
    __HAL_DMA_DISABLE(huart->hdmarx);
  }


  DMA_DBuf->PAR = (uint32_t) & (USART1->RDR); //F4中为DR
  //memory buffer 1
  //内存缓冲区1
  DMA_DBuf->M0AR = (uint32_t)(rx_buf[0]);
  //memory buffer 2
  //内存缓冲区2
  DMA_DBuf->M1AR = (uint32_t)(rx_buf[1]);
  //data length
  //数据长度
        huart->RxXferSize = RX_BUFLEN * 2;
  DMA_DBuf->NDTR = RX_BUFLEN * 2;
  //enable double memory buffer
  //使能双缓冲区
  SET_BIT(DMA_DBuf->CR, DMA_SxCR_DBM);


  //enable DMA
  //使能DMA
  __HAL_DMA_ENABLE(huart->hdmarx);
}


回调函数实体
在处理函数中也分别对两个Buffer进行处理。
bsp_uart.c
void BSP_UART_Callback(UART_HandleTypeDef *huart)
{
        DMA_DBuf = huart->hdmarx->Instance;
       
        if(huart->Instance == USART1)
  {
    if(huart->Instance->ISR & UART_FLAG_RXNE)//接收到数据  F4 为SR
    {
      __HAL_UART_CLEAR_PEFLAG(huart);
    }
    else if(huart->Instance->ISR & UART_FLAG_IDLE)
    {
      static uint16_t this_time_rx_len = 0;


      __HAL_UART_CLEAR_PEFLAG(huart);
      //disable DMA
      //失效DMA
      __HAL_DMA_DISABLE(huart->hdmarx);
      //get receive data length, length = set_data_length - remain_length
      //获取接收数据长度,长度 = 设定长度 - 剩余长度
      this_time_rx_len = huart->RxXferSize - DMA_DBuf->NDTR;
      //reset set_data_lenght
      //重新设定数据长度
      DMA_DBuf->NDTR = 36;


      if ((DMA_DBuf->CR & DMA_SxCR_CT) == RESET)
      {
        //set memory buffer 1
        //设定缓冲区1
        DMA_DBuf->CR |= DMA_SxCR_CT;
        //enable DMA
        //使能DMA
        __HAL_DMA_ENABLE(huart->hdmarx);
        if(this_time_rx_len == 18)
        {
          //LoadData(0);  此部分写自己的解包程序
        }
      }
      else
      {
        //设定缓冲区2
        DMA1_Stream1->CR &= ~(DMA_SxCR_CT);
        //enable DMA
        //使能DMA
        __HAL_DMA_ENABLE(huart->hdmarx);
        if(this_time_rx_len == 18)
        {
          //LoadData(1);    此部分写自己的解包程序
        }
      }
    }
  }
}```


5. 在stm32h7xx_it.c中加入自定义回调函数


```c
/* USER CODE BEGIN PFP */
extern void BSP_UART_Callback(UART_HandleTypeDef *huart);
/* USER CODE END PFP */


void USART1_IRQHandler(void)
{
  /* USER CODE BEGIN USART1_IRQn 0 */
        BSP_UART_Callback(&huart1);
  /* USER CODE END USART1_IRQn 0 */
  HAL_UART_IRQHandler(&huart1);
  /* USER CODE BEGIN USART1_IRQn 1 */


  /* USER CODE END USART1_IRQn 1 */
}


双缓冲的使用到这里就结束了,H7与其他芯片略有不同,需要自行找下问题,在代码中基本也都有注释,此部分学的还不够透彻,还望大佬指教更加官方的写法。
举报

更多回帖

发帖
×
20
完善资料,
赚取积分