cancel
Showing results for 
Search instead for 
Did you mean: 

DMA tranfer from GPIO IDR to RAM

leonlawww
Associate II
Posted on January 27, 2015 at 14:10

I'm new to STM32 board.

Working with F103C8, currently I could use TIM2 (24M) as trigger source to start DMA1 to transfer data from GPIOB->IDR(15:0) to RAM. However I found the speed is no more than 8MHz during the DMA transfer process, and info-loss occurs sometimes.

Is it possible to achieve a 12MHz or higher speed(cause input data in GPIO pins vary in 12MHz or higher speed) data-transfer from GPIO pins to RAM using DMA on F103C8 ? If not, is there any other ways to achieve it(with or without DMA) on F103C8 ?

#gpio #dma #speed
7 REPLIES 7
Uwe Bonnes
Principal III
Posted on January 27, 2015 at 14:53

What Clock frequncy do you have? Is your timer running at highest possible frequency? DMA events need synchronisation clock cycles and with higher clock less time is needed for that synchronisation.

Posted on January 27, 2015 at 15:03

Would DMA2 clock quicker?

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
leonlawww
Associate II
Posted on January 28, 2015 at 13:12

My trigger clock frequency is 24MHz, and I connect PA6 with PB0 on my board to change GPIOB->IDR data in a 1MHz frequency, and monitor GPIOB->IDR data using GPIO_DATA[] array.

Below is my test code:

#include ''stm32f10x.h''
#define BufferSize 1600
uint16_t GPIO_DATA[BufferSize];

void RCC_Configuration(void)
{
 // clock for DMA
 RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
 // clock for TIM2
 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2 | RCC_APB1Periph_TIM3, ENABLE);
 // clock for GPIO
 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE);
}

void GPIO_Configuration(void)
{
 GPIO_InitTypeDef GPIO_InitStructure;
 
 /* Init PB0-PB15 for DMA source */
 GPIO_InitStructure.GPIO_Pin = 0xFFFF; //Pin0 .. Pin15
 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;
 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
 GPIO_Init(GPIOB,&GPIO_InitStructure);
 
 /* Configure TIM3 Channel1 PWM output */
 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; 
 GPIO_Init(GPIOA, &GPIO_InitStructure);
}

void PWM_Configuration(void){
 TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
 TIM_OCInitTypeDef TIM_OCInitStructure;
 
 /* Time Base configuration */
 TIM_DeInit(TIM3); 
 TIM_InternalClockConfig(TIM3); 
 TIM_TimeBaseStructure.TIM_Prescaler = 0; 
 TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; 
 TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
 TIM_TimeBaseStructure.TIM_Period = 71; 
 TIM_TimeBaseInit(TIM3,&TIM_TimeBaseStructure); 
 
 /* Channel1 Configuration in PWM mode */
 TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; 
 TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; 
 
 TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; 
 TIM_OCInitStructure.TIM_Pulse = 36;
 TIM_OC1Init(TIM3, &TIM_OCInitStructure); 
 TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Enable); 
 
 TIM_Cmd(TIM3, ENABLE); 
}
void DMA_Configuration(void)
{
 DMA_InitTypeDef DMA_InitStructure;
 DMA_DeInit(DMA1_Channel2);
 DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&GPIOB->IDR;
 DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)GPIO_DATA; 
 DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
 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_HalfWord;
 DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
 DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
 DMA_InitStructure.DMA_Priority = DMA_Priority_High;
 DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
 DMA_Init(DMA1_Channel2, &DMA_InitStructure);
 DMA_ITConfig(DMA1_Channel2, DMA_IT_TC, ENABLE);
 DMA_Cmd(DMA1_Channel2, ENABLE);
}

void TIM2_Configuration(void)
{
 TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
 TIM_TimeBaseStructure.TIM_Prescaler = 0; 
 TIM_TimeBaseStructure.TIM_Period = 3; // 24M
 TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
 TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
 TIM_TimeBaseStructure.TIM_RepetitionCounter = 1;
 TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
 TIM_DMACmd(TIM2, TIM_DMA_Update, ENABLE);

 TIM_Cmd(TIM2, ENABLE);
}

int main(void)
{
 RCC_Configuration();
 GPIO_Configuration();
 PWM_Configuration();
 DMA_Configuration();
 TIM2_Configuration();
 while(1){
 };
}
 
 

leonlawww
Associate II
Posted on January 28, 2015 at 13:26

Clive,thanks for your advice, I've modify my test code to enable DMA2, but it doesn't work. I'm using F103C8 whose flash is 64K, I'm not sure whether it has DMA2 module.

Below is my test code, I don't know why it doesn't work:

#include ''stm32f10x.h''
#define BufferSize 1600
uint16_t GPIO_DATA[BufferSize]; 
void RCC_Configuration(void)
{
// clock for DMA
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA2, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5 | RCC_APB1Periph_TIM3, ENABLE);
// clock for GPIO
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE);
}
void GPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
//Init PB0-PB7 for DMA source
GPIO_InitStructure.GPIO_Pin = 0xFFFF; //Pin0 .. Pin15
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB,&GPIO_InitStructure);
/* Configure TIM3 Channel1 PWM output */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; 
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
void PWM_Configuration(void){
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
/* Time Base configuration */
TIM_DeInit(TIM3); 
TIM_InternalClockConfig(TIM3); 
TIM_TimeBaseStructure.TIM_Prescaler = 0; 
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; 
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; 
TIM_TimeBaseStructure.TIM_Period = 71; 
TIM_TimeBaseInit(TIM3,&TIM_TimeBaseStructure); 
/* Channel1 Configuration in PWM mode */
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; 
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; 
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; 
TIM_OCInitStructure.TIM_Pulse = 36; 
TIM_OC1Init(TIM3, &TIM_OCInitStructure); 
TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Enable); 
TIM_Cmd(TIM3, ENABLE); 
}
void DMA_Configuration(void)
{
DMA_InitTypeDef DMA_InitStructure;
DMA_DeInit(DMA2_Channel2);
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&GPIOB->IDR; // Source
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)GPIO_DATA; // Destination
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
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_HalfWord;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; 
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; // So we can pace via trigger
DMA_Init(DMA2_Channel2, &DMA_InitStructure);
DMA_ITConfig(DMA2_Channel2, DMA_IT_TC, ENABLE);
DMA_Cmd(DMA2_Channel2, ENABLE);
}
void TIM_Configuration(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_TimeBaseStructure.TIM_Prescaler = 0; 
TIM_TimeBaseStructure.TIM_Period = 2; // 24M
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseStructure.TIM_RepetitionCounter = 1;
TIM_TimeBaseInit(TIM5, &TIM_TimeBaseStructure);
// ''connecting'' DMA and TIM5
TIM_DMACmd(TIM5, TIM_DMA_Update, ENABLE);
// turning on TIM5
TIM_Cmd(TIM5, ENABLE);
}
int main(void)
{ 
RCC_Configuration();
GPIO_Configuration();
PWM_Configuration();
DMA_Configuration();
TIM_Configuration();
while(1){
};
}

Posted on January 28, 2015 at 13:50

Ok.

You caught the

TIM_TimeBaseStructure.TIM_Period = 3-1; // 24M

So you enabled a TC interrupt, but I don't see any service code. If you toggle a GPIO at TC what frequency do you observe? What data are you observing for the looped back 1 MHz? 24 MHz be a bit aggressive, I'd think the saturation point of the bus is going to be somewhat lower than that. I haven't actively used F1 parts in years. On other parts the DCMI offers quite a fast parallel capture, but not at 16-bit. Other examples with fast capture could use an external FIFO, like the ones stuck on CMOS Cameras.
Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
leonlawww
Associate II
Posted on January 28, 2015 at 14:48

Sorry for my unclear description. No TC interrupt are used, in fact, I'm using a F103 develop board, and I init a 1MHz PWM using TIM3 and output it in PA6. Then I connect PA6 with PB0 using a DuPont line, so the content of GPIOB->IDR varies in 1MHz frequency. At last I use DMA which trigged by TIM5(24MHz clock) to store GPIOB->IDR into GPIO_DATA[] array. So I could check DMA speed by observe GPIO_DATA[], it should be in a period of 12 low data then 12 high data if 24M speed DMA is available for my dev board.

BTW: 24MHz is just a test, my requirement is 12MHz while the result after my experiment shows only 7MHz.

Posted on January 28, 2015 at 15:16

What is the system clock and how is the system bus and the DMA controller loaded (i.e. what other ''processes'' do you expect to run simultaneously)?

How do you expect to process the captured data?

Also, the 'F1 line is slightly obsolete and has certain limitations, e.g. GPIO is on APB, i.e. behind a bridge. You might want to consider 'F2 perhaps, or even 'F4, which would allow also higher system clocks.

JW