529 lines
16 KiB
C
529 lines
16 KiB
C
|
|
#include "uart_fifo.h"
|
|
#include "ch32v20x.h"
|
|
#include <stdlib.h>
|
|
|
|
void uart_fifo_init(uart_fifo_t *fifo, USART_TypeDef *uart,
|
|
uint32_t mode_rx, uint32_t mode_tx)
|
|
{
|
|
fifo->UART = uart;
|
|
fifo->mode_rx = mode_rx;
|
|
fifo->mode_tx = mode_tx;
|
|
fifo->buffer_rx = NULL;
|
|
fifo->buffer_tx = NULL;
|
|
fifo->buffer_rx_len = 0;
|
|
fifo->buffer_tx_len = 0;
|
|
}
|
|
|
|
void uart_fifo_config(uart_fifo_t *fifo, uint32_t baud,
|
|
uint8_t wordlen, uint8_t stopbit, uint8_t parity,
|
|
size_t buff_rx_len, size_t buff_tx_len)
|
|
{
|
|
uint16_t WordLength = USART_WordLength_8b;
|
|
uint16_t StopBit = USART_StopBits_1;
|
|
uint16_t Parity = USART_Parity_No;
|
|
|
|
GPIO_InitTypeDef GPIO_InitStructure = {0};
|
|
USART_InitTypeDef USART_InitStructure = {0};
|
|
DMA_InitTypeDef DMA_InitStructure = {0};
|
|
NVIC_InitTypeDef NVIC_InitStructure = {0};
|
|
|
|
|
|
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);
|
|
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
|
|
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
|
|
|
|
|
|
if (fifo->buffer_rx)
|
|
free(fifo->buffer_rx);
|
|
if (fifo->buffer_tx)
|
|
free(fifo->buffer_tx);
|
|
|
|
fifo->buffer_rx = (uint8_t *)malloc(buff_rx_len);
|
|
fifo->buffer_tx = (uint8_t *)malloc(buff_tx_len);
|
|
fifo->buffer_rx_len = buff_rx_len;
|
|
fifo->buffer_tx_len = buff_tx_len;
|
|
fifo->buffer_tx_len_2 = buff_tx_len / 2;
|
|
|
|
USART_Cmd(fifo->UART, DISABLE);
|
|
|
|
switch (wordlen)
|
|
{
|
|
case 9:
|
|
WordLength = USART_WordLength_9b;
|
|
break;
|
|
|
|
default:
|
|
WordLength = USART_WordLength_8b;
|
|
break;
|
|
}
|
|
|
|
switch (stopbit)
|
|
{
|
|
case 2:
|
|
StopBit = USART_StopBits_2;
|
|
break;
|
|
|
|
default:
|
|
StopBit = USART_StopBits_1;
|
|
break;
|
|
}
|
|
|
|
switch (parity)
|
|
{
|
|
case 1:
|
|
Parity = USART_Parity_Odd;
|
|
break;
|
|
|
|
case 2:
|
|
Parity = USART_Parity_Even;
|
|
break;
|
|
|
|
default:
|
|
Parity = USART_Parity_No;
|
|
break;
|
|
}
|
|
|
|
USART_InitStructure.USART_BaudRate = baud;
|
|
USART_InitStructure.USART_WordLength = WordLength;
|
|
USART_InitStructure.USART_StopBits = StopBit;
|
|
USART_InitStructure.USART_Parity = Parity;
|
|
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
|
|
USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
|
|
USART_Init(fifo->UART, &USART_InitStructure);
|
|
|
|
|
|
if (fifo->buffer_rx_len || fifo->mode_rx == UART_FIFO_BLOCK)
|
|
{
|
|
switch (fifo->mode_rx)
|
|
{
|
|
case UART_FIFO_DMA:
|
|
{
|
|
DMA_InitTypeDef DMA_InitStructure = {0};
|
|
DMA_DeInit(fifo->dma_channelx_rx);
|
|
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&fifo->UART->DATAR;
|
|
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)fifo->buffer_rx;
|
|
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
|
|
DMA_InitStructure.DMA_BufferSize = fifo->buffer_rx_len;
|
|
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
|
|
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
|
|
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
|
|
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
|
|
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
|
|
DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
|
|
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
|
|
DMA_Init(fifo->dma_channelx_rx, &DMA_InitStructure);
|
|
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//usart_receive_config(com, USART_RECEIVE_DISABLE);
|
|
}
|
|
|
|
if (fifo->buffer_tx_len || fifo->mode_tx == UART_FIFO_BLOCK)
|
|
{
|
|
switch (fifo->mode_tx)
|
|
{
|
|
case UART_FIFO_DMA:
|
|
{
|
|
DMA_InitTypeDef DMA_InitStructure = {0};
|
|
DMA_DeInit(fifo->dma_channelx_tx);
|
|
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&fifo->UART->DATAR;
|
|
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)fifo->buffer_tx;
|
|
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
|
|
DMA_InitStructure.DMA_BufferSize = fifo->buffer_tx_len;
|
|
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
|
|
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
|
|
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
|
|
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
|
|
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
|
|
DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
|
|
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
|
|
DMA_Init(fifo->dma_channelx_tx, &DMA_InitStructure);
|
|
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//usart_transmit_config(com, USART_TRANSMIT_DISABLE);
|
|
}
|
|
|
|
}
|
|
|
|
void uart_fifo_open(uart_fifo_t *fifo)
|
|
{
|
|
fifo->byt_rx = 0;
|
|
fifo->byt_tx = 0;
|
|
fifo->pkg_rx = 0;
|
|
fifo->pkg_tx = 0;
|
|
fifo->last_byt_rx = 0;
|
|
fifo->last_byt_tx = 0;
|
|
fifo->last_pkg_rx = 0;
|
|
fifo->last_pkg_tx = 0;
|
|
fifo->Bps_rx = 0;
|
|
fifo->Pps_rx = 0;
|
|
fifo->Bps_tx = 0;
|
|
fifo->Pps_tx = 0;
|
|
fifo->err_rx = 0;
|
|
fifo->err_tx = 0;
|
|
fifo->buffer_rx_max = 0;
|
|
fifo->buffer_tx_max = 0;
|
|
|
|
NVIC_InitTypeDef NVIC_InitStructure = {0};
|
|
|
|
NVIC_InitStructure.NVIC_IRQChannel = fifo->nvic_irq;
|
|
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=fifo->nvic_irq_pre_priority;
|
|
NVIC_InitStructure.NVIC_IRQChannelSubPriority=fifo->nvic_irq_sub_priority;
|
|
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
|
|
NVIC_Init(&NVIC_InitStructure);
|
|
|
|
USART_ITConfig(fifo->UART, USART_IT_IDLE, ENABLE);
|
|
|
|
switch (fifo->mode_rx)
|
|
{
|
|
case UART_FIFO_IT:
|
|
if (fifo->buffer_rx_len)
|
|
{
|
|
fifo->buffer_rx_head = 0;
|
|
fifo->buffer_rx_tail = 0;
|
|
USART_ITConfig(fifo->UART, USART_IT_RXNE, ENABLE);
|
|
}
|
|
break;
|
|
case UART_FIFO_DMA:
|
|
if (fifo->buffer_rx_len)
|
|
{
|
|
DMA_Cmd(fifo->dma_channelx_rx, ENABLE);
|
|
USART_DMACmd(fifo->UART, USART_DMAReq_Rx, ENABLE);
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
switch (fifo->mode_tx)
|
|
{
|
|
case UART_FIFO_IT:
|
|
fifo->buffer_tx_head = 0;
|
|
fifo->buffer_tx_tail = 0;
|
|
break;
|
|
case UART_FIFO_DMA:
|
|
fifo->buffer_tx_head = 0;
|
|
fifo->buffer_tx_tail = 0; /* 0-not_sending; 1-sending */
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
USART_Cmd(fifo->UART, ENABLE);
|
|
}
|
|
|
|
void uart_fifo_close(uart_fifo_t *fifo)
|
|
{
|
|
USART_Cmd(fifo->UART, DISABLE);
|
|
switch (fifo->mode_rx)
|
|
{
|
|
case UART_FIFO_IT:
|
|
USART_ITConfig(fifo->UART, USART_IT_RXNE, DISABLE);
|
|
break;
|
|
case UART_FIFO_DMA:
|
|
USART_DMACmd(fifo->UART, USART_DMAReq_Tx, DISABLE);
|
|
DMA_Cmd(fifo->dma_channelx_rx, DISABLE);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
switch (fifo->mode_tx)
|
|
{
|
|
case UART_FIFO_IT:
|
|
USART_ITConfig(fifo->UART, USART_IT_TXE, DISABLE);
|
|
break;
|
|
case UART_FIFO_DMA:
|
|
USART_DMACmd(fifo->UART, USART_DMAReq_Tx, DISABLE);
|
|
DMA_Cmd(fifo->dma_channelx_tx, DISABLE);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
USART_ITConfig(fifo->UART, USART_IT_IDLE, DISABLE);
|
|
NVIC_DisableIRQ(fifo->nvic_irq);
|
|
fifo->buffer_rx_len = 0;
|
|
fifo->buffer_tx_len = 0;
|
|
}
|
|
|
|
void uart_fifo_iqr(uart_fifo_t *fifo)
|
|
{
|
|
if (RESET != USART_GetITStatus(fifo->UART, USART_IT_RXNE))
|
|
{
|
|
USART_ClearITPendingBit(fifo->UART, USART_IT_RXNE);
|
|
/* Read one byte from the receive data register */
|
|
fifo->buffer_rx[fifo->buffer_rx_head++] = (uint8_t)USART_ReceiveData(fifo->UART);
|
|
fifo->byt_rx++;
|
|
|
|
if (fifo->buffer_rx_head >= fifo->buffer_rx_len)
|
|
{
|
|
fifo->buffer_rx_head = 0;
|
|
}
|
|
}
|
|
|
|
if (RESET != USART_GetITStatus(fifo->UART, USART_IT_TXE))
|
|
{
|
|
USART_ClearITPendingBit(fifo->UART, USART_IT_TXE);
|
|
/* Write one byte to the transmit data register */
|
|
USART_SendData(fifo->UART, fifo->buffer_tx[fifo->buffer_tx_tail++]);
|
|
fifo->byt_tx++;
|
|
if (fifo->buffer_tx_tail >= fifo->buffer_tx_len)
|
|
{
|
|
fifo->buffer_tx_tail = 0;
|
|
}
|
|
|
|
if (fifo->buffer_tx_tail == fifo->buffer_tx_head)
|
|
{
|
|
/* disable the USARTx transmit interrupt */
|
|
USART_ITConfig(fifo->UART, USART_IT_TXE,DISABLE);
|
|
}
|
|
}
|
|
|
|
if ((RESET != USART_GetITStatus(fifo->UART, USART_IT_IDLE)))
|
|
{
|
|
USART_ClearITPendingBit(fifo->UART, USART_IT_IDLE);
|
|
USART_ReceiveData(fifo->UART);
|
|
fifo->pkg_rx++;
|
|
}
|
|
}
|
|
|
|
void uart_fifo_write(uart_fifo_t *fifo, const uint8_t *buff, size_t len)
|
|
{
|
|
fifo->pkg_tx++;
|
|
switch (fifo->mode_tx)
|
|
{
|
|
case UART_FIFO_DMA:
|
|
if (fifo->buffer_tx_len)
|
|
{
|
|
for (size_t i = 0; i < len; ++i)
|
|
{
|
|
fifo->buffer_tx[fifo->buffer_tx_head++] = buff[i];
|
|
if (fifo->buffer_tx_head == fifo->buffer_tx_len_2)
|
|
{
|
|
fifo->buffer_tx_head = fifo->buffer_tx_len_2 - 1;
|
|
}
|
|
else if (fifo->buffer_tx_head >= fifo->buffer_tx_len)
|
|
{
|
|
fifo->buffer_tx_head = fifo->buffer_tx_len - 1;
|
|
}
|
|
}
|
|
if (SET == DMA_GetFlagStatus(DMA1_FLAG_TC1))
|
|
{
|
|
DMA_ClearFlag(DMA1_FLAG_TC1);
|
|
fifo->buffer_tx_tail = 0;
|
|
}
|
|
|
|
if (SET == DMA_GetFlagStatus(DMA1_IT_TE1))
|
|
{
|
|
DMA_ClearFlag(DMA1_IT_TE1);
|
|
fifo->err_tx++;
|
|
fifo->buffer_tx_tail = 0;
|
|
}
|
|
|
|
if (fifo->buffer_tx_tail == 0)
|
|
{
|
|
DMA_Cmd(fifo->dma_channelx_tx,DISABLE);
|
|
if (fifo->buffer_tx_head == 0 || fifo->buffer_tx_head == fifo->buffer_tx_len_2)
|
|
{
|
|
fifo->buffer_tx_tail = 0;
|
|
}
|
|
else
|
|
{
|
|
if (fifo->buffer_tx_head < fifo->buffer_tx_len_2)
|
|
{
|
|
//dma_memory_address_config(fifo->dma_periph, fifo->dma_channelx_tx, DMA_MEMORY_0, (uint32_t)fifo->buffer_tx); //设置要发送数据的内存地址
|
|
fifo->dma_channelx_tx->MADDR = (uint32_t)fifo->buffer_tx;
|
|
|
|
if (fifo->buffer_tx_head > fifo->buffer_tx_max)
|
|
{
|
|
fifo->buffer_tx_max = fifo->buffer_tx_head;
|
|
}
|
|
DMA_SetCurrDataCounter(fifo->dma_channelx_tx, fifo->buffer_tx_head); //一共发多少个数据
|
|
fifo->buffer_tx_head = fifo->buffer_tx_len_2;
|
|
}
|
|
else
|
|
{
|
|
//dma_memory_address_config(fifo->dma_periph, fifo->dma_channelx_tx, DMA_MEMORY_0, (uint32_t)&fifo->buffer_tx[fifo->buffer_tx_len_2]);
|
|
fifo->dma_channelx_tx->MADDR = (uint32_t)&fifo->buffer_tx[fifo->buffer_tx_len_2];
|
|
|
|
uint32_t blen = fifo->buffer_tx_head - fifo->buffer_tx_len_2;
|
|
if (blen > fifo->buffer_tx_max)
|
|
{
|
|
fifo->buffer_tx_max = blen;
|
|
}
|
|
DMA_SetCurrDataCounter(fifo->dma_channelx_tx, blen); //一共发多少个数据
|
|
fifo->buffer_tx_head = 0;
|
|
}
|
|
USART_DMACmd(fifo->UART, USART_DMAReq_Tx, ENABLE);
|
|
DMA_Cmd(fifo->dma_channelx_tx, ENABLE);
|
|
|
|
fifo->buffer_tx_tail = 1;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case UART_FIFO_IT:
|
|
if (fifo->buffer_tx_len)
|
|
{
|
|
for (size_t i = 0; i < len; ++i)
|
|
{
|
|
fifo->buffer_tx[fifo->buffer_tx_head++] = buff[i];
|
|
if (fifo->buffer_tx_head >= fifo->buffer_tx_len)
|
|
{
|
|
fifo->buffer_tx_head = 0;
|
|
}
|
|
}
|
|
int blen = fifo->buffer_tx_head - fifo->buffer_tx_tail;
|
|
if (blen < 0)
|
|
{
|
|
blen += fifo->buffer_tx_len;
|
|
}
|
|
if (blen > fifo->buffer_tx_max)
|
|
{
|
|
fifo->buffer_tx_max = blen;
|
|
}
|
|
if (fifo->buffer_tx_tail != fifo->buffer_tx_head)
|
|
{
|
|
/* enable the USARTx transmit interrupt */
|
|
USART_ITConfig(fifo->UART, USART_IT_TXE, ENABLE);
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
for (size_t i = 0; i < len; ++i)
|
|
{
|
|
USART_SendData(fifo->UART, buff[i]);
|
|
while (RESET == USART_GetFlagStatus(fifo->UART, USART_IT_TXE))
|
|
;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
size_t uart_fifo_read(uart_fifo_t *fifo, uint8_t *buff, size_t len)
|
|
{
|
|
size_t i = 0;
|
|
int blen;
|
|
switch (fifo->mode_rx)
|
|
{
|
|
case UART_FIFO_DMA:
|
|
if (fifo->buffer_rx_len)
|
|
{
|
|
/*
|
|
if (SET == DMA_GetFlagStatus(fifo->dma_channelx_rx), DMA_FLAG_FEE))
|
|
{
|
|
dma_flag_clear(fifo->dma_periph, fifo->dma_channelx_rx, DMA_FLAG_FEE);
|
|
fifo->err_rx++;
|
|
}
|
|
if (SET == dma_flag_get(fifo->dma_periph, fifo->dma_channelx_rx, DMA_FLAG_TAE))
|
|
{
|
|
dma_flag_clear(fifo->dma_periph, fifo->dma_channelx_rx, DMA_FLAG_TAE);
|
|
fifo->err_rx++;
|
|
}
|
|
if (SET == dma_flag_get(fifo->dma_periph, fifo->dma_channelx_rx, DMA_FLAG_SDE))
|
|
{
|
|
dma_flag_clear(fifo->dma_periph, fifo->dma_channelx_rx, DMA_FLAG_SDE);
|
|
fifo->err_rx++;
|
|
}
|
|
*/
|
|
|
|
if (SET == DMA_GetFlagStatus(DMA1_FLAG_TC1))
|
|
{
|
|
DMA_ClearFlag(DMA1_FLAG_TC1);
|
|
}
|
|
|
|
if (SET == DMA_GetFlagStatus(DMA1_IT_TE1))
|
|
{
|
|
DMA_ClearFlag(DMA1_IT_TE1);
|
|
fifo->err_rx++;
|
|
}
|
|
|
|
fifo->buffer_rx_head = fifo->buffer_rx_len - DMA_GetCurrDataCounter(fifo->dma_channelx_rx);
|
|
blen = fifo->buffer_rx_head - fifo->buffer_rx_tail;
|
|
if (blen < 0)
|
|
{
|
|
blen += fifo->buffer_rx_len;
|
|
}
|
|
if (blen > fifo->buffer_rx_max)
|
|
{
|
|
fifo->buffer_rx_max = blen;
|
|
}
|
|
for (; i < len; ++i)
|
|
{
|
|
if (fifo->buffer_rx_tail != fifo->buffer_rx_head)
|
|
{
|
|
buff[i] = fifo->buffer_rx[fifo->buffer_rx_tail++];
|
|
fifo->byt_rx++;
|
|
if (fifo->buffer_rx_tail >= fifo->buffer_rx_len)
|
|
{
|
|
fifo->buffer_rx_tail = 0;
|
|
}
|
|
}
|
|
else
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
case UART_FIFO_IT:
|
|
if (fifo->buffer_rx_len)
|
|
{
|
|
blen = fifo->buffer_rx_head - fifo->buffer_rx_tail;
|
|
if (blen < 0)
|
|
{
|
|
blen += fifo->buffer_rx_len;
|
|
}
|
|
if (blen > fifo->buffer_rx_max)
|
|
{
|
|
fifo->buffer_rx_max = blen;
|
|
}
|
|
for (; i < len; ++i)
|
|
{
|
|
if (fifo->buffer_rx_tail != fifo->buffer_rx_head)
|
|
{
|
|
buff[i] = fifo->buffer_rx[fifo->buffer_rx_tail++];
|
|
if (fifo->buffer_rx_tail >= fifo->buffer_rx_len)
|
|
{
|
|
fifo->buffer_rx_tail = 0;
|
|
}
|
|
}
|
|
else
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
for (; i < len; ++i)
|
|
{
|
|
while (RESET == USART_GetFlagStatus(fifo->UART, USART_FLAG_RXNE))
|
|
;
|
|
buff[i] = USART_ReceiveData(fifo->UART);
|
|
}
|
|
break;
|
|
}
|
|
return i;
|
|
}
|
|
|
|
void uart_fifo_stats(uart_fifo_t *fifo)
|
|
{
|
|
fifo->Bps_rx = fifo->byt_rx - fifo->last_byt_rx;
|
|
fifo->last_byt_rx = fifo->byt_rx;
|
|
fifo->Pps_rx = fifo->pkg_rx - fifo->last_pkg_rx;
|
|
fifo->last_pkg_rx = fifo->pkg_rx;
|
|
|
|
fifo->Bps_tx = fifo->byt_tx - fifo->last_byt_tx;
|
|
fifo->last_byt_tx = fifo->byt_tx;
|
|
fifo->Pps_tx = fifo->pkg_tx - fifo->last_pkg_tx;
|
|
fifo->last_pkg_tx = fifo->pkg_tx;
|
|
}
|