371|1

504

帖子

4

TA的资源

纯净的硅(高级)

楼主
 

【瑞萨RA8D1开发板,基于M85内核的图形MCU】基于FIFO的串口收发接口 [复制链接]

本帖最后由 qinyunti 于 2024-7-24 23:48 编辑

前面我们实现了串口的收发测试,现在来基于FIFO实现好用的串口收发接口。FIFO的实现参考微信公众号”嵌入式Lee”的文章

https://mp.weixin.qq.com/s/MvL9eDesyuxD60fnbl1nag 超级精简系列之十三:超级精简的循环FIFO,C实现

 

Fifo.c源码如下

#include <string.h>
#include "fifo.h"

#define FIFO_PARAM_CHECK 0

/**
 * in????? 0~(buffer_len-1)?
 * out????? 0~(buffer_len-1)?
 * in == out?????,?????,????len??????????
 * ???in??,?????out???
 * ????out??,?????in???
 * in??out??[out,in)????????
 * in??out??[out,buffer_len)?[0,in)????????
 ***********************************************************
 *     0                                 buffer_len-1 buffer_len
 *     (1)?? in?out??0
 *     |                                             |
 *     in(0)
 *     out(0)
 *     len = 0
 *     (2)??n???? in??n?out??0 ??in??out???
 *     |                                             |
 *     out(0)������������>in(n)                      |   
 *     len = n
 *     (3)??m????(m<n) in??n?out??m ??in??out???
 *     |                                             |
 *             out(m)����>in(n)
 *     len = n-m
 *     (4)??????,?????,??in??out???
 *     |                                             |
 *             out(m)��������������������������������>
 *     ��>in(k)
 *     len = k + buffer_len-m
 */
uint32_t fifo_in(fifo_st* dev, uint8_t* buffer, uint32_t len)
{
  uint32_t space = 0;  /* ?????????? */
  /* ???? */
  #if FIFO_PARAM_CHECK
  if((dev == 0) || (buffer == 0) || (len == 0))
  {
    return 0;
  }
  if(dev->buffer == 0)
  {
    return 0;
  }
  #endif

  /* ??len??????buffer?? */
  if(len > dev->buffer_len)
  {
    len = dev->buffer_len;
  }

  /* ???????? 
   * ??dev->len?????dev->buffer_len
   */
  if(dev->buffer_len >= dev->len)
  {
    space = dev->buffer_len - dev->len; 
  }
  else
  {
    /* ???????, ?????? */
    dev->len = 0;
    space = dev->buffer_len; 
  }

  /* ???????, ??len???????????????? */
  len = (len >= space) ? space : len;  
  if(len == 0)
  {
    return 0; /* ??????????,???? */
  }

  /* ??len??????????,?????? */
  space = dev->buffer_len - dev->in; /* ??????in???????????? */
  if(space >= len)
  {
    /* ??????in??????????? */
    memcpy(dev->buffer+dev->in,buffer,len);
  }
  else
  {
    /* ??????in???????,????????? */
    memcpy(dev->buffer+dev->in,buffer,space);    /* ???tail??  */
    memcpy(dev->buffer,buffer+space,len-space);  /* ???????? */
  } 
  /* ????????????? */
  dev->in += len;
  if(dev->in >= dev->buffer_len)
  {
    dev->in -= dev->buffer_len;  /* ????? ?? dev->in %= dev->buffer->len */
  }
  dev->len += len;  /* dev->len??dev->buffer->len,??%= dev->buffer->len */
  return len;
}

uint32_t fifo_out(fifo_st* dev, uint8_t* buffer, uint32_t len)
{
  uint32_t space = 0; 
  /* ???? */
  #if FIFO_PARAM_CHECK
  if((dev == 0) || (buffer == 0) || (len == 0))
  {
    return 0;
  }
  if(dev->buffer == 0)
  {
    return 0;
  }
  #endif
  
  /* ??????? */
  if(dev->len == 0)
  {
    return 0;
  }

  /* ?????????????????? */
  len = (dev->len) > len ? len : dev->len;

  /* ??len??????????,?????? */
  space = dev->buffer_len - dev->out; /* ??????out???????????? */
  if(space >= len)
  {
    /* ??????out??????????? */
    memcpy(buffer,dev->buffer+dev->out,len);
  }
  else
  {
    /* ??????out???????,????????? */
    memcpy(buffer,dev->buffer+dev->out,space);    /* ???tail??  */
    memcpy(buffer+space,dev->buffer,len-space);   /* ???????? */
  } 
  /* ????????????? */
  dev->out += len;
  if(dev->out >= dev->buffer_len)
  {
    dev->out -= dev->buffer_len;  /* ????? ?? dev->out %= dev->buffer->len */
  }
  dev->len -= len;   /* ??dev->len ?????len,???? */
  return len;
}

uint32_t fifo_getlen(fifo_st* dev)
{
  #if FIFO_PARAM_CHECK
  if(dev == 0)
  {
    return 0;
  }
  #endif
  return dev->len;
}

void fifo_clean(fifo_st* dev)
{
  #if FIFO_PARAM_CHECK
  if(dev == 0)
  {
    return 0;
  }
  #endif
  dev->len = 0;
  dev->in = 0;
  dev->out = 0;
}

Fifo.h源码如下

#ifndef FIFO_H
#define FIFO_H

#ifdef __cplusplus
extern "C" {
#endif
  
#include <stdint.h>

/**
 * \struct fifo_st
 * FIFO?????.
 */
typedef struct 
{
  uint32_t in;          /**< ????        */ 
  uint32_t out;         /**< ????        */ 
  uint32_t len;         /**< ??????    */ 
  uint32_t buffer_len;  /**< ????        */ 
  uint8_t* buffer;      /**< ??,????   */

} fifo_st;
  
/**
 * \fn fifo_in
 * ?fifo????
 * \param[in] dev \ref fifo_st
 * \param[in] buffer ??????
 * \param[in] len ??????
 * \retval ??????????
 */
uint32_t fifo_in(fifo_st* dev, uint8_t* buffer, uint32_t len);

/**
 * \fn fifo_out
 * ?fifo????
 * \param[in] dev \ref fifo_st
 * \param[in] buffer ??????
 * \param[in] len ?????????
 * \retval ??????????
 */
uint32_t fifo_out(fifo_st* dev, uint8_t* buffer, uint32_t len);


uint32_t fifo_getlen(fifo_st* dev);

void fifo_clean(fifo_st* dev);
#ifdef __cplusplus
}
#endif

#endif


Uart.c中定义fifo实例

static uint8_t s_uart_rx_buffer[64];

static fifo_st s_uart_fifo_dev=
{
 .in = 0,
 .len = 0,
 .out = 0,
 .buffer = s_uart_rx_buffer,
 .buffer_len = sizeof(s_uart_rx_buffer),
};

 

串口接收中断中,将数据写入fifo

void user_uart3_callback(uart_callback_args_t *p_args);
void user_uart3_callback(uart_callback_args_t *p_args)
{
    uint8_t tmp;
    switch (p_args->event)
    {
        case UART_EVENT_TX_COMPLETE:
            g_data_transmit_flag = true;
        break;
        case UART_EVENT_TX_DATA_EMPTY:
            g_data_transmit_flag = true;
        break;
        case UART_EVENT_RX_COMPLETE:
            // Start Transmission
            fifo_in(&s_uart_fifo_dev, rx_buffer, 1);
            R_SCI_B_UART_Read(&g_uart3_ctrl, (uint8_t * const)(rx_buffer), 1U);
            //uart_send(rx_buffer,1);
        break;
        case UART_EVENT_RX_CHAR:
            tmp = g_uart3_ctrl.p_reg->RDR_BY;
            fifo_in(&s_uart_fifo_dev, &tmp, 1);
            //uart_send(&tmp,1);
            break;
        default:
        break;
    }
}

临界段接口,中断中操作fifo无需临界段保护,uart_read再线程中调用,需要临界段保护。

#define CriticalAlloc()
#define EnterCritical()                              __disable_irq()
#define ExitCritical()                              __enable_irq()

 

串口读接口,从fifo中读数据

uint32_t uart_read(uint8_t* buffer, uint32_t len)
{
    uint32_t rlen;
    CriticalAlloc();
    EnterCritical();
    rlen = fifo_out(&s_uart_fifo_dev, buffer, len);
    ExitCritical();
    return rlen;
}

最终的uart.c如下

#include "hal_data.h"
#include <stdio.h>
#include <stdbool.h>
#include "r_uart_api.h"
#include "r_sci_b_uart.h"
#include "uart.h"
#include "blinky_thread.h"
#include "fifo.h"


#define CriticalAlloc()
#define EnterCritical()                              __disable_irq()
#define ExitCritical()                              __enable_irq()

static uint8_t s_uart_rx_buffer[64];

static fifo_st s_uart_fifo_dev=
{
 .in = 0,
 .len = 0,
 .out = 0,
 .buffer = s_uart_rx_buffer,
 .buffer_len = sizeof(s_uart_rx_buffer),
};

volatile bool g_data_transmit_flag = false;
uint8_t rx_buffer[1];

void user_uart3_callback(uart_callback_args_t *p_args);
void user_uart3_callback(uart_callback_args_t *p_args)
{
    uint8_t tmp;
    switch (p_args->event)
    {
        case UART_EVENT_TX_COMPLETE:
            g_data_transmit_flag = true;
        break;
        case UART_EVENT_TX_DATA_EMPTY:
            g_data_transmit_flag = true;
        break;
        case UART_EVENT_RX_COMPLETE:
            // Start Transmission
            fifo_in(&s_uart_fifo_dev, rx_buffer, 1);
            R_SCI_B_UART_Read(&g_uart3_ctrl, (uint8_t * const)(rx_buffer), 1U);
            //uart_send(rx_buffer,1);
        break;
        case UART_EVENT_RX_CHAR:
            tmp = g_uart3_ctrl.p_reg->RDR_BY;
            fifo_in(&s_uart_fifo_dev, &tmp, 1);
            //uart_send(&tmp,1);
            break;
        default:
        break;
    }
}


int uart_init(void)
{
    fsp_err_t err;

    err = R_SCI_B_UART_Open(&g_uart3_ctrl, &g_uart3_cfg);
    if (FSP_SUCCESS != err)
    {
        return -1;
    }
    else
    {
        // Start Transmission
        err = R_SCI_B_UART_Read(&g_uart3_ctrl, (uint8_t * const)(rx_buffer), 1U);
        if (FSP_SUCCESS != err)
        {
             return -1;
        }
        return 0;
    }
}

uint32_t uart_send(uint8_t* buffer, uint32_t len)
{
    g_data_transmit_flag = false;

    for(uint32_t i=0;i<len;i++)
    {
        g_uart3_ctrl.p_reg->TDR_BY = buffer;
        while((g_uart3_ctrl.p_reg->CSR_b.TEND == 0) || (g_uart3_ctrl.p_reg->CSR_b.TDRE == 0));
    }

    //fsp_err_t err = R_SCI_B_UART_Write(&g_uart3_ctrl, (uint8_t * const)(buffer), len);
    //if (FSP_SUCCESS != err)
    //{
    //    return 0;
    //}
    // Wait for event receive complete
    //while (!g_data_transmit_flag)
    //{
    //}
    return len;
}

uint32_t uart_read(uint8_t* buffer, uint32_t len)
{
    uint32_t rlen;
    CriticalAlloc();
    EnterCritical();
    rlen = fifo_out(&s_uart_fifo_dev, buffer, len);
    ExitCritical();
    return rlen;
}

Uart.h如下

#ifndef UART_H
#define UART_H

#ifdef __cplusplus
extern "C" {
#endif
  
#include <stdint.h>

int uart_init(void);
uint32_t uart_send(uint8_t* buffer, uint32_t len);
uint32_t uart_read(uint8_t* buffer, uint32_t len);
#ifdef __cplusplus
}
#endif

#endif


测试

blinky_thread_entry.c中

 

#include "uart.h"

void blinky_thread_entry (void * pvParameters)
{
    uart_init();
    while(1)
    {
        static uint8_t rx_buffer[64];
        uint32_t rlen = uart_read(rx_buffer,sizeof(rx_buffer));
        if(rlen > 0)
        {
            uart_send(rx_buffer,rlen);
        }
    }

 

发送任意数据原样返回

 

 

以上实现了方便好用的串口收发接口,基于fifo接口简单非常方便。

最新回复

注释的编码不对,可以修改一下代码编码再上传一下。   详情 回复 发表于 2024-7-25 08:20
点赞 关注

回复
举报

6990

帖子

11

TA的资源

版主

沙发
 

注释的编码不对,可以修改一下代码编码再上传一下。

 
 

回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/8 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表