微波EDA网,见证研发工程师的成长!
首页 > 研发问答 > 硬件电路设计 > 硬件电路设计讨论 > 抛个砖:在 stm32 上使用二进制字库的简单方法

抛个砖:在 stm32 上使用二进制字库的简单方法

时间:12-12 整理:3721RD 点击:
ps. 实际上不限于字库,对嵌入各种二进制资源文件都适用。
以前如果我们用到不带字库的点阵 LCD, 一般都是把字库按 16 进制写成一个大数组, 再和其他源程序一起编译. 有没有方便一点的办法呢?这里给出两个方案.
1. 使用 objcopy 把字库转成目标文件 (.o/.obj)
假设我们需要嵌入的是 5x7 的 ascii 点阵字库, 文件名是 asc5x7.bin.
在 arm-gcc 环境下, 命令如下:
arm-none-eabi-objcopy -B arm -I binary -O elf32-littlearm --rename-section .data=.rodata asc5x7.bin asc5x7.o
需要注意的是, objcopy 生成的.o 文件默认是把数据放在.data 段的. 因此这里需要加个 --rename-section 的选项, 把.data 改成.text 或者.rodata, 不然单片机可怜的一点点 RAM 根本不够用. 如果是在 PC 上运行, 这里改不改就无所谓了, 不过内存还是能省点就省点的好.
在.o 里会生成三个符号: _binary_asc5x7_bin_start, _binary_asc5x7_bin_end, binary_asc5x7_bin_size.
在程序里这么调用:
extern const int _binary_asc5x7_bin_start;
uint8_t *start = (uint8_t *) (&_binary_asc5x7_bin_start);
这样我们就得到了字库的起始地址. 在 AVR 上可能会稍复杂一些, 因为数据存储在 FLASH 里, 所以需要象 PROGMEM 数组一样, 用 pgm_read_byte 之类函数来读取.
链接时会有一堆错误提示: "Conflicting CPU architectures ....", 这是因为.o 里还缺少一个叫.ARM.attributes 的段. 不过实际上也没啥影响, 程序是可以正确运行的.
2. 直接利用 GNU 汇编的.incbin 功能
这是 minux@bdwm 提供的方法, 解决得明显更漂亮一些.
首先建立一个 asc5x7.s 的源文件, 内容如下:
.section .rodata,"",%progbits
.global _binary_asc5x7_bin_start, _binary_asc5x7_bin_end, _binary_asc5x7_bin_size
_binary_asc5x7_bin_start:
.incbin "asc5x7.bin"
_binary_asc5x7_bin_end:
_binary_asc5x7_bin_size = _binary_asc5x7_bin_end - _binary_asc5x7_bin_start
其实_binary_asc5x7_bin_size 和_binary_asc5x7_bin_end 这两个符号不要也可以, 因为字库的存储格式我们事先已经知道了.
然后建立一个空的.c 文件: touch empty.c, arm-none-eabi-gcc -S empty.c, 这样我们得到了一个 empty.s, 内容如下:
.cpu arm7tdmi-s
.fpu softvfp
.eabi_attribute 20, 1
.eabi_attribute 21, 1
.eabi_attribute 23, 3
.eabi_attribute 24, 1
.eabi_attribute 25, 1
.eabi_attribute 26, 1
.eabi_attribute 30, 6
.eabi_attribute 18, 4
.file     "empty.c"
.ident     "GCC: (Sourcery G++ Lite 2011.03-42) 4.5.2"
把这些东西复制到之前那个 asc5x7.s 里, 部分内容可能要按需调整一下, 比如.cpu 这里应该改成 cortex-m0 或者 cortex-m3 之类. 这样在链接时就不会出现前面那个 "Conflicting CPU architectures ...." 的报错信息了.
如果要使用几个字库呢? 可以把它们全都放在一个段里, 但是如果只用到了某一个或几个字库, 也会把它们全都链接进去, 导致最终的可执行文件体积过大. 因此最好是拆成几个段. 假设我们用到了 asc5x7.bin, asc12.bin, asc16.bin 和 asc24.bin, 写出来应该是这样:
.section .rodata.asc5x7,"",%progbits
.global _binary_asc5x7_bin_start
_binary_asc5x7_bin_start:
.incbin "asc5x7.bin"
.section .rodata.asc12,"",%progbits
.global _binary_asc12_bin_start
_binary_asc12_bin_start:
.incbin "asc12.bin"
.section .rodata.asc16,"",%progbits
.global _binary_asc16_bin_start
_binary_asc16_bin_start:
.incbin "asc16.bin"
.section .rodata.asc24,"",%progbits
.global _binary_asc24_bin_start
_binary_asc24_bin_start:
.incbin "asc24.bin"
然后 Makefile 里需要增加几个参数, 假如之前没有的话.
CFLAGS += -ffunction-sections --data-sections,
LDFLAGS += -Wl,--gc-sections
这样就只会把实际用到的段链接到最终可执行文件了.
如果要在可执行文件里嵌入图片, 音频之类, 也可以用同样的方法.
以上程序均在 Windows 7 & Sourcery G++ & STM32F103/F030 环境下测试通过. 在 Keil/IAR 等环境下请自行类推.

可能一辈子也不会这么干,不过看看有好处,呵呵
我要是老板,估计不让员工这么干,嘿嘿

有啥别的好办法也介绍介绍呗

用程序把二进制文件转成一个.c文件内容如下
const int hex_len=1234;
const char *hex=
"\xab\xcb......."
"\x12\x23.......";
然后包含到要使用的地方去,这样编译出来的程序这个数据段是位于.data还是.text?
另外Sourcery G++是个什么软件,好用么

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top