AnsweredAssumed Answered

STM32F7 DMA Memory to GPIO by Timer, problem...

Question asked by Aurelien Robert on Jun 21, 2017
Latest reply on Jun 22, 2017 by waclawek.jan

Hello,
I'm running a STM32F767 on NucleoF767ZI board, with SW4STM32 IDE.
I'm coding a procedure that transfers with DMA a lot of data (24576 x 16bits words) from internal memory to GPIOE, cadenced by TIMER3 Output compare Channel 3.
TIMER3 output compare module is used in PWM mode, channels 1 and also used, and the three channels (1,2,3) also toggle output GPIO pins (on port B).
I mainly set my code by copying the AN4666 app note (made for STM32F4/L4 device, but I don't see any reason for STM32F7 would not support it).

This is my code :

 

TIM_HandleTypeDef TimHandle;
TIM_OC_InitTypeDef sConfig;
uint16_t output_buf[24576] __attribute__((section (".testSRAM1Location")));

int main(void)
{
SCB_EnableICache(); // for partial enable
//SCB_EnableDCache(); // for partial enable

HAL_Init();

SystemClock_Config200MHz();
BSP_LED_Init(LED1);
BSP_LED_Init(LED2);
BSP_LED_Init(LED3);

__HAL_RCC_TIM3_CLK_ENABLE();
TimHandle.Instance = TIM3;
TimHandle.Init.Period = 1250; // 12.5µs cycle at 100MHz
TimHandle.Init.Prescaler = 0;
TimHandle.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; // timer period 10ns (100MHz)
TimHandle.Init.CounterMode = TIM_COUNTERMODE_UP;
TimHandle.Init.RepetitionCounter = 0;
TimHandle.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_PWM_Init(&TimHandle) != HAL_OK) Error_Handler();

sConfig.OCMode = TIM_OCMODE_PWM1;
sConfig.OCPolarity = TIM_OCPOLARITY_HIGH;
sConfig.OCFastMode = TIM_OCFAST_DISABLE;
sConfig.OCNPolarity = TIM_OCNPOLARITY_LOW;
sConfig.OCNIdleState = TIM_OCNIDLESTATE_RESET;
sConfig.OCIdleState = TIM_OCIDLESTATE_RESET;

// Set the pulse value for channel 1
sConfig.Pulse = 250;
if (HAL_TIM_PWM_ConfigChannel(&TimHandle, &sConfig, TIM_CHANNEL_1) != HAL_OK) Error_Handler();
// Set the pulse value for channel 2
sConfig.Pulse = 600;
if (HAL_TIM_PWM_ConfigChannel(&TimHandle, &sConfig, TIM_CHANNEL_2) != HAL_OK) Error_Handler();
// Set the pulse value for channel 3
sConfig.Pulse = 670;
if (HAL_TIM_PWM_ConfigChannel(&TimHandle, &sConfig, TIM_CHANNEL_3) != HAL_OK) Error_Handler();

if (HAL_TIM_PWM_Start(&TimHandle, TIM_CHANNEL_1) != HAL_OK) Error_Handler();
if (HAL_TIM_PWM_Start(&TimHandle, TIM_CHANNEL_2) != HAL_OK) Error_Handler();
if (HAL_TIM_PWM_Start(&TimHandle, TIM_CHANNEL_3) != HAL_OK) Error_Handler();

TimHandle.hdma[TIM_DMA_ID_CC3]->XferCpltCallback = data_tramsmitted_handler;
TimHandle.hdma[TIM_DMA_ID_CC3]->XferErrorCallback = transmit_error_handler;

// Configure the GPIOE for DMA operation
__HAL_RCC_GPIOE_CLK_ENABLE();
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_All, GPIO_PIN_RESET);
GPIO_InitStruct.Pin = GPIO_PIN_All;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);

// Preload data in buffer for DMA example
for (i=0 ; i<24576 ; i++) output_buf[i] = (i+1);


while (1)
{
HAL_Delay(1000);

SCB_CleanDCache(); // clean the cache to be sure DMA get correct data
if (HAL_DMA_Start_IT(TimHandle.hdma[TIM_DMA_ID_CC3], (uint32_t)&output_buf, (GPIOE_BASE + 0x14), 24576) != HAL_OK) Error_Handler();
__HAL_TIM_ENABLE_DMA(&TimHandle, TIM_DMA_CC3);
}
}


void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef *htim)
{
GPIO_InitTypeDef GPIO_InitStruct;
static DMA_HandleTypeDef hdma_tim;

/* Enable peripherals and GPIO Clocks #################################*/
/* TIM3 Peripheral clock enable */
__HAL_RCC_TIM3_CLK_ENABLE();

/* Enable all GPIO Channels Clock requested */
__HAL_RCC_GPIOB_CLK_ENABLE();

/* Enable DMA clock */
__HAL_RCC_DMA1_CLK_ENABLE();

/* Configure PB.04 (TIM3_Channel1), PB.05 (TIM3_Channel2), PB.00 (TIM3_Channel3) in output, push-pull, alternate function mode */
/* Common configuration for all channels */
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;

GPIO_InitStruct.Alternate = GPIO_AF2_TIM3;
GPIO_InitStruct.Pin = GPIO_PIN_4;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

GPIO_InitStruct.Alternate = GPIO_AF2_TIM3;
GPIO_InitStruct.Pin = GPIO_PIN_5;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

GPIO_InitStruct.Alternate = GPIO_AF2_TIM3;
GPIO_InitStruct.Pin = GPIO_PIN_0;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

/* Configure DMA */
/* Set the parameters to be configured */
hdma_tim.Instance = DMA1_Stream7;
hdma_tim.Init.Channel = DMA_CHANNEL_5;
hdma_tim.Init.Direction = DMA_MEMORY_TO_PERIPH;
hdma_tim.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_tim.Init.MemInc = DMA_MINC_ENABLE;
hdma_tim.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
hdma_tim.Init.MemDataAlignment = DMA_PDATAALIGN_HALFWORD;
hdma_tim.Init.Mode = DMA_NORMAL;
hdma_tim.Init.Priority = DMA_PRIORITY_VERY_HIGH;
hdma_tim.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
hdma_tim.Init.MemBurst = DMA_MBURST_SINGLE;
hdma_tim.Init.PeriphBurst = DMA_PBURST_SINGLE;

/* Link hdma_tim to hdma[CC3] */
__HAL_LINKDMA(htim, hdma[TIM_DMA_ID_CC3], hdma_tim);

/* Initialize TIMx DMA handle */
HAL_DMA_Init(htim->hdma[TIM_DMA_ID_CC3]);

HAL_NVIC_SetPriority(DMA1_Stream7_IRQn, 1, 1);
HAL_NVIC_EnableIRQ(DMA1_Stream7_IRQn);
}


static void SystemClock_Config200MHz(void)
{
RCC_ClkInitTypeDef RCC_ClkInitStruct;
RCC_OscInitTypeDef RCC_OscInitStruct;

/* Enable HSE Oscillator and activate PLL with HSE as source */
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_BYPASS;
RCC_OscInitStruct.HSIState = RCC_HSI_OFF;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = 8;
RCC_OscInitStruct.PLL.PLLN = 400;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = 9;
RCC_OscInitStruct.PLL.PLLR = 7;
if(HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
while(1) {};
}

/* Select PLL as system clock source and configure the HCLK, PCLK1 and PCLK2
clocks dividers */
RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2);
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
if(HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_7) != HAL_OK)
{
while(1) {};
}
}


I did not post the error handlers here because they only consist in toggling a LED and while(1)...

When I enable the DMA and the TMR3:CC3 request, I don't see anything change on the output port and immediately after enabling TMR3:CC3 DMA request a transfert error interrupt rises.
When the error interrupt is entered, the data counter is decremented (0x5FFFF) but the memory address is not incremented ; the EN bit is automatically cleared by hardware.
When running in direct mode or in fifo mode with no burst set (DMA_PBURST_SINGLE), I get error code 1 (TE). When running in fifo mode with half full trigger and 4 burst set (DMA_MBURST_INC4) I get error code 2 (FE).

I tried with the buffer in DTCM memory, in SRAM1 memory, with data cache enabled and with data cable disabled.

Of course I checked the PWM outputs before coding DMA, and it still working well on the three outputs with correct freq et d/c.

Thank you for your ideas
Aurelien

Outcomes