2019-01-05 03:44 AM
Hello,
I want to create a simple PWM with changing duty cycle. To do so, I have created a PWM with fixed frequency. With the DMA, I change pulses which will result in a modification of duty cycle.
To create something clean, I have configured STM32CubeMX and generated fresh files (configuration in attached documents below).
If I test my PWM with fixed frequency and fixed duty cycle, everything is working (without DMA). I have not modified files, just added this line to start the PWM:
HAL_TIM_PWM_Start(&htim4, TIM_CHANNEL_4);
Result as expected:
Now I want to do the same thing with the DMA. So I have created a buffer with 2 arrays, with my 2 pulses. And I use it like that:
uint32_t buffer[2] = {42, 21}; // 42 is 50% duty cycle for my config, 21 is 25%
[...]
// At the end of timer4 init
HAL_TIM_PWM_Start_DMA(&htim4, TIM_CHANNEL_4, buffer, 2);
[...]
And here is the problem:
More particularly, it seems to crash at this moment:
/* Set the DMA error callback */
htim->hdma[TIM_DMA_ID_CC4]->XferErrorCallback = TIM_DMAError ;
Maybe I am missing to do something...
Any help would be appreciated. Thanks!
More information: I am using a stm32f103. As you can see in attached files, the last release of stm32CubeMx and the last version of F1 library : V1.7.0
I have looked carefully to provided examples (TIM_DMA, etc...) and I always reach the same result.
Quick access to some parts of the code:
main.c :
int main(void)
{
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* Configure the system clock */
SystemClock_Config();
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_DMA_Init();
MX_USB_PCD_Init();
MX_TIM4_Init();
/* Infinite loop */
while (1)
{
}
}
time.c:
uint32_t buffer[2] = {42, 21};
TIM_HandleTypeDef htim4;
DMA_HandleTypeDef hdma_tim4_up;
/* TIM4 init function */
void MX_TIM4_Init(void)
{
TIM_ClockConfigTypeDef sClockSourceConfig = {0};
TIM_MasterConfigTypeDef sMasterConfig = {0};
TIM_OC_InitTypeDef sConfigOC = {0};
htim4.Instance = TIM4;
htim4.Init.Prescaler = 0;
htim4.Init.CounterMode = TIM_COUNTERMODE_UP;
htim4.Init.Period = 84;
htim4.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim4.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
if (HAL_TIM_Base_Init(&htim4) != HAL_OK)
{
Error_Handler();
}
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
if (HAL_TIM_ConfigClockSource(&htim4, &sClockSourceConfig) != HAL_OK)
{
Error_Handler();
}
if (HAL_TIM_PWM_Init(&htim4) != HAL_OK)
{
Error_Handler();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim4, &sMasterConfig) != HAL_OK)
{
Error_Handler();
}
sConfigOC.OCMode = TIM_OCMODE_PWM1;
sConfigOC.Pulse = 42;
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
if (HAL_TIM_PWM_ConfigChannel(&htim4, &sConfigOC, TIM_CHANNEL_4) != HAL_OK)
{
Error_Handler();
}
HAL_TIM_MspPostInit(&htim4);
//HAL_TIM_PWM_Start(&htim4, TIM_CHANNEL_4);
HAL_TIM_PWM_Start_DMA(&htim4, TIM_CHANNEL_4, buffer, 2);
}
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* tim_baseHandle)
{
if(tim_baseHandle->Instance==TIM4)
{
/* TIM4 clock enable */
__HAL_RCC_TIM4_CLK_ENABLE();
/* TIM4 DMA Init */
/* TIM4_UP Init */
hdma_tim4_up.Instance = DMA1_Channel7;
hdma_tim4_up.Init.Direction = DMA_MEMORY_TO_PERIPH;
hdma_tim4_up.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_tim4_up.Init.MemInc = DMA_MINC_ENABLE;
hdma_tim4_up.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
hdma_tim4_up.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
hdma_tim4_up.Init.Mode = DMA_NORMAL;
hdma_tim4_up.Init.Priority = DMA_PRIORITY_VERY_HIGH;
if (HAL_DMA_Init(&hdma_tim4_up) != HAL_OK)
{
Error_Handler();
}
__HAL_LINKDMA(tim_baseHandle,hdma[TIM_DMA_ID_UPDATE],hdma_tim4_up);
}
}
void HAL_TIM_MspPostInit(TIM_HandleTypeDef* timHandle)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
if(timHandle->Instance==TIM4)
{
__HAL_RCC_GPIOB_CLK_ENABLE();
/**TIM4 GPIO Configuration
PB9 ------> TIM4_CH4
*/
GPIO_InitStruct.Pin = GPIO_PIN_9;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}
}
dma.c
void MX_DMA_Init(void)
{
/* DMA controller clock enable */
__HAL_RCC_DMA1_CLK_ENABLE();
/* DMA interrupt init */
/* DMA1_Channel7_IRQn interrupt configuration */
HAL_NVIC_SetPriority(DMA1_Channel7_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(DMA1_Channel7_IRQn);
}
stm32f1xx_it.c
void DMA1_Channel7_IRQHandler(void)
{
HAL_DMA_IRQHandler(&hdma_tim4_up);
}
2019-01-05 04:07 AM
see your external crystal frequency is setup correctly if it is wrong then hard fault occurs in MCU.
2019-01-05 04:19 AM
Thanks for you answer, but my problem does not seem to be related to any crystal frequency error as everything is working correctly except when I call the DMA.
My crystal seems to work correctly
And STM32CubeMx is set correctly:
2019-01-05 05:57 AM
Your need is to have PWM which when the percentage is changes should be taken into effect when the timer overflow back to 0x0000 ? If yes, this is programmable with the timer options without the need of a DMA.
I'm really not sure how the DMA will perform in this case. When and how the percentage change is triggered?
2019-01-05 06:33 AM
Likely missing an interrupt handler.
Consider also stack size, and errant pointers.
Use a better fault handler, and look at the faulting instructions/registers.
2019-01-28 04:57 AM
Hi Geo En
I faced exactly the same issue on BluePill STM32F103CB, when trying to generate a sawtooth on PB9 (Timer 4 CH4 PWM) for ADC dithering (but that's another story).
From my understanding, CubeMX generates wrong code line 76 of tim.c
It is
whereas it should be:
__HAL_LINKDMA(tim_baseHandle,hdma[TIM_DMA_ID_CC4],hdma_tim4_up);
Once this line manually fixed, the bus fault disappears.
But now i'm stuck there, I cannot get my End of DMA interrupt.
Hope this helps.
Vincent
2019-01-28 07:31 AM
Also seen here in the past
2019-01-28 08:54 AM
Hey!
I gave up... I switched from channel 4 to channel 3.
Something is not clear, in stm32cubeMx: For channel 4 we have only TIM4_UP for DMA request. But for channel 3, we have TIM4_UP and TIM4_CH3 (we need to use this one). Most of the time, stm32cubeMx is really good to work quickly. But in cases like this one, I have read a big part of the datasheet and the library to understand the problem... If I need to do this, I can configure registers myself so I don't need a wizard ... Maybe one day, there will be some descriptions in stm32cubeMx and not only drop down menus with no sense ...
2019-01-28 08:59 AM
Yep, this is exactly the problem. We don't set the good pointer. So the library use a pointer = NULL and try to execute a function = NULL...
The problem is: we don't have the possibility to use the good pointer in stm32cubeMx. Maybe because that's impossible physically, or maybe because I have made a mistake, or maybe it is a bug in cubemx. Who knows? as there is no description at all in this wizard...
2019-04-20 02:22 PM
... may be a too late but likely this will fix the error:
It wants a 32 bit pointer to match the register the data has to be 16 bit to match the counter. I hope it helps.