2022-06-27 07:47 AM
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)
{
}
}
2022-06-27 08:15 AM
"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?
2022-06-28 12:19 AM
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
2022-06-28 12:19 AM
I didn't try to debug, I am new to stm32cubeide
2022-06-28 01:42 AM
Debugging is a key part of any development project:
2022-06-28 01:44 AM
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?
2022-06-28 02:48 AM
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?
2022-06-28 02:49 AM
Okay thank you
2022-06-28 03:07 AM
@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...
2022-06-28 03:10 AM
Yes I have the pwm output on the second code, I see it with an signal analyzer