cancel
Showing results for 
Search instead for 
Did you mean: 

Data transfer from GPIO port to RAM buffer using DMA upon receiving a trigger signal on the timer capture input channel.

vimal
Associate
Posted on August 07, 2013 at 06:47

  1. Our requirement is to configure the DMA so that it transfers data from the GPIO lines (8 bit data lines) to the RAM buffer upon receiving a trigger signal on the timer capture input channel.

  2. We had received an example code from ST for the F1 series controllers and the  code is attached. The code works fine with the F1 discovery board. Now we are trying to do the same thing on the F4 board. We have implemented the same configurations for F4 board and tried with F4 discovery board but the DMA data transfer doesn�t happen.The code for F4 is also attached.

  3. The code file is attached. Please note that we have used standard peripheral library functions from ST. Can you please go through our configurations and point out errors? Or send the useful example which can fulfill our requirements.

#data-transfer-using-dma
19 REPLIES 19
munger
Associate II
Posted on June 04, 2014 at 21:52

In the end we couldn't get it to work via DMA. We are bit-banging the 4 channels of 14 bit ADC data and reassembling it after we have it all. We can read the 4 channels in something like 3 us. It's not pretty but for what we are doing ... it works.

adeelm4
Associate
Posted on July 09, 2015 at 17:41

The original post was too long to process during our migration. Please click on the provided URL to read the original post. https://st--c.eu10.content.force.com/sfc/dist/version/download/?oid=00Db0000000YtG6&ids=0680X000006I6gt&d=%2Fa%2F0X0000000btK%2F4gmhhFUIRkRodIFrEA790Eg1kbV0pdlxLvLudlwP6Pw&asPdf=false
Posted on July 09, 2015 at 18:56

Don't enable the TIM8 interrupt, 10 MHz isn't viable.

Check the repetition count setting for TIM8

Show me the logic analyzer traces for the GPIO. Have the 90 MHz signal coming out of the STM32F4 via PA8 (MCO) configured to be half the PLL as one of the traces.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
yuanchen
Associate II
Posted on November 14, 2015 at 00:05

Hello Clive1,

I'm also working on triggering a DMA interrupt on the timer input capture channel. The problem is that the interrupt service routine never gets executed. Could you take a look at my code and point out any potential problems?

Thanks in advance.

I'm using PD12 as my output, TIM4 Channel 2. Thus I use DMA1 stream 3. 

void InitializeTimer4()

   TIM_TimeBaseInitTypeDef timerInitStructure; 

   RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);

    timerInitStructure.TIM_Prescaler =8400-1;  //timer tick freqeuncy is 10kHz

    timerInitStructure.TIM_CounterMode = TIM_CounterMode_Up;

    timerInitStructure.TIM_Period = 10000-1;//PWM freq = 1Hz

    timerInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;

    timerInitStructure.TIM_RepetitionCounter = 0;

    TIM_TimeBaseInit(TIM4, &timerInitStructure);

  //  TIM_TIxExternalClockConfig(TIM4, TIM_TIxExternalCLK1Source_TI1, TIM_ICPolarity_Rising, 0);

    TIM_Cmd(TIM4, ENABLE);

    

}

void InitializeInputCapture()

{

   TIM_ICInitTypeDef TIM_CH1_ICInitStructure;

   TIM_CH1_ICInitStructure.TIM_Channel = TIM_Channel_1;

   TIM_CH1_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;

   TIM_CH1_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;

   TIM_CH1_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;

   TIM_CH1_ICInitStructure.TIM_ICFilter = 0;

   TIM_PWMIConfig(TIM4, &TIM_CH1_ICInitStructure);  

   TIM_SelectInputTrigger(TIM4, TIM_TS_TI1FP1);

   TIM_CtrlPWMOutputs(TIM4, ENABLE);

   /* Select the slave Mode: Reset Mode */

  // TIM_SelectSlaveMode(TIM4, TIM_SlaveMode_Reset);

   //TIM_SelectMasterSlaveMode(TIM4,TIM_MasterSlaveMode_Enable);

  // TIM_ITConfig(TIM4, TIM_IT_CC1, ENABLE);

    //TIM_DMAConfig(TIM4, TIM_DMABase_CCR2, TIM_DMABurstLength_1Transfer);      

    TIM_DMACmd(TIM4, TIM_DMA_CC1, ENABLE);

}

void EnableDMA1Interrupt()

{

    NVIC_InitTypeDef nvicStructure;

    nvicStructure.NVIC_IRQChannel = DMA1_Stream3_IRQn;

    nvicStructure.NVIC_IRQChannelPreemptionPriority = 0;

    nvicStructure.NVIC_IRQChannelSubPriority = 1;

    nvicStructure.NVIC_IRQChannelCmd = ENABLE;

    NVIC_Init(&nvicStructure);

}

void DMA1_Stream3_IRQHandler()

{

   if (DMA_GetITStatus(DMA1_Stream3, DMA_IT_TCIF1) != RESET)

   {

     DMA_ClearITPendingBit(DMA1_Stream3, DMA_IT_TCIF1);

      count ++;  

    GPIO_ToggleBits(GPIOD, GPIO_Pin_12);

  }

}

uint8_t buffer[8] = { 0 };

void DMA_init()

{

    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE);

    DMA_InitTypeDef DMA_InitStruct;

    DMA_DeInit(DMA1_Stream3);

    DMA_StructInit(&DMA_InitStruct);  //initialize to default

    DMA_InitStruct.DMA_Channel = DMA_Channel_2;

    DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t)&GPIOD->ODR;

    DMA_InitStruct.DMA_Memory0BaseAddr = (uint32_t)&buffer;

    DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralToMemory;

    DMA_InitStruct.DMA_BufferSize = 8;

    DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable;

    DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable;

    DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;

    DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;

    DMA_InitStruct.DMA_Mode = DMA_Mode_Circular; 

    DMA_InitStruct.DMA_Priority = DMA_Priority_High;

    DMA_InitStruct.DMA_FIFOMode = DMA_FIFOMode_Disable;

    DMA_InitStruct.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;

    DMA_InitStruct.DMA_MemoryBurst = DMA_MemoryBurst_Single;

    DMA_InitStruct.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;

    DMA_Init(DMA1_Stream3, &DMA_InitStruct); 

    DMA_ITConfig(DMA1_Stream3, DMA_IT_TC, ENABLE);  

    DMA_Cmd(DMA1_Stream3, ENABLE);  

   // TIM_SelectCCDMA(TIM4, ENABLE);

}

Posted on November 14, 2015 at 00:26

Per earlier posts, you need to use DMA2

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
yuanchen
Associate II
Posted on November 16, 2015 at 20:35

What's the difference between using DMA1 and DMA2? From datasheet I can only conclude they allow DMA2 uses APB2 which has twice the frequency.

Anyway, I used DMA2_stream6 with TIM1_ch1 but it didn't work. I'm using an IDE and it seems that the interrupt can't be triggered. I copy and pasted your code above under this thread and the code didn't work either. 

Posted on November 16, 2015 at 21:30

I copy and pasted your code above under this thread and the code didn't work either.

''Externally strap PA8 to PB4''

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Posted on November 16, 2015 at 21:39

Are you using a .CPP file?

TIM8 Example to end of [DEAD LINK /public/STe2ecommunities/mcu/Lists/cortex_mx_stm32/Flat.aspx?RootFolder=/public/STe2ecommunities/mcu/Lists/cortex_mx_stm32/DMA%20MemoryToMemory%20using%20Timer%20for%20delivery%20rate&FolderCTID=0x01200200770978C69A1141439FE559EB459D7580009C4E14902C3CDE46A77F0FFD06506F5B&currentviews=725]this thread

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Posted on November 16, 2015 at 21:51

I don't have a board to hand, this is a quick blind mod

// STM32F4 DMA GPIO OUT - sourcer32@gmail.com
// Per RM0090 DMA2, Channel6, Stream5 correlates to TIM1_UP source
// 2 KHz clock generated on TIM1_UP (Update - Timebase Period)
// Should be able to measure 1 KHz on PD[0..7] with 0x00/0xFF data pattern
#include ''stm32f4_discovery.h''
#define BufferSize 1000 // Samples at 2 KHz, loops at 2 Hz
uint8_t GPIO_DATA[BufferSize];
/*******************************************************************************
* Function Name : GPIOD Configuration
* Description : GPIO PORT configurations in such a way that so it status can be read
* Input : None
* Output : None
* Return : None
*******************************************************************************/
void GPIOD_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE); /* GPIOD clock enable */
GPIO_InitStructure.GPIO_Pin = 0xFF; // Pin0 .. Pin7
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOD, &GPIO_InitStructure);
}
/*******************************************************************************
* Function Name : Timer1 configurations
* Description : Configure Timer8 in such a way that it can initiate data transfer using DMA
* Input : None
* Output : None
* Return : None
*******************************************************************************/
void TIM1_Configuration(void)
{
#define TIM1_PERIOD (500-1) /* Timer 1 PWM period 2 KHz */
#define TIM1_PRESCALER (168-1) /* Timer 1 prescaler 1 MHz */
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE); /* TIM1 clock enable */
TIM_TimeBaseStructure.TIM_Period = TIM1_PERIOD;
TIM_TimeBaseStructure.TIM_Prescaler = TIM1_PRESCALER;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure); /* Time base configuration */
TIM_ARRPreloadConfig(TIM1, ENABLE); /* Enable the time autoreload register */
TIM_Cmd(TIM1, ENABLE); /* TIM enable counter */
TIM_DMACmd(TIM1, TIM_DMA_Update, ENABLE); /* Enable TIM1_UP DMA Requests */
}
/*******************************************************************************
* Function Name : DMA2 configuration
* Description : Transfer Data to peripheral port (GPIOD) from RAM buffer
* Input : None
* Output : None
* Return : None
*******************************************************************************/
void DMA2_Configuration(void)
{
DMA_InitTypeDef DMA_InitStructure;
/* Enable the DMA clock */
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);
/* Configure the DMA Stream */
DMA_Cmd(DMA2_Stream5, DISABLE);
DMA_DeInit(DMA2_Stream5);
/* Set the parameters to be configured */
DMA_InitStructure.DMA_Channel = DMA_Channel_6;
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&GPIO_DATA[0]; /* Read the data from the RAM buffer */
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&GPIOD->ODR; /* Send GPIO output data register */
DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;
DMA_InitStructure.DMA_BufferSize = BufferSize;
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_Circular;
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Enable;
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
DMA_Init(DMA2_Stream5, &DMA_InitStructure);
/* Enable DMA Transfer Complete interrupt */
DMA_ITConfig(DMA2_Stream5, DMA_IT_TC, ENABLE);
DMA_Cmd(DMA2_Stream5, ENABLE);
}
/**************************************************************************************/
void NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
/* Enable the DMA Stream IRQ Channel */
NVIC_InitStructure.NVIC_IRQChannel = DMA2_Stream5_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
/**************************************************************************************/
void DMA2_Stream5_IRQHandler(void) // 2 Hz - for CPP use extern ''C''
{
/* Test on DMA Stream Transfer Complete interrupt */
if (DMA_GetITStatus(DMA2_Stream5, DMA_IT_TCIF5))
{
/* Clear DMA Stream Transfer Complete interrupt pending bit */
DMA_ClearITPendingBit(DMA2_Stream5, DMA_IT_TCIF5);
/* Toggle LED3 : End of Transfer */
STM_EVAL_LEDToggle(LED3);
// Add code here to process things
}
}
/**************************************************************************************/
int main(void)
{
int i;
for(i=0;i<BufferSize; i++)
{
if((i % 2) == 0)
GPIO_DATA[i] = 0;
else
GPIO_DATA[i] = 0xFF;
}
GPIOD_Configuration();
NVIC_Configuration();
DMA2_Configuration();
TIM1_Configuration();
STM_EVAL_LEDInit(LED3); /* Configure LEDs to monitor program status */
STM_EVAL_LEDOn(LED3); /* Turn LED3 on, 1 Hz means it working */
while(1); // Don't want to exit
}
/**************************************************************************************/
#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t* file, uint32_t line)
{
/* User can add his own implementation to report the file name and line number,
ex: printf(''Wrong parameters value: file %s on line %d

'', file, line) */
/* Infinite loop */
while (1)
{
}
}
#endif

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
yuanchen
Associate II
Posted on November 16, 2015 at 23:44

Alright i figured out the problem. 

Since I'm transferring data from peripheral register (ODR) to  a memory location, I should actually use MemoryToMemory mode in my DMA initialization setting. This is also the reason I should only use DMA2 instead of DMA1 because DMA1 doesn't support M2M transaction. 

Still, thank you for your code example Clive1.