eefocus_4062187 发表于 2025-8-21 10:51:41

【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]
查看完整版本: 【RISC-V 全志-V821 PERF2B开发板评测试用试用体验】RTOS

Baidu
map