本文主要记录基于 LM401模组的3路串口调试过程,MCU 是 STM32WLE5,主要包括串口IO配置以及DMA中断配置
LM401 模组是基于 STM32WLE5
系列芯片,模组支持3路串口,其中一路可以配置为低功耗串口。另外还有2路7通道DMA
【普通串口和低功耗串口区别】
USART
可以工作在 Stop 0 1
模式,LPUART1
可以工作在 Stop 0 1 2
模式,LPUART1
在匹配 start address 或者 received frame event 时会 产生唤醒中断
板载总线示意图如下:
demo 例程中是用的 usart2
,我想用 UASRT1
的PB6
和PB7
引脚,开始串口的配置过程
可以用 STM32Cube IDE 开发环境对MCU进行可视化配置,然后生成代码接口,给码农减小了工作量。从下图中可以看出,串口的的接口是 vcom
在 uart_if.c
文件中,找到接口,是一个结构体,结构体成员是函数指针,以下4个函数功能为:
const UTIL_ADV_TRACE_Driver_s UTIL_TraceDriver =
{
vcom_Init, // 初始化串口,并分配相应的 DMA channel
vcom_DeInit, // 串口和DMA的去使能
vcom_ReceiveInit, // 串口接收数据初始化
vcom_Trace_DMA, // 使用 DMA 将databuffer 发送至串口
};
uart.c
uart_if.c
中断处理函数配置 stm32wlxx_it.c
DMA1_Channel1_IRQHandler
USART1_IRQHandler
【vcom_Init】
其中,EXTI
表示(external interrupt/event controller)外部中断控制,请参考博文:【stm32中的外部中断】
UTIL_ADV_TRACE_Status_t vcom_Init(void (*cb)(void *))
{
TxCpltCallback = cb;
MX_USART1_UART_Init(); //串口1 参数初始化
MX_DMA_Init(); // 分配 DMA
LL_EXTI_EnableIT_0_31(LL_EXTI_LINE_27); // Enable ExtiLine Interrupt request for Lines in range 0 to 31.
return UTIL_ADV_TRACE_OK;
}
下面重点分析以下,串口1初始化和分配DMA函数的功能,该功能主要涉及2个函数,在 uart.c
文件中
注意:串口DMA选择了 DMA1_Channel1
在 dma.c
文件中,配置DMA通道中断,因为选择了 DMA1_Channel1
,因此设置中断 DMA1_Channel1_IRQn
void MX_DMA_Init(void)
{
/* DMA controller clock enable */
__HAL_RCC_DMAMUX1_CLK_ENABLE();
__HAL_RCC_DMA1_CLK_ENABLE();
/* DMA interrupt init */
/* DMA1_Channel5_IRQn interrupt configuration */
HAL_NVIC_SetPriority(DMA1_Channel1_IRQn, 2, 0);
HAL_NVIC_EnableIRQ(DMA1_Channel1_IRQn);
}
在 stm32wlxx_it.c
文件中,设置中断处理函数,设置为: DMA处理来自于串口1的中断请求
// DMA 通道中断
void DMA1_Channel1_IRQHandler(void)
{
/* USER CODE BEGIN DMA1_Channel1_IRQn 0 */
/* USER CODE END DMA1_Channel1_IRQn 0 */
HAL_DMA_IRQHandler(&hdma_usart1_tx); // DMA处理来自于串口1的中断请求
/* USER CODE BEGIN DMA1_Channel1_IRQn 1 */
/* USER CODE END DMA1_Channel1_IRQn 1 */
}
// 串口中断
void USART1_IRQHandler(void)
{
/* USER CODE BEGIN USART1_IRQn 0 */
/* USER CODE END USART1_IRQn 0 */
HAL_UART_IRQHandler(&huart1);
/* USER CODE BEGIN USART1_IRQn 1 */
/* USER CODE END USART1_IRQn 1 */
}
以下是调试成功之后的打印信息,但是在调试过程中遇到过以下问题, ****************************
是初始化时打印的第一条信息
【问题1:只打印第一条信息,以后的消息不打印了】
解决: DMA 通道配置错误,造成无法正确执行
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "usart.h"
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
UART_HandleTypeDef huart1;
DMA_HandleTypeDef hdma_usart1_tx;
/* USART1 init function */
void MX_USART1_UART_Init(void)
{
huart1.Instance = USART1;
huart1.Init.BaudRate = 115200;
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;
huart1.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
huart1.Init.ClockPrescaler = UART_PRESCALER_DIV1;
huart1.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
if (HAL_UART_Init(&huart1) != HAL_OK)
{
Error_Handler();
}
if (HAL_UARTEx_SetTxFifoThreshold(&huart1, UART_TXFIFO_THRESHOLD_1_8) != HAL_OK)
{
Error_Handler();
}
if (HAL_UARTEx_SetRxFifoThreshold(&huart1, UART_RXFIFO_THRESHOLD_1_8) != HAL_OK)
{
Error_Handler();
}
if (HAL_UARTEx_EnableFifoMode(&huart1) != HAL_OK)
{
Error_Handler();
}
}
void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0};
if(uartHandle->Instance==USART1)
{
/** Initializes the peripherals clocks
*/
PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_USART1;
PeriphClkInitStruct.Usart1ClockSelection = RCC_USART1CLKSOURCE_PCLK2;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK)
{
Error_Handler();
}
/* USART1 clock enable */
__HAL_RCC_USART1_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
/**USART1 GPIO Configuration
PB7 ------> USART1_RX
PB6 ------> USART1_TX
*/
GPIO_InitStruct.Pin = USARTx_RX_Pin|USARTx_TX_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF7_USART1;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
/* USART1 DMA Init */
/* USART1_TX Init */
hdma_usart1_tx.Instance = DMA1_Channel1;
hdma_usart1_tx.Init.Request = DMA_REQUEST_USART1_TX;
hdma_usart1_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
hdma_usart1_tx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_usart1_tx.Init.MemInc = DMA_MINC_ENABLE;
hdma_usart1_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_usart1_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_usart1_tx.Init.Mode = DMA_NORMAL;
hdma_usart1_tx.Init.Priority = DMA_PRIORITY_LOW;
if (HAL_DMA_Init(&hdma_usart1_tx) != HAL_OK)
{
Error_Handler();
}
__HAL_LINKDMA(uartHandle,hdmatx,hdma_usart1_tx);
/* USART1 interrupt Init */
HAL_NVIC_SetPriority(USART1_IRQn, 2, 0);
HAL_NVIC_EnableIRQ(USART1_IRQn);
}
}
void HAL_UART_MspDeInit(UART_HandleTypeDef* uartHandle)
{
if(uartHandle->Instance==USART1)
{
/* USER CODE BEGIN USART1_MspDeInit 0 */
/* USER CODE END USART1_MspDeInit 0 */
/* Peripheral clock disable */
__HAL_RCC_USART1_CLK_DISABLE();
/**USART1 GPIO Configuration
PB7 ------> USART1_RX
PB6 ------> USART1_TX
*/
HAL_GPIO_DeInit(GPIOB, USARTx_RX_Pin|USARTx_TX_Pin);
/* USART1 DMA DeInit */
HAL_DMA_DeInit(uartHandle->hdmatx);
/* USART1 interrupt Deinit */
HAL_NVIC_DisableIRQ(USART1_IRQn);
/* USER CODE BEGIN USART1_MspDeInit 1 */
/* USER CODE END USART1_MspDeInit 1 */
}
}
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* Includes ------------------------------------------------------------------*/
#include "usart_if.h"
/* USER CODE BEGIN Includes */
/* USER CODE END Includes */
/* External variables ---------------------------------------------------------*/
/**
* @brief DMA handle
*/
extern DMA_HandleTypeDef hdma_usart1_tx;
/**
* @brief UART handle
*/
extern UART_HandleTypeDef huart1;
/**
* @brief buffer to receive 1 character
*/
uint8_t charRx;
/* USER CODE BEGIN EV */
/* USER CODE END EV */
/* Private typedef -----------------------------------------------------------*/
/**
* @brief Trace driver callbacks handler
*/
const UTIL_ADV_TRACE_Driver_s UTIL_TraceDriver =
{
vcom_Init,
vcom_DeInit,
vcom_ReceiveInit,
vcom_Trace_DMA,
};
/* USER CODE BEGIN PTD */
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
/**
* @brief TX complete callback
* @return none
*/
static void (*TxCpltCallback)(void *);
/**
* @brief RX complete callback
* @param rxChar ptr of chars buffer sent by user
* @param size buffer size
* @param error errorcode
* @return none
*/
static void (*RxCpltCallback)(uint8_t *rxChar, uint16_t size, uint8_t error);
/* USER CODE BEGIN PV */
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* Exported functions --------------------------------------------------------*/
UTIL_ADV_TRACE_Status_t vcom_Init(void (*cb)(void *))
{
TxCpltCallback = cb;
MX_USART1_UART_Init();
MX_DMA_Init();
LL_EXTI_EnableIT_0_31(LL_EXTI_LINE_26);
return UTIL_ADV_TRACE_OK;
}
UTIL_ADV_TRACE_Status_t vcom_DeInit(void)
{
/* USER CODE BEGIN vcom_DeInit_1 */
/* USER CODE END vcom_DeInit_1 */
/* ##-1- Reset peripherals ################################################## */
__HAL_RCC_USART1_FORCE_RESET();
__HAL_RCC_USART1_RELEASE_RESET();
/* ##-2- MspDeInit ################################################## */
HAL_UART_MspDeInit(&huart1);
/* ##-3- Disable the NVIC for DMA ########################################### */
/* USER CODE BEGIN 1 */
HAL_NVIC_DisableIRQ(DMA1_Channel5_IRQn);
return UTIL_ADV_TRACE_OK;
/* USER CODE END 1 */
/* USER CODE BEGIN vcom_DeInit_2 */
/* USER CODE END vcom_DeInit_2 */
}
void vcom_Trace(uint8_t *p_data, uint16_t size)
{
/* USER CODE BEGIN vcom_Trace_1 */
/* USER CODE END vcom_Trace_1 */
HAL_UART_Transmit(&huart1, p_data, size, 1000);
/* USER CODE BEGIN vcom_Trace_2 */
/* USER CODE END vcom_Trace_2 */
}
UTIL_ADV_TRACE_Status_t vcom_Trace_DMA(uint8_t *p_data, uint16_t size)
{
/* USER CODE BEGIN vcom_Trace_DMA_1 */
/* USER CODE END vcom_Trace_DMA_1 */
HAL_UART_Transmit_DMA(&huart1, p_data, size);
return UTIL_ADV_TRACE_OK;
/* USER CODE BEGIN vcom_Trace_DMA_2 */
/* USER CODE END vcom_Trace_DMA_2 */
}
UTIL_ADV_TRACE_Status_t vcom_ReceiveInit(void (*RxCb)(uint8_t *rxChar, uint16_t size, uint8_t error))
{
/* USER CODE BEGIN vcom_ReceiveInit_1 */
/* USER CODE END vcom_ReceiveInit_1 */
UART_WakeUpTypeDef WakeUpSelection;
/*record call back*/
RxCpltCallback = RxCb;
/*Set wakeUp event on start bit*/
WakeUpSelection.WakeUpEvent = UART_WAKEUP_ON_STARTBIT;
HAL_UARTEx_StopModeWakeUpSourceConfig(&huart1, WakeUpSelection);
/* Make sure that no UART transfer is on-going */
while (__HAL_UART_GET_FLAG(&huart1, USART_ISR_BUSY) == SET);
/* Make sure that UART is ready to receive) */
while (__HAL_UART_GET_FLAG(&huart1, USART_ISR_REACK) == RESET);
/* Enable USART interrupt */
__HAL_UART_ENABLE_IT(&huart1, UART_IT_WUF);
/*Enable wakeup from stop mode*/
HAL_UARTEx_EnableStopMode(&huart1);
/*Start LPUART receive on IT*/
HAL_UART_Receive_IT(&huart1, &charRx, 1);
return UTIL_ADV_TRACE_OK;
/* USER CODE BEGIN vcom_ReceiveInit_2 */
/* USER CODE END vcom_ReceiveInit_2 */
}
void vcom_Resume(void)
{
/* USER CODE BEGIN vcom_Resume_1 */
/* USER CODE END vcom_Resume_1 */
/*to re-enable lost UART settings*/
if (HAL_UART_Init(&huart1) != HAL_OK)
{
Error_Handler();
}
/*to re-enable lost DMA settings*/
if (HAL_DMA_Init(&hdma_usart1_tx) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN vcom_Resume_2 */
/* USER CODE END vcom_Resume_2 */
}
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
/* USER CODE BEGIN HAL_UART_TxCpltCallback_1 */
/* USER CODE END HAL_UART_TxCpltCallback_1 */
/* buffer transmission complete*/
if (huart->Instance == USART1)
{
TxCpltCallback(NULL);
}
/* USER CODE BEGIN HAL_UART_TxCpltCallback_2 */
/* USER CODE END HAL_UART_TxCpltCallback_2 */
}
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
/* USER CODE BEGIN HAL_UART_RxCpltCallback_1 */
/* USER CODE END HAL_UART_RxCpltCallback_1 */
if (huart->Instance == USART1)
{
if ((NULL != RxCpltCallback) && (HAL_UART_ERROR_NONE == huart->ErrorCode))
{
RxCpltCallback(&charRx, 1, 0);
}
HAL_UART_Receive_IT(huart, &charRx, 1);
}
/* USER CODE BEGIN HAL_UART_RxCpltCallback_2 */
/* USER CODE END HAL_UART_RxCpltCallback_2 */
}
#include "dma.h"
void MX_DMA_Init(void)
{
/* DMA controller clock enable */
__HAL_RCC_DMAMUX1_CLK_ENABLE();
__HAL_RCC_DMA1_CLK_ENABLE();
/* DMA interrupt init */
/* DMA1_Channel5_IRQn interrupt configuration */
HAL_NVIC_SetPriority(DMA1_Channel1_IRQn, 2, 0);
HAL_NVIC_EnableIRQ(DMA1_Channel1_IRQn);
}