cancel
Showing results for 
Search instead for 
Did you mean: 

I get STM32F103 DMA speed of 160 bytes in 1600 clock cycles => 1 transfer every 10 clock cycles. What else is contending the bus? Just seems a bit slow.

Elektraglide
Associate III

This from a project I've been building color display output blogged here:

https://medium.com/@adambillyard/experiments-in-hard-realtime-35136ed79398

15 REPLIES 15
Elektraglide
Associate III

0693W00000HnXDYQA3.pngAll my PWM calculations are based on a 72MHz timer and the scope confirms I get precisely what I expect (2us pulse width), so I believe APB2 is running at full speed.

We have no idea what do you display on that scope.

For the DMA, read AN2548. As the write is traversing an AHB-to-APB bridge, the pattern is different than with AHB-to-AHB. Detailed timing of this are unfortunately not trivial. Also, AN2548 does not deal in detail with timing of M2M DMA, it may be different from M2P/P2M timings.

Corollary is, you have to take it as it is. ST might be willing to supply additional details if you represent significant buying power to them, as expressed in $M+.

With your displaying through DMA, try to transmit a recognizable pattern (e.g. 0-1-2-3-4) and observe using logic analyzer (maybe the 4 channel oscilloscope might suffice, but you may wan to experiment with the patterns to have a recognizable sync, e.g. a long 0, and then unambiguously recognizable sequence, i.e. one which could not be confused with the sequence you get if you transmit only each 4th byte, which you probably do).

JW

Elektraglide
Associate III
	// setup PB0 driven by TIM3_CH3 PWM
	//
	GPIO_AFConfigure(AFIO_TIM3_NO_REMAP);	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
	GPIO_InitTypeDef GPIO_InitDef;
	GPIO_StructInit(&GPIO_InitDef);
	GPIO_InitDef.GPIO_Pin = GPIO_Pin_0;
	GPIO_InitDef.GPIO_Mode = GPIO_Mode_AF_PP;		// driven by TIM3_CH3 PWM
	GPIO_InitDef.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitDef);
	GPIO_SetBits(GPIOB, GPIO_Pin_0);
 
	// setup TIM3 with period 2048 ticks
	//
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
	TIM_Cmd(TIM3, DISABLE);
	TIM_TimeBaseInitTypeDef timerInitStructure;
	timerInitStructure.TIM_Prescaler = 0;
	timerInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
	timerInitStructure.TIM_Period = 2048;
	timerInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
	timerInitStructure.TIM_RepetitionCounter = 0;
	TIM_TimeBaseInit(TIM3, &timerInitStructure);
	TIM_ARRPreloadConfig(TIM3, ENABLE);
 
	// TIM3 CH3 PWM
	//
	TIM_OCInitTypeDef outputChannelInit;
	TIM_OCStructInit(&outputChannelInit);
	outputChannelInit.TIM_OCMode = TIM_OCMode_PWM2;
	outputChannelInit.TIM_OutputState = TIM_OutputState_Enable;
	outputChannelInit.TIM_Pulse = HSYNCPULSE;
	TIM_OC3Init(TIM3, &outputChannelInit);
	TIM_CtrlPWMOutputs(TIM3, ENABLE);

This code fragment sets up PB0 to be output of TIM3_CH3 and has TIM3 timer period of 2048 and CH3 as PWM mode.

Since TIM3 is on APB1 I would expect the period of the PB0 output to be 2048/36000000 = 56.8uS

What I measure is 28.4uS (see scope trace). I am clearly misunderstanding something.

[Apologies for answering my own question, but I now think I understand the STM32 behaviour]

Much of the docs refer to APB1 and APB2 and the different clock rates. Specifically, TIM1 & TIM8 being on APB2 (72MHz), other timers being on APB1 (36MHz).

I am sure I am not the only person to read this as being that, say, TIM3 is going to be clocked at the rate set by APB1.

This is not the case.

In the example code above, because the TIM3 CH3 PWM is driving the GPIOB (on APB2), the timing of TIM3 is also at 72MHz.

The same code using TIM1 driving GPIO with PWM, has the same 72MHz timing as TIM3. Now I know! Is that explained anywhere?

[Mea culpa! I've pasted the code that generates this 2uS pulse scope trace further down the thread]

And yes, I think M2M DMA performance is more nuanced than I read in the manuals.

Will try the DMA experiment. I think I need to configure the DMA to be DRQ-ed from the GPIO and not use M2M-mode to get 72MHz transactions.

[EDIT: Displaying black & white vertical stripes so I can measure pixel data easily, I measure 139ns / pixel - which confirms 5.00 cycles / byte @ 36MHz. hmm]

[ I've told my kids I want a more modern STM32 for Christmas! Though I have really enjoyed the boxed-in challenges of F1..]

Thanks again for all your help here.

> The same code using TIM1 driving GPIO with PWM, has the same 72MHz timing as TIM3. Now I know! Is that explained anywhere?

Ah, the "timers clocked at twice the APB if APB is divided" gotcha.

0693W00000HnaqYQAR.png0693W00000HnapvQAB.png 

Also, see Table 2 in RM0008. Btw, AFAIK this table is only in the 'F1 manuals.

> I think I need to configure the DMA to be DRQ-ed from the GPIO

There's no direct way to do this; you have to go through a channel of a timer set to input capture, triggering the DMA. And then you are probably better off simply triggering the DMA from a free-runnig timer. And I don't believe you'll achieve significantly higher transfer rate than what you see now.

JW