开源地址:https://gitee.com/AT32437_OpenHarmony
学习本文档的意义
1.学习移植OpenHarmony轻量系统到AT32全系列mcu上,本文档移植的具体型号为AT32F437ZMT7
2.学习OpenHarmony轻量系统开发
3.适配vprintf, vfprintf, printf, snprintf 和sprintf
1.首先获取AT32F437的底层驱动源代码(Firmware Library),我们需要从官方托管的gitee仓库AT32F435_437_Firmware_Library获取
2.找到at32f435_437_board.c文件,注释掉__io_putchar函数,使用fputc函数
// #if defined (__GNUC__) && defined (__clang__)
// #define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
// #else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
// #endif
再注释掉setvbuf
函数,这个函数影响适配适配printf
/**
* @brief initialize uart
* @param baudrate: uart baudrate
* @retval none
*/
void uart_print_init(uint32_t baudrate)
{
gpio_init_type gpio_init_struct;
// #if defined (__GNUC__) && !defined (__clang__)
// setvbuf(stdout, NULL, _IONBF, 0); //printf函数有关
// #endif
/* enable the uart and gpio clock */
crm_periph_clock_enable(PRINT_UART_CRM_CLK, TRUE);
crm_periph_clock_enable(PRINT_UART_TX_GPIO_CRM_CLK, TRUE);
3.在/device/board/artery_board/atstartf437/liteos_m/config.gni新增_malloc_r, _realloc_r, _reallocf_r, _free_r, _memalign_r, 和 _malloc_usable_size_r函数的wrap链接选项。
board_ld_flags = [ # 链接选项,与厂商Makefile中的LDFLAGS变量对应。
"-Xlinker",
"--gc-sections",# 需要的Linker 配置
"--specs=nano.specs", # 为了使用printf函数
"--specs=nosys.specs", # 为了使用printf函数
"-Wl,--wrap=_calloc_r",
"-Wl,--wrap=_malloc_r",
"-Wl,--wrap=_realloc_r",
"-Wl,--wrap=_reallocf_r",
"-Wl,--wrap=_free_r",
"-Wl,--wrap=_memalign_r",
"-Wl,--wrap=_malloc_usable_size_r",
]
4.然后重写printf和sprintf函数,具体实现查看dprintf.c
#include <stdarg.h>
#include <stdio.h>
#include "securec.h"
#include "los_interrupt.h"
unsigned int intSave = 0;
//print函数的buffer大小
#define BUFSIZE 512
static void dputs(char const *s, int (*pFputc)(int n, FILE *cookie), void *cookie)
{
intSave = LOS_IntLock();
while (*s) {
pFputc(*s++, cookie);
}
LOS_IntRestore(intSave);
}
int printf(const char *__restrict __format, ...)
{
char buf[BUFSIZE] = { 0 };
int len;
va_list ap;
va_start(ap, __format);
len = vsnprintf_s(buf, sizeof(buf), BUFSIZE - 1, __format, ap);
va_end(ap);
if(len > 0) {
dputs(buf, fputc, 0);
} else {
dputs("printf error!\n", fputc, 0);
}
return len;
}
5.在main.c的main.c里面初始化串口打印函数uart_print_init
3.适配vprintf, vfprintf, printf, snprintf 和sprintf
1.首先获取AT32F437的底层驱动源代码(Firmware Library),我们需要从官方托管的gitee仓库AT32F435_437_Firmware_Library获取
2.找到at32f435_437_board.c文件,注释掉__io_putchar函数,使用fputc函数
// #if defined (__GNUC__) && defined (__clang__)
// #define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
// #else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
// #endif
再注释掉setvbuf
函数,这个函数影响适配适配printf
/**
* @brief initialize uart
* @param baudrate: uart baudrate
* @retval none
*/
void uart_print_init(uint32_t baudrate)
{
gpio_init_type gpio_init_struct;
// #if defined (__GNUC__) && !defined (__clang__)
// setvbuf(stdout, NULL, _IONBF, 0); //printf函数有关
// #endif
/* enable the uart and gpio clock */
crm_periph_clock_enable(PRINT_UART_CRM_CLK, TRUE);
crm_periph_clock_enable(PRINT_UART_TX_GPIO_CRM_CLK, TRUE);
3.在/device/board/artery_board/atstartf437/liteos_m/config.gni新增_malloc_r, _realloc_r, _reallocf_r, _free_r, _memalign_r, 和 _malloc_usable_size_r函数的wrap链接选项。
board_ld_flags = [ # 链接选项,与厂商Makefile中的LDFLAGS变量对应。
"-Xlinker",
"--gc-sections",# 需要的Linker 配置
"--specs=nano.specs", # 为了使用printf函数
"--specs=nosys.specs", # 为了使用printf函数
"-Wl,--wrap=_calloc_r",
"-Wl,--wrap=_malloc_r",
"-Wl,--wrap=_realloc_r",
"-Wl,--wrap=_reallocf_r",
"-Wl,--wrap=_free_r",
"-Wl,--wrap=_memalign_r",
"-Wl,--wrap=_malloc_usable_size_r",
]
4.然后重写printf和sprintf函数,具体实现查看dprintf.c
#include <stdarg.h>
#include <stdio.h>
#include "securec.h"
#include "los_interrupt.h"
unsigned int intSave = 0;
//print函数的buffer大小
#define BUFSIZE 512
static void dputs(char const *s, int (*pFputc)(int n, FILE *cookie), void *cookie)
{
intSave = LOS_IntLock();
while (*s) {
pFputc(*s++, cookie);
}
LOS_IntRestore(intSave);
}
int printf(const char *__restrict __format, ...)
{
char buf[BUFSIZE] = { 0 };
int len;
va_list ap;
va_start(ap, __format);
len = vsnprintf_s(buf, sizeof(buf), BUFSIZE - 1, __format, ap);
va_end(ap);
if(len > 0) {
dputs(buf, fputc, 0);
} else {
dputs("printf error!\n", fputc, 0);
}
return len;
}
5.在main.c的main.c里面初始化串口打印函数uart_print_init
4.添加at32f437驱动库
前面提到首先获取AT32F437的底层驱动源代码(Firmware Library),我们需要从官方托管的gitee仓库AT32F435_437_Firmware_Library获取。
把原厂的驱动文件放置在device\soc\artery\at32f4xx\libraries和device\soc\artery\at32f4xx\liteos_m目录下面,为了消除编译报错需要进行一些修改
1.device/soc/artery/at32f4xx/liteos_m/include/at32f435_437.h中typedef int32_t INT32;
、typedef uint32_t UINT32;
注释掉
//typedef int32_t INT32;
typedef int16_t INT16;
typedef int8_t INT8;
//typedef uint32_t UINT32;
2.device/soc/artery/at32f4xx/liteos_m/include/at32f435_437.h中,FALSE修改为AT_FALSE,TRUE修改为AT_TRUE,避开宏的重定义
typedef enum {AT_FALSE = 0, AT_TRUE = !AT_FALSE} confirm_state;
3.device/soc/artery/at32f4xx/libraries/drivers/inc/at32f435_437_def.h中注释掉
//#define UNUSED(x) (void)x /* to avoid gcc/g++ warnings */
4.device/soc/artery/at32f4xx/libraries/drivers/src/at32f435_437_crm.c中注释DUMMY_NOP();
这个函数
/**
* @brief select system clock source
* @param value
* this parameter can be one of the following values:
* - CRM_SCLK_HICK
* - CRM_SCLK_HEXT
* - CRM_SCLK_PLL
* @retval none
*/
void crm_sysclk_switch(crm_sclk_type value)
{
CRM->cfg_bit.sclksel = value;
//DUMMY_NOP();
}
5.device/soc/artery/at32f4xx/liteos_m/include/at32f435_437_board.h中 添加 #define AT_START_F437_V1
6.device/soc/artery/at32f4xx/liteos_m/include/at32f435_437.h中相关宏为修改AT32F437ZMT7,相关代码如下
/**
* tip: to avoid modifying this file each time you need to switch between these
* devices, you can define the device in your toolchain compiler preprocessor.
*/
#define AT32F437xx
/**
* define with package
*/
#define AT32F437Zx
/**
* define with memory density
*/
#define AT32F437xM
7.device/soc/artery/at32f4xx/liteos_m/include/at32f435_437_conf.h中添加
#if !defined TRUE
#define TRUE AT_TRUE
#endif
#if !defined FALSE
#define FALSE AT_FALSE
#endif
8.所有的at32437驱动文件都要包含头文件#include "los_compiler.h"
,为了解决UNUSED
没有定义的问题
5.内核子系统适配
在vendor\artery\AT-START-F437\config.json添加内核子系统及相关配置,如下所示:
"subsystems": [
{
"subsystem": "kernel",
"components": [
{
"component": "liteos_m"
}
]
}
],
4.添加at32f437驱动库
前面提到首先获取AT32F437的底层驱动源代码(Firmware Library),我们需要从官方托管的gitee仓库AT32F435_437_Firmware_Library获取。
把原厂的驱动文件放置在device\soc\artery\at32f4xx\libraries和device\soc\artery\at32f4xx\liteos_m目录下面,为了消除编译报错需要进行一些修改
1.device/soc/artery/at32f4xx/liteos_m/include/at32f435_437.h中typedef int32_t INT32;
、typedef uint32_t UINT32;
注释掉
//typedef int32_t INT32;
typedef int16_t INT16;
typedef int8_t INT8;
//typedef uint32_t UINT32;
2.device/soc/artery/at32f4xx/liteos_m/include/at32f435_437.h中,FALSE修改为AT_FALSE,TRUE修改为AT_TRUE,避开宏的重定义
typedef enum {AT_FALSE = 0, AT_TRUE = !AT_FALSE} confirm_state;
3.device/soc/artery/at32f4xx/libraries/drivers/inc/at32f435_437_def.h中注释掉
//#define UNUSED(x) (void)x /* to avoid gcc/g++ warnings */
4.device/soc/artery/at32f4xx/libraries/drivers/src/at32f435_437_crm.c中注释DUMMY_NOP();
这个函数
/**
* @brief select system clock source
* @param value
* this parameter can be one of the following values:
* - CRM_SCLK_HICK
* - CRM_SCLK_HEXT
* - CRM_SCLK_PLL
* @retval none
*/
void crm_sysclk_switch(crm_sclk_type value)
{
CRM->cfg_bit.sclksel = value;
//DUMMY_NOP();
}
5.device/soc/artery/at32f4xx/liteos_m/include/at32f435_437_board.h中 添加 #define AT_START_F437_V1
6.device/soc/artery/at32f4xx/liteos_m/include/at32f435_437.h中相关宏为修改AT32F437ZMT7,相关代码如下
/**
* tip: to avoid modifying this file each time you need to switch between these
* devices, you can define the device in your toolchain compiler preprocessor.
*/
#define AT32F437xx
/**
* define with package
*/
#define AT32F437Zx
/**
* define with memory density
*/
#define AT32F437xM
7.device/soc/artery/at32f4xx/liteos_m/include/at32f435_437_conf.h中添加
#if !defined TRUE
#define TRUE AT_TRUE
#endif
#if !defined FALSE
#define FALSE AT_FALSE
#endif
8.所有的at32437驱动文件都要包含头文件#include "los_compiler.h"
,为了解决UNUSED
没有定义的问题
5.内核子系统适配
在vendor\artery\AT-START-F437\config.json添加内核子系统及相关配置,如下所示:
"subsystems": [
{
"subsystem": "kernel",
"components": [
{
"component": "liteos_m"
}
]
}
],