cancel
Showing results for 
Search instead for 
Did you mean: 

I'm using STM32F100RBT6. The goal is to use TIM3 CH3 to generate a PWM signal with different duty cycle using DMA transfer.

costi
Associate III

I have configured TIM3 (using CubeIDE) in such a way that it generates an event that is used to transfer measurements on the ADC channels to memory using DMA. This works.

But in the same time, I want to transfer to TIM3 CH3 the values in a table. The values are different. But this does not happen. The PWM signal generated is always with the 50% duty cycle as set using CubeIDE.

I can't figure out what else I need to do to execute the transfer of values from the table to the timer via DMA.

I want to use LL library or direct register configuration.

In the attached code in the user section I have added the necessary code to start timer 3 and DMA.

Excluding the use of HAL for now.

Some advice is welcome.

Thanks

below is TIM3 settings

pheripheral clock is 24KHz and the PWM signal is 8KHz

void MX_TIM3_Init(void)

{

 /* USER CODE BEGIN TIM3_Init 0 */

 /* USER CODE END TIM3_Init 0 */

 LL_TIM_InitTypeDef TIM_InitStruct = {0};

 LL_TIM_OC_InitTypeDef TIM_OC_InitStruct = {0};

 LL_GPIO_InitTypeDef GPIO_InitStruct = {0};

 /* Peripheral clock enable */

 LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM3);

 /* TIM3 DMA Init */

 /* TIM3_CH3 Init */

 LL_DMA_SetDataTransferDirection(DMA1, LL_DMA_CHANNEL_2, LL_DMA_DIRECTION_MEMORY_TO_PERIPH);

 LL_DMA_SetChannelPriorityLevel(DMA1, LL_DMA_CHANNEL_2, LL_DMA_PRIORITY_LOW);

 LL_DMA_SetMode(DMA1, LL_DMA_CHANNEL_2, LL_DMA_MODE_CIRCULAR);

 LL_DMA_SetPeriphIncMode(DMA1, LL_DMA_CHANNEL_2, LL_DMA_PERIPH_NOINCREMENT);

 LL_DMA_SetMemoryIncMode(DMA1, LL_DMA_CHANNEL_2, LL_DMA_MEMORY_INCREMENT);

 LL_DMA_SetPeriphSize(DMA1, LL_DMA_CHANNEL_2, LL_DMA_PDATAALIGN_HALFWORD);

 LL_DMA_SetMemorySize(DMA1, LL_DMA_CHANNEL_2, LL_DMA_MDATAALIGN_HALFWORD);

 /* USER CODE BEGIN TIM3_Init 1 */

 /* USER CODE END TIM3_Init 1 */

 TIM_InitStruct.Prescaler = 0;

 TIM_InitStruct.CounterMode = LL_TIM_COUNTERMODE_UP;

 TIM_InitStruct.Autoreload = 3000;

 TIM_InitStruct.ClockDivision = LL_TIM_CLOCKDIVISION_DIV1;

 LL_TIM_Init(TIM3, &TIM_InitStruct);

 LL_TIM_EnableARRPreload(TIM3);

 LL_TIM_SetClockSource(TIM3, LL_TIM_CLOCKSOURCE_INTERNAL);

 LL_TIM_OC_EnablePreload(TIM3, LL_TIM_CHANNEL_CH1);

 TIM_OC_InitStruct.OCMode = LL_TIM_OCMODE_PWM1;

 TIM_OC_InitStruct.OCState = LL_TIM_OCSTATE_DISABLE;

 TIM_OC_InitStruct.OCNState = LL_TIM_OCSTATE_DISABLE;

 TIM_OC_InitStruct.CompareValue = 1500;

 TIM_OC_InitStruct.OCPolarity = LL_TIM_OCPOLARITY_HIGH;

 LL_TIM_OC_Init(TIM3, LL_TIM_CHANNEL_CH1, &TIM_OC_InitStruct);

 LL_TIM_OC_DisableFast(TIM3, LL_TIM_CHANNEL_CH1);

 LL_TIM_OC_EnablePreload(TIM3, LL_TIM_CHANNEL_CH3);

 LL_TIM_OC_Init(TIM3, LL_TIM_CHANNEL_CH3, &TIM_OC_InitStruct);

 LL_TIM_OC_DisableFast(TIM3, LL_TIM_CHANNEL_CH3);

 LL_TIM_SetTriggerOutput(TIM3, LL_TIM_TRGO_UPDATE);

 LL_TIM_DisableMasterSlaveMode(TIM3);

 /* USER CODE BEGIN TIM3_Init 2 */

 LL_TIM_CC_EnableChannel(TIM3, LL_TIM_CHANNEL_CH1);      // EVENT for DMA

 LL_TIM_CC_EnableChannel(TIM3, LL_TIM_CHANNEL_CH3);      // PWM

 //LL_TIM_EnableUpdateEvent(TIM3);

 LL_TIM_EnableCounter(TIM3);

 /* prepare DMA*/

 /* buffer contains 22 diferrent values */

 LL_DMA_SetDataLength(DMA1, LL_DMA_CHANNEL_2, 22);   // number of data to transfer

 LL_DMA_ConfigAddresses(DMA1, LL_DMA_CHANNEL_2, (INT32U)&(TIM3->CCR3), (INT32U)(&buffer), LL_DMA_DIRECTION_MEMORY_TO_PERIPH); // buffer to transmit to the TIM3_CH3 using DMA

 LL_TIM_EnableDMAReq_UPDATE(TIM3);

 LL_TIM_GenerateEvent_UPDATE(TIM3);

 /* USER CODE END TIM3_Init 2 */

 LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_GPIOB);

   /**TIM3 GPIO Configuration

   PB0    ------> TIM3_CH3

   */

 GPIO_InitStruct.Pin = PWM_SENSOR_Pin;

 GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;

 GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_LOW;

 GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;

 LL_GPIO_Init(PWM_SENSOR_GPIO_Port, &GPIO_InitStruct);

}

4 REPLIES 4
gbm
Lead II

I can't see any call actually enabling/starting the DMA channel - this should be the last DMA config call.

I don't see DMA clock to be enabled in RCC, either.

At any case, always start debugging by reading out and checking the related peripherals' registers' content.

JW

costi
Associate III

OK, thank you for your fast answer.

I forgot about this line

LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_2);

although a siilar one I'm used to start DMA CH1 for ADC

but it's not enough

I have to understand how the transfer can be start

Thank you for the answer,

the clock is configured in another section of my cod.

void MX_DMA_Init(void)

{

 /* Init with LL driver */

 /* DMA controller clock enable */

 LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_DMA1);

 /* DMA interrupt init */

 /* DMA1_Channel1_IRQn interrupt configuration */

 NVIC_SetPriority(DMA1_Channel1_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),2, 0));

 NVIC_EnableIRQ(DMA1_Channel1_IRQn);

}

As I explained I am using the DMA for ADC and it is working well.

And also I want to use it for TIM3 CH3.

In the init phase the function MX_DMA_Init() is called before ti init ADC and TIM pheripherals