【RISC-V 全志-V821 PERF2B开发板评测试用试用体验】RTOS
# 【RISC-V 全志-V821 PERF2B开发板评测试用试用体验】RTOS本文介绍了 RISC-V 全志-V821 PERF2B 开发板 RTOS 开发和测试流程。
V821点点taptap安卓包含两个CPU。一个是主核心RISC-V CPU,运行Tina Linux系统,为点点taptap安卓主系统。一个是RISC-V MCU,运行 FreeRTOS 系统,主要功能是提供通用算力补充、辅助 Linux 实现休眠唤醒、低功耗管理以及WIFI相关功能。本文将重点在 RTOS 方面,演示 RTOS 系统的相关操作。
## RTOS 目录结构
RTOS 目录位于 SDK 根目录下的 `rtos` 文件夹内
!(//m.qjumbo.com/forum/data/attachment/forum/202508/21/104953rbfqyy8888p8512o.jpg)
目录结构
!(//m.qjumbo.com/forum/data/attachment/forum/202508/21/105004rnqmcb4cc5scn5kz.jpg)
## SDK 开发
V821 小核 RTOS 开发与大核是整合编译的,在编译大核时会加载小核的开发环境。
### 初始化 SDK 环境
在 SDK 根目录下执行命令初始化 SDK 环境。
```text
source build/envsetup.sh
```
### 单独编译 RTOS
在 SDK 任意位置执行命令即可编译 RTOS
```text
mrtos
```
RTOS 的编译会在 `rtos/lichee/rtos/build` 目录下进行;
目录结构如下
!(//m.qjumbo.com/forum/data/attachment/forum/202508/21/105016gbtcefbyfbek0sib.jpg)
其中 `img` 文件夹为编译出的 `elf` 文件,`map` 文件等,调试时使用。
```text
├── rt_system.bin
├── rt_system.elf
├── rt_system.map
├── rt_system.syms
├── sys_config.bin
└── sys_config.fex
```
编译完成的固件会自动拷贝到对应板级的板级目录下,以供打包使用,例如这里的 perf2 板级的 RTOS 被拷贝到 `evice/config/chips/v821/configs/perf2/bin` 目录下,并且重命名为 `amp_rv0.bin`
### 清理 RTOS 编译产物
在 SDK 任意位置执行命令即可清理 RTOS 的编译产物
```text
mrtos clean
```
### 配置 RTOS 组件
在 SDK 任意位置执行命令即可配置 RTOS 的模块,类似于 Linux 的 `menuconfig`
```text
mrtos menuconfig
```
## RTOS 调试
介绍 FreeRTOS 系统方案支持的常用软件调试方法,提高解决软件问题的效率。
### 栈回溯
栈回溯是指获取程序的调用链信息,通过栈回溯信息,能帮助开发者快速理清程序执行流程,提高分析问题的效率。
1. 获取程序调用关系,理清程序执行流程。
2. 在系统触发异常时,快速分析异常所在位置及其调用链。
3. 在分析某任务卡死原因时,可以通过对该任务进行栈回溯,快速分析卡死点。
4. 分析某些资源如 sem、mutex 的获取、释放信息。
#### 配置
```text
Kernel Options ‑‑‑>
Backtrace Select (debug backtrace by machine code) ‑‑‑>
(X) debug backtrace by machine code// 通过解析机器码方式进行回溯
( ) debug backtrace by frame pointer // 通过解析frame pointer方式进行回溯
( ) no backtrace // 关闭栈回溯
```
#### 接口
```c
int backtrace(char *taskname, void *output[], int size, int offset, print_function print_func);
```
#### 终端命令
在设备端的终端界面上支持使用 backtrace 命令对指定的任务进行回溯。
```text
作用:查看指定任务堆栈回溯信息
用法:backtrace
```
### 内存泄露分析
FreeRTOS 系统提供轻量级的内存泄露分析功能,启动内存泄露分析后,每当申请内存时,将该内存块挂入链表中,释放时将其从链表中摘除。最终还存在于链表之中的,便是可疑的内存泄露点。
#### 用途
可用于分析、定位 FreeRTOS 系统的内存泄露问题。
#### 配置
```text
System components ‑‑‑>
aw components ‑‑‑>
Memleak Components Support ‑‑‑>
[*] Tina RTOS Memleak #使能内存泄露分析工具
(16) Tina RTOS Memleak Backtrace Level @ 内存泄露分析栈回溯层数
```
#### 终端命令
##### memleak
```text
作用:内存泄露分析
用法:
memleak 1 使能内存泄露分析,记录所有内存块申请信息
memleak 0 关闭内存泄露分析,删除所有内存块的申请信息
memleak 1 thread_name1 thread_name2 使能内存泄露分析,记录指定任务的内存块申请信息
memleak show 不关闭内存泄露分析,打印出所有内存块申请信息
```
##### memallocate
```text
作用:查看指定任务的内存泄露分析信息
用法:memallocate thread_name
```
## RTOS 驱动
包括 GPIO、PWM、RTC、TRNG、TWI、UART 等,这里以常用的 UART 为例进行测试。
### UART
Universal Asynchronous Receiver/Transmitter,通用异步收发传输器
#### 模块配置
其menuconfig 的配置如下:
```shell
Kernel Setup --->
Drivers Setup --->
SoC HAL Drivers --->
UART devices --->
[*] enable uart driver
[*] enbale uart hal APIs Test command
```
#### 源码结构
```c
.
│hal_uart.c # 驱动源码
│platform-uart.h # 平台选择头文件
│uart.h # 驱动私有头文件
└─platform
uart-sun20iw2p1.h # 平台特化定义
```
#### 模块接口
头文件
```c
#include <hal_uart.h>
```
#### 发送数据
函数原型:
```c
int32_t hal_uart_send(int32_t dev, const uint8_t *data, uint32_t num);
```
#### 接收数据
函数原型:
```c
int32_t hal_uart_receive(int32_t dev, uint8_t *data, uint32_t num);
```
#### 使能 RX 中断
函数原型:
```c
int32_t hal_uart_enable_rx(int32_t uart_port);
```
### 模块使用
通过两个测试函数 `cmd_test_uart`(基本 UART 回环测试)和 `cmd_test_uart_stress`(压力测试)给出 UART 驱动的使用例程。
#### 流程图
!(//m.qjumbo.com/forum/data/attachment/forum/202508/21/105043fuba9ttzb9ftfzmu.jpg)
#### 代码
```c
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <hal_log.h>
#include <hal_cmd.h>
#include <hal_timer.h>
#include <hal_uart.h>
static void cmd_usage(void)
{
printf("Usage:\n"
"\t hal_uart <port> <baudrate>\n");
}
int cmd_test_uart(int argc, char **argv)
{
uint8_t tbuf = {"hello"};
uint8_t rbuf = {0};
uart_port_t port;
uint32_t baudrate;
_uart_config_t uart_config;
int i;
hal_log_info("Testing UART in loopback mode");
if (argc != 3) {
cmd_usage();
return -1;
}
port = strtol(argv, NULL, 0);
baudrate = strtol(argv, NULL, 0);
if(CONFIG_CLI_UART_PORT == port){
hal_log_info("uart0 can't test, please use other port!");
return -1;
}
memset(rbuf, 0, 10 * sizeof(uint8_t));
switch (baudrate) {
case 4800:
uart_config.baudrate = UART_BAUDRATE_4800;
break;
case 9600:
uart_config.baudrate = UART_BAUDRATE_9600;
break;
case 115200:
uart_config.baudrate = UART_BAUDRATE_115200;
break;
case 1500000:
uart_config.baudrate = UART_BAUDRATE_1500000;
break;
case 4000000:
uart_config.baudrate = UART_BAUDRATE_4000000;
break;
default:
hal_log_info("Using default baudrate: 115200");
uart_config.baudrate = UART_BAUDRATE_115200;
break;
}
uart_config.word_length = UART_WORD_LENGTH_8;
uart_config.stop_bit = UART_STOP_BIT_1;
uart_config.parity = UART_PARITY_NONE;
hal_uart_init(port);
hal_uart_control(port, 0, &uart_config);
hal_uart_disable_flowcontrol(port);
hal_uart_set_loopback(port, 1);
/* send */
hal_uart_send(port, tbuf, 5);
/* loopback receive */
hal_uart_receive_no_block(port, rbuf, 5, MS_TO_OSTICK(1000));
printf("Sending:");
for (i = 0; i < 5; i++)
printf("%c", tbuf);
printf("\n");
printf("Receiving:");
for (i = 0; i < 5; i++)
printf("%c", rbuf);
printf("\n");
/* verify data */
for (i = 0; i < 5; i++) {
if (tbuf != rbuf)
break;
}
if (i == 5) {
hal_log_info("Test hal_uart_init API success!");
hal_log_info("Test hal_uart_control API success!");
hal_log_info("Test hal_uart_disable_flowcontrol API success!");
hal_log_info("Test hal_uart_set_loopback API success!");
hal_log_info("Test hal_uart_send API success!");
hal_log_info("Test hal_uart_receive API success!");
hal_log_info("Test hal_uart_deinit API success!");
hal_log_info("Test uart hal APIs success!");
} else {
hal_log_info("Test uart hal APIs failed!");
}
hal_msleep(1000);
hal_uart_deinit(port);
return 0;
}
FINSH_FUNCTION_EXPORT_CMD(cmd_test_uart, hal_uart, uart hal APIs tests)
#define BUFFSIZE 4096
static void cmd_stress_usage(void)
{
printf("Usage:\n"
"\t hal_uart <port> <baudrate> <flowctrl> <loopback> <len>\n");
}
int cmd_test_uart_stress(int argc, char **argv)
{
uint8_t *tbuf = malloc(BUFFSIZE);
uint8_t *rbuf = malloc(BUFFSIZE);
uart_port_t port;
uint32_t baudrate;
_uart_config_t uart_config;
int i;
int flowctrl, loopback, testlen;
hal_log_info("Testing UART in loopback mode with stress");
if (argc != 6) {
cmd_stress_usage();
free(tbuf);
free(rbuf);
return -1;
}
port = strtol(argv, NULL, 0);
baudrate = strtol(argv, NULL, 0);
flowctrl = strtol(argv, NULL, 0);
loopback = strtol(argv, NULL, 0);
testlen = strtol(argv, NULL, 0);
for (i = 0; i < BUFFSIZE; i++) {
tbuf = ('a' + i) & 0xff;
}
memset(rbuf, 0, BUFFSIZE * sizeof(uint8_t));
switch (baudrate) {
case 4800:
uart_config.baudrate = UART_BAUDRATE_4800;
break;
case 9600:
uart_config.baudrate = UART_BAUDRATE_9600;
break;
case 115200:
uart_config.baudrate = UART_BAUDRATE_115200;
break;
case 1500000:
uart_config.baudrate = UART_BAUDRATE_1500000;
break;
default:
hal_log_info("Using default baudrate: 115200");
uart_config.baudrate = UART_BAUDRATE_115200;
break;
}
uart_config.word_length = UART_WORD_LENGTH_8;
uart_config.stop_bit = UART_STOP_BIT_1;
uart_config.parity = UART_PARITY_NONE;
hal_uart_init(port);
hal_uart_control(port, 0, &uart_config);
printf("flow:%d, loopback:%d len:%d\n", flowctrl, loopback, testlen);
if (flowctrl)
hal_uart_set_hardware_flowcontrol(port);
else
hal_uart_disable_flowcontrol(port);
if (loopback)
hal_uart_set_loopback(port, 1);
else
hal_uart_set_loopback(port, 0);
/* send */
printf("send\n");
hal_uart_send(port, tbuf, testlen);
printf("send done\n");
printf("recv\n");
/* loopback receive */
hal_uart_receive(port, rbuf, testlen);
printf("recv done\n");
#if 0
printf("Sending:");
for (i = 0; i < testlen; i++) {
if (i % 16 == 0)
printf("\n");
printf("0x%x ", tbuf);
}
printf("\n");
printf("Receiving:");
for (i = 0; i < testlen; i++) {
if (i % 16 == 0)
printf("\n");
printf("0x%x ", rbuf);
}
printf("\n");
#endif
/* verify data */
for (i = 0; i < testlen; i++) {
if (tbuf != rbuf) {
printf("check %d fail, 0x%x != 0x%x\n", i, tbuf, rbuf);
break;
}
}
if (i == testlen) {
hal_log_info("Test hal_uart_init API success!");
hal_log_info("Test hal_uart_control API success!");
hal_log_info("Test hal_uart_disable_flowcontrol API success!");
hal_log_info("Test hal_uart_set_loopback API success!");
hal_log_info("Test hal_uart_send API success!");
hal_log_info("Test hal_uart_receive API success!");
hal_log_info("Test hal_uart_deinit API success!");
hal_log_info("Test uart hal APIs success!");
} else {
hal_log_info("Test uart hal APIs failed!");
}
hal_msleep(1000);
hal_uart_deinit(port);
free(tbuf);
free(rbuf);
return 0;
}
FINSH_FUNCTION_EXPORT_CMD(cmd_test_uart_stress, hal_uart_stress, uart hal APIs tests)
```
详见:(https://docs.aw-ol.com/docs/soc/v821/rtos/rtos_module/uart#模块使用范例) .
### 总结
本文介绍了 RISC-V 全志-V821 PERF2B 开发板 RTOS 开发和测试流程,以 UART 为例给出具体的模块使用测试方案,为全志 V821 系列产品的开发设计和快速应用提供了参考。
页:
[1]