历史上的今天
返回首页

历史上的今天

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

正在发生

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

2018-10-13 来源:eefocus

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();   // 初始化UART0 

    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


推荐阅读

史海拾趣

Dean Technology公司的发展小趣事

随着产品技术的不断成熟,Dean Technology公司开始注重品牌建设和市场推广。他们积极参加各类电子展会,展示公司的最新产品和技术,与行业内外的客户建立联系。同时,公司还通过广告宣传、合作伙伴关系等方式,提高品牌知名度和美誉度。这些努力使得Dean Technology的高压二极管产品逐渐在市场上获得了认可。

Advanced Power Solutions公司的发展小趣事

Advanced Power Solutions公司自创立之初,就致力于电源管理技术的研发。在一次偶然的实验中,公司的研发团队发现了一种新的电源转换技术,可以显著提高能源利用效率。公司迅速投入资源,完善这项技术,并成功将其应用于新产品中。这款高效能的产品迅速在市场上获得了认可,为公司带来了可观的收益,也奠定了公司在电源管理领域的领先地位。

General Transistor Corp公司的发展小趣事

随着技术的不断进步,GTC意识到仅仅作为分销商已无法满足市场需求。于是,公司开始逐步涉足电子元器件的生产领域,专注于研发和生产具有自主知识产权的产品。通过持续的技术创新和研发投入,GTC成功推出了一系列高性能的晶体管、集成电路等新产品,进一步丰富了其产品线。这些产品不仅在国内市场受到好评,还逐渐走向国际市场。

Devar Inc公司的发展小趣事

Devar Inc公司自创立之初,就致力于在增强现实(AR)领域取得突破。经过多年的研发,公司成功推出了世界上首个用于AR的生成式AI神经网络。这项技术允许用户通过简单的文本提示创建3D对象和其他AR资产,极大地简化了AR内容的创作过程。Devar的AR平台结合了神经网络和云解决方案,让用户能够轻松创建并分享AR内容,开启了AR创作的新时代。

Goldentech Discrete Semiconductor Inc公司的发展小趣事

在快速发展的同时,Goldentech始终关注环境保护和社会责任。公司积极推行绿色制造理念,采用环保材料和节能技术,减少生产过程中的碳排放和资源消耗。此外,Goldentech还投入大量资金研发可回收和可降解的半导体产品,旨在为全球电子行业的可持续发展贡献力量。这一环保理念不仅提升了公司的社会形象,还吸引了更多注重可持续发展的客户和合作伙伴。

常州能动(ENDRIVE)公司的发展小趣事

随着环保意识的日益增强,常州能动积极响应国家政策,加大环保投入。公司引进了先进的环保设备和技术,对生产过程中的废弃物进行无害化处理。同时,公司还注重节能减排和资源循环利用,推动公司向绿色、低碳、可持续发展的方向迈进。这些努力不仅提升了公司的社会形象,也为公司的长远发展打下了坚实基础。

问答坊 | AI 解惑

工程师的发展之路

中长期规划---螺旋式上升方式修改完善职业之路 一、中长期职业发展的自我准备 1、心态上随时做好准备 机会是给有准备的人的------“有准备”是你在做准备的过程中让“别人”认为你“有准备”!别人是包括 ...…

查看全部问答>

wince应用程序ICO图标问题

在vs中的工程设置的图标 程序原来在wm上运行,图标显示是正常的 到了wince上就显示不正常了 好像是分辨率的问题 请问这个怎么解决呢…

查看全部问答>

学usb驱程有用吗

老师上课说大四做毕业设计有做usb驱程的,我有些兴趣就买了相关方面的书看,可是刚看前言作者就说学usb驱程很复杂也没有什么用,想问一下学这个对开发嵌入式有用吗…

查看全部问答>

关于计算机的二进制计算问题

最近在看汇编,但是很是困惑: 1.我们一般在高级语言里碰到的int\\float,与我们在讲解二进制加法时用的8位有什么关系? 2.若汇编老师在讲解完计算机内的数字存储后,发问7+251=?那到底怎么做呢?   251=11111011已经八位了啊!!? ...…

查看全部问答>

wince writefile 总是发送不了数据,但不报错!

问题如下:        我现在接手别人的工作,驱动别人是用evc4.2写dll,驱动经测试可用。        我现在用C#开发应用程序。        现在的问题是,驱动writefile第二个参数他传的是 ...…

查看全部问答>

WINCE驱动和WINDOWS驱动的关系???

想学WINCE的驱动,但书籍好少,于是我想先看WINDOWS的驱动,从这里入门,下面这三种那种更接近WINCE的驱动编程呢?区别又在那呢? 1)WIN9X虚拟设备驱动VxD 2)WIN NT驱动 3)WIN 2000 WDM驱动 …

查看全部问答>

初学ATmega128,有个数据存储的问题想请教各位大虾

在C51中,char xdata doc[19]=\"AT+CMGF=0\"; 我想请教一下各位大虾,在ATmega128中,这个语句应该怎样写呢? …

查看全部问答>

89s52的的几个基础问题

1、89S52的波特率发生器是T2还是T1,还是两个都可以? 2、多机通信的时候SCON是设置成方式1还是方式3?(我要通过SM2来控制发送的是地址还是数据) 3、S52用KEIL在线仿真是接在COM口还是打印机口?…

查看全部问答>

菜鸟,请你们珍爱生命,远离protues

       今天,用protues搭了一个电路,写了一个相应的程序,调试运行了一下,竟然无效, 于是乎,我就把原本庞大的电路删减一部分剩下基本的显示数码管,可是竟然还是不 对,那么,我首先怀疑是不是我的程序有问题 ...…

查看全部问答>

STM32哪个开发板好?

                    STM神舟3  和 神舟4 哪个板子适合学习?如果有其他的,那推荐一个,非常感谢!…

查看全部问答>