cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F103C8 PWM with DMA

Sudhakar.R
Associate III

Hello,

I'm using Timer_2 channel_1 PWM with DMA to generate the low polarity Pulse.

I set the value of PSC = 72, ARR = 2000 and Fosc = 72 MHz.

uint16_t TIM2_CCR1_Value[25] = {2100, 2100, 2100, 2100, 2100, 2100, 2100, 2100, 1200, 1500, 1500, 1500, 1500, 500, 1500, 1500, 1500, 1500, 500, 500, 1500, 1500, 1500, 1500, 500};

Explanation of above I given TIM2_CCR1 array value,

Free bit {2100, 2100, 2100, 2100, 2100, 2100, 2100, 2100} = {0, 0, 0, 0, 0, 0, 0, 0}.

Start bit 1200 mean 1.2ms off and 0.8ms on.

Data_0 {1500, 1500, 1500, 1500, 500, 1500, 1500, 1500} = {0, 0, 0, 0, 1, 0, 0, 0}.

Data_1 {1500, 500, 500, 1500, 1500, 1500, 1500, 500} = {0, 1, 1, 0, 0, 0, 0, 1}.

below I given the TIM2_CCR1 array values WaveForm,

0693W00000aJ1xGQAS.jpghere, Free bit and Start bit timing is 20.0155 ms. Data_0 and Data_1 totally 16 bit but i get only 15 bit. after I found that missing first bit data(value is 0).

I don't know where I made a mistake and how to slove this.

7 REPLIES 7

Try to change TIM2_CCR1_Value so that it displays some different sequence. Still missing one pulse?

JW

Sudhakar.R
Associate III

@Community member​ 

Thank you for your comment and i change the

Free bit {2001, 2001, 2001, 2001, 2001, 2001, 2001, 2001} = {0, 0, 0, 0, 0, 0, 0, 0}.

but still missing one pulse(same problem).

I don't know what are you doing and how are you doing it, you've posted no code - and honestly, even if you would, I probably wouldn't want to read it.

Also, as far as timer functionality goes, there's no difference between

Free bit {2001, 2001, 2001, 2001, 2001, 2001, 2001, 2001} = {0, 0, 0, 0, 0, 0, 0, 0}

and

Free bit {2100, 2100, 2100, 2100, 2100, 2100, 2100, 2100} = {0, 0, 0, 0, 0, 0, 0, 0}.

both are CCR1>ARR thus both result in output being permanently low.

What I had in mind was, that you change the values which actually produce pulses, in a way that you can see on the waveform what has changed; change the number of those pulses, maybe to a small number - four perhaps? - and make all of them different so you can distinguish them on the output.

You have an error in your program, and I want you to find that error. Quite likely it's something like you are stopping DMA or timer prematurely or something like that. Making significant/related changes and observing the result is the way to debug.

JW

Sudhakar.R
Associate III

hi,

0693W00000aIND8QAO.pngi try to achive this(above example) type of wave form.

i upload my code,

#include<stm32f10x.h>
 
uint16_t TIM2_CCR1_Value[25] = {2001, 2001, 2001, 2001, 2001, 2001, 2001, 2001, 1200, 1500, 1500, 1500, 1500, 500, 1500, 1500, 1500, 1500, 500, 500, 1500, 1500, 1500, 1500, 500};
 
void TIM2_PWM()
{
	RCC->APB1ENR |= 0x00000001;  //Timer 2 clock is Enable
	RCC->APB2ENR |= RCC_APB2ENR_IOPAEN ;  // I/O port A clock is Enable
	
	RCC->AHBENR |= RCC_AHBENR_DMA1EN;  // DMA1 clock enable
	
	GPIOA->CRL = 0x0000000B;  // Output Mode For PWM Pin is PA0
	
	TIM2->ARR = 2000;     //ARR VALUE IS 0 - 65535
	TIM2->PSC = 72 - 1;   //PERSCALER VALUE IS 0 - 65535
	TIM2->CNT = 0;  //Reset the current count
	
	TIM2->CCMR1 |= 0x00000068; //Configure the pins as PWM
	TIM2->CCER |= (TIM_CCER_CC1E | TIM_CCER_CC1P); //Capture/Compare 1 output enable & Capture/Compare 1 output polarity
	
	TIM2->DIER |= TIM_DIER_CC1DE;  //Capture/Compare 1 DMA request enable
	
	TIM2->DIER |= TIM_DIER_UIE;  //Update interrupt enable
	NVIC_EnableIRQ(TIM2_IRQn);  //Interrupt enable
	
	TIM2->CR1 |= 0x00000001; //Enable counter
	
/********** TIM2_CHANNEL1 PWM with DMA1_CHANNEL_5 **********/
	
	DMA1_Channel5->CPAR =(uint32_t)&TIM2->CCR1;  // Configure the peripheral data register address
	DMA1_Channel5->CMAR =(uint32_t)TIM2_CCR1_Value;  // Configure the memory address
	DMA1_Channel5->CNDTR = 25;  // Number of data to transfer
	
	/*** Data transfer direction, Memory increment mode, Circular mode ***/
	DMA1_Channel5->CCR |= (DMA_CCR5_DIR |  DMA_CCR5_MINC | DMA_CCR5_CIRC);
	DMA1_Channel5->CCR |= (DMA_CCR5_MSIZE_0 | DMA_CCR5_PSIZE_0);  // Memory size is 01: 16-bits & Peripheral size is 01: 16-bits
	
	DMA1_Channel5->CCR |= DMA_CCR5_EN;  //  Enable DMA Channel 5
}
 
int main()
{
	TIM2_PWM();
	
	while(1)
	{
 
	}
}
 
void TIM2_IRQHandler(void)
{
	TIM2->SR&= ~TIM_SR_UIF;
}

I don't know where I made a mistake. help me.

> TIM2->DIER |= TIM_DIER_CC1DE; //Capture/Compare 1 DMA request enable

No. Use TIM_DIER_UDE.

JW

CNT           acting-CCR1   buffer-CCR1   
1999          2001          2001          acting-CCR1 and buffer-CCR1 from 
                                          previous DMA transfers 
2000          2001          2001          CNT==ARR => update event, 
                                          at the same time CC1 event 
                                          (because CCR1>ARR) 
                                          => request towards DMA 
0             2001          2001          buffer-CCR1 was transferred to 
                                          acting-CCR1 because of Update 
                                          (because CCMR1.OC1PE=1)
1                                         
...                                       
5             2001          1200          it took some time for DMA to be 
                                          triggered and perform transfer
                                          - maybe not 5 timer ticks, but 
                                          lets say this is a good rough 
                                          estimate -  so buffer-CCR1 now 
                                          holds the new value DMA moved
                                          from the array in memory
...                                       
1999          2001          1200          
2000          2001          1200          CNT==ARR => update event, 
                                          at the same time CC1 event 
                                          (because CCR1>ARR) 
                                          => request towards DMA 
0             1200          1200          buffer-CCR1 transferred to 
                                          acting-CCR1
1             1200          1200          
...                                       
5             1200          first 1500    DMA transferred the first 1500
...                                       
1190          1200          first 1500    
1200          1200          first 1500    CC1 event => request towards DMA
...                                       
1205          1200          second 1500   DMA transferred the second 1500 
                                          -- note, that the first 1500 is 
                                          at this point overwritten without 
                                          having been used
...                                       
2000          1200          second 1500   CNT==ARR => update event
0             second 1500   second 1500   buffer-CCR1 transferred 
                                          to acting-CCR1
 
etc. - in this period, pulse is output at 1500 as expected, 
but there were two DMA transfers in the previous period 
thus one value (the "first 1500") was already "lost", 
which is exactly what was observed
 
Using Update for DMA triggering, instead of CC1, ensures 
that there is exactly one DMA transfer each period,
avoiding this problem.

Another take (created using https://wavedrom.com/ an impresive free online waveform "drawer"), maybe more illustrative ?

0693W00000aJU4tQAG.pnga, f, k, t, y -- when CNT==ARR, CNT is zeroed and UPdate event is generated

d, i, n, u, z -- UPdate event causes the value from buffer-CCR1

 to be transferred into acting-CCR1

b, g, l -- if acting-CCR1>ARR, Compare (CC1) event is generated at UPdate

q, v -- if acting-CCR1<=ARR (as is usual), CC1 event is generated

 when CNT==acting_CCR1

c, h, m, r, w -- DMA is set so that it is triggered by the CC1 event;

 it takes some time until DMA fulfills the request by transferring data from

 memory to buffer-CCR1, here we used as an example 5 timer-cycles

e, j, o, s, x -- DMA transfers value from buffer in RAM into buffer-CCR1

 and increments the pointer into memory (DMA_MAR)

Note, that in the period between k and t there are two DMA transfers. This means,

that there's one less timer period than total DMA transfers, thus one less pulse

in the observed pulsetrain. The value 1500 from memory buffer position 8 (marked

as 1500 [1]) gets overwritten in the buffer-CCR1 by the next value (1500 [2])

before UPdate, i.e. it never contributes to pulse generation, so between

the 1200- and 500-pulse there are only two 1500-pulses, instead of three.

Remedy is simple, for PWM, perform the DMA-to-CCRx transfer upon UPdate event,

not upon the CCRx event. In that way, there's exactly one transfer per period.

CCRx buffering ensures that whatever the DMA transfer delay is, the new value

won't be used in this particular period, but in the next period (after the next

UPdate event transfers this value from buffer-CCRx into acting-CCR).

JW