AMetal平台学习——初步了解篇

AMetal是广州周立功科技股份有限公司开发的一套轻量级嵌入式开发平台,它为各种外设定义了统一的抽象接口,使应用程序与芯片底层可以完全分离,轻松实现“跨平台”复用。除此之外,AMetal还致力于为用户提供大量“可裁剪、可替换、可配置”的组件,提升开发的灵活性。

目前Amteal原生支持的MCU情况如下:
在这里插入图片描述
理论上,Ametal支持所有的MCU,但是官方仅推出了以上表格中所列举的MCU(PS:居然都没有STM32???)的硬件层驱动,如果想移植到其他MCU上,需要自己实现硬件层驱动,实际上,同一内核的MCU硬件层驱动实现方法类似,移植起来难度不是很大,就是比较繁琐,这也是我接下来需要完成的工作。

接下来就进入正题,开始移植Ametal到STM32F103RCT6芯片上,由于STM32F103RCT6是Cortex-M3内核,所以我决定在同是M3内核的ZLG217芯片的源码基础上进行修改移植,这样就大大降低了工作量。

一、获取源码

AMetal 的源码已在 github及码云上进行开源,源码地址为:github gitee

Down下来的Ametal源码目录如下:
在这里插入图片描述
AMetal 根目录结构:

在这里插入图片描述
documents目录下有很多Ametal的说明与应用文档以及API参考手册等。我们可以将documents目录下的文档都通读一遍,简单了解下Ametal,有利于后面的移植工作。board目录下是各种开发板的模版工程,由于我们是基于ZLG217开发板进行移植,所以我们需要打开ZLG217下的模版工程,打开路径:ametal\board\am217_core\project_example\projects_keil5的keil5工程。打开main.c(user_code文件夹下)
在这里插入图片描述
工程目录结构说明:

文件夹说明
bsp_common通用的板级支持文件,例如C库的适配文件“am_bsp_armlib.c” 、系统堆的适配文件“am_bsp_system_heap.c”等。
armARM 内核相关的文件,如 NVIC、SysTick 等文件。
drivers通用外设及模块的标准驱动文件,如按键、矩阵键盘、温度传感器模块、ZigBee 模块等。
libcC 库适配器文件,如 armlib_adpater,主要用于适配相应的 C 库。
service通用服务组件的驱动文件,如 ADC、蜂鸣器等。
utilAMetal 通用辅助工具文件,如堆管理器、软件定时器以及打印输出函数等。
soc包含了与 MCU 密切相关的文件,包括硬件层和驱动层文件。
examples_board板级例程,它们调用驱动层和硬件层的例层,控制开发板的各个硬件
examples_components常用芯片的例程 如常见的 flash 芯片“EP24Cxx”和“MX25xx”等。
examples_soc硬件层例程,这些例程通过调用硬件层函数实现。
examples_std驱动层例程,主要通过调用驱动层的函数来实现
startup内核的启动代码,是一个汇编文件
user_code用户代码 如main.c
user_config用户配置文件 每个外设都对应一个配置文件

这个工程包含很多例程(examples_开头的文件夹),以及很多外设和模块的驱动,这些都不需要修改,因为它们都是调用标准接口实现的,与具体的MCU无关。对于移植工作,我们需要重点关注的就是soc文件夹下的文件,它包括硬件层和驱动层文件,这些文件是与具体的MCU息息相关的。

刚刚我们注意到main.c这个文件中并没有main函数,而是am_main函数,实际上,在Ametal中,main函数在user_config文件夹下的am_prj_config.c文件中,这里的main函数的主要作用是完成时钟、NVIC、GPIO以及板级外设初始化,并在函数的最后调用am_main函数。这样做的好处是屏蔽了硬件,应用开发者无需关心底层硬件,真正意义上做到了应用和硬件分离。
在这里插入图片描述
AMetal共分为三层,硬件层、驱动层和标准接口层,这三层对应的接口均可被应用程序使用。硬件层对SOC做最原始封装;驱动层在硬件层的基础上进一步封装,简化对外设的操作;标准接口层提取出了一套标准API接口,用户使用这些标准API接口开发程序,即可做到一次编程、终生使用、跨平台。

Ametal架构如下图所示:
在这里插入图片描述
硬件层(HardWare):硬件层对 SOC做最原始封装,其提供的 API 基本上是直接操作寄存器的内联函数,效率最高。当需要操作外设的特殊功能,或者对效率等有需求时,可以调用硬件层 API。硬件层等价于传统SOC原厂的裸机包。硬件层接口使用amhw_/AMHW_ +芯片名作为命名空间,如 amhw_zlg116、AMHW_ZLG116。

驱动层(Driver):驱动层在硬件层的基础上做了进一步封装,进一步简化对外设的操作。驱动层分为标准驱动和非标准驱动,前者是指GPIO、UART、ADC、SPI、I2C等常见外设驱动,这类驱动通常只会提供一个初始化函数(例如,ZLG116 的 ADC 标准驱动提供的初始化函数命名形形式可能为:am_zlg116_adc_init()),初始化后即可使用标准接口操作相应的外设。
后者是指DMA等特殊外设,它未能实现标准化接口,它需要用户自定义接口供应用程序调用。

标准接口层(Standard API):标准接口层对常见外设的操作进行了抽象,提出了一套标准 API 接口,可以保证在不同的硬件上,标准 API 的行为都是一样的,接口命名空间 am_/AM_。用户使用一个 GPIO 的过程:先调用驱动初始化函数,后续在编写应用程序时仅需直接调用标准接口函数即可。可见,应用程序基于标准 API 实现的,标准 API 与硬件平台无关,使得应用程序可以轻松的在不同的硬件平台上运行,传统实现是直接实现接口。

二、Ametal思想

Ametal的核心思想是面向对象的思想,同时提出了服务(Handle)的概念,所有的设备都被抽象成一个标准服务,也就是一个对象,比如LED设备、UART设备、SPI设备等等。标准接口都是基于这些服务实现的,因为服务是抽象的,它与具体芯片没有任何关系,所以标准接口也与具体芯片没有关系,这样就实现了跨平台性。

下面是一段uart设备的标准接口代码:

int am_uart_poll_send (am_uart_handle_t  handle,
                       const uint8_t    *p_txbuf,
                       uint32_t          nbytes)
参数说明
handleUART标准服务
p_txbuf发送缓存区
nbytes发送数据长度

UART标准服务由底层UART设备初始化代码提供:

/** UART1实例初始化,获得uart1标准服务句柄 */
am_uart_handle_t am_zlg217_uart1_inst_init (void)
{
    return am_zlg_uart_init(&__g_uart1_dev, &__g_uart1_devinfo);
}

am_uart_handle_t 的定义如下:

/**
 * \brief UART服务
 */
typedef struct am_uart_serv 
{

    /** \brief UART驱动函数结构体指针    */
    struct am_uart_drv_funcs *p_funcs;

    /** \brief 用于驱动函数的第一个参数  */
    void                     *p_drv;
} am_uart_serv_t;

/** \brief UART标准服务操作句柄类型定义  */
typedef am_uart_serv_t *am_uart_handle_t;

am_uart_drv_funcs 是一个函数指针结构体,里面包含了UART设备操作函数的集合,类似Linux设备驱动下的file_operations结构体,它的定义如下:

/**
 * \brief UART驱动函数结构体
 */
struct am_uart_drv_funcs 
{

    /**\brief UART控制函数     */
    int (*pfn_uart_ioctl)(void *p_drv,int request, void *p_arg);

    /**\brief 启动UART发送函数 */
    int (*pfn_uart_tx_startup)(void *p_drv);

    /**\brief 设置串口回调函数 */
    int (*pfn_uart_callback_set)(void  *p_drv,
                                 int    callback_type,
                                 void  *pfn_callback,
                                 void  *p_arg);

    /**\brief 从串口获取一个字符(查询模式) */
    int (*pfn_uart_poll_getchar)(void *p_drv, char *p_inchar);

    /**\brief 输出一个字符(查询模式)       */
    int (*pfn_uart_poll_putchar)(void *p_drv, char outchar);

};

上面提到的串口实例化初始化函数am_zlg217_uart1_inst_init实现的主要功能就是初始化串口和填充am_uart_drv_funcs 结构体。这样就相当于建立了标准接口层和底层硬件的联系。UART驱动函数结构体的实现如下:

/** \brief 标准层接口函数实现 */
static const struct am_uart_drv_funcs __g_uart_drv_funcs = 
{
    __uart_ioctl,
    __uart_tx_startup,
    __uart_callback_set,
    __uart_poll_getchar,
    __uart_poll_putchar,
};
//这些函数就是直接操作串口对应的寄存器实现对应的功能

Ametal架构大致的思想就是这样,上述的也仅仅针对UART、SPI等标准外设,对于DMA等特殊外设还需要特殊处理,这放在后面再详细讲解。总结来说,Ametal就是通过抽象服务的概念实现跨平台和复用的。

  • 5
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
AMetal 是一款开源的 Android 运行时环境,它可以让 Android 应用程序在不同的硬件平台上运行。在 AMetal 中,input 子系统是非常重要的一部分,它负责处理输入设备的数据。下面我来介绍一下如何实现 input 子系统。 1. 定义 input 设备 首先,我们需要定义 input 设备的结构体,包括设备名称、设备类型、设备 ID 等信息。例如: ``` struct input_dev { const char *name; unsigned int type; unsigned int id; struct input_absinfo absinfo[3]; ... }; ``` 2. 注册 input 设备 接着,我们需要注册 input 设备,让系统能够识别并使用它。我们可以通过 `input_register_device()` 函数来注册一个 input 设备,例如: ``` struct input_dev *dev = input_allocate_device(); dev->name = "My Input Device"; dev->type = EV_KEY; dev->id.bustype = BUS_USB; dev->id.vendor = 0x1234; dev->id.product = 0x5678; dev->id.version = 0x0100; input_set_capability(dev, EV_KEY, KEY_A); input_set_capability(dev, EV_KEY, KEY_B); ... input_register_device(dev); ``` 在上面的示例中,我们创建了一个名为 "My Input Device" 的 input 设备,并定义了其类型为 EV_KEY(按键设备),ID 为 USB 类型,厂商 ID 为 0x1234,产品 ID 为 0x5678,版本号为 0x0100。然后,我们通过 `input_set_capability()` 函数来设置该设备支持的按键,例如 KEY_A 和 KEY_B。 最后,我们调用 `input_register_device()` 函数来注册该设备。 3. 处理 input 事件 一旦我们的 input 设备被注册成功,就可以开始处理输入事件了。我们可以通过 `input_event()` 函数来发送 input 事件,例如: ``` struct input_event ev; ev.type = EV_KEY; ev.code = KEY_A; ev.value = 1; input_event(dev, &ev); ev.value = 0; input_event(dev, &ev); ``` 在上面的示例中,我们发送了一个按下 KEY_A 按键的事件,然后再发送一个松开 KEY_A 按键的事件。 当 input 事件被发送到 input 子系统后,系统会将其传递给应用程序或系统服务进行处理。 以上就是实现 input 子系统的基本步骤,当然实际实现时还需要考虑更多的细节问题,例如输入设备的数据格式、输入事件的处理方式等等。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值