资讯分类
全部资讯
最新活动
商城公告
行业信息
新品推荐
元器件知识
资讯标签
艾迈斯欧司朗(96) 英伟达NVIDIA(70) 艾为awinic(45) 飞腾派V3(37) 萤火工场(30) 罗彻斯特电子(28) Jetson Orin Nano SUPER 开发套件(21) 资料下载专区(18) 进迭时空(15) 艾为 awinic(15) 兆易创新(14) 赛昉科技(StarFive)(12) 灵动微电子(11) 小华半导体(9) 日清纺微电子(9) 上海雷卯Leiditech(8) 赛昉科技(8) 微源半导体 LPSemi(8) NVIDIA(8) Seeed矽递科技(8) 龙芯中科(7) GD32VW553-IOT(7) 物奇WuQi(7) 日清纺微电子Nisshinbo(5) 庆科(5) 开源口碑分享(5) 航顺芯片(4) CEM5826-M11(4) Geehy极海半导体(4) 飞腾派(4) 创捷电子(4) TROQ创捷电子(4) 一件包邮专区(3) FTHR-G0001(3) 罗彻斯特(3) 飞腾派eMMC(3) iCEasy商城(3) MM32SPIN060G(3) 飞腾官网飞腾派(2) 弈安云(2) 飞腾派下载专区(2) 村田(2) 英伟达初创加速计划(2) 极海(2) 中国星坤(2) 极海半导体(2) 小华EVB-HC32F4A0开发板(2) 国产开源硬件(2) 野火(2) 杭晶(HCI)(2) Mini-SPIN0230(2) NVIDIA品牌专区(2) 华润微电子(2) 口碑评测(2) EVB-L0130(2) 教育优惠申请链接(2) 启明云端(2) NVIDIA DGX™ Spark:桌面级AI超级计算机(1) 品牌清仓(1) QCS8550 SOM EVB(1) Jetson AGX Orin 64GB开发套件(1) 24GHz毫米波雷达模块(1) 技术问答专区(1) 英特尔(1) NVIDIA Jetson Nano 模组(1) QCS6490 SOM EVB(1) 天微电子商家页(1) 国产毫米波雷达模块(1) 飞腾派专链(1) 瑞隆源产品(1) 龙芯教育派(1) CEK8902-S905D3(1) EV Board (MM32L0136C7P)(1) 迈巨微电子品牌专区(1) NVIDIA NIM(1) 世野(Khadas)(1) 618大促(1) 竞买活动(1) 雷卯(1) 飞腾派试用申请链接(1) BeagleBone Black快速入门指南(1) 样片申请(1) 飞腾派调研问卷链接(1) 微雪电子(1) 一件免邮专区(1) SFH 7018B(1) 极海半导体(Geehy)(1) Arduino品牌页(1) 小脚丫(1) 618大促专区(1) 艾为(AWINIC)(1) 英伟达 NVIDIA品牌专区(1) MUSE Paper(1) 8月7日竞拍竞买(1) 飞腾派V3版本上新(1) 飞虹半导体(1) 野火RK3566开发板(1) 乐动机器人(1) 海凌科电子(Hi-Link)(1) VF202040-A0(1) 教育优惠(1) 萤火工场GD32VW553-IOT(1) 润石(1) 格力新元(1) CEM5825F(1) COMBO模组 EMC3020-PZI5(1) 松科智能(1) Jetson AGX Thor 开发套件/模组(1) Mini-F5333(1) 微源半导体(1) 周年抽奖活动(1) 庆科信息(MXCHIP)品牌专区(1) 附件(1) 迈巨微(1) 华大北斗(1) GD32无线生态专区(1) JETSON_AGX_ORIN_64GB_DEVELOPER_KIT(1) QCS6490 SOM EVB开发板(1) 附件下载地址(1) 台容积电(1) 雷克沙(1) GD32VW553-IOT V2版本(1) QCS8550 SOM EVB开发板(1) 申请样片:高光效红光OSCONIQ® P 3030, GR QSSPA1.23(1) GD32VW553-IOT V2(1) CEM5881-M11(1) NVIDIA Jetson Orin Nano 开发套件(1) 萤火工场品牌专区(1) 商城下载专区(1) 飞腾人才赋能(1) Jetson AGX Orin 64GB开发套件(1) 荣湃半导体(2Pai Semi)品牌专区(1) 进迭时空品牌页(1) B站风扇视频(1) Jetson AGX Xavier(32GB)(1) BeagleBoard.org®(1) 社区评奖活动(1) Arduino UNO Rev 4 Minima开发板(1) 下载专区(1) 国产自主可控(1) 英伟达 NVIDIA(1) CEM5861G-M11(1) 赛昉科技9折活动券(1) NVIDIA Jetson Orin Nano 开发套件(1) Arduino品牌专区(1)

飞腾派部署openAMP(二) | 基于 Phytium-openAMP框架从核 GPIO 驱动

发布时间:2025-07-31

文章来源:郭霞

1. 项目简介

飞腾派开发板搭载异构系统级芯片(SoC),基于 ARMV8 架构,集成四核处理器(2×FTC664@1.8GHz + 2×FTC310@1.5GHz)。非对称多处理(AMP)系统要求支持同一芯片上多操作系统环境并行运行,OpenAMP 通过标准化共享内存方案,为异构多处理应用提供多核并行性利用能力,简化 SoC 协同机制。​

《飞腾派部署 openAMP》系列将分两期发布,采用 “主核 Linux 系统 + 从核裸机系统” 的 openAMP 拓扑架构:

u 第一期《PIOSv2.1 部署与 AMP 启动》:阐述飞腾派基础操作系统 Phytium-Pi-OSv2.1(简称 PIOSv2.1)的部署流程,以及 Phytium-openAMP 的集成方法,实现主从核协同的 AMP 拓扑。​

u 第二期《基于 Phytium-openAMP框架从核 GPIO 驱动》:基于首期构建的 OpenAMP 环境,实现并演示从核通过 OpenAMP 机制实现 GPIO 外设驱动的应用实例,具体以驱动飞腾派开发板上的LED20灯为例。

2. 项目准备

硬件规格:飞腾派

软件要求:开发板已经部署支持openAMP的PIOSV2.1

3. LED20硬件原理

(1) LED20在开发板上的位置

(2) LED20的硬件原理图

(3) 根据原理图,LED20连接到E37引脚,该引脚对应微控制器的GPIO1_8。因此,需要配置GPIO1_8为输出功能(Output Mode)以驱动LED20本文我们利用Phytium-Standalone-SDK来实现。

4. Phytium-Standalone-SDK

(1) 基本介绍

a)项目地址
https://gitee.com/phytium_embedded/phytium-standalone-sdk
b) 项目基本功能介绍
本项目发布了 Phytium 系列 CPU 的 嵌入式软件开源开发工具包,包括板级支持包、第三方开源中间件、交叉编译构建工具、及其 Baremetal 参考例程,在支持多平台裸机应用开发的基础上,能够为多种RTOS提供外设驱动和配置构建工具。

(2) Phytium-Standalone-SDK源代码目录

example 目录:包含5大类案例。包括外设应用peripherals、网络应用network、多媒体应用media、存储类应用storage和其他系统类应用system。每一个example中包含了用于编译的makefile和用于配置的sdkconfig、Kconfig文件,用户基于这些文件可以直接编译生成可执行文件,并上板跑测这些example示例。本文使用example/system/amp/openamp_for_linux案例。
drivers目录:在本文中我们用到的driver模块,主要有drivers/iomux/fiopad/以及drivers/pin/fgpio/两个模块。
third-party目录phytium-opemAMP依赖第三方库openamp和libmetal。

(3) IOMUX 模块

1) IOMUX简介

飞腾派CPU支持 IO PAD 复用,用户可以通过配置控制寄存器来完成复用、上下拉电阻、驱动能力的调整以及延迟的选择。

2) 相关的API函数

a)FIOMuxInit初始化函数
      函数原型:_WEAK void FIOMuxInit(void)
      函数位置:phytium-standalone-sdk/board/firefly/fio_mux.c
      函数功能:调用FIOPadCfgInitialize函数初始化IOPAD模块。
FIOPadCfgInitialize函数在drivers/iomux/fiopad/fiopad.c中实现。

b)FIOPadSetGpioMux初始化函数
      函数原型:void FIOPadSetGpioMux(u32 gpio_id, u32 pin_id)
      函数位置:phytium-standalone-sdk/board/firefly/fio_mux.c
      函数功能:调用FIOPadSetFunc函数设置指定的gpio_id的pin_id的GPIO功能。
FIOPadSetFunc函数在drivers/iomux/fiopad/fiopad.c中实现。
      函数参数:
u32 gpio_id:取值范围FGPIO_CTRL_0~FGPIO_CTRL_5
u32 pin_id:0-16

(4) GPIO 模块

1) GPIO模块简介

飞腾派CPU飞腾派集成 6 个 GPIO 控制器,每个控制器16位信号,共提供 96 位 GPIO 信号。

2) 相关的API函数

a)FGpioLookupConfig
      函数原型:const FGpioConfig *FGpioLookupConfig(u32 gpio_id)
      函数位置:phytium-standalone-sdk/drivers/pin/fgpio/fgpio.c
      函数功能:根据gpio_id获取指定gpio引脚的默认配置。
      函数参数:gpio_id=gpio_ctrl*16+pin_id,比如gpio1_8,它的gpio_id=1*16+8=24
                 SDK提供了宏FGPIO_ID(ctrl, pin)  计算gpio_id。
      FGpioConfig结构
typedef struct{
    u32 id; /* GPIO标号,0 ~ FGPIO_NUM */
    u32 ctrl; /* GPIO所属的控制器,0 ~ FGPIO_CTRL_NUM */
    u32 port; /* GPIO所属的Port, Port A, B */
    u32 pin; /* GPIO的引脚号,0 ~ FGPIO_PIN_NUM */
    uintptr base_addr;  /* GPIO控制器基地址 */
    u32 irq_num; /* GPIO中断号,如果不支持中断,置位为 0 */
    u32 irq_priority; /* 中断优先级 */
    u32 cap; /* GPIO引脚能力集 */
} FGpioConfig; /* GPIO引脚配置 */

b)FGpioCfgInitializex
      函数原型:FError FGpioCfgInitialize(FGpio *const pin, const FGpioConfig *const config)
      函数位置:phytium-standalone-sdk/drivers/pin/fgpio/fgpio.c
   函数功能:根据FGpioConfig结构的默认配置config,初始化GPIO引脚实例pin
   函数参数:
const FGpioConfig *const config,默认参数,通过FGpioLookupConfig获取的
FGpio *const pin,初始化后的参数。
FGpio的结构:
typedef struct
{
    FGpioConfig config;
    u32 is_ready;
    FGpioInterruptCallback irq_cb; /* 中断回调函数 */
    void *irq_cb_params; /* 中断回调函数的入参 */
} FGpio; /* GPIO引脚实例 */

c)FGpioSetDirection
      函数原型:void FGpioSetDirection(FGpio *const pin, FGpioDirection dir)
      函数位置:phytium-standalone-sdk/drivers/pin/fgpio/fgpio.c
   函数功能:设置GPIO引脚的输入输出方向
   函数参数:
FGpio *const pin,初始化引脚的参数,通过FGpioCfgInitialize函数初始化。
FGpioDirection dir,初始化后的参数。
typedef enum
{
    FGPIO_DIR_INPUT = 0, /* 输入 */
    FGPIO_DIR_OUTPUT /* 输出 */
} FGpioDirection; /* GPIO引脚的输入输出方向 */
d)FGpioSetOutputValue
      函数原型:FError FGpioSetOutputValue(FGpio *const pin, const FGpioVal output)
      函数位置:phytium-standalone-sdk/drivers/pin/fgpio/fgpio.c
   函数功能:设置GPIO引脚的输出值
   函数参数:
FGpio *const pin,初始化引脚的参数,通过FGpioCfgInitialize函数初始化。
const FGpioVal output,初始化后的参数。
typedef enum
{
    FGPIO_PIN_LOW = 0,/* 低电平 */
    FGPIO_PIN_HIGH/* 高电平 */
} FGpioVal; /* GPIO引脚电平类型 */
e)返回值FError
FGPIO_SUCCESS : success
FGPIO_ERR_INVALID_PARA : invalid input parameters
FGPIO_ERR_INVALID_STATE : invalid state

(5) openamp_for_linux案例

1) openamp_for_linux案例介绍

openamp_for_linux案例位于phytium-standalone/example/system/amp/openamp_for_linux ,基于开源openamp项目 OpenAMP。案例提供了PHYTIUMPI 裸机与 linux 系统之间的测试例程,通过使用rpmsg来实现核间通信的应用程序。openamp_for_linux案例为从机程序,linux 中的程序为主核程序,其目标是主核主动发送数据之后,从机程序会将收到的数据重新发生给主核。

2) openamp_for_linux目录

3) openamp_for_linux的主要函数

a)main
      函数原型:int main(void)
      函数位置:phytium-standalone/example/system/amp/openamp_for_linux/main.c
      函数功能:从核函数的入口函数,调用slave00_rpmsg_echo_process函数初始化从核。
b)slave00_rpmsg_echo_process
      函数原型:int slave00_rpmsg_echo_process(void)
      函数位置:phytium-standalone/example/system/amp/openamp_for_linux/src/slaver_00_example.c
      函数功能:运行在从核(如FreeRTOS或裸机环境)上的核心任务,负责实现数据回显(Echo)功能。,主要负责数据接收与回传以及通信生命周期管理。主要调用的实现函数是FRpmsgEchoApp。
c)FRpmsgEchoApp
      函数原型:static int FRpmsgEchoApp(struct rpmsg_device *rdev, void *priv)
      函数位置:phytium-standalone/example/system/amp/openamp_for_linux/src/slaver_00_example.c
      函数功能:
。初始化 RPMSG 通信:负责配置和初始化 RPMSG 通道,建立处理器间(通常是主机与从机)的通信链路,包括设置端点(endpoint)、注册回调函数等。
。消息收发处理:实现核心的 "回声" 功能 —— 接收来自通信对端(如主机)的消息后,将消息原样返回给发送方,以此验证通信链路的有效性。
。通信管理:可能包含对消息队列、缓冲区的管理,以及处理通信过程中的异常情况(如消息超时、传输错误等)。
。演示 RPMSG 机制:作为示例应用,它直观展示了 RPMSG 的基本使用流程,包括消息接收、处理和发送的完整闭环,帮助开发者理解跨处理器通信的实现方式。
d)rpmsg_endpoint_cb
      函数原型:static int rpmsg_endpoint_cb(struct rpmsg_endpoint *ept, void *data, size_t len, uint32_t src, void *priv)
      函数位置:phytium-standalone/example/system/amp/openamp_for_linux/src/slaver_00_example.c
      函数功能:RPMSG 通信中消息接收与处理的核心回调入口,是实现处理器间数据交互的关键环节
函数参数:其中参数分别代表:RPMSG 端点、接收的数据、数据长度、消息源地址、私有数据。

4) openamp_for_linux数据流

5. OpenAMP从核驱动LED20案例

(1) openamp_for_linux工程配置

工程目录:phytium-pi-os/output/build/phytium-standalone-openamp-v1.0/example/system/amp/openamp_for_linux
配置文件:configs/phytiumpi_aarch64_firefly_openamp_core0.config
增加如下内容:
CONFIG_USE_GPIO=y
CONFIG_ENABLE_FGPIO=y
CONFIG_LOG_VERBOS=y

(2) 增加LED20控制的新文件openamp_for_linux/src/led20set.c

#include <stdio.h>
#include "sdkconfig.h"
#include "fdebug.h"
/*common*/
#include "fio.h"
#include"ftypes.h"
#include"fkernel.h"
#include"fsleep.h"
#include "fassert.h"
/*drivers/iomux/fiopad*/
#include "fiopad.h"
/*drivers/pin/fgpio*/
#include "fgpio_hw.h"
#include "fgpio.h"
/*board/firefly*/
#include "fio_mux.h"
#include "slaver_00_example.h"
#include "fgpio.h"

int initFLag = 0;
u32 gpIO1_8_FGpio_id ;
const FGpioConfig *gpI01_8_FGpioconfig = NULL;
FGpio gpI01_8_FGpio;


void led20Set(int flag )	
{
	if(0 == initFLag)
	{
	
		gpIO1_8_FGpio_id = FGPIO_ID(FGPIO_CTRL_1,FGPIO_PIN_8);

		gpI01_8_FGpioconfig =FGpioLookupConfig(gpIO1_8_FGpio_id);
		if(NULL == gpI01_8_FGpioconfig)
		{
			SLAVE_DEBUG_E("led20Set():FGpioLookupConfig error\r\n");
			return ;
		}
		memset(&gpI01_8_FGpio,0,sizeof(gpI01_8_FGpio ));
		if(FGPIO_SUCCESS != FGpioCfgInitialize(&gpI01_8_FGpio,gpI01_8_FGpioconfig))
		{
			SLAVE_DEBUG_E("led20Set():FGpioCfgInitialize() error\r\n");
			return ;
		
		}
		FIOMuxInit();
		FIOPadSetGpioMux(FGPIO_CTRL_1,FGPIO_PIN_8);

		FGpioSetDirection(&gpI01_8_FGpio,FGPIO_DIR_OUTPUT);

 	    initFLag = 1;
	}
	if( 0 == flag )
	{
		SLAVE_DEBUG_I("set led20 low n");
		FGpioSetOutputValue(&gpI01_8_FGpio,FGPIO_PIN_LOW);
	}
	else if( 1 == flag)
	{	
		SLAVE_DEBUG_I("set led20 high\r\n");
		FGpioSetOutputValue(&gpI01_8_FGpio,FGPIO_PIN_HIGH);
	}
	return;
     
}

(3) 修改回调函数rpmsg_endpoint_cb,执行LED20的控制命令

 static int rpmsg_endpoint_cb(struct rpmsg_endpoint *ept, void *data, size_t len, uint32_t src, void *priv)
{
	SLAVE_DEBUG_W("[%s:%d] start %s %s\r\n",__FUNCTION__,__LINE__,__DATE__,__TIME__);

    (void)priv;
    (void)src;

    int ret;
    int i = 0;
    (void)priv;
    SLAVE_DEBUG_I("src:0x%x",src);
    ept->dest_addr = src;

    ret = parse_protocol_data((char *)data, len, &protocol_data);
    if(ret != 0)
    {
        SLAVE_DEBUG_E("parse protocol data error,ret:%d",ret);
        return RPMSG_SUCCESS;/* 瑙f瀽澶辫触锛屽拷鐣ユ暟鎹?*/
    }
    SLAVE_DEBUG_I("command:0x%x,length:%d.",protocol_data.command,protocol_data.length);
    switch (protocol_data.command)
    {
        case DEVICE_CORE_START:
        {
            break;
        }
        case DEVICE_CORE_SHUTDOWN:
        {
            shutdown_req = 1;
            break;
        }
        case DEVICE_CORE_CHECK:
        {
            /* Send temp_data back to master */
           ret = rpmsg_send(ept, &protocol_data, len);
            if (ret < 0)
            {
                SLAVE_DEBUG_E("rpmsg_send failed.\r\n");
                return ret;
            }
            break;
        }
#if 1//for LED20
	case  LED_ON:
		SLAVE_DEBUG_I("rpmsg_endpoint_cb:LED_ON");
		led20Set(1);
		break;
	case LED_OFF:
		SLAVE_DEBUG_I("rpmsg_endpoint_cb:LED_OFF");
		led20Set(0);
		break;
#endif	
        default:
            break;
    }

    return RPMSG_SUCCESS;
}

(4) 编译从核程序

 phytium-pi-os# make phytium-standalone-rebuild
生成的elf文件的位置:
example/system/amp/openamp_for_linux/phytiumpi_aarch64_firefly_openamp_core0.elf
Note:注意需要在交叉编译环境的phytium-pi-os目录下编译。

(5) 拷贝到开发板上

 开发板文件位置:/lib/firmware
文件名需要同设备树指定的文件一致,openamp_core0.elf

6. 验证和测试

(1) 主机程序,修改rpmsg-demo-single.c控制LED20,并在开发板上编译

 #include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <poll.h>
#include <linux/rpmsg.h>
#include <errno.h>

#define MAX_DATA_LENGTH 256

#define DEVICE_CORE_START     0x0001U
#define DEVICE_CORE_STOP      0x0002U
#define DEVICE_CORE_CHECK     0x0003U
#if 1//for LED20
#define LED_ON 0x004U
#define LED_OFF 0X005U
#define LED_RUNNING 0x006U
#endif
......
int main(int argc, char **argv)
{
	int ctrl_fd, rpmsg_fd, ret;
	int leng;
	struct rpmsg_endpoint_info eptinfo;
	struct pollfd fds;
	char *buff;
	data_packet test_data;
	data_packet test_data_r;
	char buff_r[MAX_DATA_LENGTH];

	printf("argc: %d\n", argc);
	for (int i = 0; i < argc; i++) {
		printf("Argument %d: %s\n", i, argv[i]);
	}

	test_data.command = DEVICE_CORE_CHECK;
	buff = test_data.data;

	ctrl_fd = open("/dev/rpmsg_ctrl0", O_RDWR);
	if (ctrl_fd < 0) {
		perror("open rpmsg_ctrl0 failed.\n");
		return -1;
	}

	memcpy(eptinfo.name, "xxxx", 32);
	eptinfo.src = 0;
	eptinfo.dst = 0;

	ret = ioctl(ctrl_fd, RPMSG_CREATE_EPT_IOCTL, eptinfo);
	if (ret != 0) {
		perror("ioctl RPMSG_CREATE_EPT_IOCTL failed.\n");
		goto err0;
	}

	rpmsg_fd = open("/dev/rpmsg0", O_RDWR);
	if (rpmsg_fd < 0) {
		perror("open rpmsg0 failed.\n");
		goto err1;
	}
#if 1//for LED20
if (argc > 2 && strcmp(argv[1], "led") == 0) {
	if (strcmp(argv[2], "0") == 0) {
		printf("led off \n");
		test_data.command = LED_OFF;
		test_data.length = 1;
		ret = write_full(rpmsg_fd, &test_data, sizeof(data_packet));
		if (ret < 0) {
			perror("write_full failed.\n");
		}
	} 
	else if (strcmp(argv[2], "1") == 0) {
		printf("led on 0\n");
		test_data.command = LED_ON;
		test_data.length = 1;
		ret = write_full(rpmsg_fd, &test_data, sizeof(data_packet));
		if (ret < 0) {
			perror("write_full failed.\n");
		}
	} 	
	else {
		printf("stop para err!\n");
	}
#endif
	goto err1;
}
在开发板编译用户测试程序:
gcc rpmsg-demo-single.c -o rpmsg-demo-single

(2) 启动远程服务器

启动远程服务器 echo start > /sys/class/remoteproc/remoteproc0/state

绑定驱动名字 echo rpmsg_chrdev > /sys/bus/rpmsg/devices/virtio0.rpmsg-openamp-demo-channel.-1.0/driver_override

(3) 从核关闭led20

 ./rpmsg-demo-single led 0

(4) 从核打开led20

 ./rpmsg-demo-single led 1

7.参考资料链接

飞腾派开发板资料下载www.iceasy.com/cloud/Phytium