cancel
Showing results for 
Search instead for 
Did you mean: 

I tried the Arbitrary waveform generation using timer DMA-burst feature but it doesn't work, can someone help me? F446RE

YSall.1
Senior

I'm trying to generate an arbitrary waveform on PA_5 pin, tim2 channel1 in PMW output, using stream5 channel3 DMA

I tried to do exactly what is written on the application note AN4776 using a nucleo F446RE but it doesn't work here are all my code:

dma.C

 
#include "stm32f4xx.h"
#include "dma.h"
 
#define RCC_AHB1ENR_DMA1_EN 		(1<<21) // Enable clock access to DMA1
#define DMA_PRIORITY_HIGH			((1<<17)|(1<<16)) // Very high priority
#define DMA_CIRCULAR				(1<<8) // Circular mode
#define DMA_MEMORY_TO_PERIPH		(1<<6) // DMA de la mémoire au périph
#define DMA_MINC_ENABLE				(1<<10) //Incrémentation de la zone de mémoire
#define DMA_CHANNEL_3				((1<<26)|(1<<25)) // Selection channel 3
#define DMA_MSIZE					(1<<14) // Les données de mémoire sont de types word 32bits
#define DMA_PSIZE					(1<<12) // Les données périphériques sont de types word 32bits
#define TIM2_DMAR_ADDRESS 			0x4000004C
 
 
void dmaInit(uint32_t * src)
{
 RCC->AHB1ENR |= RCC_AHB1ENR_DMA1_EN; // Enable clock access to DMA1
 
 DMA1_Stream5->CR = 0;
 
 DMA1_Stream5->CR |= DMA_MEMORY_TO_PERIPH | DMA_MINC_ENABLE|DMA_CIRCULAR | DMA_PRIORITY_HIGH|DMA_CHANNEL_3|DMA_MSIZE|DMA_PSIZE;
 
 DMA1_Stream5->NDTR = 9;
 
 DMA1_Stream5->PAR = TIM2_DMAR_ADDRESS ; // ARR Adress
 
 DMA1_Stream5->M0AR = src;
 
 NVIC_EnableIRQ(DMA1_Stream5_IRQn);
 
 DMA1_Stream5->CR|= (1<<0);
 
 
 // Manque l'autorisation des interruptions?
 
}

tim.C

#include "stm32f4xx.h"
#include "tim.h"
 
#define PW1	((1<<6)|(1<<5))
#define Preload1 (1<<3)
#define autoReload (1<<7)
#define TIM2EN		(1U<<0)
#define CR1_CEN		(1U<<0)
#define TIM_DMA_UPDATE	(1U<<8)
#define TIM2_DCR_DBL (1<<9) // 3 DMA burst transfer and start from ARR register
#define TIM2_DCR_DBA ((1<<0)|(1<<1))
 
 
 
 
void timInit(void)
 
{
 
 
	RCC->APB1ENR |=TIM2EN;
 
	/*Set prescaler value*/
	TIM2->PSC =  1 - 1 ;
 
	TIM2->ARR =  90000000 - 1;
 
	TIM2->CCR1= 45000000-1;
 
	TIM2->CNT = 0;
 
	TIM2->CR1 |= autoReload;
 
	TIM2->CCMR1 |= PW1 | Preload1;
 
 
	TIM2-> DIER|= TIM_DMA_UPDATE;
 
	TIM2-> DCR|=  (TIM2_DCR_DBL | TIM2_DCR_DBA);// 3 DMA burst transfer and start from ARR register
 
	TIM2-> EGR|= TIM_EGR_UG;
 
	while((TIM2->EGR & TIM_EGR_UG) == SET){}
 
	TIM2->EGR |= TIM_EGR_UG;
 
	TIM2->BDTR|=TIM_BDTR_MOE;
 
	TIM2->CCER |= TIM_CCER_CC1E;
 
	TIM1->CR1 |= TIM_CR1_CEN;
 
	TIM2->CR1 |=CR1_CEN;
 
}

rcc.C

/*
 * rcc.c
 *
 *  Created on: Jun 22, 2022
 *      Author: ysalliege
 */
#include "stm32f4xx.h"
#include "rcc.h"
 
#define PLL_M 	8
#define PLL_N 	360
#define PLL_P 	0  // PLLP = 2
 
void rccInit(void)
{
 
	RCC->CR |= 1<<16;
	while (!(RCC->CR & (1<<17)));
 
	RCC->APB1ENR |= 1<<28;
 
	PWR->CR |= 3<<14;
 
	FLASH->ACR = (1<<8) | (1<<9)| (1<<10)| (5<<0);
 
	// AHB PR
	RCC->CFGR &= ~(1<<4);
 
	// APB1 PR
	RCC->CFGR |= (5<<10);
 
	// APB2 PR
	RCC->CFGR |= (4<<13);
 
	RCC->PLLCFGR = (PLL_M <<0) | (PLL_N << 6) | (PLL_P <<16) | (1<<22);
 
	RCC->CR |= (1<<24);
	while (!(RCC->CR & (1<<25)));
 
	RCC->CFGR |= (2<<0);
	while (!(RCC->CFGR & (2<<2)));
}

main.c

#include "stm32f4xx.h"
#include "dma.h"
#include "rcc.h"
#include "tim.h"
 
 
 
#define GPIOAEN		(1U<<0)
#define PIN5		(1U<<5)
#define LED_PIN		PIN5
#define AFR5_TIM	(1U<<20)
 
int main (void)
{
 
	uint32_t buffer32b[9] = {90000000, 0, 45000000, 180000000, 0, 90000000,90000000, 0, 45000000};
	/*GPIO INIT*/
 
	RCC->AHB1ENR |=GPIOAEN;
	GPIOA->MODER |=(1U<<10);
	GPIOA->MODER &=~(1U<<11);
	GPIOA->PUPDR |=(1U<<10);
	GPIOA->OSPEEDR|= ((1U<<10)|(1U<<11)); // High speed
	GPIOA->AFR[0] |=AFR5_TIM;
 
 
	rccInit();
	timInit();
	dmaInit(buffer32b);
 
	while(1)
	{
 
	}
}

20 REPLIES 20
Andrew Neil
Evangelist III

"it doesn't work"

You need to give more information.

What is it doing, and how does that differ from what you were expecting?

What testing / investigation / debugging have you done to find what's going on? What did you find?

I was expecting to have a PWM signal with this buffer that contains the folowing registers ARR RCR and CCR1

uint32_t buffer32b[9] = {90000000, 0, 45000000, 180000000, 0, 90000000,90000000, 0, 45000000};

But I had nothing on output

I didn't try to debug, I am new to stm32cubeide

How are you observing the output?

Is the code actually running?

Is the hardware correct?

Have you done a basic test to see if you can just toggle the pin with a simple loop, setting it high & low?

The code is running , the harware correct, I can toggle a pin without problem

An easy solution without using manually register is to use those function

aSRC_Buffer[0] = 180000000;
  aSRC_Buffer[1] = 0;
  aSRC_Buffer[2] = 90000000;
  aSRC_Buffer[3] = 90000000;
  aSRC_Buffer[4] = 0;
  aSRC_Buffer[5] = 45000000;
 
 
  HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1);
  HAL_TIM_DMABurst_MultiWriteStart(&htim2, TIM_DMABASE_ARR, TIM_DMA_UPDATE, (uint32_t*)aSRC_Buffer, TIM_DMABURSTLENGTH_4TRANSFERS, 6);

but when I look at CCR1 and ARR registers they don't change

while (1)
  {
    /* USER CODE END WHILE */
	  HAL_Delay(1000);
	  debug= TIM2->CCR1;
	  debug2=TIM2->ARR;
 
    /* USER CODE BEGIN 3 */
  }

So I tried this code

pwmData[0] = 10;
  pwmData[1] = 20;
  pwmData[2] = 30;
  pwmData[3] = 40;
  pwmData[4] = 50;
  pwmData[5] = 60;
  pwmData[6] = 70;
  pwmData[7] = 80;
  pwmData[8] = 90;
  pwmData[9] = 100;
 
  HAL_TIM_PWM_Start_DMA(&htim2, TIM_CHANNEL_1, (uint32_t *)pwmData, 10);

And this code works because when I looked at CCR1 register it got updated, why the HAL_TIM_DMABurst_MultiWriteStart doesn't want to work?

Okay thank you

@YSall.1​ "this code works because when I looked at CCR1 register it got updated"

And do you get the PWM output?

So it looks like your original code does not pass your data table correctly through to the HAL_TIM_PWM_Start_DMA().

So try stepping through the original code to see where that's going wrong ...

EDIT

In the original code, you have:

int main (void)
{
 
	uint32_t buffer32b[9] = {90000000, 0, 45000000, 180000000, 0, 90000000,90000000, 0, 45000000};

Note that the buffer here is a local (auto) variable.

You'll get away with that in this case, because main() never exits, but you need to be careful about it in general - the storage for auto variables "disappears" when the function exits...

Yes I have the pwm output on the second code, I see it with an signal analyzer