Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: STM32F407(417) rev A DMA1 problem
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
nis
Для одного из проектов протребовалось использовать DMA вместе с таймером 2.

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

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

Исходный код тестовой программы приведён внизу, также приложен архив с проектом (Coocox, GNU GCC).
CODE
#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 всё проходит как надо:
CODE
#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 по поводу этой ошибки ничего не говорит, гугл тоже.
Flexz
См. мануал: Figure 1. System architecture и Figure 22. System implementation of two DMA controllers.
DMA1 не имеет связи с AHB1, а GPIO как раз там.
nis
Спасибо, опять моя невнимательность сыграла со мной злую шутку.
Tolyaha
Цитата(nis @ Oct 16 2012, 20:54) *
Спасибо, опять моя невнимательность сыграла со мной злую шутку.

Это не только невнимательность, ST эмщики как будто специально скрывали в даташите этот недостаток. В разделе про DMA ни слова и поди догадайся про это, где-то там в другом конце шита на рисунке линии не проведено и все!!!
Я тоже долго ломал голову, пока не нашел презентацию этого МК, где про это говорилось, тогда уже и отсутствие линии досмотрел.
nis
Цитата(Tolyaha @ Oct 18 2012, 16:56) *
Это не только невнимательность, ST эмщики как будто специально скрывали в даташите этот недостаток. В разделе про DMA ни слова и поди догадайся про это, где-то там в другом конце шита на рисунке линии не проведено и все!!!
Я тоже долго ломал голову, пока не нашел презентацию этого МК, где про это говорилось, тогда уже и отсутствие линии досмотрел.

Вообще очень странно что в топовом контроллере полноценным(работающим по схеме память-память) DMA является только DMA2. Т.е по сути это накладывает кучу гемороя и пустого расхода таймеров.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.