¡Hola compañeros ingenieros electrónicos!
Tengo un pequeño problema con la configuración de la placa STM32F072-Nucleo como una carcasa pequeña (quiero enviar comandos a través de UART y establecer/obtener varias configuraciones de la aplicación que estoy creando) usando UART con DMA en modo de interrupción.
El código se basa en BrinirController . El problema es que si bien puedo recibir el primer carácter y repetirlo, después de esa primera interrupción, la MCU no hace otra interrupción si intento escribir otro carácter. El HAL que estoy usando es 1.2.1 (junto con el STM32CubeMX) y no tiene la macro __HAL_UART_FLUSH_DRREGISTER(&huart2)
para vaciar el búfer de datos RX del UART.
¿La función __HAL_UART_SEND_REQ(&huart2, UART_RXDATA_FLUSH_REQUEST)
hace lo mismo que la macro __HAL_UART_FLUSH_DRREGISTER(&huart2)
en la versión anterior de HAL?
¿Podría ser este el problema: el búfer de datos RX está lleno, por lo que simplemente no iniciará otra interrupción mientras no se borre / lea?
La RxCpltCallback
función de devolución de llamada se llama solo la primera vez que ingreso algo en el terminal serial... Simplemente no interrumpirá la segunda vez... ¡Parece que lo he intentado todo! :D ¿Cuál podría ser la solución? Estoy usando la placa STM32F072RBT6 (STM32F072-Nucleo)
El código es así:
UART_HandleTypeDef huart2;
DMA_HandleTypeDef hdma_usart2_rx;
DMA_HandleTypeDef hdma_usart2_tx;
/* USART2 init function */
void MX_USART2_UART_Init(void)
{
huart2.Instance = USART2;
huart2.Init.BaudRate = 9600;
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;
huart2.Init.OneBitSampling = UART_ONEBIT_SAMPLING_DISABLED ;
huart2.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
HAL_UART_Init(&huart2);
}
void HAL_UART_MspInit(UART_HandleTypeDef* huart)
{
GPIO_InitTypeDef GPIO_InitStruct;
if(huart->Instance==USART2)
{
/* USER CODE BEGIN USART2_MspInit 0 */
/* USER CODE END USART2_MspInit 0 */
/* Peripheral clock enable */
__USART2_CLK_ENABLE();
/**USART2 GPIO Configuration
PA2 ------> USART2_TX
PA3 ------> USART2_RX
*/
GPIO_InitStruct.Pin = GPIO_PIN_2;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_LOW;
GPIO_InitStruct.Alternate = GPIO_AF1_USART2;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_3;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_LOW;
GPIO_InitStruct.Alternate = GPIO_AF1_USART2;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/* Peripheral DMA init*/
hdma_usart2_rx.Instance = DMA1_Channel5;
hdma_usart2_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_usart2_rx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_usart2_rx.Init.MemInc = DMA_MINC_ENABLE;
hdma_usart2_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_usart2_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_usart2_rx.Init.Mode = DMA_NORMAL;
hdma_usart2_rx.Init.Priority = DMA_PRIORITY_MEDIUM;
HAL_DMA_Init(&hdma_usart2_rx);
__HAL_LINKDMA(huart,hdmarx,hdma_usart2_rx);
hdma_usart2_tx.Instance = DMA1_Channel4;
hdma_usart2_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
hdma_usart2_tx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_usart2_tx.Init.MemInc = DMA_MINC_ENABLE;
hdma_usart2_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_usart2_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_usart2_tx.Init.Mode = DMA_NORMAL;
hdma_usart2_tx.Init.Priority = DMA_PRIORITY_LOW;
HAL_DMA_Init(&hdma_usart2_tx);
__HAL_LINKDMA(huart,hdmatx,hdma_usart2_tx);
/* USER CODE BEGIN USART2_MspInit 1 */
/* USER CODE END USART2_MspInit 1 */
}
}
y la función de devolución de llamada de interrupción:
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
__HAL_UART_SEND_REQ(&huart2, UART_RXDATA_FLUSH_REQUEST); // Clear the buffer to prevent overrun
int i = 0;
HAL_UART_Transmit_DMA(&huart2, (uint8_t *)&rxBuffer, 1);
if (rxBuffer == 8 || rxBuffer == 127) // If Backspace or del
{
printf(" \b"); // "\b space \b" clears the terminal character. Remember we just echoced a \b so don't need another one here, just space and \b
rxindex--;
if (rxindex < 0) rxindex = 0;
}
else if (rxBuffer == '\n' || rxBuffer == '\r') // If Enter
{
executeSerialCommand(rxString);
rxString[rxindex] = 0;
rxindex = 0;
for (i = 0; i < MAXSTRING; i++) rxString[i] = 0; // Clear the string buffer
}
else
{
rxString[rxindex] = rxBuffer; // Add that character to the string
rxindex++;
if (rxindex > MAXSTRING) // User typing too much, we can't have commands that big
{
rxindex = 0;
for (i = 0; i < MAXSTRING; i++) rxString[i] = 0; // Clear the string buffer
printf("\r\nKonsole> ");
}
}
}
Por supuesto, estoy llamando a HAL_UART_Receive_DMA(&huart2, &rxBuffer, 1) en la rutina principal antes del bucle infinito y he definido estas variables como búferes:
uint8_t rxBuffer = '\000';
uint8_t rxString[MAXSTRING];
int rxindex = 0;
Cambie el modo RX DMA a DMA_CIRCULAR. El modo DMA normal se ejecuta una vez y debe configurarlo nuevamente. El modo circular le permite hacer la misma operación hasta que la detenga explícitamente.
usuario126563