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

STM32F407(417) rev A DMA1 problem

Для одного из проектов протребовалось использовать DMA вместе с таймером 2.

 

Алгоритм работы следующий: По событию совпадения с регистром сравнения 2 происходит запуск DMA1_Stream6. DMA пересылает 640 байт и переконфигурируется.

 

Однако всегда происходит ошибка передачи DMA, пробовал вычленять и запускать только эту часть кода - аналогичный результат, также попробовал камни разных ревизий и серий - f407 rev A, Z; f417 rev A.

 

Исходный код тестовой программы приведён внизу, также приложен архив с проектом (Coocox, GNU GCC).

#include "stm32f4xx_rcc.h"
#include "stm32f4xx_dma.h"
#include "misc.h"
#include "stm32f4xx_gpio.h"
#include "stm32f4xx_tim.h"

char Buffer[640];

int main(void)
{
  NVIC_InitTypeDef NVIC_InitStructure;
  DMA_InitTypeDef DMA_InitStructure;
  TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
  TIM_OCInitTypeDef		 TIM_OCInitStructure;
  GPIO_InitTypeDef GPIO_InitStructure;

  NVIC_InitStructure.NVIC_IRQChannel = DMA1_Stream6_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);

  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE);
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);

  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_All;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  GPIO_Init(GPIOD, &GPIO_InitStructure);

  TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
  TIM_TimeBaseStructure.TIM_Period = 1000;
  TIM_TimeBaseStructure.TIM_Prescaler = 160;
  TIM_TimeBaseStructure.TIM_ClockDivision = 0;
  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
  TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);

  TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
  TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Disable;
  TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
  TIM_OCInitStructure.TIM_Pulse = 500;
  TIM_OC1Init(TIM2, &TIM_OCInitStructure);

  TIM_DMACmd(TIM2, TIM_DMA_CC2, ENABLE);

  DMA_Cmd(DMA1_Stream6, DISABLE);
  DMA_DeInit(DMA1_Stream6);
  DMA_StructInit(&DMA_InitStructure);
  DMA_InitStructure.DMA_PeripheralBaseAddr = (unsigned int)&(GPIOD->ODR);
  DMA_InitStructure.DMA_Memory0BaseAddr = (unsigned int)&Buffer;
  DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;
  DMA_InitStructure.DMA_BufferSize = 640;
  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
  DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
  DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
  DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
  DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
  DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
  DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
  DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
  DMA_InitStructure.DMA_Channel = DMA_Channel_3;

  DMA_Init(DMA1_Stream6, &DMA_InitStructure);
  DMA_ITConfig(DMA1_Stream6, DMA_IT_TC | DMA_IT_TE, ENABLE);
  DMA_Cmd(DMA1_Stream6, ENABLE);

  TIM_Cmd(TIM2, ENABLE);

  GPIO_SetBits(GPIOD, GPIO_Pin_All);
  GPIO_ResetBits(GPIOD, GPIO_Pin_12 | GPIO_Pin_14);

while(1)
{
   GPIO_ResetBits(GPIOD, GPIO_Pin_12 | GPIO_Pin_14);
}
}

void DMA1_Stream6_IRQHandler(void) {
  TIM2->CR1 &= ~TIM_CR1_CEN;
  if (DMA1->HISR & DMA_HISR_TEIF6)
  GPIO_SetBits(GPIOD, GPIO_Pin_14);
  if (DMA1->HISR & DMA_HISR_TCIF6) {
  GPIO_SetBits(GPIOD, GPIO_Pin_12);
  DMA1_Stream6->M0AR = (unsigned int)&Buffer;
  DMA1_Stream6->CR |= DMA_SxCR_EN;
  }
  DMA_ClearITPendingBit(DMA1_Stream6, DMA_IT_TC | DMA_IT_TE);
  TIM2->CR1 |= TIM_CR1_CEN;
}

 

Однако используя DMA2 всё проходит как надо:

#include "stm32f4xx_rcc.h"
#include "stm32f4xx_dma.h"
#include "misc.h"
#include "stm32f4xx_gpio.h"
#include "stm32f4xx_tim.h"

char Buffer[640];

int main(void)
{
  NVIC_InitTypeDef NVIC_InitStructure;
  DMA_InitTypeDef DMA_InitStructure;
  TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
  TIM_OCInitTypeDef		 TIM_OCInitStructure;
  GPIO_InitTypeDef GPIO_InitStructure;

  NVIC_InitStructure.NVIC_IRQChannel = DMA2_Stream2_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);

  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);

  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_All;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  GPIO_Init(GPIOD, &GPIO_InitStructure);

  TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
  TIM_TimeBaseStructure.TIM_Period = 1000;
  TIM_TimeBaseStructure.TIM_Prescaler = 1600;
  TIM_TimeBaseStructure.TIM_ClockDivision = 0;
  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
  TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);

  TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
  TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Disable;
  TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
  TIM_OCInitStructure.TIM_Pulse = 500;
  TIM_OC1Init(TIM1, &TIM_OCInitStructure);

  TIM_DMACmd(TIM1, TIM_DMA_CC2, ENABLE);

  DMA_Cmd(DMA2_Stream2, DISABLE);
  DMA1->LIFCR |= DMA_LIFCR_CDMEIF2 | DMA_LIFCR_CFEIF2 |
	 DMA_LIFCR_CHTIF2 | DMA_LIFCR_CTCIF2 | DMA_LIFCR_CTEIF2;
  DMA_DeInit(DMA2_Stream2);
  DMA_StructInit(&DMA_InitStructure);
  DMA_InitStructure.DMA_PeripheralBaseAddr = (unsigned int)&(GPIOD->ODR);
  DMA_InitStructure.DMA_Memory0BaseAddr = (unsigned int)&Buffer;
  DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;
  DMA_InitStructure.DMA_BufferSize = 640;
  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
  DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
  DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
  DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
  DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
  DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
  DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
  DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
  DMA_InitStructure.DMA_Channel = DMA_Channel_6;

  DMA_Init(DMA2_Stream2, &DMA_InitStructure);
  DMA_ITConfig(DMA2_Stream2, DMA_IT_TC | DMA_IT_TE, ENABLE);
  DMA_Cmd(DMA2_Stream2, ENABLE);

  TIM_Cmd(TIM1, ENABLE);

  GPIO_SetBits(GPIOD, GPIO_Pin_All);
  GPIO_ResetBits(GPIOD, GPIO_Pin_12 | GPIO_Pin_14);

while(1)
{
   GPIO_ResetBits(GPIOD, GPIO_Pin_12 | GPIO_Pin_14);
}
}

void DMA2_Stream2_IRQHandler(void) {
  TIM1->CR1 &= ~TIM_CR1_CEN;
  if (DMA2->LISR & DMA_LISR_TEIF2)
  GPIO_SetBits(GPIOD, GPIO_Pin_14);
  if (DMA2->LISR & DMA_LISR_TCIF2) {
  GPIO_SetBits(GPIOD, GPIO_Pin_12);
  DMA2_Stream2->M0AR = (unsigned int)&Buffer;
  DMA2_Stream2->CR |= DMA_SxCR_EN;
  }
  DMA_ClearITPendingBit(DMA2_Stream2, DMA_IT_TC | DMA_IT_TE);
  TIM1->CR1 |= TIM_CR1_CEN;
}

void assert_param(unsigned int error) {
 ;
}

 

В общем я в замешательстве, errata по поводу этой ошибки ничего не говорит, гугл тоже.

Изменено пользователем IgorKossak
[codebox] для длинного кода!!!

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


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

См. мануал: Figure 1. System architecture и Figure 22. System implementation of two DMA controllers.

DMA1 не имеет связи с AHB1, а GPIO как раз там.

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


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

Спасибо, опять моя невнимательность сыграла со мной злую шутку.

Изменено пользователем IgorKossak
бездумное цитирование

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


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

Спасибо, опять моя невнимательность сыграла со мной злую шутку.

Это не только невнимательность, ST эмщики как будто специально скрывали в даташите этот недостаток. В разделе про DMA ни слова и поди догадайся про это, где-то там в другом конце шита на рисунке линии не проведено и все!!!

Я тоже долго ломал голову, пока не нашел презентацию этого МК, где про это говорилось, тогда уже и отсутствие линии досмотрел.

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


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

Это не только невнимательность, ST эмщики как будто специально скрывали в даташите этот недостаток. В разделе про DMA ни слова и поди догадайся про это, где-то там в другом конце шита на рисунке линии не проведено и все!!!

Я тоже долго ломал голову, пока не нашел презентацию этого МК, где про это говорилось, тогда уже и отсутствие линии досмотрел.

Вообще очень странно что в топовом контроллере полноценным(работающим по схеме память-память) DMA является только DMA2. Т.е по сути это накладывает кучу гемороя и пустого расхода таймеров.

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


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

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

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

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

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

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

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

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

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

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