2023-02-23 01:48 AM
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);
}
2023-02-23 02:00 AM
I can't see any call actually enabling/starting the DMA channel - this should be the last DMA config call.
2023-02-23 02:40 AM
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
2023-02-23 02:58 AM
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
2023-02-23 03:32 AM
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