694 views|1 replies

501

Posts

4

Resources
The OP
 

[Renesas Electronics 200MHz Cortex-M33 RA6E2 Evaluation Board] Serial port driver based on circular buffer reception [Copy link]

Preface

Previously, we used Demo to test the serial port's sending and receiving. In order to use the serial port conveniently later, we need to do some encapsulation to realize the serial port's sending and receiving interface.

Design ideas

The core idea is to design a FIFO ring buffer, write data into the FIFO during the serial port receive interrupt, and discard it when it is full.

The user receives the API to query the FIFO. If there is data, it will be read out. If there is no data, it will wait.

Both interrupts and user APIs operate FIFO, so FIFO needs to be protected from critical section operations.

The sending method is similar, but for simplicity, the query method is used for sending.

designing process

data structure

#include <stdint.h>

The ring buffer data structure is as follows

typedef struct

{

uint32_t datalen_u32;

uint32_t maxlen_u32;

uint32_t in_u32;

uint32_t out_u32;

uint8_t* buffer_pu8;

}ring_buffer_t;

Timing buffer stores received data

uint8_t uart_ring_buffer[128];

Instantiate a buffer

ring_buffer_t s_ring_buffer_t=

{

.datalen_u32 = 0,

.maxlen_u32 = sizeof(uart_ring_buffer),

.in_u32 = 0,

.out_u32 = 0,

.buffer_pu8 = uart_ring_buffer,

};

Critical Section Processing

The critical section is implemented by disabling interrupts when operating FIFO in Rx API

#include "bsp_api.h"



#define Alloc_Critical() FSP_CRITICAL_SECTION_DEFINE

#define Enter_Critical() FSP_CRITICAL_SECTION_ENTER

#define Exit_Critical() FSP_CRITICAL_SECTION_EXIT

Receive interrupt processing

void uart_rx_handler(const uint8_t *buffer, uint32_t length)

{

uint32_t i;

for(i=0;i<length; i++)

{

if(s_ring_buffer_t.datalen_u32 < s_ring_buffer_t.maxlen_u32)

{

s_ring_buffer_t.buffer_pu8[s_ring_buffer_t.in_u32] = buffer[i];

s_ring_buffer_t.datalen_u32++;

s_ring_buffer_t.in_u32++;

s_ring_buffer_t.in_u32 %= s_ring_buffer_t.maxlen_u32;

}

else

{

/* full */

break;

}

}

}

Uart_ep.c

#include "uart.h"

void user_uart_callback(uart_callback_args_t *p_args)

{

/* Logged the event in global variable */

g_uart_event = (uint8_t)p_args->event;

if(UART_EVENT_RX_CHAR == p_args->event)

{

uint8_t tmp = (uint8_t ) p_args->data;

uart_rx_handler(&tmp, 1);

}

}

Receiving API

uint32_t uart_read(uint8_t *buff, uint32_t len)

{

uint32_t readlen = 0;

//uint32_t mask;

if(s_ring_buffer_t.datalen_u32 == 0)

{

return 0;

}

Alloc_Critical();

Enter_Critical();

uint32_t i;

for(i=0;i<len;i++)

{

if(s_ring_buffer_t.datalen_u32 > 0)

{

buff[i] = s_ring_buffer_t.buffer_pu8[s_ring_buffer_t.out_u32];

s_ring_buffer_t.datalen_u32--;

s_ring_buffer_t.out_u32++;

s_ring_buffer_t.out_u32 %= s_ring_buffer_t.maxlen_u32;

readlen++;

}

else

{

break;

}

}

Exit_Critical();

return readlen;

}

Send API

int uart_write(uint8_t *buff, uint32_t len)

{

uint32_t i;

for(i=0; i<len ;i++)

{

uart_sendbyte(buff[i]);

}

return 0;

}

uart_sendbyte is implemented in uart_ep.c

void uart_sendbyte(uint8_t ch)

{

uint8_t tmp = ch;

fsp_err_t err = FSP_SUCCESS;

uint32_t local_timeout = (DATA_LENGTH * UINT16_MAX);

/* Reset callback capture variable */

g_uart_event = RESET_VALUE;



/* Writing to terminal */

err = R_SCI_UART_Write (&g_uart_ctrl, &tmp, 1);

if (FSP_SUCCESS != err)

{

return;

}



/* Check for event transfer complete */

while ((UART_EVENT_TX_COMPLETE != g_uart_event) && (--local_timeout))

{

/* Check if any error event occurred */

if (UART_ERROR_EVENTS == g_uart_event)

{

return;

}

}

return;

}

Serial port initialization

Use the original uart_initialize

test

uint8_t buffer[128];

for(;;)

{

uint32_t len=0;

if((len = uart_read(buffer, sizeof(buffer))) >0)

{

uart_write(buffer, len);

}

}

The host computer sends and the development board returns the data as it is. If the sent and received data are consistent, it means the function is OK.

Code

uart.c

#include <stdint.h>
#include "uart.h"
#include "bsp_api.h"

#define Alloc_Critical() FSP_CRITICAL_SECTION_DEFINE
#define Enter_Critical() FSP_CRITICAL_SECTION_ENTER
#define Exit_Critical()   FSP_CRITICAL_SECTION_EXIT
			
typedef struct
{
        uint32_t datalen_u32;
        uint32_t maxlen_u32;
        uint32_t in_u32;
        uint32_t out_u32;
        uint8_t* buffer_pu8;
}ring_buffer_t;

 
uint8_t uart_ring_buffer[128];

ring_buffer_t s_ring_buffer_t=
{
	.datalen_u32 = 0,
	.maxlen_u32 = sizeof(uart_ring_buffer),
  .in_u32 = 0,
  .out_u32 = 0,
  .buffer_pu8 = uart_ring_buffer,
};

void uart_rx_handler(const uint8_t *buffer, uint32_t length)
{
    uint32_t i;
    for(i=0;i<length; i++)
    {
        if(s_ring_buffer_t.datalen_u32 < s_ring_buffer_t.maxlen_u32)
        {
            s_ring_buffer_t.buffer_pu8[s_ring_buffer_t.in_u32] = buffer;
            s_ring_buffer_t.datalen_u32++;
            s_ring_buffer_t.in_u32++;
            s_ring_buffer_t.in_u32 %= s_ring_buffer_t.maxlen_u32;
        }
        else
        {
            /* full */
            break;
        }
    }
}

uint32_t uart_read(uint8_t *buff, uint32_t len)
{
    uint32_t readlen = 0;
    //uint32_t mask;
    if(s_ring_buffer_t.datalen_u32 == 0)
    {
        return 0;
    }
		Alloc_Critical();
    Enter_Critical();
    uint32_t i;
    for(i=0;i<len;i++)
    {
			if(s_ring_buffer_t.datalen_u32 > 0)
      {
				buff = s_ring_buffer_t.buffer_pu8[s_ring_buffer_t.out_u32];
				s_ring_buffer_t.datalen_u32--;
				s_ring_buffer_t.out_u32++;
				s_ring_buffer_t.out_u32 %= s_ring_buffer_t.maxlen_u32;
				readlen++;
			}
			else
			{
				break;
			}
    }
    Exit_Critical();
    return readlen;
}

int uart_write(uint8_t *buff, uint32_t len)
{
	uint32_t i;
	for(i=0; i<len ;i++)
	{
		uart_sendbyte(buff);
	}
	return 0;
}

uart.h

#ifndef UART_H
#define UART_H

#include <stdint.h>

void uart_rx_handler(const uint8_t *buffer, uint32_t length);
uint32_t uart_read(uint8_t *buff, uint32_t len);
int uart_write(uint8_t *buff, uint32_t len);

extern void uart_sendbyte(uint8_t ch);

#endif

Summarize

Relying on the underlying serial port driver, a serial port driver interface based on a circular buffer FIFO is implemented to facilitate use by the subsequent application layer.

Thanks to the official complete driver and Demo, it can be implemented quickly.

This post is from Renesas Electronics MCUs

Latest reply

Does this point use a lot of memory space? In fact, you can use RTT, and the shell it brings is more powerful.   Details Published on 2023-10-18 19:46

6827

Posts

11

Resources
2
 

Does this point use a lot of memory space? In fact, you can use RTT, and the shell it brings is more powerful.

This post is from Renesas Electronics MCUs
 
 

Just looking around
Find a datasheet?

EEWorld Datasheet Technical Support

Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号
快速回复 返回顶部 Return list