历史上的今天

今天是:2024年10月13日(星期日)

正在发生

2018年10月13日 | Tiny210裸机简单命令的实现

发布者:tony520 来源: eefocus关键字:Tiny210  简单命令 手机看文章 扫描二维码
随时随地手机看文章

start.S源码:

.global _start

_start:

    ldr sp, =0xD0030000    @初始化堆栈

    

    b main

==================================================================

main.c源码:

#include "command.h"

#include "clock.h"

#include "led.h"

#include "uart.h"

#include "lib.h"

#define  CFG_PROMPT  "WY_BOOT # " // Monitor Command Prompt    

#define  CFG_CBSIZE  256                      // Console I/O Buffer Size    

char *argv[10];

int readline (const char *const prompt)

{

    char console_buffer[CFG_CBSIZE];     // console I/O buffer    

    char *buf = console_buffer;

    int argc = 0;

    int state = 0;

    puts(prompt);

    gets(console_buffer);

    

    while (*buf)

    {

        if (*buf != ' ' && state == 0)

        {

            argv[argc++] = buf;

            state = 1;

        }

        

        if (*buf == ' ' && state == 1)

        {

            *buf = '\0';

            state = 0;

        }

        buf++;    

    }

    return argc;

}

void message(void)

{

    wy_printf("This bootloader support some command to test peripheral:\n");

    wy_printf("Such as: LCD, IIS, BUZZER \n");

    wy_printf("Try 'help' to learn them \n");    

}

int main(void)

{

    int argc = 0;

    int i = 0;

    led_init();     // 设置对应管脚为输出 

    clock_init(); // 初始化时钟 

    uart_init();   // 初始化UART

    wy_printf("\n************************************************\n");

    wy_printf("               wy_bootloader\n");

    wy_printf("               vars: %d \n",2012);

    wy_printf("************************************************\n");

    while (1)

    {

        argc = readline (CFG_PROMPT);

        if(argc == 0 && i ==0)

        {

            message();

            i=1;

        }

        run_command(argc, argv);

    }

    return 0;

}

==================================================================

clock.S源码:

#define APLL_CON      (*(volatile unsigned int *)0xe0100100) 

#define CLK_SRC0      (*(volatile unsigned int *)0xe0100200) 

#define CLK_DIV0      (*(volatile unsigned int *)0xe0100300) 

#define MPLL_CON      (*(volatile unsigned int *)0xe0100108)  

void clock_init(void)

{

    // 设置时钟为:

    // ARMCLK=1000MHz, HCLKM=200MHz, HCLKD=166.75MHz

    // HCLKP =133.44MHz, PCLKM=100MHz, PCLKD=83.375MHz, 

    // PCLKP =66.7MHz

     

    // SDIV[2:0]  : S = 1

    // PDIV[13:8] : P = 0x3

    // MDIV[25:16]: M = 0x7d

    // LOCKED [29]: 1 = 使能锁

    // ENABLE [31]: 1 = 使能APLL控制器

    // 得出FoutAPLL = 500MHz

    APLL_CON = (1<<31)|(1<<29)|(0x7d<<16)|(0x3<<8)|(1<<0);

    

    // 时钟源的设置

    // APLL_SEL[0] :1 = FOUTAPLL

    // MPLL_SEL[4] :1 = FOUTMPLL

    // EPLL_SEL[8] :1 = FOUTEPLL

    // VPLL_SEL[12]:1 = FOUTVPLL

    // MUX_MSYS_SEL[16]:0 = SCLKAPLL

    // MUX_DSYS_SEL[20]:0 = SCLKMPLL

    // MUX_PSYS_SEL[24]:0 = SCLKMPLL

    // ONENAND_SEL [28]:1 = HCLK_DSYS

    CLK_SRC0 = (1<<28)|(1<<12)|(1<<8)|(1<<4)|(1<<0);

    

    // 设置分频系数

    // APLL_RATIO[2:0]: APLL_RATIO = 0x0

    // A2M_RATIO [6:4]: A2M_RATIO  = 0x4

    // HCLK_MSYS_RATIO[10:8]: HCLK_MSYS_RATIO = 0x4

    // PCLK_MSYS_RATIO[14:12]:PCLK_MSYS_RATIO = 0x1

    // HCLK_DSYS_RATIO[19:16]:HCLK_DSYS_RATIO = 0x3

    // PCLK_DSYS_RATIO[22:20]:PCLK_DSYS_RATIO = 0x1

    // HCLK_PSYS_RATIO[27:24]:HCLK_PSYS_RATIO = 0x4

    // PCLK_PSYS_RATIO[30:28]:PCLK_PSYS_RATIO = 0x1

    CLK_DIV0 = (0x1<<28)|(0x4<<24)|(0x1<<20)|(0x3<<16)|(0x1<<12)|(0x4<<8)|(0x4<<4);

     

    // SDIV[2:0]  : S = 1

    // PDIV[13:8] : P = 0xc

    // MDIV[25:16]: M = 0x29b

    // VSEL   [27]: 0

    // LOCKED [29]: 1 = 使能锁

    // ENABLE [31]: 1 = 使能MPLL控制器

    // 得出FoutAPLL = 667MHz

    APLL_CON = (1<<31)|(1<<29)|(0x29d<<16)|(0xc<<8)|(1<<0);

}

==================================================================

uart.c源码:

#define GPA0CON      (*(volatile unsigned int *)0xE0200000) 

#define ULCON0      (*(volatile unsigned int *)0xE2900000) 

#define UCON0          (*(volatile unsigned int *)0xE2900004) 

#define UTRSTAT0      (*(volatile unsigned int *)0xE2900010)

#define UTXH0          (*(volatile unsigned char *)0xE2900020) 

#define URXH0          (*(volatile unsigned char *)0xE2900024) 

#define UBRDIV0     (*(volatile unsigned int *)0xE2900028) 

#define UDIVSLOT0      (*(volatile unsigned int *)0xE290002C)

void uart_init(void)

{

    // 设置对应GPIO用于UART0 

    GPA0CON |= 0x22;

            

    // 设置UART0寄存器 

    // bit[1:0]:0x3 = 8位数据位

    // 其他位默认,即1位停止位,无校验,正常模式

    ULCON0 |= (0x3<<0);

    

    // Receive Mode [1:0]:1 = 接收采用查询或者中断模式

    // Transmit Mode[3:2]:1 = 发送采用查询或者中断模式

    // bit[6]:1 = 产生错误中断

    // bit[10]:0 = 时钟源为PCLK

    UCON0 = (1<<6)|(1<<2)|(1<<0);

    

    // 设置波特率(详细信息请参考手册或者学习日记)

    // DIV_VAL = UBRDIVn + (num of 1's in UDIVSLOTn)/16

    // DIV_VAL = (PCLK / (bps x 16)) - 1

    UBRDIV0 = 0x23;

    UDIVSLOT0 = 0x808;

    return;

}

char uart_getchar(void)

{

    char c;

    

    // 查询状态寄存器,直到有有效数据 

    while (!(UTRSTAT0 & (1<<0)));

    

    c = URXH0; // 读取接收寄存器的值 

        

    return c;

}

void uart_putchar(char c)

{

    // 查询状态寄存器,直到发送缓存为空 

    while (!(UTRSTAT0 & (1<<2)));

    

    UTXH0 = c; // 写入发送寄存器 

    

    return;

}

==================================================================

lib.c源码:

#include "uart.h"

#define UTRSTAT0      (*(volatile unsigned int *)0xE2900010)

#define UTXH0          (*(volatile unsigned char *)0xE2900020) 

#define URXH0          (*(volatile unsigned char *)0xE2900024) 

void delay(void)

{

    volatile int i = 0x100000;

    while (i--);

}

void putchar_hex(char c)

{

    char * hex = "0123456789ABCDEF";

    

    uart_putchar(hex[(c>>4) & 0x0F]);

    uart_putchar(hex[(c>>0) & 0x0F]);

    return;

}

int putchar(int c)

{

    if(c == '\r')

    {

        while(!(UTRSTAT0&(1<<1)));

        UTXH0 = '\n';

    }

    

    if(c == '\n')

    {

        while(!(UTRSTAT0&(1<<1)));

        UTXH0 = '\r';

    }

    while(!(UTRSTAT0&(1<<1)));

    UTXH0 = c;

}

int getchar(void)

{

    int c;

    

    c = (int)uart_getchar();

    

    if (c == '\r')

        return '\n';

    

    return c;

}

int puts(const char * s)

{

    while (*s)

        putchar(*s++);

        

    return 0;

}

char * gets(char * s)

{

    char * p = s;

    while ((*p = getchar()) != '\n')

    {

        if (*p != '\b')

        {

            putchar(*p++);

        }

        else

        {

            if (p > s)

            {

                puts ("\b \b");

                p--;

            }    

         }      

    }

    *p = '\0';

    putchar('\n');

        

    return s;

}

void putint_hex(int a)

{

    putchar_hex( (a>>24) & 0xFF );

    putchar_hex( (a>>16) & 0xFF );

    putchar_hex( (a>>8) & 0xFF );

    putchar_hex( (a>>0) & 0xFF );

}

char *itoa(int a, char * buf)

{

    int num = a;

    int i = 0;

    int len = 0;

    

    do 

    {

        buf[i++] = num % 10 + '0';

        num /= 10;        

    }while (num);

    buf[i] = '\0';

    

    len = i;

    for (i = 0; i < len/2; i++)

    {

        char tmp;

        tmp = buf[i];

        buf[i] = buf[len-i-1];

        buf[len-i-1] = tmp;

    }

    return buf;    

}

int strcmp(const char * s1, const char * s2)

{

    while (*s1 == *s2)

    {

        if (*s1 == '\0')

            return 0;    

        s1++;

        s2++;                

    }

    return *s1 - *s2;

}

int atoi(char * buf)

{

    int value = 0;    

    int base = 10;

    int i = 0;

    

    if (buf[0] == '0' && buf[1] == 'x')

    {

        base = 16;

        i = 2;

    }

    // 123 = (1 * 10 + 2) * 10 + 3

    // 0x1F = 1 * 16 + F(15)    

    while (buf[i])

    {

        int tmp;

        

        if (buf[i] <= '9' && buf[i] >= '0') 

            tmp = buf[i] - '0';

        else

            tmp = buf[i] - 'a' + 10;

                    

        value = value * base + tmp;

        

        i++;

    }

    return value;

}

typedef int * va_list;

#define va_start(ap, A)   (ap = (int *)&(A) + 1)

#define va_arg(ap, T)     (*(T *)ap++)

#define va_end(ap)        ((void)0)

int wy_printf(const char * format, ...)

{

    char c;   

     

    va_list ap;

    va_start(ap, format);

    

    while ((c = *format++) != '\0')

    {

        switch (c)

        {

            case '%':

                c = *format++;

                

                switch (c)

                {

                    char ch;

                    char * p;

                    int a;

                    char buf[100];

                                    

                    case 'c':

                        ch = va_arg(ap, int);

                        putchar(ch);

                        break;

                    case 's':

                        p = va_arg(ap, char *);

                        puts(p);

                        break;                    

                    case 'x':

                        a = va_arg(ap, int);

                        putint_hex(a);

                        break;        

                    case 'd':

                        a = va_arg(ap, int);

                        itoa(a, buf);

                        puts(buf);

                        break;    

                    

                    default:

                        break;

                }                

                break;        

        

            default:

                putchar(c);

                break;

        }

    }

    return 0;    

}

==================================================================

command.c源码:

#include "lib.h"

int help(int argc, char * argv[])

{

    wy_printf("do_command 《$s》 \n", argv[0]);  //"《"实际为“<”,"$"实际为"%",避免格式冲突

    wy_printf("help message: \n");

    wy_printf("md - memory dispaly\n");

    wy_printf("mw - memory write\n");

    return 0;

}

int md(int argc, char * argv[])

{    

    unsigned long *p = (unsigned long *)0;

    int i, j;

    wy_printf("do_command 《$s》 \n", argv[0]); //"《"实际为“<”,"$"实际为"%",避免格式冲突

    if (argc <= 1) {

        wy_printf ("Usage:\n%s\n", "md address");

        return 1;

    }

    

    if (argc >= 2)

        p = (unsigned long *)atoi(argv[1]);

        

    for (j = 0; j < 16; j++)

    {    

        wy_printf("%x: ", p);

        for (i = 0; i < 4; i++)

            wy_printf("%x ", *p++);    

        wy_printf("\n");

    }

        

    return 0;

}

int mw(int argc, char * argv[])

{    

    unsigned long *p = (unsigned long *)0;

    int v = 0;

    wy_printf("do_command 《$s》 \n", argv[0]); //"《"实际为“<”,"$"实际为"%",避免格式冲突

    if (argc <= 2) {

        wy_printf ("Usage:\n%s\n", "md address data");

        return 1;

    }

    

    if (argc >= 2)

        p = (unsigned long *)atoi(argv[1]);

        

    if (argc >= 3)

        v = atoi(argv[2]);

        

    *p = v;

    

    return 0;

}

void run_command(int argc, char * argv[])

{

    if (strcmp(argv[0], "help") == 0)

    {

        help(argc, argv);

        return;

    }

    

    if (strcmp(argv[0], "md") == 0)

    {

        md(argc, argv);

        return;

    }

    

    if (strcmp(argv[0], "mw") == 0)

    {

        mw(argc, argv);

        return;

    }

    if(argc >= 1)

        wy_printf("Unknown command '%s' - try 'help' \n",argv[0]);

    return;

}

==================================================================

Makefile文件:

uart.bin:start.s main.c uart.c clock.c led.c lib.c command.c

    arm-linux-gcc -nostdlib -c start.s -o start.o

    arm-linux-gcc -nostdlib -c main.c -o main.o

    arm-linux-gcc -nostdlib -c uart.c -o uart.o

    arm-linux-gcc -nostdlib -c lib.c -o lib.o

    arm-linux-gcc -nostdlib -c clock.c -o clock.o    

    arm-linux-gcc -nostdlib -c led.c -o led.o    

    arm-linux-gcc -nostdlib -c command.c -o command.o    

    arm-linux-ld -Ttext 0xD0020010 start.o main.o uart.o lib.o clock.o led.o command.o -o uart_elf

    arm-linux-objcopy -O binary -S uart_elf uart.bin

clean:

    rm -rf *.o *.bin uart_elf *.dis

==================================================================

源码解析:

分析过u-boot的朋友们,应该对readline()函数不陌生吧,我这里将实现一个简化的readline()函数,实现在终端显示输入提示符,并从终端获取命令,实现过程如下:

int readline (const char *const prompt)

{

    char console_buffer[CFG_CBSIZE];    // 定义一个缓存数组,用于接收终端输入的字符串 

    char *buf = console_buffer;               // 定义个指针,指向上面的数组 

    int argc = 0;                                        // 用于指明命令参数的个数 

    int state = 0;                                       // 状态标志 

    puts(prompt);                                    // 显示输入提示符:WY_BOOT #  

    gets(console_buffer);                        // 从终端获取字符串,并存入缓存数组 

    

    while (*buf)//该while实现对终端输入的命令的解析,将命令,参数拆分,分别存入argv[n]

    {

        if (*buf != ' ' && state == 0)

        {

            argv[argc++] = buf;

            state = 1;

        }

        

        if (*buf == ' ' && state == 1)

        {

            *buf = '\0';

            state = 0;

        }

        

        buf++;    

    }

    

    return argc;                         // 返回参数的个数 

}

//一下是大家更加熟悉的u-boot中的run_command函数的简化版本,实现过程如下,只是将argv[0]指向的数组和另外一个数组进行比较,如果相等,则执行该if分支里面的函数。strcmp()函数的实现也非常简单,我已经在共享的代码中给出,请大家自行分析之。

void run_command(int argc, char * argv[])

{

    if (strcmp(argv[0], "help") == 0)

    {

        do_help(argc, argv);

        return;

    }

    

    if (strcmp(argv[0], "md") == 0)

    {

        do_md(argc, argv);

        return;

    }

    

    if (strcmp(argv[0], "mw") == 0)

    {

        do_mw(argc, argv);

        return;

    }

    if(argc >= 1)

        wy_printf("Unknown command '%s' - try 'help' \n",argv[0]);

    return;

}

注意:

本章实现的命令几乎算是和硬件无关的了,以后每当写完一个具体外设的裸板程序的时候,会添加相应命令的支持,比如nand read,nand write等等函数。添加的过程其实就是在run_command()函数里面多添加一个strcmp()函数的调用,然后用if判断其返回值,若相等,则调用具体的命令执行函数do_XXX


关键字:Tiny210  简单命令 引用地址:Tiny210裸机简单命令的实现

上一篇:Tiny210裸机之nand_flash操作
下一篇:Tiny210裸机之实现printf功能

推荐阅读

配置内核支持UVC驱动,然后make uImage编译内核,烧写内核到nand flash,再启动开发板,把USB摄像头插到JZ2440开发板上以后,弹出以下错误,使用ls /dev/video*命令查看不到设备节点,参照以下方法解决问题:usb 1-1: new full speed USB device usings3c2410-ohci and address 2usb 1-1: device descriptor read/64, error -62usb 1-...
(文章来源:中国智能化网) 在国外很多的国家工业机器人的使用比国内要普及的多,最早的机器人取代了不受人们欢迎的工作。机器人接管了危险的手动工作和繁琐的工作,如在制造和施工中操作重型机械或在实验室中处理危险化学品。很多的机器人在很大程度上可以做到独立运作,在未来机器人将会与人类合作。 工业机器人的保障措施是确保机器人和工作人员...
环境:开发环境:MDK5.23rt-thread版本:2.1.0lwip版本:1.4.1单片机型号:stm32f407phy芯片型号:说明:本程序是udp客户端模块。绑定固定端口进行收发。udp接收是一个线程,接收到数据利用邮箱机制推送到其他处理模块。udp发送提供了多种发送接口。源码:udp_socket.h/*** Copyright (c), 2015-2025* @file udp_socket.h* @brief udp端口头文件* @...
网络分析仪一种能在宽频带内进行扫描测量以确定网络参量的综合性微波测量仪器。可以进行 S 参数测量、Polar 极坐标图、Smith 史密斯图等的测量,网络分析仪是测量网络参数的一种新型仪器,可直接测量有源或无源、可逆或不可逆的双口和单口网络的复数散射参数,并以扫频方式给出各散射参数的幅度、相位频率特性。网络分析仪应用领域:测量应用领域:放...

史海拾趣

问答坊 | AI 解惑

USB设备,你到底占用多少电流?

现在市场上,各种usb设备可谓应接不暇,但是,主板究竟为usb口输出多少电流? 有测试设备的大侠就帮个忙,测试一下吧。 原由,我们是否该为usb设备加电流? 市面上99%的usb hub,只能扩展一下键盘、鼠标之类的小东西, 要是插个大容量u盘之类的 ...…

查看全部问答∨

凌阳模组资料

本帖最后由 paulhyde 于 2014-9-15 09:10 编辑 凌阳更多模组资料  …

查看全部问答∨

有用过BISS0001红外热释电处理芯片的吗?现金交易,找人做开发

有用过BISS0001红外热释电处理芯片的吗?现金交易,找人做开发。 可先看看这个http://www.xie-gang.com/ot0001.htm QQ:184949533 Email:genens@126.com…

查看全部问答∨

哪位好心人能帮帮我 我的电脑每次关机后都不能启动

我的电脑每次关机后都不能启动显示的是(因以下文件的损坏或者丢失windows无法启动windows\\system32\\c_936.nis)每次装了系统后只要1关机就会出现这种情况,请问一下怎么解决啊,是不是硬盘有了物理坏道了…

查看全部问答∨

这个坛子里有玩ARM9的吗,~~看看这个平台怎么样?

硬件特性 (主版) -------------------------------------------------------------------------------- 硬 件 部 件  功 能 描 述  备 注 主板类型 5.25”单板结构    主处理器 Atmel AT91RM9200(PQFP) A ...…

查看全部问答∨

请教TMS320LF2407 与TMS320LF2407A的区别

请教TMS320LF2407 与TMS320LF2407A的区别? 有哪些…

查看全部问答∨

STM32的USB问题---回执问题

在使用STM32时,PC端与STM32有自定一个规范(或者称作协议?) 在规范(协议)中,可能需要一个命令告知对方是否需要回执 想请问下: 1、若要求回执,回执一个“错误”是根据什么来决定的呢? 2、若USB数据传送错误,又该如何判断?并重发相关 ...…

查看全部问答∨

edk作为ise子模块时,和其他ise中的模块连接的时候,有什么需要注意的吗

我做了一个edk,当把这个edk放进ise中,没有其他逻辑的时候,一切正常。可是,我加上其他逻辑的时候就开始报错。 想问,edk作为ise子模块时,和其他ise中的模块连接的时候,有什么需要注意的吗? 因为报错时,总提示edk里面的某些管脚IBUF如何如 ...…

查看全部问答∨

请高手用FPGA做个数据采集卡,高报酬

我要做一块数据采集卡,卡上有两个通道,分别是一个模拟输入通道和一个模拟输出通道。和计算机通讯 采用USB的方式。具体的要求如下 1.一个模拟输入通道,精度16位,最高采样率1M/s(可设置),采集范围可设,量程(-10到+10V,-5到+5V,-2.5到+ ...…

查看全部问答∨

矩阵键盘扫描的疑问

键扫描函数:这一句俺没看懂:   while((scancode&0x10)!=0)   这句怎么理解啊?为什么这句是逐行扫描的开始?                 &n ...…

查看全部问答∨
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved