Jump to content

    
Sign in to follow this  
4th

DMA(UART+ADC) ARM

Recommended Posts

Вечер добрый. Чисто в учебных целях было решено оцифровывать сигнал с ADC1, сохранять его в uint16_t переменной и в прерывании от DMA(ADC1) копировать результат в массив uint8_t mass[2] и запускать отправку по UART через тот же DMA. А в прерывании DMA(UART) запускать преобразование АЦП заново. И так по кругу...

В режиме отладки при включенных бряках на DMA1_Channel1_IRQHandler (АЦП) и DMA1_Channel1_IRQHandler (UART) этот результат достигается. Но при роботе в реальном времени (ну или без брейкпоинтов) происходит следующее:

  • из main запускается HAL_ADC_Start_DMA(&hadc1, (uint32_t *) &adc_buffer, sizeof(adc_buffer));
  • при завершении преобразования уходит в прерывание DMA1_Channel1_IRQHandler;
  • копирует данные из adc_buffer в uart_buffer[]; запускает посылку по UART: HAL_UART_Transmit_DMA(&huart2, uart_buffer, sizeof(uart_buffer));
  • и останавливает АЦП: HAL_ADC_Stop_DMA(&hadc1);
  • после этого он должен попасть в обработчик завершения передачи DMA1_Channel7_IRQHandler, но этого не происходит (но происходит только при пошаговой отладке)

В общем не могу понять что мешает ему работать как задумано.

Ниже куски кода, которые наверняка захотят увидеть:

int main(void)
{

  HAL_Init();

  SystemClock_Config();
  
  MX_GPIO_Init();
  MX_DMA_Init();
  MX_ADC1_Init();
  MX_USART2_UART_Init();

  HAL_ADC_Start_DMA(&hadc1, (uint32_t *) &adc_buffer, sizeof(adc_buffer));

  while (1) {  }

}

void DMA1_Channel1_IRQHandler(void)
{
   HAL_DMA_IRQHandler(&hdma_adc1);

  uart_buffer[0]=adc_buffer>>8;
  uart_buffer[1]=adc_buffer;
  HAL_UART_Transmit_DMA(&huart2, uart_buffer, sizeof(uart_buffer));
  HAL_ADC_Stop_DMA(&hadc1);

}

void DMA1_Channel7_IRQHandler(void)
{
  
  HAL_DMA_IRQHandler(&hdma_usart2_tx);

HAL_ADC_Start_DMA(&hadc1, (uint32_t *) &adc_buffer, sizeof(adc_buffer));        //заходит сюда только в пошаговом режиме

}

2016_06_30_22_18_11.png

 

Share this post


Link to post
Share on other sites
в RM написано, что есть "peripheral-to-peripheral transfers"

Предлагаете сразу через DMA копировать данные. Понимаю. Но это не совсем подходящее решение. Предполагается, что перед копированием в буфер UARTa, может выполнять работа с данными. Поэтому делал изначально в прерывании.

Это не решает задачу полностью, но все-равно спасибо.

 

Share this post


Link to post
Share on other sites

Найдено решение:

В обработчике прерывания DMA(UART) было добавлено:

  • проверку условия срабатывания прерывания: if( HAL_DMA_GetState(&hdma_usart2_tx)==HAL_DMA_STATE_READY) {...}
  • принудительную остановку передачи в DMA по UART - HAL_UART_DMAStop(&huart2);
  • запуск АЦП - HAL_ADC_Start_DMA(&hadc1, (uint32_t *) &adc_buffer, sizeof(adc_buffer));

 

Следует отметить что без принудительной остановки HAL_UART_DMAStop(&huart2) - отказывается работать.

Также следует отметить что условий срабатывания прерывания DMA(UART) уйма, точнее сказать на любое состояние DMA:

typedef enum
{
  HAL_DMA_STATE_RESET             = 0x00,  /*!< DMA not yet initialized or disabled */
  HAL_DMA_STATE_READY             = 0x01,  /*!< DMA initialized and ready for use   */
  HAL_DMA_STATE_READY_HALF        = 0x11,  /*!< DMA Half process success            */
  HAL_DMA_STATE_BUSY              = 0x02,  /*!< DMA process is ongoing              */
  HAL_DMA_STATE_TIMEOUT           = 0x03,  /*!< DMA timeout state                   */
  HAL_DMA_STATE_ERROR             = 0x04,  /*!< DMA error state                     */
}HAL_DMA_StateTypeDef;

 

Поэтому в прерывании DMA(UART) следует выполнять проверку на причину возникновения прерывания.

 

Листинг основных кусков кода ниже:

int main(void)
{

  HAL_Init();

  SystemClock_Config();

  MX_GPIO_Init();
  MX_DMA_Init();
  MX_ADC1_Init();
  MX_USART2_UART_Init();

  HAL_ADC_Start_DMA(&hadc1, (uint32_t *) &adc_buffer, sizeof(adc_buffer));

   while (1)  {}

}

void DMA1_Channel1_IRQHandler(void)
{

  HAL_DMA_IRQHandler(&hdma_adc1);

  uart_buffer[0]=adc_buffer>>8;
  uart_buffer[1]=adc_buffer;
  HAL_UART_Transmit_DMA(&huart2, uart_buffer, sizeof(uart_buffer));
  HAL_ADC_Stop_DMA(&hadc1);

}

void DMA1_Channel7_IRQHandler(void)
{
  
  HAL_DMA_IRQHandler(&hdma_usart2_tx);
  if( HAL_DMA_GetState(&hdma_usart2_tx)==HAL_DMA_STATE_READY){
      HAL_UART_DMAStop(&huart2);
      HAL_ADC_Start_DMA(&hadc1, (uint32_t *) &adc_buffer, sizeof(adc_buffer));        
  }
}

 

Думаю такое решение будет кому-то полезным :tongue:

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Sign in to follow this