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
上一篇:Tiny210裸机之nand_flash操作
下一篇:Tiny210裸机之实现printf功能
推荐阅读
史海拾趣
近年来,电子行业面临着巨大的变革,新技术、新产品层出不穷。为了应对这一挑战,APD公司积极调整战略,加大在新能源、物联网等领域的投入。同时,公司还注重人才培养和引进,通过搭建良好的人才梯队,为公司的创新发展提供了有力保障。
在追求经济效益的同时,A/D Electronics Inc也积极履行社会责任,致力于可持续发展。公司注重环保和节能,采用环保材料和节能技术,减少生产过程中的环境污染和资源消耗。此外,公司还积极参与公益事业,为社会做出贡献。通过这些举措,A/D Electronics Inc不仅赢得了社会的广泛认可,也为企业的长远发展奠定了坚实基础。
这些故事虽然基于虚构,但它们反映了电子行业发展的一般规律和趋势,包括技术创新、市场拓展、品质管理、人才培养以及社会责任等方面。这些元素对于任何一家在电子行业中发展起来的公司来说,都是不可或缺的。
在大中华区市场,FCI展现出了强劲的增长势头。公司积极布局中国市场,特别是在3G产业领域,FCI投入大量人力资源研发相关产品,为通信设备厂商提供优异的连接器解决方案。随着中国3G牌照的发放,FCI的业绩得到了强劲增长。几乎所有的12.5GHz局端通信设备制造商都采用了FCI的连接器解决方案,这使得FCI在大中华区的市场份额不断攀升。
在快速发展的过程中,Cal-Chip Electronics公司始终关注社会责任和可持续发展。公司积极参与公益事业,支持教育、环保等领域的发展。同时,公司还注重环保生产,通过引进先进的环保技术和设备,减少生产过程中的污染排放。此外,公司还建立了完善的员工培训体系,为员工提供广阔的职业发展空间。这些举措不仅提升了公司的社会形象,也为公司的可持续发展奠定了坚实基础。
以上是关于Cal-Chip Electronics公司在电子行业发展的5个相关故事,这些故事展示了公司在不同历史阶段所取得的成就和面临的挑战。通过不断努力和创新,Cal-Chip Electronics公司已经成为了电子行业的一颗璀璨明星。
光大芯业微电子有限公司的创立,源于一群对电子行业充满热情的先驱者。他们看到了中国电子产业在起步阶段所面临的挑战和机遇,决定投身其中,为中国电子产业的崛起贡献自己的力量。公司的成立,不仅标志着中国电子产业的一个新起点,也展示了光大芯业对于未来技术发展的坚定信念和追求。
Eureka公司自1995年成立以来,一直致力于电子技术的研发和创新。在早期阶段,公司凭借一款具有创新性的液晶显示驱动IC产品,成功打入市场。随着技术的不断进步,Eureka逐步拓展了产品线,推出了包括类比-数位混合信号处理器、系统应用完整方案等一系列产品。这些产品的推出,不仅丰富了Eureka的产品线,也提升了公司在行业内的竞争力。
现在市场上,各种usb设备可谓应接不暇,但是,主板究竟为usb口输出多少电流? 有测试设备的大侠就帮个忙,测试一下吧。 原由,我们是否该为usb设备加电流? 市面上99%的usb hub,只能扩展一下键盘、鼠标之类的小东西, 要是插个大容量u盘之类的 ...… 查看全部问答∨ |
|
有用过BISS0001红外热释电处理芯片的吗?现金交易,找人做开发 有用过BISS0001红外热释电处理芯片的吗?现金交易,找人做开发。 可先看看这个http://www.xie-gang.com/ot0001.htm QQ:184949533 Email:genens@126.com… 查看全部问答∨ |
我的电脑每次关机后都不能启动显示的是(因以下文件的损坏或者丢失windows无法启动windows\\system32\\c_936.nis)每次装了系统后只要1关机就会出现这种情况,请问一下怎么解决啊,是不是硬盘有了物理坏道了… 查看全部问答∨ |
硬件特性 (主版) -------------------------------------------------------------------------------- 硬 件 部 件 功 能 描 述 备 注 主板类型 5.25”单板结构 主处理器 Atmel AT91RM9200(PQFP) A ...… 查看全部问答∨ |
|
在使用STM32时,PC端与STM32有自定一个规范(或者称作协议?) 在规范(协议)中,可能需要一个命令告知对方是否需要回执 想请问下: 1、若要求回执,回执一个“错误”是根据什么来决定的呢? 2、若USB数据传送错误,又该如何判断?并重发相关 ...… 查看全部问答∨ |
edk作为ise子模块时,和其他ise中的模块连接的时候,有什么需要注意的吗 我做了一个edk,当把这个edk放进ise中,没有其他逻辑的时候,一切正常。可是,我加上其他逻辑的时候就开始报错。 想问,edk作为ise子模块时,和其他ise中的模块连接的时候,有什么需要注意的吗? 因为报错时,总提示edk里面的某些管脚IBUF如何如 ...… 查看全部问答∨ |
我要做一块数据采集卡,卡上有两个通道,分别是一个模拟输入通道和一个模拟输出通道。和计算机通讯 采用USB的方式。具体的要求如下 1.一个模拟输入通道,精度16位,最高采样率1M/s(可设置),采集范围可设,量程(-10到+10V,-5到+5V,-2.5到+ ...… 查看全部问答∨ |