/* * @Author: * @Date: 2023-07-31 11:47:35 * @LastEditors: xxx * @LastEditTime: 2023-08-25 15:30:33 * @Description: LL库的串口驱动 * email: * Copyright (c) 2023 by xxx, All Rights Reserved. */ #include "uarts.h" /** * @brief 清除DMA传输完成标志 * @param {DMA_HandleTypeDef} *DMAX DMA总线句柄 * @param {uint32_t} CHx DMA通道号 * @return {*} 操作结果 * @note: 该宏用于清除DMA总线的传输完成标志。它首先检查DMA总线的传输完成标志是否已置位,如果已置位,则清除该标志。 */ #define DMA_ClEAR_FLAG_TC(DMAX, CHx) \ do \ { \ if (LL_DMA_IsActiveFlag_TC##CHx(DMAX)) \ { \ LL_DMA_ClearFlag_TC##CHx(DMAX); \ } \ } while (__LINE__ == -1) /** * @brief 清除DMA传输错误标志 * @param {DMA_HandleTypeDef} *DMAX DMA总线句柄 * @param {uint32_t} CHx DMA通道号 * @return {*} 操作结果 * @note: 该宏用于清除DMA总线的传输错误标志。它首先检查DMA总线的传输错误标志是否已置位,如果已置位,则清除该标志。 */ #define DMA_ClEAR_FLAG_TE(DMAX, CHx) \ do \ { \ if (LL_DMA_IsActiveFlag_TE##CHx(DMAX)) \ { \ LL_DMA_ClearFlag_TE##CHx(DMAX); \ } \ } while (__LINE__ == -1) /** * @file uarts.c * @brief This file contains the implementation of DMA_CLEAR_FLAG_TC_CHANNEL macro. */ /** * @brief Clear the Transfer Complete (TC) flag of a specific DMA channel. * * @param dma The DMA peripheral. * @param channel The DMA channel number. */ #define DMA_CLEAR_FLAG_TC_CHANNEL(dma, channel) \ switch (channel) \ { \ case LL_DMA_CHANNEL_1: \ DMA_ClEAR_FLAG_TC(dma, 1); \ break; \ case LL_DMA_CHANNEL_2: \ DMA_ClEAR_FLAG_TC(dma, 2); \ break; \ case LL_DMA_CHANNEL_3: \ DMA_ClEAR_FLAG_TC(dma, 3); \ break; \ case LL_DMA_CHANNEL_4: \ DMA_ClEAR_FLAG_TC(dma, 4); \ break; \ case LL_DMA_CHANNEL_5: \ DMA_ClEAR_FLAG_TC(dma, 5); \ break; \ case LL_DMA_CHANNEL_6: \ DMA_ClEAR_FLAG_TC(dma, 6); \ break; \ case LL_DMA_CHANNEL_7: \ DMA_ClEAR_FLAG_TC(dma, 7); \ break; \ default: \ break; \ } /** * @brief Clear the Transfer Error (TE) flag for the specified DMA channel. * * @param dma The DMA peripheral. * @param channel The DMA channel number. */ #define DMA_CLEAR_FLAG_TE_CHANNEL(dma, channel) \ switch (channel) \ { \ case 1: \ DMA_ClEAR_FLAG_TE(dma, 1); \ break; \ case 2: \ DMA_ClEAR_FLAG_TE(dma, 2); \ break; \ case 3: \ DMA_ClEAR_FLAG_TE(dma, 3); \ break; \ case 4: \ DMA_ClEAR_FLAG_TE(dma, 4); \ break; \ case 5: \ DMA_ClEAR_FLAG_TE(dma, 5); \ break; \ case 6: \ DMA_ClEAR_FLAG_TE(dma, 6); \ break; \ case 7: \ DMA_ClEAR_FLAG_TE(dma, 7); \ break; \ default: \ break; \ } /** * @brief 创建一个UART设备 * @param {USART_TypeDef} *huart USART总线设备句柄 * @param {BOOL} rx_dma_en 接收DMA使能标志 * @param {uint16_t} rxsize 接收缓冲区大小 * @param {rx_interrupt_cb_t} rx_cb 接收中断回调函数 * @param {BOOL} tx_dma_en 发送DMA使能标志 * @param {uint16_t} txsize 发送缓冲区大小 * @param {tx_complete_cb_t} tx_complete_cb 发送完成回调函数 * @return {*} 创建的UART设备指针 * @note: 该函数用于创建一个UART设备。它首先断言huart不为空,然后分配内存用于接收缓冲区和发送缓冲区,并设置相关标志。最后,返回创建的UART设备指针。 */ uart_t *uart_create(USART_TypeDef *huart, BOOL rx_dma_en, uint16_t rxsize, rx_interupt_cb_t rx_cb, BOOL tx_dma_en, uint16_t txsize, tx_complete_cb_t tx_complete_cb) { DBG_ASSERT(huart != NULL __DBG_LINE); // 分配内存 uart_t *uart = (uart_t *)osel_mem_alloc(sizeof(uart_t)); DBG_ASSERT(uart != NULL __DBG_LINE); // 设置接收回调函数 uart->rx_interupt_cb = rx_cb; // 设置接收数据大小 uart->rxsize = rxsize; // 设置发送完成回调函数 uart->tx_complete_cb = tx_complete_cb; // 设置发送数据大小 uart->txsize = txsize; // 如果接收大小大于0,则分配内存 if (rxsize > 0) { uart->rxbuf = (uint8_t *)osel_mem_alloc(rxsize); DBG_ASSERT(uart->rxbuf != NULL __DBG_LINE); } // 如果发送大小大于0,则分配内存 if (txsize > 0) { uart->txbuf = (uint8_t *)osel_mem_alloc(txsize); DBG_ASSERT(uart->txbuf != NULL __DBG_LINE); } // 设置接收DMA禁用 uart->rx_dma_en = rx_dma_en; // 设置发送DMA禁用 uart->tx_dma_en = tx_dma_en; // 设置huart uart->huart = huart; // 返回uart return uart; } /** * @brief 使能UART接收 * @param {uart_t} *uart UART设备句柄 * @return {*} 操作结果 * @note: 该函数用于使能UART设备的接收功能。它首先检查UART设备的接收DMA使能标志,然后禁用接收中断,配置RX DMA并启用RX DMA通道。最后,检查UART设备的发送DMA使能标志,配置TX DMA并启用TX DMA通道。 */ void uart_recv_en(uart_t *uart) { if (FALSE == uart->rx_dma_en) { LL_USART_EnableIT_RXNE(uart->huart); // 使用接收中断处理 } else { LL_USART_ClearFlag_IDLE(uart->huart); // LL_USART_EnableIT_RXNE(uart->huart); // 加上这个,否则第一条数据会接受不到 // 配置RX DMA LL_DMA_DisableChannel(uart->dma, uart->dma_tx_channel); LL_DMA_DisableChannel(uart->dma, uart->dma_rx_channel); // 配置RX DMA LL_DMA_SetPeriphAddress(uart->dma, uart->dma_rx_channel, LL_USART_DMA_GetRegAddr(uart->huart, LL_USART_DMA_REG_DATA_RECEIVE)); LL_DMA_SetMemoryAddress(uart->dma, uart->dma_rx_channel, (uint32_t)uart->rxbuf); LL_DMA_SetDataLength(uart->dma, uart->dma_rx_channel, uart->rxsize); LL_DMA_EnableIT_TC(uart->dma, uart->dma_rx_channel); LL_DMA_EnableChannel(uart->dma, uart->dma_rx_channel); LL_USART_EnableDMAReq_RX(uart->huart); LL_USART_EnableIT_IDLE(uart->huart); // 配置TX DMA LL_DMA_SetPeriphAddress(uart->dma, uart->dma_tx_channel, LL_USART_DMA_GetRegAddr(uart->huart, LL_USART_DMA_REG_DATA_TRANSMIT)); // 配置内存地址 LL_DMA_SetMemoryAddress(uart->dma, uart->dma_tx_channel, (uint32_t)uart->txbuf); LL_DMA_EnableIT_TC(uart->dma, uart->dma_tx_channel); LL_USART_EnableDMAReq_TX(uart->huart); uart->tx_dma_ok = TRUE; } } /** * @brief 释放UART设备资源 * @param {uart_t} *uart UART设备句柄 * @return {*} 操作结果 * @note: 该函数用于释放UART设备的接收缓冲区、发送缓冲区和UART设备本身。 */ void uart_free(uart_t *uart) { if (uart != NULL) { if (uart->rxbuf != NULL) { osel_mem_free(uart->rxbuf); } if (uart->txbuf != NULL) { osel_mem_free(uart->txbuf); } osel_mem_free(uart); } } /** * @brief 发送数据 * @param {uart_t} *uart UART设备句柄 * @param {uint8_t} *data 要发送的数据 * @param {uint16_t} len 要发送的数据长度 * @return {*} 操作结果 * @note: 该函数用于发送数据。首先检查UART设备的发送DMA使能标志,然后禁用发送中断,配置TX DMA并启用TX DMA通道。最后,发送数据直到发送缓冲区满或发送中断发生。 */ void uart_send_data(uart_t *uart, uint8_t *data, uint16_t len) { DBG_ASSERT(uart != NULL __DBG_LINE); DBG_ASSERT(data != NULL __DBG_LINE); DBG_ASSERT(len > 0 __DBG_LINE); uint8_t count = 0; if (TRUE == uart->tx_dma_en) { if (uart->tx_dma_ok == FALSE) { return; } uart->tx_dma_ok = FALSE; osel_memcpy(uart->txbuf, data, len); // 拷贝数据到发送缓冲区 LL_DMA_DisableChannel(uart->dma, uart->dma_tx_channel); // 配置数据长度 LL_DMA_SetDataLength(uart->dma, uart->dma_tx_channel, len); // 使能DMA STREAM 也就是发送数据 LL_DMA_EnableChannel(uart->dma, uart->dma_tx_channel); } else { count = 0; for (uint16_t i = 0; i < len; i++) { count = 0; while (!LL_USART_IsActiveFlag_TXE(uart->huart)) { if (count++ >= 0xFE) { return; } } LL_USART_TransmitData8(uart->huart, data[i]); } count = 0; while (!LL_USART_IsActiveFlag_TC(uart->huart)) { if (count++ >= 0xFE) { return; } } } } /** * @brief 接收中断回调函数 * @param {uart_t} *uart UART设备句柄 * @return {*} 操作结果 * @note: 该函数用于处理接收中断。首先检查接收DMA使能标志,然后禁用接收中断,配置RX DMA并启用RX DMA通道。当接收到数据时,将数据复制到接收缓冲区,并调用接收中断回调函数。当接收缓冲区满时,关闭RX DMA通道并重置接收索引。 */ void uart_reception_callback(uart_t *uart) { DBG_ASSERT(uart != NULL __DBG_LINE); if (LL_USART_IsEnabledIT_RXNE(uart->huart) && LL_USART_IsActiveFlag_RXNE(uart->huart)) { uart->rxbuf[uart->rx_index++] = LL_USART_ReceiveData8(uart->huart); if (uart->rx_dma_en == FALSE) // 中断方式:一个字节一个字节的接收 { if (uart->rx_interupt_cb != NULL) { uart->rx_interupt_cb(uart->uart_index, uart->rxbuf, uart->rx_index); } uart->rx_index = 0; } } else if (LL_USART_IsEnabledIT_IDLE(uart->huart) && LL_USART_IsActiveFlag_IDLE(uart->huart)) { if (uart->rx_dma_en == TRUE) { LL_DMA_DisableChannel(uart->dma, uart->dma_rx_channel); uart->rx_index = uart->rxsize - LL_DMA_GetDataLength(uart->dma, uart->dma_rx_channel); if (uart->rx_interupt_cb != NULL && (uart->rx_index > 0 && uart->rx_index <= uart->rxsize)) { uart->rx_interupt_cb(uart->uart_index, uart->rxbuf, uart->rx_index); osel_memset(uart->rxbuf, 0, uart->rxsize); } LL_DMA_SetDataLength(uart->dma, uart->dma_rx_channel, uart->rxsize); // 这个不能少 先关闭DMA才能重新设置长度 LL_DMA_EnableChannel(uart->dma, uart->dma_rx_channel); } uart->rx_index = 0; LL_USART_ClearFlag_IDLE(uart->huart); } if (LL_USART_IsEnabledIT_TC(uart->huart) && LL_USART_IsActiveFlag_TC(uart->huart)) { if (uart->tx_complete_cb != NULL) { uart->tx_complete_cb(); } LL_USART_ClearFlag_TC(uart->huart); } if (LL_USART_IsEnabledIT_PE(uart->huart) && LL_USART_IsActiveFlag_PE(uart->huart)) { LL_USART_ClearFlag_PE(uart->huart); } if (LL_USART_IsActiveFlag_FE(uart->huart) && LL_USART_IsActiveFlag_FE(uart->huart)) { LL_USART_ClearFlag_FE(uart->huart); } if (LL_USART_IsActiveFlag_NE(uart->huart) && LL_USART_IsActiveFlag_NE(uart->huart)) { LL_USART_ClearFlag_NE(uart->huart); } if (LL_USART_IsActiveFlag_ORE(uart->huart) && LL_USART_IsActiveFlag_ORE(uart->huart)) { LL_USART_ClearFlag_ORE(uart->huart); } } /** * @brief 用于处理串口DMA接收中断的回调函数 * @param {uart_t} *uart - 串口对象 * @return {*} 无 * @note: */ void uart_dma_reception_callback(uart_t *uart) { // 检查输入参数是否为空 DBG_ASSERT(uart != NULL __DBG_LINE); // 禁用串口DMA的发送通道 LL_DMA_DisableChannel(uart->dma, uart->dma_tx_channel); // 清除发送中断标志位 DMA_CLEAR_FLAG_TC_CHANNEL(uart->dma, uart->dma_tx_channel); // 使能发送中断,用于关闭发送使能引脚 LL_USART_EnableIT_TC(uart->huart); // 使能发送中断,用于关闭发送使能引脚 uart->tx_dma_ok = TRUE; // 清除传输错误标志 DMA_CLEAR_FLAG_TE_CHANNEL(uart->dma, uart->dma_tx_channel); }