DMA : Timer Trigger Memory-to-memory mode,
The 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."
// 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); }