STMicroelectronics / STM32CubeF1

STM32Cube MCU Full Package for the STM32F1 series - (HAL + LL Drivers, CMSIS Core, CMSIS Device, MW libraries plus a set of Projects running on all boards provided by ST (Nucleo, Evaluation and Discovery Kits))
Other
504 stars 169 forks source link

Memory address does not increase in UART DMA receive #34

Closed tiantian1645 closed 2 years ago

tiantian1645 commented 3 years ago

Describe the set-up

Describe the bug

  1. Start UART DMA receive
  2. Send data with serial
  3. View data in HAL_UART_RxHalfCpltCallback/HAL_UART_RxCpltCallback
  4. Send 12 34 56 78 12 34 56 78 12 34 56 78 12 34 56 78 but dma receive buffer is 78 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

How To Reproduce

  1. Indicate the global behavior of your application project. Use UART DMA receive and transmit like https://github.com/MaJerle/stm32-usart-uart-dma-rx-tx

  2. The modules that you suspect to be the cause of the problem (Driver, BSP, MW ...). UART MSP Init

  3. The use case that generates the problem.

  4. How we can reproduce the problem. I upload a mina.c and a ioc file, you can use it and send 16 bytes from serial.

Additional context Just add HAL_UART_MspInit(&huart2) before start DMA , it works.

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_USART2_UART_Init();
  MX_DMA_Init();
  /* USER CODE BEGIN 2 */

  HAL_UART_MspInit(COMM_DEBUG_UART); // add this line fix

  HAL_UART_Receive_DMA(COMM_DEBUG_UART, g_comm_debug_rx_dma_buffer, ARRAY_LEN(g_comm_debug_rx_dma_buffer));
  __HAL_UART_ENABLE_IT(COMM_MAIN_UART, UART_IT_IDLE);

Screenshots image

ioc file F1_DMA_Test - .ioc.txt

#MicroXplorer Configuration settings - do not modify
Dma.Request0=USART2_RX
Dma.Request1=USART2_TX
Dma.RequestsNb=2
Dma.USART2_RX.0.Direction=DMA_PERIPH_TO_MEMORY
Dma.USART2_RX.0.Instance=DMA1_Channel6
Dma.USART2_RX.0.MemDataAlignment=DMA_MDATAALIGN_BYTE
Dma.USART2_RX.0.MemInc=DMA_MINC_ENABLE
Dma.USART2_RX.0.Mode=DMA_CIRCULAR
Dma.USART2_RX.0.PeriphDataAlignment=DMA_PDATAALIGN_BYTE
Dma.USART2_RX.0.PeriphInc=DMA_PINC_DISABLE
Dma.USART2_RX.0.Priority=DMA_PRIORITY_LOW
Dma.USART2_RX.0.RequestParameters=Instance,Direction,PeriphInc,MemInc,PeriphDataAlignment,MemDataAlignment,Mode,Priority
Dma.USART2_TX.1.Direction=DMA_MEMORY_TO_PERIPH
Dma.USART2_TX.1.Instance=DMA1_Channel7
Dma.USART2_TX.1.MemDataAlignment=DMA_MDATAALIGN_BYTE
Dma.USART2_TX.1.MemInc=DMA_MINC_ENABLE
Dma.USART2_TX.1.Mode=DMA_NORMAL
Dma.USART2_TX.1.PeriphDataAlignment=DMA_PDATAALIGN_BYTE
Dma.USART2_TX.1.PeriphInc=DMA_PINC_DISABLE
Dma.USART2_TX.1.Priority=DMA_PRIORITY_LOW
Dma.USART2_TX.1.RequestParameters=Instance,Direction,PeriphInc,MemInc,PeriphDataAlignment,MemDataAlignment,Mode,Priority
File.Version=6
KeepUserPlacement=false
Mcu.Family=STM32F1
Mcu.IP0=DMA
Mcu.IP1=NVIC
Mcu.IP2=RCC
Mcu.IP3=SYS
Mcu.IP4=USART2
Mcu.IPNb=5
Mcu.Name=STM32F103R(C-D-E)Tx
Mcu.Package=LQFP64
Mcu.Pin0=PA2
Mcu.Pin1=PA3
Mcu.Pin2=PA13
Mcu.Pin3=PA14
Mcu.Pin4=VP_SYS_VS_Systick
Mcu.PinsNb=5
Mcu.ThirdPartyNb=0
Mcu.UserConstants=
Mcu.UserName=STM32F103RCTx
MxCube.Version=6.3.0
MxDb.Version=DB.6.0.30
NVIC.BusFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false
NVIC.DMA1_Channel6_IRQn=true\:0\:0\:false\:false\:true\:false\:true
NVIC.DMA1_Channel7_IRQn=true\:0\:0\:false\:false\:true\:false\:true
NVIC.DebugMonitor_IRQn=true\:0\:0\:false\:false\:true\:false\:false
NVIC.ForceEnableDMAVector=true
NVIC.HardFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false
NVIC.MemoryManagement_IRQn=true\:0\:0\:false\:false\:true\:false\:false
NVIC.NonMaskableInt_IRQn=true\:0\:0\:false\:false\:true\:false\:false
NVIC.PendSV_IRQn=true\:0\:0\:false\:false\:true\:false\:false
NVIC.PriorityGroup=NVIC_PRIORITYGROUP_4
NVIC.SVCall_IRQn=true\:0\:0\:false\:false\:true\:false\:false
NVIC.SysTick_IRQn=true\:15\:0\:false\:false\:true\:false\:true
NVIC.UsageFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false
PA13.Mode=Serial_Wire
PA13.Signal=SYS_JTMS-SWDIO
PA14.Mode=Serial_Wire
PA14.Signal=SYS_JTCK-SWCLK
PA2.Locked=true
PA2.Mode=Asynchronous
PA2.Signal=USART2_TX
PA3.Locked=true
PA3.Mode=Asynchronous
PA3.Signal=USART2_RX
PinOutPanel.RotationAngle=0
ProjectManager.AskForMigrate=true
ProjectManager.BackupPrevious=false
ProjectManager.CompilerOptimize=6
ProjectManager.ComputerToolchain=false
ProjectManager.CoupleFile=false
ProjectManager.CustomerFirmwarePackage=
ProjectManager.DefaultFWLocation=true
ProjectManager.DeletePrevious=true
ProjectManager.DeviceId=STM32F103RCTx
ProjectManager.FirmwarePackage=STM32Cube FW_F1 V1.8.4
ProjectManager.FreePins=false
ProjectManager.HalAssertFull=false
ProjectManager.HeapSize=0x200
ProjectManager.KeepUserCode=true
ProjectManager.LastFirmware=true
ProjectManager.LibraryCopy=1
ProjectManager.MainLocation=Core/Src
ProjectManager.NoMain=false
ProjectManager.PreviousToolchain=
ProjectManager.ProjectBuild=false
ProjectManager.ProjectFileName=F1_DMA_Test.ioc
ProjectManager.ProjectName=F1_DMA_Test
ProjectManager.RegisterCallBack=
ProjectManager.StackSize=0x400
ProjectManager.TargetToolchain=STM32CubeIDE
ProjectManager.ToolChainLocation=
ProjectManager.UnderRoot=true
ProjectManager.functionlistsort=1-SystemClock_Config-RCC-false-HAL-false,2-MX_GPIO_Init-GPIO-false-HAL-true,3-MX_USART2_UART_Init-USART2-false-HAL-true,4-MX_DMA_Init-DMA-false-HAL-true
RCC.APB1Freq_Value=8000000
RCC.APB2Freq_Value=8000000
RCC.FamilyName=M
RCC.IPParameters=APB1Freq_Value,APB2Freq_Value,FamilyName,PLLCLKFreq_Value,PLLMCOFreq_Value,TimSysFreq_Value
RCC.PLLCLKFreq_Value=8000000
RCC.PLLMCOFreq_Value=4000000
RCC.TimSysFreq_Value=8000000
USART2.IPParameters=VirtualMode
USART2.VirtualMode=VM_ASYNC
VP_SYS_VS_Systick.Mode=SysTick
VP_SYS_VS_Systick.Signal=SYS_VS_Systick
board=custom
isbadioc=false

main.c

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; Copyright (c) 2021 STMicroelectronics.
  * All rights reserved.</center></h2>
  *
  * This software component is licensed by ST under BSD 3-Clause license,
  * the "License"; You may not use this file except in compliance with the
  * License. You may obtain a copy of the License at:
  *                        opensource.org/licenses/BSD-3-Clause
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */

/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
typedef enum {
    e_serial_irq_dma_half,
    e_serial_irq_dma_full,
    e_serial_irq_idle,
    e_serial_irq_idle_timeout,
} e_serial_irq;

typedef struct {
    uint16_t cur_pos;
    uint16_t old_pos;
    uint16_t dma_size;
    uint8_t * p_dma_buffer;
} s_serial_rx_dma;
/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
#define COMM_DEBUG_UART (&huart2)

/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
#define ARRAY_LEN(x) (sizeof(x) / sizeof((x)[0]))

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/
UART_HandleTypeDef huart2;
DMA_HandleTypeDef hdma_usart2_rx;
DMA_HandleTypeDef hdma_usart2_tx;

/* USER CODE BEGIN PV */

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_USART2_UART_Init(void);
static void MX_DMA_Init(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
static uint8_t g_comm_debug_rx_dma_buffer[32];
static s_serial_rx_dma g_comm_debug_dma_rx_info;

/**
 * @brief  comm_debug 接收中断回调
 * @note   HAL_UART_RxHalfCpltCallback
 * @note   HAL_UART_RxCpltCallback
 * @note   USART2_IRQHandler
 * @param  irq_type 中断类型
 * @retval None
 */
void comm_debug_IRQ_handle(e_serial_irq irq_type)
{
    s_serial_rx_dma * p_dma_info;

    p_dma_info = &g_comm_debug_dma_rx_info;

    /* Calculate current position in buffer */
    p_dma_info->cur_pos = p_dma_info->dma_size - __HAL_DMA_GET_COUNTER(&hdma_usart2_rx);
    if (p_dma_info->cur_pos == p_dma_info->old_pos && irq_type == e_serial_irq_dma_full) {
        HAL_UART_Transmit(COMM_DEBUG_UART, &p_dma_info->p_dma_buffer[p_dma_info->old_pos], p_dma_info->dma_size - p_dma_info->old_pos, 10);
        if (p_dma_info->cur_pos > 0) {
            HAL_UART_Transmit(COMM_DEBUG_UART, &p_dma_info->p_dma_buffer[0], p_dma_info->cur_pos, 10);
        }
    }
    if (p_dma_info->cur_pos != p_dma_info->old_pos) {    /* Check change in received data */
        if (p_dma_info->cur_pos > p_dma_info->old_pos) { /* Current position is over previous one */
            /* We are in "linear" mode */
            /* Process data directly by subtracting "pointers" */
            HAL_UART_Transmit(COMM_DEBUG_UART, &p_dma_info->p_dma_buffer[p_dma_info->old_pos], p_dma_info->cur_pos - p_dma_info->old_pos, 10);
        } else {
            /* We are in "overflow" mode */
            /* First process data to the end of buffer */
            HAL_UART_Transmit(COMM_DEBUG_UART, &p_dma_info->p_dma_buffer[p_dma_info->old_pos], p_dma_info->dma_size - p_dma_info->old_pos, 10);
            /* Check and continue with beginning of buffer */
            if (p_dma_info->cur_pos > 0) {
                HAL_UART_Transmit(COMM_DEBUG_UART, &p_dma_info->p_dma_buffer[0], p_dma_info->cur_pos, 10);
            }
        }
        p_dma_info->old_pos = p_dma_info->cur_pos; /* Save current position as old */
    }

    /* Check and manually update if we reached end of buffer */
    if (p_dma_info->old_pos == p_dma_info->dma_size) {
        p_dma_info->old_pos = 0;
    }
}

/**
 * @brief  DMA接收一半中断回调
 * @param  argument: Not used
 * @retval None
 */
void HAL_UART_RxHalfCpltCallback(UART_HandleTypeDef * huart)
{
    switch ((uint32_t)(huart->Instance)) {
        case (uint32_t)USART2:
            comm_debug_IRQ_handle(e_serial_irq_dma_half);
            break;
    }
}

/**
 * @brief  DMA接收完满中断回调
 * @param  argument: Not used
 * @retval None
 */
void HAL_UART_RxCpltCallback(UART_HandleTypeDef * huart)
{
    switch ((uint32_t)(huart->Instance)) {
        case (uint32_t)USART2:
            comm_debug_IRQ_handle(e_serial_irq_dma_full);
            break;
    }
}
/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_USART2_UART_Init();
  MX_DMA_Init();
  /* USER CODE BEGIN 2 */

  g_comm_debug_dma_rx_info.cur_pos = 0;
  g_comm_debug_dma_rx_info.old_pos = ARRAY_LEN(g_comm_debug_rx_dma_buffer);
  g_comm_debug_dma_rx_info.dma_size = ARRAY_LEN(g_comm_debug_rx_dma_buffer);
  g_comm_debug_dma_rx_info.p_dma_buffer = g_comm_debug_rx_dma_buffer;

  HAL_UART_MspInit(COMM_DEBUG_UART);
  HAL_UART_Receive_DMA(COMM_DEBUG_UART, g_comm_debug_rx_dma_buffer, ARRAY_LEN(g_comm_debug_rx_dma_buffer));
  __HAL_UART_ENABLE_IT(COMM_DEBUG_UART, UART_IT_IDLE);
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }
  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK)
  {
    Error_Handler();
  }
}

/**
  * @brief USART2 Initialization Function
  * @param None
  * @retval None
  */
static void MX_USART2_UART_Init(void)
{

  /* USER CODE BEGIN USART2_Init 0 */

  /* USER CODE END USART2_Init 0 */

  /* USER CODE BEGIN USART2_Init 1 */

  /* USER CODE END USART2_Init 1 */
  huart2.Instance = USART2;
  huart2.Init.BaudRate = 115200;
  huart2.Init.WordLength = UART_WORDLENGTH_8B;
  huart2.Init.StopBits = UART_STOPBITS_1;
  huart2.Init.Parity = UART_PARITY_NONE;
  huart2.Init.Mode = UART_MODE_TX_RX;
  huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart2.Init.OverSampling = UART_OVERSAMPLING_16;
  if (HAL_UART_Init(&huart2) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN USART2_Init 2 */

  /* USER CODE END USART2_Init 2 */

}

/**
  * Enable DMA controller clock
  */
static void MX_DMA_Init(void)
{

  /* DMA controller clock enable */
  __HAL_RCC_DMA1_CLK_ENABLE();

  /* DMA interrupt init */
  /* DMA1_Channel6_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(DMA1_Channel6_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(DMA1_Channel6_IRQn);
  /* DMA1_Channel7_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(DMA1_Channel7_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(DMA1_Channel7_IRQn);

}

/**
  * @brief GPIO Initialization Function
  * @param None
  * @retval None
  */
static void MX_GPIO_Init(void)
{

  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOA_CLK_ENABLE();

}

/* USER CODE BEGIN 4 */

/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */
  __disable_irq();
  while (1)
  {
  }
  /* USER CODE END Error_Handler_Debug */
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
tiantian1645 commented 3 years ago

And a similar problem in Timer trigger ADC1 DMA ,it will only get in HAL_ADC_ConvCpltCallback once, but there is no problem if changed to ADC3,.

ASELSTM commented 2 years ago

Hi @tiantian1645,

This is unfortunately a CubeMX generation problem. To fix the issue you can change the order of the initialization functions generated by CubeMX by placing the DMA initialization before the UART initialization as following :

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_DMA_Init();
  MX_USART2_UART_Init();
  /* USER CODE BEGIN 2 */

Would you please update the initialization sequence as described above in the code snippet and check back if you still have the erroneous behavior or not.

With regards,

tiantian1645 commented 2 years ago

I had tried to swap the initialization sequence but it does not work. I am not able to check back because I have resigned from this project.

ASELSTM commented 2 years ago

Hi @tiantian1645,

We have implemented the proposed fix on the code you have provide and it works perfectly. As explained in the first comment, the point you reported is related to the CubeMX generation problem and not to the firmware published in this repository. Please allow me then to close this thread as we don't treat aspect related to CubeMX tool in our GitHub repositories. Thank you for your comprehension and for your contribution.

With regards,