Skip to content

将 AWTK 移植到 STM32f103ze 裸系统

AWTK 的可移植性很高,在移植时只需要实现平台初始化、lcd 和 mainloop 三个方面的东西。本文以 STM32f103ze 为例介绍移植 AWTK 到新平台的过程。

一、平台初始化

除了基本的libc函数外,AWTK对平台没有特别要求,实现获取当前时间的函数get_time_ms64和sleep_ms函数即可。另外需要给GUI分配一块内存空间,并调用tk_mem_init。

我们使用 systick 来实现 get_time_ms64 和 sleep_ms 两个函数,裸系统上只需加入 src/platforms/raw/sys_tick.c 并初始化 sys_tick 即可。

以下是初始化内存的代码。

ret_t platform_prepare(void) {
  static bool_t inited = FALSE;
  static uint32_t s_heam_mem[4000];

  if (!inited) {
    inited = TRUE;
    tk_mem_init(s_heam_mem, sizeof(s_heam_mem));
  }

  return RET_OK;
}

参考:awtk-port/platform.c

以下是初始化 systick 的代码(在板子提供代码上修改而来)。

static u8 fac_us = 0; 
static u16 fac_ms = 0; 

void systick_enable_int(void) {
  SysTick->CTRL |= SysTick_CTRL_TICKINT_Msk;
  SysTick->LOAD = fac_ms;
  SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk;
}

void SysTick_Init(void) {
  SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);
  fac_us = SystemCoreClock / 8000000;
  fac_ms = (u16)fac_us * 1000;
}

void delay_us(u32 nus) {
  u32 temp = 0;
  SysTick->LOAD = nus * fac_us; 
  SysTick->VAL = 0x00;          
  do {
    temp = SysTick->CTRL;
  } while ((temp & 0x01) && !(temp & (1 << 16))); 
}

void delay_ms(u16 nms) {
  u32 temp = 0;
  SysTick->LOAD = (u32)nms * fac_ms;
  SysTick->VAL = 0x00;              
  do {
    temp = SysTick->CTRL;
  } while ((temp & 0x01) && !(temp & (1 << 16))); 
}

参考:awtk-port/SysTick.c

二、实现 lcd

lcd_t 接口提供基本的显示功能,AWTK 提供基于寄存器帧缓冲片段帧缓冲三种缺省实现,在此基础上实现自己的 lcd_t 接口非常方便。

stm32f103ze 使用基于片段帧缓冲的 lcd 的缺省实现,只需要提供 set_window_func 和 write_data_func 两个函数/宏即可。这里直接使用了 TFT_SetWindow 和 TFT_WriteData 两个函数。

直接写寄存器的方式容易闪烁,而帧缓冲又需要大量内存,片段帧缓冲能有效解决低内存平台的闪烁问题。

include "tftlcd.h"
include "tkc/mem.h"
include "lcd/lcd_mem_fragment.h"

typedef uint16_t pixel_t;

define LCD_FORMAT BITMAP_FMT_BGR565
define pixel_from_rgb(r, g, b)                                                \
  ((((r) >> 3) << 11) | (((g) >> 2) << 5) | ((b) >> 3))
define pixel_to_rgba(p)                                                       \
  { (0xff & ((p >> 11) << 3)), (0xff & ((p >> 5) << 2)), (0xff & (p << 3)) }

define set_window_func LCD_Set_Window
define write_data_func LCD_WriteData_Color

include "base/pixel.h"
include "blend/pixel_ops.inc"
include "lcd/lcd_mem_fragment.inc"

参考 awtk-port/lcd_stm32_raw.c

三、实现 main_loop

main_loop 主要负责事件分发和绘制这个不断循环的过程。main_loop_raw.inc 里实现了裸系统 main_loop 的基本功能,在移植时加上输入事件的的分发即可:


include "key.h"
include "led.h"
include "rtc.h"
include "stdlib.h"
include "tftlcd.h"
include "touch.h"
include "usart.h"


include "base/idle.h"
include "base/timer.h"
include "tkc/platform.h"
include "base/main_loop.h"
include "base/event_queue.h"
include "base/font_manager.h"
include "lcd/lcd_mem_fragment.h"
include "main_loop/main_loop_simple.h"


ret_t platform_disaptch_input(main_loop_t *l) { return RET_OK; }

static lcd_t *platform_create_lcd(wh_t w, wh_t h) {
  return lcd_mem_fragment_create(w, h);
}

void dispatch_input_events(void) {
  int key = KEY_Scan(0);

  switch (key) {
  case KEY_UP: {
    key = TK_KEY_UP;
    break;
  }
  case KEY_DOWN: {
    key = TK_KEY_DOWN;
    break;
  }
  case KEY_LEFT: {
    key = TK_KEY_RETURN;
    break;
  }
  case KEY_RIGHT: {
    key = TK_KEY_BACK;
    break;
  }
  default: { key = 0; }
  }

  if (key) {
    main_loop_post_key_event(main_loop(), TRUE, key);
  } else {
    main_loop_post_key_event(main_loop(), FALSE, key);
  }

  if (TOUCH_Scan() == 0) {
    main_loop_post_pointer_event(main_loop(), TRUE, TouchData.lcdx,
                                 TouchData.lcdy);
  } else {
    main_loop_post_pointer_event(main_loop(), FALSE, TouchData.lcdx,
                                 TouchData.lcdy);
  }
}

void TIM3_IRQHandler(void) {
  if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) {
    dispatch_input_events();
    TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
  }
}

include "main_loop/main_loop_raw.inc"

参考 awtk-port/main_loop_stm32_raw.c

四、Keil 设置

    1. 勾选 c99
    1. 定义 HAS_AWTK_CONFIG
    1. 增加如下头文件路径:
awtk\src
awtk\3rd
awtk-port

请根据项目文件位置进行调整。

五、其它配置

其它配置请参考 awtk-port/awtk_config.h

注:目前以 普中科技 STM32F103ZET6 开发实验板 为载体移植,其它开发板应该差不多。

完整项目和源码请参考:awtk-stm32f103ze-raw

六、常见问题

  • 1.莫名其妙的崩溃,可能是栈溢出。请修 Stack_Size 的大小。
 Stack_Size      EQU     0x00001000
  • 2.如果出现 wcsxxx 之类的函数没有定义时,请在 awtk-port/awtk_config.h 中定义 WITH_WCSXXX。