chạy unity trên chip nhúng

Trong khi đọc cuốn Test Driven Development for Embedded C tôi được giới thiệu làm quen với unity. Unity là test framework gọn nhẹ, viết hoàn toàn bằng C; điều này có nghĩa là  nó có thể dịch chạy trên PC và cho cả trên MCU nhúng.

Ngoài việc viết test unit chạy trên PC, tôi cũng muốn các test unit này chạy trực tiếp trên MCU. Tại sao? Tôi nghĩ code sẽ chạy trên MCU, tại sao không test trực tiếp trên đối tượng hoạt động, đặt biệt khi trình một trình biên dịch phổ biến cho hệ thống nhúng cũng có nhiều lỗi.

Để khởi đầu cho hành trình này, tôi sử dụng CC3200 MCU với arm-none-eabi-gcc 4.8.2. Để tiết kiệm thời gian chạy các test tôi load chương trình trực tiếp xuống RAM thông qua JTAG để chạy thay vì flash. Nguyên nhân: quá trình test càng chậm thì tôi càng ít muốn chạy test, điều này không tốt cho quá trình phát triển TDD, khi lời khuyên là chạy test cho mỗi lần commit.

Unity có một vài file, nên liên kết đến nó sẽ khá đơn giản:

UNITY_ROOT=$(PROJECTROOT)/tools/unity

UNITY_DIR = \
$(UNITY_ROOT)/src \
$(UNITY_ROOT)/extras/fixture/src

VPATH += $(UNITY_DIR)
IPATH += $(UNITY_DIR)

Bài test đầu tiên của tôi là kiểm tra flash driver của CC3200. Và khi dịch thì báo lỗi như bên dưới.

/usr/lib/gcc/arm-none-eabi/4.8.2/../../../arm-none-eabi/lib/armv7e-m/libc.a(lib_a-writer.o): In function `_write_r':
/build/buildd/newlib-2.1.0/build/arm-none-eabi/armv7e-m/newlib/libc/reent/../../../../../../newlib/libc/reent/writer.c:58: undefined reference to `_write'
/usr/lib/gcc/arm-none-eabi/4.8.2/../../../arm-none-eabi/lib/armv7e-m/libc.a(lib_a-closer.o): In function `_close_r':
/build/buildd/newlib-2.1.0/build/arm-none-eabi/armv7e-m/newlib/libc/reent/../../../../../../newlib/libc/reent/closer.c:53: undefined reference to `_close'
/usr/lib/gcc/arm-none-eabi/4.8.2/../../../arm-none-eabi/lib/armv7e-m/libc.a(lib_a-fstatr.o): In function `_fstat_r':
/build/buildd/newlib-2.1.0/build/arm-none-eabi/armv7e-m/newlib/libc/reent/../../../../../../newlib/libc/reent/fstatr.c:62: undefined reference to `_fstat'
/usr/lib/gcc/arm-none-eabi/4.8.2/../../../arm-none-eabi/lib/armv7e-m/libc.a(lib_a-isattyr.o): In function `_isatty_r':
/build/buildd/newlib-2.1.0/build/arm-none-eabi/armv7e-m/newlib/libc/reent/../../../../../../newlib/libc/reent/isattyr.c:58: undefined reference to `_isatty'
/usr/lib/gcc/arm-none-eabi/4.8.2/../../../arm-none-eabi/lib/armv7e-m/libc.a(lib_a-lseekr.o): In function `_lseek_r':
/build/buildd/newlib-2.1.0/build/arm-none-eabi/armv7e-m/newlib/libc/reent/../../../../../../newlib/libc/reent/lseekr.c:58: undefined reference to `_lseek'
/usr/lib/gcc/arm-none-eabi/4.8.2/../../../arm-none-eabi/lib/armv7e-m/libc.a(lib_a-readr.o): In function `_read_r':
/build/buildd/newlib-2.1.0/build/arm-none-eabi/armv7e-m/newlib/libc/reent/../../../../../../newlib/libc/reent/readr.c:58: undefined reference to `_read'

 

Nguyên nhân do Unity sử dụng UNITY_OUTPUT_CHAR để in kết quả. Theo mặt định, UNITY_OUTPUT_CHAR liên kết đến putchar() để kết quả hiển thị lên terminal nhờ libc.a khi dịch trên PC. Trong trường hợp CC3200 (và hầu hết các hệ thống nhúng khác), OS nhúng không cung cấp sẵn implement cho hàm này, dẫn đến lỗi khi dịch. Tôi cần chỉ dẫn unity sử dụng hàm khác để in ra cổng UART.

Nhìn vào unity_internals.h, tôi thấy cách để liên kết con trỏ UNITY_OUTPUT_CHAR này mà không thay đổi thư viện unity bẳng lệnh tiền xử lý

#ifdef UNITY_INCLUDE_CONFIG_H
#include "unity_config.h"
#endif

...

#ifndef UNITY_OUTPUT_CHAR
//Default to using putchar, which is defined in stdio.h
#include <stdio.h>
#define UNITY_OUTPUT_CHAR(a) putchar(a)
#else
//If defined as something else, make sure we declare it here so it's ready for use
extern int UNITY_OUTPUT_CHAR(int);
#endif

Vậy thêm cờ ở  Makefile

CFLAGS+=-DUNITY_INCLUDE_CONFIG_H

, đồng thời thêm file unity_config.h

#define UNITY_OUTPUT_CHAR(x) PRINT(x)

PRINT(x) được thực thi ở đâu đó trong chương trình, nhằm đẩy byte x ra cổng UART.

 

Đây là kết quả khiêm tốn cho một số test:

Unity test run 1 of 1
......

-----------------------
6 Tests 0 Failures 0 Ignored

 

Kết luận: Unity là một công cụ nhỏ rất tiện lợi để test chương trình, có thể chạy trên PC hoặc trên MCU nhờ vào việc nó sư dụng C thuần túy và sự gọn nhẹ của thư viện này.

Gửi phản hồi

Mời bạn điền thông tin vào ô dưới đây hoặc kích vào một biểu tượng để đăng nhập:

WordPress.com Logo

Bạn đang bình luận bằng tài khoản WordPress.com Log Out / Thay đổi )

Twitter picture

Bạn đang bình luận bằng tài khoản Twitter Log Out / Thay đổi )

Facebook photo

Bạn đang bình luận bằng tài khoản Facebook Log Out / Thay đổi )

Google+ photo

Bạn đang bình luận bằng tài khoản Google+ Log Out / Thay đổi )

Connecting to %s