stm 32シリアルポートHALライブラリのDMA送信問題

4018 ワード

本稿ではstm 32 f 411 retのシリアルポート1のDMA方式でデータを送信し,デバッグを開始するとシリアルポートが1回しかデータを送信できないことに気づき,その後システムhangを停止した.ネット上で資料を探したり、試したりすることで、問題はコールバック関数が書かれていない原因であることが分かった.
HALライブラリのDMAを使用するには、DMA割り込みコールバック関数とシリアルポート割り込みコールバック関数を同時に実現する必要がある.
void DMA2_Stream7_IRQHandler(void)
{
    HAL_DMA_IRQHandler(Uart1Handle.hdmatx);
}

void USART1_IRQHandler(void)
{
  HAL_NVIC_ClearPendingIRQ(USART1_IRQn);
  HAL_UART_IRQHandler(&Uart1Handle);
}

次に、私のdma構成とシリアルポート構成関数を添付します.
dma構成
void HAL_UART1_dma_Init(void)
{
  static DMA_HandleTypeDef hdma_tx;

  __HAL_RCC_DMA2_CLK_ENABLE();                //  DMA2  
  /*##-3- Configure the DMA streams ##########################################*/
  /* Configure the DMA handler for Transmission process */
  hdma_tx.Instance                 = DMA2_Stream7;      
  hdma_tx.Init.Channel             = DMA_CHANNEL_4;        //  1    stream7、channel4,       DMA    
  hdma_tx.Init.Direction           = DMA_MEMORY_TO_PERIPH;    //      :  ->  
  hdma_tx.Init.PeriphInc           = DMA_PINC_DISABLE;        //     ,       
  hdma_tx.Init.MemInc              = DMA_MINC_ENABLE;        //      
  hdma_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;    //     
  hdma_tx.Init.MemDataAlignment    = DMA_MDATAALIGN_BYTE;    //        
  hdma_tx.Init.Mode                = DMA_NORMAL;              //    ,         ,        
  hdma_tx.Init.Priority            = DMA_PRIORITY_LOW;        //    
  hdma_tx.Init.FIFOMode            = DMA_FIFOMODE_DISABLE;    
  hdma_tx.Init.FIFOThreshold       = DMA_FIFO_THRESHOLD_FULL;
  hdma_tx.Init.MemBurst            = DMA_MBURST_INC4;
  hdma_tx.Init.PeriphBurst         = DMA_PBURST_INC4;
  
  HAL_DMA_Init(&hdma_tx);   
  
  /* Associate the initialized DMA handle to the the UART handle */
  __HAL_LINKDMA(&Uart1Handle, hdmatx, hdma_tx);            // dma   handle     1 hdmatx  
  /*##-4- Configure the NVIC for DMA #########################################*/
  /* NVIC configuration for DMA transfer complete interrupt (USARTx_TX) */
  HAL_NVIC_SetPriority(DMA2_Stream7_IRQn, 0, 1);           //  dma     
  HAL_NVIC_EnableIRQ(DMA2_Stream7_IRQn);                   //  dma  
}

シリアルピン構成
void Init_Usart1(void)
{
	GPIO_InitTypeDef  GPIO_InitStruct;
  
  /*##-1- Enable peripherals and GPIO Clocks #################################*/
  /* Enable GPIO TX/RX clock */
  __HAL_RCC_GPIOA_CLK_ENABLE();  
  /* Enable USARTx clock */
   __HAL_RCC_USART1_CLK_ENABLE();
  
  /*##-2- Configure peripheral GPIO ##########################################*/  
  /* UART TX GPIO pin configuration  */
  GPIO_InitStruct.Pin       = GPIO_PIN_9;
  GPIO_InitStruct.Mode      = GPIO_MODE_AF_PP;
  GPIO_InitStruct.Pull      = GPIO_PULLUP;
  GPIO_InitStruct.Speed     = GPIO_SPEED_FAST;
  GPIO_InitStruct.Alternate = GPIO_AF7_USART1;
  
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
    
  /* UART RX GPIO pin configuration  */
  GPIO_InitStruct.Pin = GPIO_PIN_10;
  GPIO_InitStruct.Alternate = GPIO_AF7_USART1;
    
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
	
	HAL_NVIC_SetPriority(USART1_IRQn,0,0);
	HAL_NVIC_EnableIRQ(USART1_IRQn);				
	
}

シリアルポート構成
void Usart1_Configuration(uint32_t BaudRate)
{								   
  Uart1Handle.Instance          = USART1;
  
  Uart1Handle.Init.BaudRate     = BaudRate;
  Uart1Handle.Init.WordLength   = UART_WORDLENGTH_8B;
  Uart1Handle.Init.StopBits     = UART_STOPBITS_1;
  Uart1Handle.Init.Parity       = UART_PARITY_NONE;
  Uart1Handle.Init.HwFlowCtl    = UART_HWCONTROL_NONE;
  Uart1Handle.Init.Mode         = UART_MODE_TX_RX;
  Uart1Handle.Init.OverSampling = UART_OVERSAMPLING_16;
    
  if(HAL_UART_Init(&Uart1Handle) != HAL_OK)
  {
    /* Initialization Error */
    Error_Handler(); 
  }	
    
}

送信データは次の関数を呼び出せばよい
HAL_UART_Transmit_DMA(&Uart1Handle, (uint8_t*)aTxBuffer, 32)

実際の操作では、シリアルポートの中断にフラグビットを設定して、シリアルポートの送信が完了したことをマークし、メインプログラムで送信関数の呼び出しをフラグビットで制御することができます.