STM32 DMA Transferir el puente entre 2 puertos uart

5

Estoy usando un stm32f103 y estoy tratando de transmitir simplemente todos los datos recibidos en 1 uart a otro uart y viceversa.

Cuando se utilizan 2 programas de terminal, funciona bien, todo lo que escribo se transmite sin problemas. Pero si envía una cadena larga, por ejemplo '12345678' a la vez, entonces el resultado es '1357'. Así que es casi saltar cada segundo personaje. Se siente como si extrañara cada segundo carácter cuando está ocupado transmitiendo el primer carácter.

¿Alguna idea sobre cómo se puede cambiar esto para no hacer esto?

Este es mi código actual (base generada desde stm32cubemx):


/* Includes ------------------------------------------------------------------*/
#include "stm32f1xx_hal.h"


/* Private variables ---------------------------------------------------------*/
UART_HandleTypeDef huart1;
UART_HandleTypeDef huart2;
DMA_HandleTypeDef hdma_usart1_rx;
DMA_HandleTypeDef hdma_usart1_tx;
DMA_HandleTypeDef hdma_usart2_rx;
DMA_HandleTypeDef hdma_usart2_tx;

/* Private variables ---------------------------------------------------------*/

uint8_t rxBuffer = '

/* Includes ------------------------------------------------------------------*/
#include "stm32f1xx_hal.h"


/* Private variables ---------------------------------------------------------*/
UART_HandleTypeDef huart1;
UART_HandleTypeDef huart2;
DMA_HandleTypeDef hdma_usart1_rx;
DMA_HandleTypeDef hdma_usart1_tx;
DMA_HandleTypeDef hdma_usart2_rx;
DMA_HandleTypeDef hdma_usart2_tx;

/* Private variables ---------------------------------------------------------*/

uint8_t rxBuffer = '%pre%0';
uint8_t rxBuffer2 = '%pre%0';

uint8_t txBuffer = '%pre%0';
uint8_t txBuffer2 = '%pre%0';


/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_DMA_Init(void);
static void MX_USART2_UART_Init(void);
static void MX_USART1_UART_Init(void);


void uart1( char *msg )
{
    HAL_UART_Transmit_DMA(&huart1, (uint8_t *)msg, 1);
}

void uart2( char *msg )
{
    HAL_UART_Transmit_DMA(&huart2, (uint8_t *)msg, 1);
}


void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{

    if ( huart == &huart1 )
    {
        __HAL_UART_FLUSH_DRREGISTER(&huart1); // Clear the buffer to prevent overrun
        txBuffer = rxBuffer;
        uart2(&txBuffer);
        HAL_UART_Receive_DMA(&huart1, &rxBuffer, 1);

        return;
    }

    if ( huart == &huart2 )
    {
        __HAL_UART_FLUSH_DRREGISTER(&huart2); // Clear the buffer to prevent overrun
        txBuffer2 = rxBuffer2;
        uart1(&txBuffer2);
        HAL_UART_Receive_DMA(&huart2, &rxBuffer2, 1);
        return;
    }
}



/* USER CODE END 0 */

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_USART2_UART_Init();
  MX_USART1_UART_Init();

  // starting bridge
  __HAL_UART_FLUSH_DRREGISTER(&huart1);
  HAL_UART_Receive_DMA(&huart1, &rxBuffer, 1);

  __HAL_UART_FLUSH_DRREGISTER(&huart2);
  HAL_UART_Receive_DMA(&huart2, &rxBuffer2, 1);



  /* Infinite loop */
  while (1)
  {
  }

}

/** System Clock Configuration
*/
void SystemClock_Config(void)
{

  RCC_OscInitTypeDef RCC_OscInitStruct;
  RCC_ClkInitTypeDef RCC_ClkInitStruct;

  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSICalibrationValue = 16;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI_DIV2;
  RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL12;
  HAL_RCC_OscConfig(&RCC_OscInitStruct);

  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
  HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1);

  HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000);

  HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);

  /* SysTick_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);
}

/* USART1 init function */
void MX_USART1_UART_Init(void)
{

  huart1.Instance = USART1;
  huart1.Init.BaudRate = 230400;
  huart1.Init.WordLength = UART_WORDLENGTH_8B;
  huart1.Init.StopBits = UART_STOPBITS_1;
  huart1.Init.Parity = UART_PARITY_NONE;
  huart1.Init.Mode = UART_MODE_TX_RX;
  huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart1.Init.OverSampling = UART_OVERSAMPLING_16;
  HAL_UART_Init(&huart1);

}

/* USART2 init function */
void MX_USART2_UART_Init(void)
{

  huart2.Instance = USART2;
  huart2.Init.BaudRate = 230400;
  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;
  HAL_UART_Init(&huart2);

}

/** 
  * Enable DMA controller clock
  */
void MX_DMA_Init(void) 
{
  /* DMA controller clock enable */
  __HAL_RCC_DMA1_CLK_ENABLE();

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

}

/** Configure pins as 
        * Analog 
        * Input 
        * Output
        * EVENT_OUT
        * EXTI
*/
void MX_GPIO_Init(void)
{

  GPIO_InitTypeDef GPIO_InitStruct;

  /* GPIO Ports Clock Enable */
  __GPIOA_CLK_ENABLE();
  __GPIOB_CLK_ENABLE();

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(DUT_RESET_GPIO_Port, DUT_RESET_Pin, GPIO_PIN_RESET);

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(GPIOA, LED_Pin|GPIO_PIN_15, GPIO_PIN_RESET);

  /*Configure GPIO pin : DUT_RESET_Pin */
  GPIO_InitStruct.Pin = DUT_RESET_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Speed = GPIO_SPEED_LOW;
  HAL_GPIO_Init(DUT_RESET_GPIO_Port, &GPIO_InitStruct);

  /*Configure GPIO pins : LED_Pin PA15 */
  GPIO_InitStruct.Pin = LED_Pin|GPIO_PIN_15;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Speed = GPIO_SPEED_LOW;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  /*Configure GPIO pin : PB9 */
  GPIO_InitStruct.Pin = GPIO_PIN_9;
  GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

}

/* USER CODE BEGIN 4 */

/* USER CODE END 4 */

#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

/**
  * @}
  */ 

/**
  * @}
*/ 

0'; uint8_t rxBuffer2 = '%pre%0'; uint8_t txBuffer = '%pre%0'; uint8_t txBuffer2 = '%pre%0'; /* Private function prototypes -----------------------------------------------*/ void SystemClock_Config(void); static void MX_GPIO_Init(void); static void MX_DMA_Init(void); static void MX_USART2_UART_Init(void); static void MX_USART1_UART_Init(void); void uart1( char *msg ) { HAL_UART_Transmit_DMA(&huart1, (uint8_t *)msg, 1); } void uart2( char *msg ) { HAL_UART_Transmit_DMA(&huart2, (uint8_t *)msg, 1); } void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) { if ( huart == &huart1 ) { __HAL_UART_FLUSH_DRREGISTER(&huart1); // Clear the buffer to prevent overrun txBuffer = rxBuffer; uart2(&txBuffer); HAL_UART_Receive_DMA(&huart1, &rxBuffer, 1); return; } if ( huart == &huart2 ) { __HAL_UART_FLUSH_DRREGISTER(&huart2); // Clear the buffer to prevent overrun txBuffer2 = rxBuffer2; uart1(&txBuffer2); HAL_UART_Receive_DMA(&huart2, &rxBuffer2, 1); return; } } /* USER CODE END 0 */ 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_USART2_UART_Init(); MX_USART1_UART_Init(); // starting bridge __HAL_UART_FLUSH_DRREGISTER(&huart1); HAL_UART_Receive_DMA(&huart1, &rxBuffer, 1); __HAL_UART_FLUSH_DRREGISTER(&huart2); HAL_UART_Receive_DMA(&huart2, &rxBuffer2, 1); /* Infinite loop */ while (1) { } } /** System Clock Configuration */ void SystemClock_Config(void) { RCC_OscInitTypeDef RCC_OscInitStruct; RCC_ClkInitTypeDef RCC_ClkInitStruct; RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI; RCC_OscInitStruct.HSIState = RCC_HSI_ON; RCC_OscInitStruct.HSICalibrationValue = 16; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI_DIV2; RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL12; HAL_RCC_OscConfig(&RCC_OscInitStruct); RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2; RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2; RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1); HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000); HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK); /* SysTick_IRQn interrupt configuration */ HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0); } /* USART1 init function */ void MX_USART1_UART_Init(void) { huart1.Instance = USART1; huart1.Init.BaudRate = 230400; huart1.Init.WordLength = UART_WORDLENGTH_8B; huart1.Init.StopBits = UART_STOPBITS_1; huart1.Init.Parity = UART_PARITY_NONE; huart1.Init.Mode = UART_MODE_TX_RX; huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE; huart1.Init.OverSampling = UART_OVERSAMPLING_16; HAL_UART_Init(&huart1); } /* USART2 init function */ void MX_USART2_UART_Init(void) { huart2.Instance = USART2; huart2.Init.BaudRate = 230400; 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; HAL_UART_Init(&huart2); } /** * Enable DMA controller clock */ void MX_DMA_Init(void) { /* DMA controller clock enable */ __HAL_RCC_DMA1_CLK_ENABLE(); /* DMA interrupt init */ HAL_NVIC_SetPriority(DMA1_Channel4_IRQn, 0, 0); HAL_NVIC_EnableIRQ(DMA1_Channel4_IRQn); HAL_NVIC_SetPriority(DMA1_Channel5_IRQn, 0, 0); HAL_NVIC_EnableIRQ(DMA1_Channel5_IRQn); HAL_NVIC_SetPriority(DMA1_Channel6_IRQn, 0, 0); HAL_NVIC_EnableIRQ(DMA1_Channel6_IRQn); HAL_NVIC_SetPriority(DMA1_Channel7_IRQn, 0, 0); HAL_NVIC_EnableIRQ(DMA1_Channel7_IRQn); } /** Configure pins as * Analog * Input * Output * EVENT_OUT * EXTI */ void MX_GPIO_Init(void) { GPIO_InitTypeDef GPIO_InitStruct; /* GPIO Ports Clock Enable */ __GPIOA_CLK_ENABLE(); __GPIOB_CLK_ENABLE(); /*Configure GPIO pin Output Level */ HAL_GPIO_WritePin(DUT_RESET_GPIO_Port, DUT_RESET_Pin, GPIO_PIN_RESET); /*Configure GPIO pin Output Level */ HAL_GPIO_WritePin(GPIOA, LED_Pin|GPIO_PIN_15, GPIO_PIN_RESET); /*Configure GPIO pin : DUT_RESET_Pin */ GPIO_InitStruct.Pin = DUT_RESET_Pin; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Speed = GPIO_SPEED_LOW; HAL_GPIO_Init(DUT_RESET_GPIO_Port, &GPIO_InitStruct); /*Configure GPIO pins : LED_Pin PA15 */ GPIO_InitStruct.Pin = LED_Pin|GPIO_PIN_15; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Speed = GPIO_SPEED_LOW; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); /*Configure GPIO pin : PB9 */ GPIO_InitStruct.Pin = GPIO_PIN_9; GPIO_InitStruct.Mode = GPIO_MODE_INPUT; GPIO_InitStruct.Pull = GPIO_NOPULL; HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); } /* USER CODE BEGIN 4 */ /* USER CODE END 4 */ #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 /** * @} */ /** * @} */
    
pregunta Tom Van den Bon

1 respuesta

3

Considere el siguiente fragmento del manual STM32F1 con respecto al USART registro de datos y su bit de estado correspondiente 'TXE':

  

Comunicación de un solo byte

     

El bit TXE siempre se borra con una escritura en   el registro de datos El bit TXE está configurado por hardware e indica:

     

• Los datos se han trasladado del TDR al registro de desplazamiento y los datos   la transmisión ha comenzado

     

• El registro TDR está vacío.

     

• Los siguientes datos se pueden escribir en el registro USART_DR sin sobrescribir los datos anteriores.

     

Este indicador genera una interrupción si el bit TXEIE es   conjunto.

¿Se puede imaginar un escenario en el que esté escribiendo en el registro de datos antes de que el byte anterior haya ingresado en el registro de desplazamiento? Piense en la secuencia de eventos cuando recibe un flujo de bytes, especialmente cuando recibe el tercer o cuarto byte, ¿qué está haciendo su transmisor en este momento? ¿Está ocupado su registro de datos?

Como se mencionó en un comentario anterior, es probable que necesite una forma de almacenar el (los) byte (s) anterior (es) si el bit de estado TXE no está establecido. Escribir en el registro de datos USART mientras el bit de estado TXE no está establecido es una forma garantizada de perder información.

Editar en respuesta al comentario:

Esa es una forma de hacerlo, me imagino que funcionaría. Sin embargo, creo que eliminar un DMA y utilizar las interrupciones USART sería un mejor enfoque. Puede tener 2 rutinas de servicio de interrupción para cuando se recibe un byte y cuando el registro de datos de transmisión está vacío. En función de esos dos eventos, puede decidir almacenar los datos en el búfer (en el controlador de RX) y vaciar el búfer (en el controlador de TX completo). Se debe tener cuidado al decidir cuándo habilitar / deshabilitar la interrupción completa de TX. Creo que la sobrecarga de configurar DMA tiene más sentido para transacciones secuenciales más grandes en (o fuera de) buffers, y menos en el caso de byte por byte único.

    
respondido por el Jon L

Lea otras preguntas en las etiquetas