Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: HAL+UART+DMA
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > ARM, 32bit
Sprite
Доброго всем времени суток!
Контроллер stm32f107, проект собран в Cube, пытаюсь сделать отправку по USART с DMA.
Инициализация:
Код
void MX_UART4_Init(void)
{

  huart4.Instance = UART4;
  huart4.Init.BaudRate = 9600;
  huart4.Init.WordLength = UART_WORDLENGTH_8B;
  huart4.Init.StopBits = UART_STOPBITS_1;
  huart4.Init.Parity = UART_PARITY_NONE;
  huart4.Init.Mode = UART_MODE_TX;
  huart4.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart4.Init.OverSampling = UART_OVERSAMPLING_16;
  HAL_UART_Init(&huart4);

}

Код
void MX_DMA_Init(void)
{
  /* DMA controller clock enable */
  __HAL_RCC_DMA2_CLK_ENABLE();

  /* DMA interrupt init */
  HAL_NVIC_SetPriority(DMA2_Channel5_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(DMA2_Channel5_IRQn);

}

Связка USART<->DMA:
Код
void HAL_UART_MspInit(UART_HandleTypeDef* huart)
{

  GPIO_InitTypeDef GPIO_InitStruct;
  if(huart->Instance==UART4)
  {
  /* USER CODE BEGIN UART4_MspInit 0 */

  /* USER CODE END UART4_MspInit 0 */
    /* Peripheral clock enable */
    __UART4_CLK_ENABLE();
  
    /**UART4 GPIO Configuration    
    PC10     ------> UART4_TX
    PC11     ------> UART4_RX
    */
    GPIO_InitStruct.Pin = GPIO_PIN_10;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Speed = GPIO_SPEED_LOW;
    HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = GPIO_PIN_11;
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

    /* Peripheral DMA init*/
  
    hdma_uart4_tx.Instance = DMA2_Channel5;
    hdma_uart4_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
    hdma_uart4_tx.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_uart4_tx.Init.MemInc = DMA_MINC_ENABLE;
    hdma_uart4_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
    hdma_uart4_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
    hdma_uart4_tx.Init.Mode = DMA_NORMAL;
    hdma_uart4_tx.Init.Priority = DMA_PRIORITY_LOW;
    HAL_DMA_Init(&hdma_uart4_tx);

    __HAL_LINKDMA(huart,hdmatx,hdma_uart4_tx);

  /* USER CODE BEGIN UART4_MspInit 1 */

  /* USER CODE END UART4_MspInit 1 */
  }

}

Посылка данных:
Код
  uint8_t data[8] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08};
  
  while (1)
  {
      HAL_UART_Transmit_DMA(&huart4, data, 8);
      HAL_Delay(500);
  }

Но отправляется только первая посылка. Далее huart4.State переходит в состояние HAL_UART_STATE_BUSY_TX.
Пробовал делать отправку без HAL (регистрами) - все работает. Хочется разобраться с hal и понять что делаю не так.
Tanya
Цитата(Sprite @ May 6 2015, 08:30) *
Но отправляется только первая посылка. Далее huart4.State переходит в состояние HAL_UART_STATE_BUSY_TX.
Пробовал делать отправку без HAL (регистрами) - все работает. Хочется разобраться с hal и понять что делаю не так.

Первая посылка - это сколько байт?
А что у Вас делает обработчик прерываний? И зачем тут прерывания?
Sprite
Цитата(Tanya @ May 6 2015, 12:19) *
Первая посылка - это сколько байт?
А что у Вас делает обработчик прерываний? И зачем тут прерывания?

Первая посылка - это все 8 байт (data[8]). Про прерывания был мой второй вопрос wink.gif Дело в том, что при конфигурации DMA в Cube галка "DMA channel 5 global interrupt" не снимается. Мне прерывания не нужны. Контроль отправки посылки можно делать опросом бита TCIF5 регистра DMA2->ISR.
Tanya
Цитата(Sprite @ May 6 2015, 10:05) *
Первая посылка - это все 8 байт (data[8]). Про прерывания был мой второй вопрос wink.gif Дело в том, что при конфигурации DMA в Cube галка "DMA channel 5 global interrupt" не снимается. Мне прерывания не нужны. Контроль отправки посылки можно делать опросом бита TCIF5 регистра DMA2->ISR.

Да, это у меня тоже после обновления КУБа возникло с галками... Пришлось откатиться на старую версию. Или писать callback, что мне не нужно было совсем... но работало.
Sprite
Цитата(Tanya @ May 6 2015, 13:28) *
Да, это у меня тоже после обновления КУБа возникло с галками... Пришлось откатиться на старую версию. Или писать callback, что мне не нужно было совсем... но работало.

А причем здесь прерывания? У меня обработчик прерывания пустой, но huart4.State переходит в состояние HAL_UART_STATE_BUSY_TX. Мне нужно State менять на Ready в обработчике прерывания?
Sprite
Вчера CMSIS, сегодня HAL, завтра еще что-нибудь придумают.. в итоге сделал все через регистры - быстро, красиво и универсально. Все работает, тему можно считать закрытой.
_sR_
Вдруг кто еще столкнется с этим.
Вот на форуме stm нашли в чем причина

Если в кратце, то обработчик прерывания по завершению передачи от DMA (UART_DMATransmitCplt) не восстанавливает состояние уарта (huart->State).
что бы все работало без правки исходников HAL надо определить штатный обработчик прерывания UART который и вернет состояние в HAL_UART_STATE_READY.
Код
void USARTx_IRQHandler(void)
{
HAL_UART_IRQHandler(&UartHandle);
}

Альтернативно, если прерывания от UART не нужны, то можно изменить саму UART_DMATransmitCplt
Вот как это предложили на форуме st.

Код
static void UART_DMATransmitCplt(DMA_HandleTypeDef *hdma)    
{
  UART_HandleTypeDef* huart = ( UART_HandleTypeDef* )((DMA_HandleTypeDef* )hdma)->Parent;
  /* DMA Normal mode*/
  if ( HAL_IS_BIT_CLR(hdma->Instance->CCR, DMA_CCR_CIRC) )
{
    huart->TxXferCount = 0;
    
    /* Disable the DMA transfer for transmit request by setting the DMAT bit
       in the UART CR3 register */
    CLEAR_BIT(huart->Instance->CR3, USART_CR3_DMAT);


    /* Enable the UART Transmit Complete Interrupt */  
    __HAL_UART_ENABLE_IT(huart, UART_IT_TC);
        huart->State=HAL_UART_STATE_READY;  //<--- i add this line to solve the //problem
  }
  /* DMA Circular mode */
  else
  {
    HAL_UART_TxCpltCallback(huart);
  }
}


В описании на драйверы HAL (я смотрел Description of STM32F0xx HAL drivers rev 1) про это ничего нет.
Tarbal
В соседней теме, где нас обозвали теоретиками мы как раз обсуждали этот вопрос.

Дело в том, что DMA начинает слать следующий байт по сигналу инициириванному флагом буфер пуст, но по логике статус должен стать равным HAL_UART_STATE_READY после пересылки байта. В предыдущей версии куба внутри обработчика прерывания DMA в цикле крутились все время пока передается последний байт. В более новой версии поступили иначе. Разрешили прерывание по UART_IT_TC и перенесли код в соответствующий обработчик прерывания. Вот обработчик для 429го процессора, а все детали вы можете посмотерть в соседней теме.

Код
/**
  * @brief  Wraps up transmission in non blocking mode.
  * @param  huart: pointer to a UART_HandleTypeDef structure that contains
  *                the configuration information for the specified UART module.
  * @retval HAL status
  */
static HAL_StatusTypeDef UART_EndTransmit_IT(UART_HandleTypeDef *huart)
{
  /* Disable the UART Transmit Complete Interrupt */    
  __HAL_UART_DISABLE_IT(huart, UART_IT_TC);
  
  /* Check if a receive process is ongoing or not */
  if(huart->State == HAL_UART_STATE_BUSY_TX_RX)
  {
    huart->State = HAL_UART_STATE_BUSY_RX;
  }
  else
  {
    /* Disable the UART Parity Error Interrupt */
    __HAL_UART_DISABLE_IT(huart, UART_IT_PE);

    /* Disable the UART Error Interrupt: (Frame error, noise error, overrun error) */
    __HAL_UART_DISABLE_IT(huart, UART_IT_ERR);

    huart->State = HAL_UART_STATE_READY;
  }
  
  HAL_UART_TxCpltCallback(huart);
  
  return HAL_OK;
}
eu1cc
Привет всем. Аналогичная проблемма. Советы выше не помогают.
Не выходит из while...
Как такое может быть?


Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2024 Invision Power Services, Inc.