STM32F7 DMA Memory to GPIO by Timer, problem...
- June 21, 2017
- 9 replies
- 2056 views
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 enableHAL_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