Перейти к содержанию
    

DMA(UART+ADC) ARM

Вечер добрый. Чисто в учебных целях было решено оцифровывать сигнал с 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

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

в RM написано, что есть "peripheral-to-peripheral transfers"

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

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

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

В обработчике прерывания 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:

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

у тебя, скорее всего, просто не успевали отправиться данные. ацп, наверняка, шпарил на всю катушку, быстрее, чем пересылка usart

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...