Jump to content

    

Данные с порта в память(DMA)

День добрый
Есть внешний параллельный АЦП, который я тактирую шимом одного из таймеров(STM32F4), вручную забирая данные с порта к которому подключен АЦП.
Возникло желание использовать для этих целей DMA.

ШИМ настроен на:  TIM4 - Channel 4 - PWM Generation CH4


Добавил DMA
Событие: TIM4_UP
Направление передачи: Периферия - Память
Инкрементируется адрес памяти

 

Собственно инициализация в кубе:

__HAL_RCC_GPIOB_CLK_ENABLE();
/**TIM4 GPIO Configuration    
PB9     ------> TIM4_CH4 
*/
GPIO_InitStruct.Pin = GPIO_PIN_9;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Alternate = GPIO_AF2_TIM4;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
    
    
__HAL_RCC_TIM4_CLK_ENABLE();
/* TIM4 DMA Init */
/* TIM4_UP Init */
hdma_tim4_up.Instance = DMA1_Stream6;
hdma_tim4_up.Init.Channel = DMA_CHANNEL_2;
hdma_tim4_up.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_tim4_up.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_tim4_up.Init.MemInc = DMA_MINC_ENABLE;
hdma_tim4_up.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
hdma_tim4_up.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
hdma_tim4_up.Init.Mode = DMA_NORMAL;
hdma_tim4_up.Init.Priority = DMA_PRIORITY_VERY_HIGH;
hdma_tim4_up.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
if (HAL_DMA_Init(&hdma_tim4_up) != HAL_OK)
{
  Error_Handler();
}

__HAL_LINKDMA(htim_base,hdma[TIM_DMA_ID_UPDATE],hdma_tim4_up);

Запускаю ШИМ, запускаю DMA:

HAL_TIM_PWM_Start(&htim4, TIM_CHANNEL_4);
HAL_DMA_Start(&hdma_tim4_up, (uint32_t)&PORT_ADC->IDR, &TestDMA[0], 100);

На выходе имею пустой массив

Опирался на AN4666, но что то делаю не так

Укажите пожалуйста на ошибку

Share this post


Link to post
Share on other sites

А не заменить-ли Вам DMA1 на DMA2 ?  По-моему, GPIO находятся на шине AHB1, которая соединена с DMA2.

Share this post


Link to post
Share on other sites

Да вы правы, мне уже подсказали это. И я заменил DMA1 на DMA2, но это не помогло.

Share this post


Link to post
Share on other sites
В 09.09.2019 в 12:27, Nosaer сказал:

На выходе имею пустой массив

Опирался на AN4666, но что то делаю не так

Укажите пожалуйста на ошибку

Ошибки у вас нет, но есть недодел -   нет тактирования и разрешения прерываний для DMA.

Тактирование для вашего DMA1_Stream6 добавляется так:

  __HAL_RCC_DMA1_CLK_ENABLE();

иначе он на месте стоит и ничего не делает.

Разрешить ему прерывания:

  HAL_NVIC_SetPriority(DMA1_Stream6_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(DMA1_Stream6_IRQn);

И хандлер для их приема сделать:

void DMA1_Stream6_IRQHandler(void)
{
  HAL_DMA_IRQHandler(&hdma_tim4_up);
}

Вот вроде бы и всё.

Share this post


Link to post
Share on other sites
1 час назад, Xenia сказал:

Ошибки у вас нет, но есть недодел -   нет тактирования и разрешения прерываний для DMA.

Если это делалось в кубе и стоят галочки, то он включает это всё в MX_DMA_Init()

1 час назад, Xenia сказал:

И хандлер для их приема сделать:

void DMA1_Stream6_IRQHandler(void)
{
  HAL_DMA_IRQHandler(&hdma_tim4_up);
}

По идеологии куба  хэндлер HAL_DMA_IRQHandler() обычно уже есть(если галки стоят) и он вызывает колбэки, которые надо описать в main :

XferCpltCallback( struct __DMA_HandleTypeDef * hdma)

XferHalfCpltCallback( struct __DMA_HandleTypeDef * hdma)

XferM1CpltCallback( struct __DMA_HandleTypeDef * hdma)

XferM1HalfCpltCallbac)( struct __DMA_HandleTypeDef * hdma)

XferErrorCallback( struct __DMA_HandleTypeDef * hdma)

XferAbortCallback( struct __DMA_HandleTypeDef * hdma)

Share this post


Link to post
Share on other sites

Xenia, тактирование и запуск прерываний прописан в MX_DMA_INIT, как и написал HardEgor.

static void MX_DMA_Init(void)
{
  /* DMA controller clock enable */
  __HAL_RCC_DMA2_CLK_ENABLE();

  /* DMA interrupt init */
  /* DMA2_Stream5_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(DMA2_Stream5_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(DMA2_Stream5_IRQn);
}

Хандлер для их приема тоже автоматически сгенерирован кубом.

П.С. Как я уже писал выше, заменил DMA1 на DMA2.

Share this post


Link to post
Share on other sites
3 часа назад, Nosaer сказал:

П.С. Как я уже писал выше, заменил DMA1 на DMA2.

А DMA вручную менялся или как положено в кубе?

И вообще, что за контроллер?

GPIO_PIN_9 точно выдает импульсы?

Share this post


Link to post
Share on other sites

DMA менял в кубе.

Контроллер STM32F407

С шимом проблем нет, в этом плане все работает.

Пробовал считывать все порты, во всех случаях вижу только 0xFF.

У меня больше подозрений на запуск:

HAL_DMA_Start(&hdma_tim4_up, (uint32_t)&PORT_ADC->IDR, &TestDMA[0], 100);

Возможно не так запускаю или не то использую. Пробовал так же 

HAL_DMA_Start_IT(&hdma_tim4_up, (uint32_t)&PORT_ADC->IDR, &TestDMA[0], 100);

Результата тоже не дало

Share this post


Link to post
Share on other sites

Я в кубе не волоку и может глупость скажу, а не может быть быть так, что ПДП запускается и отрабатывает всю пересылку сразу, не дожидаясь сигнала запуска пересылки, пока ваше АЦП еще не успело выставить данные?

Share this post


Link to post
Share on other sites

Я пока не использую АЦП. А просто пытаюсь считать любой порт, где заведомо подал сигналы на некоторые выводы.

Share this post


Link to post
Share on other sites

Тогда смотрите внутрь __HAL_LINKDMA() и HAL_DMA_Start_IT(), те ли параметры передаются  - в одну hdma_tim4_up,  а в другую указатель.

Share this post


Link to post
Share on other sites
В 13.09.2019 в 07:39, HardEgor сказал:

Тогда смотрите внутрь __HAL_LINKDMA() и HAL_DMA_Start_IT(), те ли параметры передаются  - в одну hdma_tim4_up,  а в другую указатель.

Действительно, со вторым параметром __HAL_LINKDMA что-то явно неладно:

__HAL_LINKDMA(htim_base,hdma[TIM_DMA_ID_UPDATE],hdma_tim4_up);

А за HAL_DMA_Start_IT() можно не волноваться, т.к. это - функция, и сама способна проверять типы своих параметров, тогда как __HAL_LINKDMA - макрос.

Share this post


Link to post
Share on other sites

А у таймера есть разрешение генерировать события для DMA?

Бит UDE в регистре DIER таймера должен быть установлен в единицу.

Переключать DMA на DMA2 не нужно. Событие TIM4_UP привязано к Stream6 Cnannel 2 DMA1. На DMA2 оно просто работать не будет.

Если так нужно DMA2 то стоит взять другой таймер, который может генерировать события именно для 

DMA2. Например TIM1 или TIM8.

Share this post


Link to post
Share on other sites

Всем большое спасибо. Проблема была в том, что при инициализации не выставлялся бит UDE в DIER.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now