This repository has been archived on 2025-01-02. You can view files and clone it, but cannot push or open issues or pull requests.
torsion/User/system/bsp/uarts.c

301 lines
11 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* @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)
/**
* @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);
}
}
/**
* @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)
{
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
{
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(uart->dma, 2);
DMA_ClEAR_FLAG_TC(uart->dma, 7);
// 使能发送中断,用于关闭发送使能引脚
LL_USART_EnableIT_TC(uart->huart); // 使能发送中断,用于关闭发送使能引脚
// 清除接收中断标志位
DMA_ClEAR_FLAG_TE(uart->dma, 2);
DMA_ClEAR_FLAG_TE(uart->dma, 7);
}