393 lines
14 KiB
C
393 lines
14 KiB
C
/*
|
||
* @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
|
||
* @param {uint32_t} baudrate 波特率
|
||
* @return {*}
|
||
* @note
|
||
*/
|
||
void uart_set_baudrate(uart_t *uart, uint32_t baudrate)
|
||
{
|
||
LL_USART_SetBaudRate(uart->huart, SystemCoreClock, LL_USART_OVERSAMPLING_16, baudrate);
|
||
}
|
||
|
||
/**
|
||
* @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);
|
||
}
|