前两篇文章已经实现ZBar在Windows平台下的编译和使用,本文将介绍如何把ZBar移植到STM32F429,IDE使用MDK。
1. MDK工程设置
(1)不勾选Use MicroLIB ,使用ISO C。
如MDK 帮助文档关于MicroLIB的介绍,故在硬件资源允许的情况还是优先使用ISO C。
(2)勾选C99 Mode,因为ZBar源码是基于C99的
(3)不勾选Use Memory Layout From Target Dialog,使用自定义Scatter File
2.工程目录结构
3. ZBar源码修改地方
由于MDK使用的编译器不是GCC,故不能支持一些特殊GCC语法和相应的C库函数。
(1) error.c和error.h文件中strdup函数报错。
处理方法:屏蔽该函数相关代码或者自己实现strdup函数
(2) 屏蔽img_scanner.c文件中的
.....
//#include <unistd.h>
//#include <time.h> /* clock_gettime */
//#include <sys/time.h> /* gettimeofday */
....
// struct timeval abstime;
// gettimeofday(&abstime, NULL);
// iscn->time = (abstime.tv_sec * 1000) + ((abstime.tv_usec / 500) + 1) / 2;
.....
(3) GCC默认void*为char*,MDK的编译器对void指针的加减操作当作错误处理
处理方法:把void指针强制转换为char指针
4. 系统存储空间分配
对于STM32来说ZBar对Heap消耗较大,跟解析的二维码图片大小有关,将系统未使用的内存 全部分配给Heap。
Scatter file 如下
LR_IROM1 0x08000000 0x00100000 { ; load region size_region
ER_IROM1 0x08000000 0x00100000 { ; load address = execution address
*.o (RESET, +First)
*(InRoot$$Sections)
.ANY (+RO)
}
RW_IRAM_DATA 0x20000000 0x00030000 { ; RW data
.ANY (+RW +ZI)
}
ARM_LIB_STACK 0x20030000 EMPTY -(0x20030000 - ImageLimit(RW_IRAM_DATA)) ; Stack region growing down
{ }
RW_ERAM 0xD0000000 0x00800000 { ;Extern SDRAM
main.o(+RW +ZI)
}
ARM_LIB_HEAP +0 EMPTY (0xD0800000 - ImageLimit(RW_ERAM)) ; Heap region growing up
{ }
}
5. 修改默认的启动文件startup_stm32f429_439xx.s
(1) Stack和Heap已经在Scatter文件中指定,故屏蔽startup_stm32f429_439xx.s中Stack和Heap的相关代码。
;Stack_Size EQU 0x00000400
;AREA STACK, NOINIT, READWRITE, ALIGN=3
;Stack_Mem SPACE Stack_Size
;__initial_sp
;; <h> Heap Configuration
;; <o> Heap Size (in Bytes) <0x0-0xFFFFFFFF:8>
;; </h>
;Heap_Size EQU 0x00000200
;AREA HEAP, NOINIT, READWRITE, ALIGN=3
;__heap_base
;Heap_Mem SPACE Heap_Size
;__heap_limit
......
;IF :DEF:__MICROLIB
;EXPORT __initial_sp
;EXPORT __heap_base
;EXPORT __heap_limit
;ELSE
;IMPORT __use_two_region_memory
;EXPORT __user_initial_stackheap
;__user_initial_stackheap
;LDR R0, = Heap_Mem
;LDR R1, =(Stack_Mem + Stack_Size)
;LDR R2, = (Heap_Mem + Heap_Size)
;LDR R3, = Stack_Mem
;BX LR
;ALIGN
;ENDIF
(2) 把Scatter文件指定的Stack基地址赋给向量表的首地址
.....
IMPORT |Image$$ARM_LIB_STACK$$Base|
__Vectors DCD |Image$$ARM_LIB_STACK$$Base|;__initial_sp ; Top of Stack
.....
(3) 因为Heap分配在外部SDRAM中,故在进入__main前需初始化SDRAM
....
IMPORT SystemInit
IMPORT SDRAM_Init
IMPORT __main
LDR R0, =SystemInit
BLX R0
LDR R0, =SDRAM_Init
BLX R0
LDR R0, =__main
BX R0
ENDP
....
6.测试代码
之前Windows平台下的测试例程是直接读取PNG格式的二维码,在STM32F429平台下没有移植文件系统和PNG解码库,为了简单起见,直接把待
测试的二维码图片转换为二值化数组,然后把该该数组传给ZBar。
#include "type_define.h"
#include "usart.h"
#include "sdram.h"
#include "zbar.h"
#include "image.h"
//280X280的二维码图片灰度值数组
const uint8_t image_data_buf[] = {
.......
};
int Zbar_Test(void* raw, int width, int height)
{
zbar_image_scanner_t *scanner = NULL;
/* create a reader */
scanner = zbar_image_scanner_create();
/* configure the reader */
zbar_image_scanner_set_config(scanner, 0, ZBAR_CFG_ENABLE, 1);
/* obtain image data */
//int width = 0, height = 0;
//void *raw = NULL;
//get_data("barcode.png", &width, &height, &raw);
/* wrap image data */
zbar_image_t *image = zbar_image_create();
zbar_image_set_format(image, *(int*)"Y800");
zbar_image_set_size(image, width, height);
zbar_image_set_data(image, raw, width * height, zbar_image_free_data);
/* scan the image for barcodes */
int n = zbar_scan_image(scanner, image);
printf("n = %d\r\n", n);
/* extract results */
const zbar_symbol_t *symbol = zbar_image_first_symbol(image);
for(; symbol; symbol = zbar_symbol_next(symbol)) {
/* do something useful with results */
zbar_symbol_type_t typ = zbar_symbol_get_type(symbol);
const char *data = zbar_symbol_get_data(symbol);
printf("decoded %s symbol \"%s\"\r\n",
zbar_get_symbol_name(typ), data);
printf("len = %d\r\n",strlen(data));
for(int k=0; k<strlen(data); k++)
{
printf("%X ", (uint8_t)data[k]);
}
}
/* clean up */
zbar_image_destroy(image);
zbar_image_scanner_destroy(scanner);
return(0);
}
int main(void)
{
Usart_Init();
printf("Hello CJS\r\n ");
Zbar_Test((void* )image_data_buf,280,280);
while(1)
{
}
return 0;
}
7.运行结果
编译下载到STM32F429后,运行结果如下
到此,ZBar已经能正常在STM32F429上运行了,但有点小问题,如上图,会检测到decoded I2/5 symbol "",原因未知。
工程传送门:http://www.openedv.com/forum.php?mod=viewthread&tid=266510&page=1#pid828789