# 3. 适配准备工作

# 3.1 平台堆栈配置

AWTK 最低的栈(Stack)要求为 9KB,如果需要支持 jpg/png 图片解码,则栈至少需要 32KB。

不同平台设置栈大小的方法不一样,比如在 AWTK 针对 STM32F767igtx 平台的 移植层 (opens new window) 中,需要修改 startup_stm32f767xx.s 文件中的 Stack_Size 属性值。在实时操作系统的平台上,AWTK GUI 线程使用的栈就是开辟线程时定义的栈,所以需要修改线程栈大小。

堆(Heap)用于程序运行过程中使用 malloc 开辟内存空间,对 AWTK 来讲,堆就是 AWTK 的动态运行内存,通常用于创建控件、定时器、idle 等各种对象以及保存图片、字模等缓存。其初始化方法详见下一个小节,堆推荐配置范围是 64KB~8MB,具体需根据模块裁剪和应用程序的实际情况调整,计算方法请参考下文裁剪篇的内容。

# 3.2 平台初始化

AWTK 程序启动时,会在 tk_init 函数中调用 platform_prepare 函数初始化平台相关的准备模块,AWTK 运行流程详见本文 1.3 章节。

用户可以选择使用系统内存堆或让 AWTK 自行管理内存。如果用户希望 AWTK 使用系统标准 malloc 管理内存,则应该在工程中定义 HAS_STD_MALLOC 宏;如果用户希望 AWTK 自行管理堆内存,则可以在 platform_prepare 函数中调用 tk_mem_init 函数给 GUI 分配一块内存。代码如下:

/* 给 AWTK 开辟一块大小为 TK_MEM_SIZE 的内存 s_mem */
#define TK_MEM_SIZE 8 * 1024 * 1024
ret_t platform_prepare(void) {
/* 定义宏 HAS_STD_MALLOC 将使用系统标准 malloc 函数,具体详见本文附录二 */
#ifndef HAS_STD_MALLOC  
  static uint8_t s_mem[TK_MEM_SIZE];  /* 此处以静态数组为例 */
  tk_mem_init(s_mem, sizeof(s_mem));  /* 初始化 AWTK 内存管理器 */
#endif
  return RET_OK;
}

其他平台相关的准备模块,比如时间管理模块,同样也可以在 platform_prepare 函数中初始化,具体请参考:awtk/src/tkc/date_time.h。

# 3.3 时钟和睡眠移植

在 AWTK 中,时钟一般用来计算时间间隔,实现定时器和动画等功能;睡眠一般用于 AWTK 主循环限制 GUI 帧率。移植时钟和睡眠通常只需实现 awtk/src/tkc/platform.h 文件中的 get_time_ms64 函数和 sleep_ms 函数即可,代码如下:

uint64_t get_time_ms64() {
  /* 返回平台当前时间(单位:毫秒) */
  return system_time_ms;
}

void sleep_ms(uint32_t ms) {
  /* 调用平台相关接口实现睡眠 */     
  system_sleep_ms(ms);
}

需要注意的是,移植层需要确保 get_time_ms64 函数返回的时间是 64 位毫秒计数器。如果平台没有提供 64 位计数器,则需要用户自行通过系统中断或硬件定时器实现。如果强行在 get_time_ms64 函数返回 32 位计数器,GUI 长时间运行后可能存在计数溢出风险和不可预测的问题。

此外,在裸系统平台上也可以通过 SysTick 来实现以上函数,只需初始化 SyeTick 并且在编译时添加 awtk/src/platforms/raw/sys_tick_handler.c 文件即可,具体请参考 AWTK 针对 STM32f103ze 裸系统的 移植层 (opens new window)

AWTK 提供了常见 RTOS 的时钟与睡眠实现,具体详见 awtk/src/platforms 目录下对应平台的实现代码,用户可直接加入工程使用。

# 3.4 AWTK 的宏配置

在 PC 或嵌入式 Linux 系统中,AWTK 的宏配置直接在 SCons 脚本(awtk_config.py)中定义。在其他嵌入式平台上,为方便用户配置,AWTK 相关的宏配置通常写在 awtk_config.h 文件中,它主要用于设置平台相关的配置以及开关某些功能模块,示例详见:awtk/src/base/awtk_config_sample.h,代码如下:

/* awtk_config.h */
#ifndef AWTK_CONFIG_H
#define AWTK_CONFIG_H

/* 嵌入式系统有自己的main函数时,请定义本宏 */
#define USE_GUI_MAIN 1

/* 如果支持png/jpeg图片,请定义本宏 */
#define WITH_STB_IMAGE 1

... 

/* 如果启用矢量画布 VGCANVAS,请定义本宏 */
#define WITH_VGCANVAS 1

...

#endif /*AWTK_CONFIG_H*/

需要注意的是,使用 awtk_config.h 文件需要在配置工程时定义宏 HAS_AWTK_CONFIG,例如,在 Keil 项目中设置编译宏如下图所示:

图3.1 定义宏HAS_AWTK_CONFIG
图3.1 定义宏HAS_AWTK_CONFIG

各个功能模块的介绍及其宏定义详见文本附录二。

# 3.5 将 AWTK 代码添加到工程

AWTK 的核心代码结构详见本文 1.4 章节中的表格,根据项目裁剪需求,添加对应的代码文件到工程中,详见本文 10.3 章节。

# 3.6 自带例程及运行异常问题排查

移植完成后,请尝试在板子上运行 AWTK 自带例程 demoui,验证移植效果。用户需要将 awtk/demos 文件夹下的 assets.c(或assets-1m.c)、demo_ui_app.c 加入到工程中编译,如运行出现莫名其妙的异常或崩溃,请按如下步骤排查:

  1. 增加系统 Stack 大小,如果使用 RTOS 线程,则调整 GUI 线程 Stack 大小。建议尝试设置 Stack 大小>=32KB;
  2. 增加系统 Heap 大小,如果使用 AWTK 自己管理的 Heap,则调整对应的数组大小。建议尝试设置Heap大小>=4MB;
  3. 降低工程编译优化等级。