STM32N6 GPIO DMA Pattern Gen by Timer trigger
Hello,
I'm trying to do pattern generation on GPIO port using DMA timed by TIM trigger, but I cannot make it running.
My code:
TIM2 INIT
void MX_TIM2_Init(void)
{
__HAL_RCC_TIM2_CLK_ENABLE();
HAL_NVIC_SetPriority(TIM2_IRQn, 3, 0);
HAL_NVIC_EnableIRQ(TIM2_IRQn);
TIM_ClockConfigTypeDef sClockSourceConfig = { 0 };
TIM_MasterConfigTypeDef sMasterConfig = { 0 };
htim2.Instance = TIM2;
htim2.Init.Prescaler = 399;
htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
htim2.Init.Period = 999;
htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
htim2.Init.RepetitionCounter = 0;
if (HAL_TIM_Base_Init(&htim2) != HAL_OK)
{
Error_Handler();
}
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK)
{
Error_Handler();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK)
{
Error_Handler();
}
}
DMA INIT
void MX_GPDMA1_Init(void)
{
DMA_TriggerConfTypeDef TriggerConfig = { 0 };
__HAL_RCC_GPDMA1_CLK_ENABLE();
HAL_NVIC_SetPriority(GPDMA1_Channel0_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(GPDMA1_Channel0_IRQn);
handle_GPDMA1_Channel0.Instance = GPDMA1_Channel0;
handle_GPDMA1_Channel0.Init.Request = DMA_REQUEST_SW;
handle_GPDMA1_Channel0.Init.BlkHWRequest = DMA_BREQ_SINGLE_BURST;
handle_GPDMA1_Channel0.Init.Direction = DMA_MEMORY_TO_PERIPH;
handle_GPDMA1_Channel0.Init.SrcInc = DMA_SINC_INCREMENTED;
handle_GPDMA1_Channel0.Init.DestInc = DMA_DINC_FIXED;
handle_GPDMA1_Channel0.Init.SrcDataWidth = DMA_SRC_DATAWIDTH_HALFWORD;
handle_GPDMA1_Channel0.Init.DestDataWidth = DMA_DEST_DATAWIDTH_HALFWORD;
handle_GPDMA1_Channel0.Init.Priority = DMA_LOW_PRIORITY_HIGH_WEIGHT;
handle_GPDMA1_Channel0.Init.SrcBurstLength = 1;
handle_GPDMA1_Channel0.Init.DestBurstLength = 1;
handle_GPDMA1_Channel0.Init.TransferAllocatedPort = DMA_SRC_ALLOCATED_PORT0 | DMA_DEST_ALLOCATED_PORT0;
handle_GPDMA1_Channel0.Init.TransferEventMode = DMA_TCEM_BLOCK_TRANSFER;
handle_GPDMA1_Channel0.Init.Mode = DMA_NORMAL;
if (HAL_DMA_Init(&handle_GPDMA1_Channel0) != HAL_OK)
{
Error_Handler();
}
TriggerConfig.TriggerMode = DMA_TRIGM_SINGLE_BURST_TRANSFER;
TriggerConfig.TriggerPolarity = DMA_TRIG_POLARITY_RISING;
TriggerConfig.TriggerSelection = GPDMA1_TRIGGER_TIM2_TRGO;
if (HAL_DMAEx_ConfigTrigger(&handle_GPDMA1_Channel0, &TriggerConfig) != HAL_OK)
{
Error_Handler();
}
HAL_GPIO_ConfigPinAttributes(GPIOD, GPIO_PIN_10, GPIO_PIN_SEC | GPIO_PIN_PRIV);
if (HAL_DMA_ConfigChannelAttributes(&handle_GPDMA1_Channel0,
DMA_CHANNEL_PRIV | DMA_CHANNEL_SEC | DMA_CHANNEL_SRC_SEC | DMA_CHANNEL_DEST_SEC) != HAL_OK)
{
Error_Handler();
}
HAL_DMA_RegisterCallback(&handle_GPDMA1_Channel0, HAL_DMA_XFER_CPLT_CB_ID, TransferComplete);
}
Reduced main:
__attribute((aligned(32))) uint16_t _output[128];
...
int main(void)
{
...
MX_TIM2_Init();
MX_GPDMA1_Init();
...
for (uint16_t i = 0; i < 128; i++)
{
_output[i] = i % 2 == 0 ? GPIO_PIN_10 : 0;
}
SCB_CleanDCache_by_Addr(_output, 256);
if (HAL_DMA_Start_IT(&handle_GPDMA1_Channel0, (uint32_t) &_output[0], (uint32_t) &GPIOD->ODR, 256) != HAL_OK)
{
Error_Handler();
}
if (HAL_TIM_Base_Start_IT(&htim2) != HAL_OK)
{
/* Starting Error */
Error_Handler();
}
...
}
void TransferComplete(DMA_HandleTypeDef *hdma)
{
asm volatile ("nop"); //breakpoint
}
However, when I run the code, nothing happens, GPIOD_Pin10 stays low and the TransferComplete function never gets called.
I have verified:
- The Timer is running and working, trigerring at 1ms as expected
- The GPIOD PIN10 is set as output and I can toggle it "manually" by code
- When I change the DMA DIR to MEM_TO_MEM, DEST_INC to INCREMENT but leave everything the same and call it with two arrays
HAL_DMA_Start_IT(&handle_GPDMA1_Channel0, (uint32_t) &_output[0], (uint32_t) &_newOutput[0], 256)
This works, I get the TransferComplete callback and I can see the contents of data were copied to the new buffer.
I have tried many many other things, playing with the parameters of the DMA when it's set to GPIO, but with no success.
Anybody has any idea where I'm wrong?
Thank you.
