UART 串口空闲中断+DMA传输半完成、完成中断
文章目录
UART 串口空闲中断+DMA传输半完成、完成中断
简介
UART(Universal Asynchronous Receiver/Transmitter)通用异步收发传输器,UART 作为异步串口通信协议提供标准异步收发模式。是在应用程序开发过程中使用频率最高的数据总线。
UART串口的特点是将数据一位一位地顺序传送,只要 2 根传输线就可以实现双向通信,一根线发送数据的同时用另一根线接收数据。UART 串口通信有几个重要的参数,分别是波特率、起始位、数据位、停止位和奇偶检验位,对于两个使用 UART 串口通信的端口,这些参数必须匹配,否则通信将无法正常完成。UART 串口传输的数据格式如下图所示,仅为8 数据位和 1 停止位模式,其他不做介绍
协议格式
波特率
数据位、起始位、停止位的维持电平时间的倒数,例如波特率为115200bps时,数据位宽度约为8.68us
起始位
起始位为一个周期宽度的低电平
停止位
停止位为一个周期宽度的高电平,根据芯片不同有时可以配置成0.5、1、1.5或者2个停止位。
校验位(非必须)
偶校验位,奇校验位,无校验位,上图中为无校验。
数据位
数据位一般是8位,根据芯片不同可能有4、5、6、7、8、9等数量;
硬件连接
实现方式
为减轻处理器的负担,可以采用串口中断搭配DMA访问数据缓冲区。
数据发送
- 串口发送完成中断
- 串口DMA传输
数据接收
方式 | 优点 | 缺点 |
---|---|---|
串口RXNE | 实现简单 | 每收一个字节中断一次,在数据量大时,会频繁触发中断浪费CPU资源 |
串口空闲中断+DMA传输 | 可以接收不定长数据,将连续数据接收完成后才触发中断 | 如果单次接收数据长度超过DMA配置长度就会有数据丢失,对单片机缓冲区和数据发送方有要求。 |
串口空闲中断+DMA传输完成、半完成中断 | 可以接收不定长数据,DMA数据传输完成一半、传输完成时触发DMA中断处理数据;串口空闲中断触发时处理数据。 | 实现复杂 |
这里我采用发送方式为串口DMA;接收方式为串口空闲中断+DMA传输完成、半完成中断。
实际上DMA传输半完成中断和完成中断的实现类似于双缓冲区接收,只不过使用同一块连续内存,半完成使用前半部分,完成使用后半部分。仅使用DMA中断还存在一个隐患,当尾数据数量不足导致半完成中断始终未触发,此时就需要借助串口空闲中断将尾数据提取出来。
例如上图中DMA长度为4,假如串口接收数据为byte0-byte8,共9个字节,会触发两次DMA半完成中断,两次DMA完成中断,这样可以收取前8字节,尾数据仅剩byte8是无法通过DMA中断来收取,这时引入串口空闲中断来收尾即可。
程序实现
STM32F407VET6+标准库
缓冲区定义
// 串口发送缓冲区大小
#define FK_LOG_TX_BUFFER 512 // 根据自己需求配置
#define FK_LOG_TX_DMA_BUFFER 64 // dma发送buffer
// 串口接收缓冲区大小
#define FK_LOG_RX_BUFFER 512 // 根据自己需求配置
#define FK_LOG_RX_DMA_BUFFER 64 // dma接收buffer
// dma发送缓冲区
struct log_tx_buffer
{
struct fk_ringbuffer ringbuffer; // 环队
int flag; // 发送完成标志
fk_uint8_t buff[FK_LOG_TX_BUFFER]; // 环队空间申请
char dma_buff[FK_LOG_TX_DMA_BUFFER];// dma发送缓冲区
};
// dma接收缓冲区
struct log_rx_buffer
{
struct fk_ringbuffer ringbuffer; // 环队
int flag; // 发送完成标志
fk_uint8_t buff[FK_LOG_RX_BUFFER]; // 环队空间申请
char dma_buff[FK_LOG_RX_DMA_BUFFER];// dma接收缓冲区
};
#define LOG_BUFF_DEFAULT {.flag=1};
static struct log_tx_buffer log_tx = LOG_BUFF_DEFAULT;
static struct log_rx_buffer log_rx = LOG_BUFF_DEFAULT;
gpio初始化
static void usart_gpio_config(void)
{//GPIO
GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
// 复用功能配置
GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_USART1);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_USART1);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
// PA9 USART1-TX
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// PA10 USART1-RX
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
uart初始化
static void usart_config(void)
{// USART
USART_InitTypeDef USART_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
USART_DeInit( USART1 );
USART_InitStructure.USART_BaudRate = 115200;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init( USART1, &USART_InitStructure );
USART_ClearFlag(USART1, USART_FLAG_TC);
USART_ClearFlag(USART1, USART_FLAG_RXNE);
USART_Cmd( USART1, ENABLE);
}
usart_dma 配置
static void usart_dma_config(DMA_Stream_TypeDef *DMAx_Streamx ,
uint32_t DMA_Channel_x ,
uint32_t DMA_PAddr ,
uint32_t DMA_dir )
{
DMA_InitTypeDef DMA_InitStructure;
//DMA TX DMA2-CH4
// DMA时钟
if( DMAx_Streamx<=DMA1_Stream7 )
{
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE);
}
else
{
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);
}
// 复位初始化DMA数据流
DMA_DeInit(DMAx_Streamx);
// 确保DMA数据流复位完成
while (DMA_GetCmdStatus(DMAx_Streamx) != DISABLE) {
}
// usart1 tx对应dma2,通道4,数据流7
DMA_InitStructure.DMA_Channel = DMA_Channel_x;
// 设置DMA源:串口数据寄存器地址
DMA_InitStructure.DMA_PeripheralBaseAddr = DMA_PAddr;
// 方向:从内存到外设
DMA_InitStructure.DMA_DIR = DMA_dir;
// 外设地址不增
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
// 内存地址自增
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
// 外设数据单位-1Byte
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
// 内存数据单位-1Byte
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
// DMA模式:不循环
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
// 优先级:low
DMA_InitStructure.DMA_Priority = DMA_Priority_Low;
/*禁用FIFO*/
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
// 存储器突发传输 16个节拍
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
// 外设突发传输 1个节拍
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
// 内存地址-要传输的变量的指针
DMA_InitStructure.DMA_Memory0BaseAddr = 0;
// 传输大小
DMA_InitStructure.DMA_BufferSize = 0;
// 配置DMA2的数据流7
DMA_Init(DMAx_Streamx, &DMA_InitStructure);
/*使能DMA*/
DMA_Cmd(DMAx_Streamx, DISABLE);
// DMA_Cmd(DMA2_Stream7, ENABLE);
// LOG_D( "USART1 init" );
}
中断优先级 配置
static void nvic_irq_config(uint8_t NVIC_IRQChannel, uint8_t Priority)
{
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = NVIC_IRQChannel;//串口1发送中断通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = Priority; //优先级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
初始化调用
static void usart_init(void)
{
// uart配置
usart_gpio_config();
usart_config();
//RX
// dma
usart_dma_config( DMA2_Stream5 ,
DMA_Channel_4 ,
(uint32_t)(&USART1->DR) ,
DMA_DIR_PeripheralToMemory );
// 传输完成、半完成中断
nvic_irq_config(DMA2_Stream5_IRQn, 15);
DMA_ITConfig(DMA2_Stream5, DMA_IT_TC, ENABLE);
DMA_ITConfig(DMA2_Stream5, DMA_IT_HT, ENABLE);
usart1_dma_recv( log_rx.dma_buff, sizeof(log_rx.dma_buff) );
// 空闲中断
nvic_irq_config(USART1_IRQn, 10);
USART_ITConfig(USART1, USART_IT_IDLE, ENABLE);
// USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
//TX
// dma
usart_dma_config( DMA2_Stream7 ,
DMA_Channel_4 ,
(uint32_t)(&USART1->DR) ,
DMA_DIR_MemoryToPeripheral );
// 使能中断
nvic_irq_config(DMA2_Stream7_IRQn, 15);
// 传输完成中断
DMA_ITConfig(DMA2_Stream7, DMA_IT_TC, ENABLE);
// uart启动
USART_DMACmd(USART1,USART_DMAReq_Tx,ENABLE);
USART_DMACmd(USART1,USART_DMAReq_Rx,ENABLE);
}
中断服务函数
void USART1_IRQHandler(void)
{
fk_size_t length = 0;
if(USART_GetITStatus(USART1,USART_IT_IDLE) != RESET)//接收到一帧数据 空闲中断触发
{
USART1->SR;//先读SR
USART1->DR;//再读DR
USART_ClearFlag(USART1,USART_FLAG_IDLE);
// 接收数据入队
length = sizeof(log_rx.dma_buff) - DMA_GetCurrDataCounter(DMA2_Stream5);
fk_ringbuffer_put( &log_rx.ringbuffer, \
( fk_uint8_t *)log_rx.dma_buff, \
length);
// 启动下次dma传输
DMA_ClearFlag(DMA2_Stream5,DMA_FLAG_TCIF5); //清除DMA2_Steam7传输完成标志
usart1_dma_recv( log_rx.dma_buff, sizeof(log_rx.dma_buff) );
}
// if(USART_GetITStatus(USART1,USART_IT_RXNE) != RESET)//接收到一帧数据 空闲中断触发
// {
// USART_ClearFlag(USART1,USART_FLAG_RXNE);
//
//
// }
}
// 发送中断
void DMA2_Stream7_IRQHandler(void)
{
fk_size_t length = 0;
//清除标志
if(DMA_GetFlagStatus(DMA2_Stream7,DMA_FLAG_TCIF7)!=RESET)//等待DMA2_Steam7传输完成
{
DMA_ClearFlag(DMA2_Stream7,DMA_FLAG_TCIF7); //清除DMA2_Steam7传输完成标志
DMA_Cmd(DMA2_Stream7,DISABLE); //关闭使能
// 串口空闲
log_tx.flag=1;
// 获取缓冲区剩余数据,再次发送
length = fk_ringbuffer_get(&log_tx.ringbuffer, (fk_uint8_t*)log_tx.dma_buff, sizeof(log_tx.dma_buff));
if( length )
{
usart1_dma_send( log_tx.dma_buff, length);
log_tx.flag=0; // 串口忙碌
}
}
}
// 接收
void DMA2_Stream5_IRQHandler(void)
{
//清除标志
if(DMA_GetFlagStatus(DMA2_Stream5,DMA_FLAG_TCIF5)!=RESET)//等待DMA2_Steam7传输完成
{
DMA_Cmd(DMA2_Stream5,DISABLE); //关闭使能
// log_rx.flag=1;
// 接收数据入队 (log_rx.dma_buff+sizeof(log_rx.dma_buff)/2)
fk_ringbuffer_put( &log_rx.ringbuffer, \
( fk_uint8_t *)(log_rx.dma_buff+sizeof(log_rx.dma_buff)/2), \
sizeof(log_rx.dma_buff));
usart1_dma_recv( log_rx.dma_buff, sizeof(log_rx.dma_buff) );
DMA_ClearFlag(DMA2_Stream5,DMA_FLAG_TCIF5); //清除DMA2_Steam7传输完成标志
}
if(DMA_GetFlagStatus(DMA2_Stream5,DMA_FLAG_HTIF5)!=RESET)// 半完成
{
// 接收数据入队
fk_ringbuffer_put( &log_rx.ringbuffer, \
( fk_uint8_t *)log_rx.dma_buff, \
sizeof(log_rx.dma_buff)/2);
DMA_ClearFlag(DMA2_Stream5,DMA_FLAG_HTIF5);
}
}
串口DMA及其他函数
/***************************** DMA 发送 ********************************/
static void usart1_dma_send(const char *add, unsigned int length)
{
while( !log_tx.flag ) { }
log_tx.flag=0;
//关闭DMA传输
DMA_Cmd(DMA2_Stream7, DISABLE);
DMA_ClearFlag(DMA2_Stream7,DMA_FLAG_TCIF7);
DMA_ClearFlag(DMA2_Stream7,DMA_FLAG_TCIF7); //清除DMA2_Steam7传输完成标志
//确保DMA可以被设置
while (DMA_GetCmdStatus(DMA2_Stream7) != DISABLE){}
// DMA2_Stream7->M0AR = (uint32_t)add;
DMA_MemoryTargetConfig(DMA2_Stream7, (uint32_t) add, DMA_Memory_0);
//数据传输量
DMA_SetCurrDataCounter(DMA2_Stream7, length);
//开启DMA传输
DMA_Cmd(DMA2_Stream7, ENABLE);
}
/***************************** DMA 接收 ********************************/
static void usart1_dma_recv(const char *add, unsigned int length)
{
//关闭DMA传输
DMA_Cmd(DMA2_Stream5, DISABLE);
DMA_ClearFlag(DMA2_Stream5,DMA_FLAG_TCIF5); //清除DMA2_Steam7传输完成标志
//确保DMA可以被设置
while (DMA_GetCmdStatus(DMA2_Stream5) != DISABLE){}
DMA2_Stream7->M0AR = (uint32_t)add;
DMA_MemoryTargetConfig(DMA2_Stream5, (uint32_t) add, DMA_Memory_0);
//数据传输量
DMA_SetCurrDataCounter(DMA2_Stream5, length);
//开启DMA传输
DMA_Cmd(DMA2_Stream5, ENABLE);
}
// fk_printf 重新实现
#include <string.h>
void fk_hw_console_output(const char *str)
{
usart1_dma_send( str, strlen(str));
}
int fk_printf(const char *fmt, ...)
{
char log_buff[FK_LOG_TX_BUFFER];
va_list args;
fk_size_t length = 0;
fk_size_t len = 0;
va_start(args, fmt);
// 阻塞
// while( fk_ringbuffer_data_len(&log_queue) )
// {
// }
// 非阻塞
length = log_tx.ringbuffer.buffer_size-fk_ringbuffer_data_len(&log_tx.ringbuffer);
// FK_ASSERT(length<=FK_LOG_BUFFER);
// 2.字符串格式化 - 有可能缓冲区(FK_LOG_TX_BUFFER)不足导致丢数
length = vsnprintf(log_buff, length, fmt, args);
// 3.入队
len = fk_ringbuffer_put(&log_tx.ringbuffer, (const fk_uint8_t *)log_buff, length);
// 4.串口空闲?
if(log_tx.flag)
{// 串口空闲,发起dma
length = fk_ringbuffer_get(&log_tx.ringbuffer, (fk_uint8_t*)log_tx.dma_buff, sizeof(log_tx.dma_buff));
usart1_dma_send( log_tx.dma_buff, length);
}
va_end(args);
// 实际数量
return len;
}
int fk_send(const fk_uint8_t *add, unsigned int length)
{
fk_size_t len = 0;
// 阻塞
// while( fk_ringbuffer_data_len(&log_queue) )
// {
// }
// 非阻塞
// 3.入队
len = fk_ringbuffer_put(&log_tx.ringbuffer, (const fk_uint8_t *)add, length);
// 4.串口空闲?
if(log_tx.flag)
{// 串口空闲,发起dma
length = fk_ringbuffer_get(&log_tx.ringbuffer, (fk_uint8_t*)log_tx.dma_buff, sizeof(log_tx.dma_buff));
usart1_dma_send( log_tx.dma_buff, length);
}
return len;
}
// 串口接收数据回显
int fk_recv_test(void)
{
fk_size_t len;
static fk_uint8_t buff[512];
// 缓冲区数据获取
len = fk_ringbuffer_get(&log_rx.ringbuffer, (fk_uint8_t*)buff, sizeof(buff));
if( len )
{// 获取成功发送
fk_send( buff, len);
}
}
/********************************* 环境初始化 ********************************/
int board_env_start_up(void)
{
NVIC_PriorityGro upConfig( NVIC_PriorityGroup_4 );
// 0. 时钟
// 1. dbg串口 // dbg uart
// log_tx.flag = 1;// 空闲
// log_rx.flag = 1;
fk_ringbuffer_init (&log_tx.ringbuffer,log_tx.buff,sizeof(log_tx.buff));
fk_ringbuffer_reset (&log_tx.ringbuffer);
fk_ringbuffer_init (&log_rx.ringbuffer,log_rx.buff,sizeof(log_rx.buff));
fk_ringbuffer_reset (&log_rx.ringbuffer);
usart_init();
// 2. systick
// systick_config();
return 0;
}
使用例程
int main(void){
board_env_start_up();
fk_printf("fk_printf:hello world!!!\r\n");
fk_send("QWER\r\n",6);
while ( 1 )
{
fk_recv_test();
}
}
使用说明
发送函数接口为
int fk_printf(const char *fmt, ...);
int fk_send(const fk_uint8_t *add, unsigned int length);
数据接收使用例程
int fk_recv_test(void)
{
fk_size_t len;
static fk_uint8_t buff[512];
// 缓冲区数据获取
len = fk_ringbuffer_get(&log_rx.ringbuffer, (fk_uint8_t*)buff, sizeof(buff));
if( len )
{
// len非0 获取数据成功,数据处理
fk_send( buff, len);
}
}
缓冲区支持
以上操作中用到了环形缓冲区(FIFO),用作串口接收发送的缓冲空间
// ringbuffer.h
#ifndef __RING_BUFFER_H__
#define __RING_BUFFER_H__
#ifdef __cplusplus
extern "C" {
#endif
//#include <framework.h>
typedef signed char fk_int8_t; /**< 8bit integer type */
typedef signed short fk_int16_t; /**< 16bit integer type */
typedef signed int fk_int32_t; /**< 32bit integer type */
typedef unsigned char fk_uint8_t; /**< 8bit unsigned integer type */
typedef unsigned short fk_uint16_t; /**< 16bit unsigned integer type */
typedef unsigned int fk_uint32_t; /**< 32bit unsigned integer type */
typedef fk_ubase_t fk_size_t; /**< Type for size number */
typedef fk_base_t fk_ssize_t; /**< Used for a count of bytes or an error indication */
#define fk_inline static __inline
/* ring buffer */
struct fk_ringbuffer
{
fk_uint8_t *buffer_ptr;
/* use the msb of the {read,write}_index as mirror bit. You can see this as
* if the buffer adds a virtual mirror and the pointers point either to the
* normal or to the mirrored buffer. If the write_index has the same value
* with the read_index, but in a different mirror, the buffer is full.
* While if the write_index and the read_index are the same and within the
* same mirror, the buffer is empty. The ASCII art of the ringbuffer is:
*
* mirror = 0 当前缓冲区 mirror = 1 镜像缓冲区
* +---+---+---+---+---+---+---+|+~~~+~~~+~~~+~~~+~~~+~~~+~~~+
* | 0 | 1 | 2 | 3 | 4 | 5 | 6 ||| 0 | 1 | 2 | 3 | 4 | 5 | 6 | Full
* +---+---+---+---+---+---+---+|+~~~+~~~+~~~+~~~+~~~+~~~+~~~+
* read_idx-^ write_idx-^
*
* +---+---+---+---+---+---+---+|+~~~+~~~+~~~+~~~+~~~+~~~+~~~+
* | 0 | 1 | 2 | 3 | 4 | 5 | 6 ||| 0 | 1 | 2 | 3 | 4 | 5 | 6 | Empty
* +---+---+---+---+---+---+---+|+~~~+~~~+~~~+~~~+~~~+~~~+~~~+
* read_idx-^^-write_idx
*/
fk_uint32_t read_mirror : 1;
fk_uint32_t read_index : 31;
fk_uint32_t write_mirror : 1;
fk_uint32_t write_index : 31;
/* as we use msb of index as mirror bit, the size should be signed and
* could only be positive. */
fk_int32_t buffer_size;
};
enum ringbuffer_state
{
RINGBUFFER_EMPTY,
RINGBUFFER_FULL,
/* half full is neither full nor empty */
RINGBUFFER_HALFFULL,
};
void fk_ringbuffer_init (struct fk_ringbuffer *rb, fk_uint8_t *pool, fk_int32_t size);
void fk_ringbuffer_reset (struct fk_ringbuffer *rb);
fk_size_t fk_ringbuffer_put (struct fk_ringbuffer *rb, const fk_uint8_t *ptr, fk_uint32_t length);
fk_size_t fk_ringbuffer_put_force (struct fk_ringbuffer *rb, const fk_uint8_t *ptr, fk_uint32_t length);
fk_size_t fk_ringbuffer_putchar (struct fk_ringbuffer *rb, const fk_uint8_t ch);
fk_size_t fk_ringbuffer_putchar_force (struct fk_ringbuffer *rb, const fk_uint8_t ch);
fk_size_t fk_ringbuffer_get (struct fk_ringbuffer *rb, fk_uint8_t *ptr, fk_uint32_t length);
fk_size_t fk_ringbuffer_peek (struct fk_ringbuffer *rb, fk_uint8_t **ptr);
fk_size_t fk_ringbuffer_getchar (struct fk_ringbuffer *rb, fk_uint8_t *ch);
fk_size_t fk_ringbuffer_data_len (struct fk_ringbuffer *rb);
/**
* @brief Get the buffer size of the ring buffer object.
*
* @param rb A pointer to the ring buffer object.
*
* @return Buffer size.
*/
fk_inline fk_uint32_t fk_ringbuffer_get_size(struct fk_ringbuffer *rb)
{
FK_ASSERT(rb != FK_NULL);
return rb->buffer_size;
}
/** return the size of empty space in rb */
#define fk_ringbuffer_space_len(rb) ((rb)->buffer_size - fk_ringbuffer_data_len(rb))
#ifdef __cplusplus
}
#endif
#endif
ringbuffer.c
#include <ringbuffer.h>
#include <string.h> // memcpy
#include <stdlib.h> // 动态内存
#define fk_memcpy memcpy
// 静态 获取队列当前状态
fk_inline enum ringbuffer_state fk_ringbuffer_status(struct fk_ringbuffer *rb)
{
// 队列头尾索引相同
if (rb->read_index == rb->write_index)
{
if (rb->read_mirror == rb->write_mirror)
return RINGBUFFER_EMPTY;
else
return RINGBUFFER_FULL;
}
return RINGBUFFER_HALFFULL;
}
/**
* @brief Initialize the ring buffer object.
*
* @param rb A pointer to the ring buffer object.
* @param pool A pointer to the buffer.
* @param size The size of the buffer in bytes.
*/
// 初始化缓冲区
void fk_ringbuffer_init(struct fk_ringbuffer *rb,
fk_uint8_t *pool,
fk_int32_t size)
{
FK_ASSERT(rb != FK_NULL);
FK_ASSERT(size > 0);
/* initialize read and write index */
rb->read_mirror = rb->read_index = 0;
rb->write_mirror = rb->write_index = 0;
/* set buffer pool and size */
rb->buffer_ptr = pool;
rb->buffer_size = FK_ALIGN_DOWN(size, FK_ALIGN_SIZE);
}
/**
* @brief Put a block of data into the ring buffer. If the capacity of ring buffer is insufficient, it will discard out-of-range data.
*
* @param rb A pointer to the ring buffer object.
* @param ptr A pointer to the data buffer.
* @param length The size of data in bytes.
*
* @return Return the data size we put into the ring buffer.
*/
// 将 ptr 入队
fk_size_t fk_ringbuffer_put(struct fk_ringbuffer *rb,
const fk_uint8_t *ptr,
fk_uint32_t length)
{
fk_uint32_t size;
FK_ASSERT(rb != FK_NULL);
/* whether has enough space */
// 获取剩余空间
size = fk_ringbuffer_space_len(rb);
/* no space */
if (size == 0)
return 0;
// 丢弃多余数据
/* drop some data */
if (size < length)
length = size;
// 剩余连续空间足够,直接写入
if (rb->buffer_size - rb->write_index > length)
{
/* read_index - write_index = empty space */
fk_memcpy(&rb->buffer_ptr[rb->write_index], ptr, length);
/* this should not cause overflow because there is enough space for
* length of data in current mirror */
rb->write_index += length;
return length;
}
// 剩余连续空间不够,分段写入
fk_memcpy(&rb->buffer_ptr[rb->write_index],
&ptr[0],
rb->buffer_size - rb->write_index);
fk_memcpy(&rb->buffer_ptr[0],
&ptr[rb->buffer_size - rb->write_index],
length - (rb->buffer_size - rb->write_index));
// 写入使用镜像空间,
/* we are going into the other side of the mirror */
rb->write_mirror = ~rb->write_mirror;
rb->write_index = length - (rb->buffer_size - rb->write_index);
return length;
}
/**
* @brief Put a block of data into the ring buffer.
If the capacity of ring buffer is insufficient,
it will overwrite the existing data in the ring buffer.
*
* @param rb A pointer to the ring buffer object.
* @param ptr A pointer to the data buffer.
* @param length The size of data in bytes.
*
* @return Return the data size we put into the ring buffer.
*/
//强制写入,写不下就覆盖
fk_size_t fk_ringbuffer_put_force(struct fk_ringbuffer *rb,
const fk_uint8_t *ptr,
fk_uint32_t length)
{
fk_uint32_t space_length;
FK_ASSERT(rb != FK_NULL);
// 获取剩余空间
space_length = fk_ringbuffer_space_len(rb);
if (length > rb->buffer_size)
{
ptr = &ptr[length - rb->buffer_size];
length = rb->buffer_size;
}
if (rb->buffer_size - rb->write_index > length)
{
/* read_index - write_index = empty space */
fk_memcpy(&rb->buffer_ptr[rb->write_index], ptr, length);
/* this should not cause overflow because there is enough space for
* length of data in current mirror */
rb->write_index += length;
if (length > space_length)
rb->read_index = rb->write_index;
return length;
}
fk_memcpy(&rb->buffer_ptr[rb->write_index],
&ptr[0],
rb->buffer_size - rb->write_index);
fk_memcpy(&rb->buffer_ptr[0],
&ptr[rb->buffer_size - rb->write_index],
length - (rb->buffer_size - rb->write_index));
/* we are going into the other side of the mirror */
rb->write_mirror = ~rb->write_mirror;
rb->write_index = length - (rb->buffer_size - rb->write_index);
if (length > space_length)
{
if (rb->write_index <= rb->read_index)
rb->read_mirror = ~rb->read_mirror;
rb->read_index = rb->write_index;
}
return length;
}
/**
* @brief Get data from the ring buffer.
*
* @param rb A pointer to the ring buffer.
* @param ptr A pointer to the data buffer.
* @param length The size of the data we want to read from the ring buffer.
*
* @return Return the data size we read from the ring buffer.
*/
fk_size_t fk_ringbuffer_get(struct fk_ringbuffer *rb,
fk_uint8_t *ptr,
fk_uint32_t length)
{
fk_size_t size;
FK_ASSERT(rb != FK_NULL);
/* whether has enough data */
size = fk_ringbuffer_data_len(rb);
/* no data */
if (size == 0)
return 0;
/* less data */
if (size < length)
length = size;
if (rb->buffer_size - rb->read_index > length)
{
/* copy all of data */
fk_memcpy(ptr, &rb->buffer_ptr[rb->read_index], length);
/* this should not cause overflow because there is enough space for
* length of data in current mirror */
rb->read_index += length;
return length;
}
fk_memcpy(&ptr[0],
&rb->buffer_ptr[rb->read_index],
rb->buffer_size - rb->read_index);
fk_memcpy(&ptr[rb->buffer_size - rb->read_index],
&rb->buffer_ptr[0],
length - (rb->buffer_size - rb->read_index));
/* we are going into the other side of the mirror */
rb->read_mirror = ~rb->read_mirror;
rb->read_index = length - (rb->buffer_size - rb->read_index);
return length;
}
/**
* @brief Get the first readable byte of the ring buffer.
*
* @param rb A pointer to the ringbuffer.
* @param ptr When this function return, *ptr is a pointer to the first readable byte of the ring buffer.
*
* @note It is recommended to read only one byte, otherwise it may cause buffer overflow.
*
* @return Return the size of the ring buffer.
*/
fk_size_t fk_ringbuffer_peek(struct fk_ringbuffer *rb, fk_uint8_t **ptr)
{
fk_size_t size;
FK_ASSERT(rb != FK_NULL);
*ptr = FK_NULL;
/* whether has enough data */
size = fk_ringbuffer_data_len(rb);
/* no data */
if (size == 0)
return 0;
*ptr = &rb->buffer_ptr[rb->read_index];
if ((fk_size_t)(rb->buffer_size - rb->read_index) > size)
{
rb->read_index += size;
return size;
}
size = rb->buffer_size - rb->read_index;
/* we are going into the other side of the mirror */
rb->read_mirror = ~rb->read_mirror;
rb->read_index = 0;
return size;
}
/**
* @brief Put a byte into the ring buffer. If ring buffer is full, this operation will fail.
*
* @param rb A pointer to the ring buffer object.
* @param ch A byte put into the ring buffer.
*
* @return Return the data size we put into the ring buffer. The ring buffer is full if returns 0. Otherwise, it will return 1.
*/
fk_size_t fk_ringbuffer_putchar(struct fk_ringbuffer *rb, const fk_uint8_t ch)
{
FK_ASSERT(rb != FK_NULL);
/* whether has enough space */
if (!fk_ringbuffer_space_len(rb))
return 0;
rb->buffer_ptr[rb->write_index] = ch;
/* flip mirror */
if (rb->write_index == rb->buffer_size - 1)
{
rb->write_mirror = ~rb->write_mirror;
rb->write_index = 0;
}
else
{
rb->write_index++;
}
return 1;
}
/**
* @brief Put a byte into the ring buffer. If ring buffer is full, it will discard an old data and put into a new data.
*
* @param rb A pointer to the ring buffer object.
* @param ch A byte put into the ring buffer.
*
* @return Return the data size we put into the ring buffer. Always return 1.
*/
fk_size_t fk_ringbuffer_putchar_force(struct fk_ringbuffer *rb, const fk_uint8_t ch)
{
enum ringbuffer_state old_state;
FK_ASSERT(rb != FK_NULL);
old_state = fk_ringbuffer_status(rb);
rb->buffer_ptr[rb->write_index] = ch;
/* flip mirror */
if (rb->write_index == rb->buffer_size - 1)
{
rb->write_mirror = ~rb->write_mirror;
rb->write_index = 0;
if (old_state == RINGBUFFER_FULL)
{
rb->read_mirror = ~rb->read_mirror;
rb->read_index = rb->write_index;
}
}
else
{
rb->write_index++;
if (old_state == RINGBUFFER_FULL)
rb->read_index = rb->write_index;
}
return 1;
}
/**
* @brief Get the size of data in the ring buffer in bytes.
*
* @param rb The pointer to the ring buffer object.
*
* @return Return the size of data in the ring buffer in bytes.
*/
fk_size_t fk_ringbuffer_data_len(struct fk_ringbuffer *rb)
{
switch (fk_ringbuffer_status(rb))
{
case RINGBUFFER_EMPTY:
return 0;
case RINGBUFFER_FULL:
return rb->buffer_size;
case RINGBUFFER_HALFFULL:
default:
{
fk_size_t wi = rb->write_index, ri = rb->read_index;
if (wi > ri)
return wi - ri;
else
return rb->buffer_size - (ri - wi);
}
}
}
/**
* @brief Reset the ring buffer object, and clear all contents in the buffer.
*
* @param rb A pointer to the ring buffer object.
*/
void fk_ringbuffer_reset(struct fk_ringbuffer *rb)
{
FK_ASSERT(rb != FK_NULL);
rb->read_mirror = 0;
rb->read_index = 0;
rb->write_mirror = 0;
rb->write_index = 0;
}
作者:toyoutoyou001