tiny4412 基础(七)移植command
tiny4412
先看效果图

这个图是在裸机下跑的,移植了u-boot的command, 新的u-boot改成cli(命令行接口)
使用起来非常方便:
static int do_version (struct cmd_tbl_s *cmd_tbl_t, int argc, int type, char * const argv[])
{
puts("version : V1.0 \r\n");
return 0;
}
REGISTER_CMD(
ver,
1,
ARG_TYPE_NONE,
do_version,
"print monitor version"
);
在任意文件里面都可以添加命令。
REGISTER_CMD宏即
#define REGISTER_CMD(name,maxargs,type,handler,usage) \
const cmd_tbl_t cmd_##name __attribute__ ((section (".cli_cmd"))) = {#name, maxargs, type, handler, usage}
也即REGISTER_CMD宏定义的命令最终都会链接到“.cli_cmd”段里面,在链接脚本里面:
SECTIONS
{
. = 0x02023400;
.text : {
src/head.o
* (.text)
}
.data : {
* (.data)
}
__cli_cmd_start = .;
.cli_cmd : {
*(.cli_cmd)
}
__cli_cmd_end = .;
bss_start = .;
.bss : {
* (.bss)
}
bss_end = .;
}
可以看到.cli_cmd字段。
上面简单描述了效果即简单解析。
目录结构
.
├── basic.lds
├── common
├── HAL
│ ├── uart.c
│ └── uart.h
├── include
│ ├── system_clock.h
│ └── tiny4412.h
├── Makefile
├── src
│ ├── command.c
│ ├── command.h
│ ├── head.S
│ ├── main.c
│ └── system_clock.c
└── tools
├── bl2.bin
├── E4412_N.bl1.bin
├── E4412_tzsw.bin
├── Makefile
├── mkbl2
├── sd_fuse.sh
└── V310-EVT1-mkbl2.c
其中basic.lds就是链接脚本,内容在上面以及贴出来了。
Makefile
CC = /home/flinn/tools/4.5.1/bin/arm-none-linux-gnueabi-gcc
LD = /home/flinn/tools/4.5.1/bin/arm-none-linux-gnueabi-ld
AR = /home/flinn/tools/4.5.1/bin/arm-none-linux-gnueabi-ar
OBJCOPY = /home/flinn/tools/4.5.1/bin/arm-none-linux-gnueabi-objcopy
OBJDUMP = /home/flinn/tools/4.5.1/bin/arm-none-linux-gnueabi-objdump
CFLAGS := -Wall -O2 -nostdlib -fno-builtin \
-I./include \
-I./HAL \
-I./common \
-I./src \
-lgcc -L/home/flinn/tools/4.5.1/arm-none-linux-gnueabi/lib
OBJS := src/head.o src/main.o src/system_clock.o HAL/uart.o src/command.o
VER = 1.0
TARGET = tiny4412_$(VER).bin
$(TARGET): $(OBJS)
${LD} -Tbasic.lds -o $(TARGET)_elf $^
${OBJCOPY} -O binary -S $(TARGET)_elf $@
${OBJDUMP} -D -m arm $(TARGET)_elf > $(TARGET).dis
%.o:%.c
${CC} $(CFLAGS) -c -o $@ $<
%.o:%.S
${CC} $(CFLAGS) -c -o $@ $<
clean:
rm -f $(TARGET) $(TARGET)_elf $(TARGET).dis *.o *.bin $(OBJS)
main
main很简单:
include "tiny4412.h"
#include "system_clock.h"
#include "uart.h"
#include "command.h"
int main(void)
{
int i = 0;
system_clock_init();
uart_init();
command_init();
puts("\r\nstart...\r\n");
while (1)
{
command_loop();
}
return 0;
}
其中需要初始化串口。
command_init()和command_loop()两个实现都在src/command.c里面
以上代码没有实现itoa,strlen, printf , vsprintf等标准库函数,并运行在tiny4412裸机上,对于其他平台,比如fpga,stm32, msp430, 51等平台,一般IDE支持标准库函数,移植起来更方便。熟悉u-boot移植的人来说,cli接口是必不可少的调试神器。
所有代码由以下方式获取:
git clone git@github.com:fanglinn/tiny4412.git
最后还是补充一下:
如果你想使用以上框架,需要做如下几点:
1.在Makefile里面修改你的编译器gcc路径
2.实现uart底层读写函数,必须实现putc, puts, getc, tstc四个函数,分别表示发送字符,发送字符串, 获
取一个字符, 监测是否有数据来
3.插入SD卡,使用sudo fdisk -l来识别,比如/dev/sdc
4.进入tools目录,执行sudo ./sd_fuse /dev/sdc 即可
最后还是贴上代码,以便自己后面使用:
src/command.c
#include "command.h"
#include "uart.h"
char console_buffer[CONFIG_SYS_CBSIZE + 1]; /* console I/O buffer */
static const char erase_seq[] = "\b \b"; /* erase sequence */
static const char tab_seq[] = " "; /* used to expand TABs */
static cmd_tbl_t * CLI_cmd_start;
static cmd_tbl_t * CLI_cmd_end ;
static int do_version (struct cmd_tbl_s *cmd_tbl_t, int argc, int type, char * const argv[])
{
puts("version : V1.0 \r\n");
return 0;
}
REGISTER_CMD(
ver,
1,
ARG_TYPE_NONE,
do_version,
"print monitor version"
);
int do_help(struct cmd_tbl_s *cmd, int argc, int type, char * const argv[])
{
cmd_tbl_t *cmdtp;
int len = CLI_cmd_end - CLI_cmd_start;
for (cmdtp = CLI_cmd_start; cmdtp != CLI_cmd_start + len; cmdtp++)
{
puts(cmdtp->name);
puts("\t");
puts(cmdtp->usage);
puts("\r\n");
}
return 0;
}
REGISTER_CMD(
help,
1,
ARG_TYPE_NONE,
do_help,
"print help information"
);
char * strcpy(char * dest,const char *src)
{
char *tmp = dest;
while ((*dest++ = *src++) != '\0')
/* nothing */;
return tmp;
}
unsigned int strlen(const char * s)
{
const char *sc;
for (sc = s; *sc != '\0'; ++sc)
/* nothing */;
return sc - s;
}
int strcmp(const char * cs,const char * ct)
{
register signed char __res;
while (1) {
if ((__res = *cs - *ct++) != 0 || !*cs++)
break;
}
return __res;
}
static char * delete_char (char *buffer, char *p, int *colp, int *np, int plen)
{
char *s;
if (*np == 0) {
return (p);
}
if (*(--p) == '\t') { /* will retype the whole line */
while (*colp > plen) {
puts (erase_seq);
(*colp)--;
}
for (s=buffer; s<p; ++s) {
if (*s == '\t') {
puts (tab_seq+((*colp) & 07));
*colp += 8 - ((*colp) & 07);
} else {
++(*colp);
putc (*s);
}
}
} else {
puts (erase_seq);
(*colp)--;
}
(*np)--;
return (p);
}
int readline_into_buffer(const char *const prompt, char *buffer, int timeout)
{
char *p = buffer;
char * p_buf = p;
int n = 0; /* buffer index */
int plen = 0; /* prompt length */
int col; /* output column cnt */
char c;
/* print prompt */
if (prompt) {
plen = strlen (prompt);
puts (prompt);
}
col = plen;
for (;;)
{
c = getc();
/*
* Special character handling
*/
switch (c){
case '\r': /* Enter */
case '\n':
*p = '\0';
puts ("\r\n");
return p - p_buf;
case '\0': /* nul */
continue;
case 0x03: /* ^C - break */
p_buf[0] = '\0'; /* discard input */
return -1;
case 0x15: /* ^U - erase line */
while (col > plen) {
puts (erase_seq);
--col;
}
p = p_buf;
n = 0;
continue;
case 0x17: /* ^W - erase word */
p=delete_char(p_buf, p, &col, &n, plen);
while ((n > 0) && (*p != ' ')) {
p=delete_char(p_buf, p, &col, &n, plen);
}
continue;
case 0x08: /* ^H - backspace */
case 0x7F: /* DEL - backspace */
p=delete_char(p_buf, p, &col, &n, plen);
continue;
default:
/*
* Must be a normal character then
*/
if (n < CONFIG_SYS_CBSIZE-2) {
if (c == '\t') { /* expand TABs */
puts (tab_seq+(col&07));
col += 8 - (col&07);
} else {
char buf[2];
/*
* Echo input using puts() to force an
* LCD flush if we are using an LCD
*/
++col;
buf[0] = c;
buf[1] = '\0';
puts(buf);
}
*p++ = c;
++n;
} else { /* Buffer full */
putc ('\a');
}
}
}
}
int readline (const char *const prompt)
{
/*
* If console_buffer isn't 0-length the user will be prompted to modify
* it instead of entering it from scratch as desired.
*/
console_buffer[0] = '\0';
return readline_into_buffer(prompt, console_buffer, 0);
}
int parse_line (char *line, char *argv[])
{
int nargs = 0;
while (nargs < CONFIG_SYS_MAXARGS) {
/* skip any white space */
while (isblank(*line))
++line;
if (*line == '\0') {