2013-09-10 03:08 AM
Hi guys,
I'm having a few issues setting of a DMA transfer based on a timer and hoping someone might be able to point out where I'm going wrong. I have a timer (timer 2) which is set to 50 Hz and as far as I can tell, this timer is associated with DMA1 Ch2 if I want to use the Timer2_Update? (Chip is STM32F103ZG). The timer seems to be successfully triggering the DMA, but not at the 50 Hz rate I'm looking for. My timer code looks like this: void Timer2_config(void){ GPIO_Digital_Output(GPIOF_BASE, _GPIO_PINMASK_ALL); // Enable digital output on PORTE GPIOF_ODR = 0; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE); GPIO_StructInit(&GPIO_InitStructure); GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; GPIO_Init(GPIOA, &GPIO_InitStructure); RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); RCC_APB1ENR.TIM2EN = 1; TIM2_CR1.CEN = 0; TIM2_PSC = 72; TIM2_ARR = 10000; //TIM_OCInitTypeDef TIM_OCInitStructure; TIM_OCStructInit(&TIM_OCInitStructure); TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Toggle; TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; TIM_OC2Init(TIM2, &TIM_OCInitStructure); //NVIC_IntEnable(IVT_INT_TIM2); // Enable timer interrupt TIM_DMACmd(TIM2, TIM_DMA_CC2, ENABLE); //TIM2_CR2.CCDS=1; TIM2_CR1.CEN = 1; } Whilst my DMA is configured like this: void DMA1Config(void){ /* Configure clock for DMA Controller */ RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE); /* Deintialize DMA Channels */ DMA_DeInit(DMA1_Channel2); DMA1_CCR2.EN = 0; DMA1_CCR2.DIR_ = 0; //READ FROM PERIPHERAL DMA1_CCR2.CIRC = 0; //CIRCULAR MODE DISABLED (NORMAL MODE) DMA1_CCR2.PINC = 0; //PERIPHERAL INCREMENT MODE DISABLED DMA1_CCR2.MINC = 0; //MEMORY INCREMENT MODE DISABLED DMA1_CCR2.PSIZE0 = 1; //SET PERIPHERAL SIZE TO 16 BITS DMA1_CCR2.PSIZE1 = 0; //SET PERIPHERAL SIZE TO 16 BITS DMA1_CCR2.MSIZE0 = 1; //SET MEMORY SIZE TO 16 BITS DMA1_CCR2.MSIZE1 = 0; //SET MEMORY SIZE TO 16 BITS DMA1_CCR2.PL0 = 0; //SET CHANNEL PRIORITY HIGH DMA1_CCR2.PL1 = 1; //SET CHANNEL PRORITY HIGH DMA1_CCR2.MEM2MEM = 1; //ENABLE MEM2MEM MODE DMA1_CNDTR2 = 2; DMA1_CPAR2 = (uint32_t)DummyDisplayBuffer; NVIC_IntEnable(IVT_INT_DMA1_Channel2); DMA1_CCR2.TCIE = 1; DMA1_CCR2.EN = 1; } The DMA transfer complete interrupt simply toggles an LED so I can see the speed it's transferring at.2013-09-10 07:42 AM
// STM32 TIM2 DMA Mem-to-Mem pacing VLDiscovery - sourcer32@gmail.com
#include ''STM32vldiscovery.h''
#define OUTLENGTH 5
volatile u16 InBuffer[OUTLENGTH], OutBuffer[OUTLENGTH];
/**************************************************************************************/
void RCC_Configuration(void)
{
// clock for DMA
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
// clock for TIM2
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
}
/**************************************************************************************/
void NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
/******************************************************************************/
void DMA1_Channel2_IRQHandler(void) // Called at 10 Hz
{
if (DMA_GetITStatus(DMA1_IT_TC2))
{
DMA_ClearITPendingBit(DMA1_IT_TC2);
STM32vldiscovery_LEDToggle(LED3); // Toggle 5 Hz
STM32vldiscovery_LEDToggle(LED4);
// Do something
}
}
/**************************************************************************************/
void DMA_Configuration(void)
{
DMA_InitTypeDef DMA_InitStructure;
DMA_DeInit(DMA1_Channel2);
DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&InBuffer[0]; // Source
DMA_InitStructure.DMA_MemoryBaseAddr = (u32)&OutBuffer[0]; // Destination
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
DMA_InitStructure.DMA_BufferSize = OUTLENGTH;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Enable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; // Repetitive, for my convenience
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; // So we can pace via trigger
DMA_Init(DMA1_Channel2, &DMA_InitStructure);
/* Enable DMA1 Channel2 Transfer Complete interrupt */
DMA_ITConfig(DMA1_Channel2, DMA_IT_TC, ENABLE);
// turning DMA on (DMA1 Channel2 -> TIM2_UP)
DMA_Cmd(DMA1_Channel2, ENABLE);
}
/**************************************************************************************/
void TIM2_Configuration(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_TimeBaseStructure.TIM_Prescaler = (SystemCoreClock / 1000000) - 1; // 1 MHz
TIM_TimeBaseStructure.TIM_Period = 20000-1; // 1MHz/20000 = 50 Hz
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseStructure.TIM_RepetitionCounter = 1;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
// ''connecting'' DMA and TIM2
TIM_DMACmd(TIM2, TIM_DMA_Update, ENABLE);
// turning on TIM2
TIM_Cmd(TIM2, ENABLE);
}
/**************************************************************************************/
int main(void)
{
/* Initialise LEDs LD3 & LD4 */
STM32vldiscovery_LEDInit(LED3);
STM32vldiscovery_LEDInit(LED4);
STM32vldiscovery_LEDOn(LED3);
STM32vldiscovery_LEDOff(LED4);
RCC_Configuration();
NVIC_Configuration();
DMA_Configuration();
TIM2_Configuration();
while(1);
}
2013-09-10 08:18 AM
Great, thanks Clive! Only major difference I'm noticing is that your code seems to indicate that Mem2Mem isn't possible when trying to trigger DMA with a timer. Is that the case?
2013-09-10 08:34 AM
If you use DMA_M2M_Enable it will try to do so as rapidly as possible, as it ignores all peripheral side inputs.
From RM0008''Memory-to-memory modeThe DMA channels can also work without being triggered by a request from a peripheral.
This mode is called Memory to Memory mode.
If the MEM2MEM bit in the DMA_CCRx register is set, then the channel initiates transfers as soon as it is enabled by software by setting the Enable bit (EN) in the DMA_CCRx register.''
That, and I program the timers with N-1 values to get the timing correct, and use the time base update rather than a channel.
2015-05-23 11:04 AM
Sorry to revive this post but I'm trying to trigger DMA with a timer as the owner post.
My board is a STM32F4 The problem i get is that when I enable the TIM3, the timer which enables a dma transfer I get a Tranfer Errror Interrupt Flag right away. Code:void DMA_Config(void){
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
NVIC_InitTypeDef NVIC_InitStructure;
DMA_InitTypeDef DMA_InitStructure;
__IO uint32_t Timeout = 50000;
int i;
/* Enable DMA clock & TIM3 Clock*/
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3 ,ENABLE);
/*
Time base configuration
Frequency of 18Mhz
*/
TIM_TimeBaseStructure.TIM_Period = 20 - 1;
TIM_TimeBaseStructure.TIM_Prescaler = 0;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
//TIM_Cmd(TIM3, ENABLE); /* TIM enable counter */ //MUDAR POSICAO
TIM_DMACmd(TIM3, TIM_DMA_Update, ENABLE ); /* Enable TIM3_Updates DMA Requests */
//SET COUNTER TO 1
/* Reset DMA Stream registers (for debug purpose) */
DMA_DeInit(DMA1_Stream2);
/* Configure DMA Stream */
DMA_InitStructure.DMA_Channel = DMA_Channel_5;
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&(GPIOB->ODR); //dest
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)fb; //source
DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;
DMA_InitStructure.DMA_BufferSize = (uint32_t)VTOTAL;
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_Mode = DMA_Mode_Normal;
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
DMA_Init(DMA1_Stream2, &DMA_InitStructure);
/* Enable DMA Stream Transfer Complete interrupt */
DMA_ITConfig(DMA1_Stream2, DMA_IT_TC, ENABLE);
DMA_Cmd(DMA1_Stream2,ENABLE);
Timeout = 50000;
while ((DMA_GetCmdStatus(DMA1_Stream2) != ENABLE) && (Timeout-- > 0))
{
}
/* Check if a timeout condition occurred */
if (Timeout == 0)
{
/* Manage the error: to simplify the code enter an infinite loop */
while (1)
{
}
}
/* Enable the DMA Stream IRQ Channel */
NVIC_InitStructure.NVIC_IRQChannel = DMA1_Stream2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
TIM_Cmd(TIM3,ENABLE);
}
It's really strange since from reference manual TIM3_UP -> DMA1 Stream2 Channel 5
Thanks a lot in advance
Edit: GPIOB clock is enabled
2015-05-23 12:33 PM
I think I found the problem to be in:
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&(GPIOB->ODR);I tried a diferent address based on 0x400000xx and the dma wrote with sucess.I still don´t know why the dma does not write to GPIOB ODR or how to solve it :(.Edit: From RM0090 I found that DMA1 does not has access to AHB1 Peripherals. I think I have to change to DM2 to solve the problem2015-05-23 02:21 PM
I've covered F4 GPIO + DMA + TIM (Internal and External) on the forum at various times.
2015-05-23 03:21 PM
Hi clive,
Thanks, i already saw that post on month ago but I did not remember it.Anyway, I need to do the oposite thing and write to the GPIO. I also need to do it at 18Mhz speed. Is this achivable with stm32f407 at 144Mhz?I'm trying but when I try to get my timer to high speed I see a FIFO error, and I believe it's because the DMA can not transfer everything.Thanks2015-05-23 03:58 PM
Also the DMA is disabling itself after the first entry on the iterrupt without giving an fifo error in this case:
void DMA_Config(void){
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
NVIC_InitTypeDef NVIC_InitStructure;
DMA_InitTypeDef DMA_InitStructure;
GPIO_InitTypeDef GPIO_InitStrucuture;
__IO uint32_t Timeout = 50000;
int i;
/* Enable DMA clock & TIM3 Clock*/
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM8 ,ENABLE);
//RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
/*Enable GPIOB Pins as digital output*/
/*
Time base configuration
Frequency of 18Mhz
*/
TIM_TimeBaseStructure.TIM_Period = 5000-1;
TIM_TimeBaseStructure.TIM_Prescaler = 0; //Not sure if 144Mhz timer
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM8, &TIM_TimeBaseStructure);
TIM_DMACmd(TIM8, TIM_DMA_Update, ENABLE ); /* Enable TIM3_Updates DMA Requests */
//SET COUNTER
/* Reset DMA Stream registers (for debug purpose) */
DMA_DeInit(DMA2_Stream2);
/* Configure DMA Stream */
DMA_InitStructure.DMA_Channel = DMA_Channel_7;
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&(GPIOB->ODR); //;0x40000010 &(GPIOB->ODR)//dest
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)fb; //source
DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;
DMA_InitStructure.DMA_BufferSize = (uint32_t)VTOTAL;
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_Mode = DMA_Mode_Normal;
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
DMA_Init(DMA2_Stream1, &DMA_InitStructure);
/* Enable DMA Stream Transfer Complete interrupt */
DMA_ITConfig(DMA2_Stream1, DMA_IT_TC, ENABLE);
DMA_Cmd(DMA2_Stream1,ENABLE);
/* Enable DAC Channel2 */
Timeout = 50000;
while ((DMA_GetCmdStatus(DMA2_Stream1) != ENABLE) && (Timeout-- > 0))
{
}
/* Check if a timeout condition occurred */
if (Timeout == 0)
{
/* Manage the error: to simplify the code enter an infinite loop */
while (1)
{
}
}
/* Enable the DMA Stream IRQ Channel */
NVIC_InitStructure.NVIC_IRQChannel = DMA2_Stream1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
TIM_Cmd(TIM8,ENABLE);
}
void DMA2_Stream1_IRQHandler(void)
{
TIM8->CR1 &= ~0x1; //Disable Timer Stop trigger
DMA2->LIFCR = 0xC00; //Clear IT HT Flag from stream 1 DMA 2
DMA2_Stream1->NDTR = VTOTAL - 1; //Reload Bytes to send !!!!! not sure about -1 !!!!
}