start.S源码:
.globl _start
_start:
// 0 地址
b reset // 复位时,cpu跳到0地址
ldr pc, =undefined_instruction // cpu遇到不能识别的指令时
ldr pc, _vector_swi // 当执行swi指令时, 进入swi模 式
b halt @ldr pc, _prefetch_abort // 预取中止异常
b halt @ldr pc, _data_abort // 数据访问异常
b halt @ldr pc, _not_used // 没用到
ldr pc, _irq // 0x18 中断异常
b halt @ldr pc, _fiq // 快中断异常
_irq :
.word vector_irq
_vector_swi:
.word vector_swi
vector_swi:
// 1. 保存现场
ldr sp, =0x56000000
stmdb sp!, {r0-r12, lr} // lr就是swi的下一条指令地址
// 2. 处理异常
mrs r0, cpsr
ldr r1, =swi_str
bl print_cpsr
// 3. 恢复现场
ldmia sp!, {r0-r12, pc}^ // ^表示把spsr恢复到cpsr
swi_str:
.word 0x00697773 // swi
undefined_instruction:
// 1. 保存现场
ldr sp, =0x55000000
stmdb sp!, {r0-r12, lr}
// 2. 处理异常
mrs r0, cpsr
ldr r1, =und_str
bl print_cpsr
// 3. 恢复现场
ldmia sp!, {r0-r12, pc}^ // ^表示把spsr恢复到cpsr
und_str:
.word 0x00646e75 // und
usr_str:
.word 0x00727375 // usr
vector_irq:
// 1. 保存现场
ldr sp, =0x54000000
sub lr, lr, #4
stmdb sp!, {r0-r12, lr} // lr就是swi的下一条指令地址
// 2. 处理异常
bl do_irq
// 3. 恢复现场
ldmia sp!, {r0-r12, pc}^ // ^表示把spsr恢复到cpsr
reset:
// 硬件相关的设置
// Peri port setup
ldr r0, =0x70000000
orr r0, r0, #0x13
mcr p15,0,r0,c15,c2,4 @ 256M(0x70000000-0x7fffffff)
// 关看门狗
// 往WTCON(0x7E004000)写0
ldr r0, =0x7E004000
mov r1, #0
str r1, [r0]
// 设置栈
ldr sp, =8*1024
// 设置时钟
bl clock_init
bl ddr_init
bl init_uart
//把片内内存中程序的代码段、数据段复制到它的链接地址去
adr r0, _start // 获得_start指令当前所在的地址 : 0
ldr r1, =_start // _start的链接地址 0x51000000
ldr r2, =bss_start // bss段的起始链接地址
sub r2, r2, r1
cmp r0,r1
beq clean_bss
bl copy2ddr
cmp r0, #0
bne halt
// 清BSS
// 把BSS段对应的内存清零
clean_bss:
ldr r0, =bss_start
ldr r1, =bss_end
mov r3, #0
cmp r0, r1
ldreq pc, =on_ddr
clean_loop:
str r3, [r0], #4
cmp r0, r1
bne clean_loop
ldr pc, =on_ddr
on_ddr:
bl irq_init
mrs r0, cpsr
bic r0,r0,#0x9f // 清cpsr的I位,M4~M0
orr r0,r0,#0x10
msr cpsr,r0 // 进入user mode
ldr sp, =0x57000000
ldr r1, =usr_str
bl print_cpsr
swi 0
// cpu进入svc模式
// 把之前的cpsr保存到spsr_svc
// 切换到r13_svc, r14_svc
// 把swi的下一条指令存到r14(lr)_svc
// 跳到地址8
bl hello
undef:
.word 0xff000000
// cpu进入Undefined模式
// 把之前的cpsr保存到spsr_und
// 切换到r13_und, r14_und
// 把下一条指令存到r14(lr)_und
// 跳到地址4
swi_ret:
bl main
halt:
b halt
=====================================================================
irq.c源码:
#define GPNCON (*((volatile unsigned long *)0x7F008830))
#define GPNDAT (*((volatile unsigned long *)0x7F008834))
#define EINT0CON0 (*((volatile unsigned long *)0x7F008900))
#define EINT0MASK (*((volatile unsigned long *)0x7F008920))
#define EINT0PEND (*((volatile unsigned long *)0x7F008924))
#define PRIORITY (*((volatile unsigned long *)0x7F008280))
#define SERVICE (*((volatile unsigned long *)0x7F008284))
#define SERVICEPEND (*((volatile unsigned long *)0x7F008288))
#define VIC0IRQSTATUS (*((volatile unsigned long *)0x71200000))
#define VIC0FIQSTATUS (*((volatile unsigned long *)0x71200004))
#define VIC0RAWINTR (*((volatile unsigned long *)0x71200008))
#define VIC0INTSELECT (*((volatile unsigned long *)0x7120000c))
#define VIC0INTENABLE (*((volatile unsigned long *)0x71200010))
#define VIC0INTENCLEAR (*((volatile unsigned long *)0x71200014))
#define VIC0PROTECTION (*((volatile unsigned long *)0x71200020))
#define VIC0SWPRIORITYMASK (*((volatile unsigned long *)0x71200024))
#define VIC0PRIORITYDAISY (*((volatile unsigned long *)0x71200028))
#define VIC0VECTADDR0 (*((volatile unsigned long *)0x71200100))
#define VIC0VECTADDR1 (*((volatile unsigned long *)0x71200104))
#define VIC0ADDRESS (*((volatile unsigned long *)0x71200f00))
#define VIC1IRQSTATUS (*((volatile unsigned long *)0x71300000))
#define VIC1VECTADDR5 (*((volatile unsigned long *)0x71300114))
#define VIC1INTENABLE (*((volatile unsigned long *)0x71300010))
#define VIC1ADDRESS (*((volatile unsigned long *)0x71300f00))
void eint0_3_irq(void)
{
int i;
printf("eint0_3_irq\n\r"); // K1~K4
for (i = 0; i < 4; i ++)
{
if (EINT0PEND & (1<
{
if (GPNDAT & (1<
{
printf("K%d released\n\r", i+1);
}
else
{
printf("K%d pressed\n\r", i+1);
}
}
}
}
void eint4_11_irq(void)
{
int i;
printf("eint4_11_irq\n\r"); // K5~K6
for (i = 4; i < 6; i ++)
{
if (EINT0PEND & (1<
{
if (GPNDAT & (1<
{
printf("K%d released\n\r", i+1);
}
else
{
printf("K%d pressed\n\r", i+1);
}
}
}
}
void irq_init(void)
{
key_irq_init();
uart_irq_init();
}
void uart_irq(void)
{
// 调用具体的中断处理函数
do_uart_irq();
// 清中断
VIC1ADDRESS = 0;
}
void uart_irq_init(void)
{
VIC1INTENABLE |= (1<<5); // bit5: int_uart0
VIC1VECTADDR5 = uart_irq;
}
void key_irq_init(void)
{
// 配置GPIO引脚为中断引脚
// GPN0~5 设为中断引脚
GPNCON &= ~(0xfff);
GPNCON |= 0xaaa;
// 设置中断触发方式为: 双边沿触发
EINT0CON0 &= ~(0xfff);
EINT0CON0 |= 0x777;
// 使能中断
EINT0MASK &= ~(0x3f);
// 在中断控制器里使能这些中断
VIC0INTENABLE |= (0x3); // bit0: eint0~3, bit1: eint4~11
VIC0VECTADDR0 = eint0_3_irq;
VIC0VECTADDR1 = eint4_11_irq;
// 设置优先级
}
void do_irq(void)
{
int i = 0;
void (*the_isr)(void);
if (VIC0IRQSTATUS)
{
the_isr = VIC0ADDRESS;
// 2.1 分辨是哪个中断
// 2.2 调用它的处理函数
// 2.3 清中断
the_isr();
EINT0PEND = 0x3f; // 清中断
VIC0ADDRESS = 0;
}
else if (VIC1IRQSTATUS)
{
the_isr = VIC1ADDRESS;
// 2.1 分辨是哪个中断
// 2.2 调用它的处理函数
// 2.3 清中断
the_isr();
}
}
===================================================================
uart.c源码:
#define ULCON0 (*((volatile unsigned long *)0x7F005000))
#define UCON0 (*((volatile unsigned long *)0x7F005004))
#define UFCON0 (*((volatile unsigned long *)0x7F005008))
#define UMCON0 (*((volatile unsigned long *)0x7F00500C))
#define UTRSTAT0 (*((volatile unsigned long *)0x7F005010))
#define UFSTAT0 (*((volatile unsigned long *)0x7F005018))
#define UTXH0 (*((volatile unsigned char *)0x7F005020))
#define URXH0 (*((volatile unsigned char *)0x7F005024))
#define UBRDIV0 (*((volatile unsigned short *)0x7F005028))
#define UDIVSLOT0 (*((volatile unsigned short *)0x7F00502C))
#define UINTP0 (*((volatile unsigned long *)0x7F005030))
#define UINTM0 (*((volatile unsigned long *)0x7F005038))
#define GPACON (*((volatile unsigned long *)0x7F008000))
#define ENABLE_FIFO 1
static delay(void)
{
volatile int i = 10;
while (i--);
}
void uart_tx_int_enable(void)
{
UINTM0 &= ~(1<<2);
}
void uart_tx_int_disable(void)
{
UINTM0 |= (1<<2);
}
void init_uart(void)
{
GPACON &= ~0xff;
GPACON |= 0x22;
// ULCON0
ULCON0 = 0x3; // 数据位:8, 无较验, 停止位: 1, 8n1
UCON0 = 0x5 | (1<<9); // 使能UART发送、接收, tx interrupt request type = level
#ifdef ENABLE_FIFO
UFCON0 = 0x07 | (1<<6); // FIFO enable, tx fifo trigger level = 16 bytes
#else
UFCON0 = 0x00; // FIFO disable
#endif
UMCON0 = 0;
// 波特率
// DIV_VAL = (PCLK / (bps x 16 ) ) - 1
// bps = 57600
// DIV_VAL = (66500000 / (115200 x 16 ) ) - 1
// = 35.08
UBRDIV0 = 35;
// x/16 = 0.08
// x = 1
UDIVSLOT0 = 0x1;
}
unsigned char getc(void)
{
#ifdef ENABLE_FIFO
while ((UFSTAT0 & 0x7f) == 0)delay();
#else
while ((UTRSTAT0 & (1<<0)) == 0);
#endif
return URXH0;
}
int getc_nowait(unsigned char *pChar)
{
#ifdef ENABLE_FIFO
if ((UFSTAT0 & 0x7f) == 0)
#else
if ((UTRSTAT0 & (1<<0)) == 0)
#endif
{
return -1;
}
else
{
*pChar = URXH0;
return 0;
}
}
#define TX_BUF_LEN 2048
static unsigned char txbuf[2047];
static unsigned int r_idx = 0;
static unsigned int w_idx = 0;
static int isFull(void)
{
if ((w_idx + 1) % TX_BUF_LEN == r_idx)
return 1;
else
return 0;
}
static int isEmpty(void)
{
return (w_idx == r_idx);
}
static int putData(unsigned char data)
{
if (isFull())
return -1;
else
{
txbuf[w_idx] = data;
w_idx = (w_idx + 1) % TX_BUF_LEN;
return 0;
}
}
static int getData(unsigned char *pdata)
{
if (isEmpty())
{
return -1;
}
else
{
*pdata = txbuf[r_idx];
r_idx = (r_idx + 1) % TX_BUF_LEN;
return 0;
}
}
void putc(char c)
{
putData(c); // 把数据放到缓冲区里去
// 如果"uart 发送中断"未使能的话,使能"uart 发送中断"
uart_tx_int_enable();
}
void do_uart_irq(void)
{
int i;
int cnt;
unsigned char c;
if (UINTP0 & (1<<2))
{
// 对于发送中断
if (isEmpty())
{
// 禁止中断
uart_tx_int_disable();
}
else
{
// 从环型缓冲区里取出数据, 放到TX FIFO里去
cnt = (UFSTAT0 >> 8) & 0x3f;
cnt = 64 - cnt;
for (i = 0; i < cnt; i++)
{
if (getData(&c) == 0)
{
UTXH0 = c;
}
else
{
break;
}
}
}
}
else if (UINTP0 & (1<<0))
{
// 对于接收中断, 从RX FIFO里取出数据
}
// 清中断
UINTP0 = 0xf;
}
====================================================================
Makefile文件:
CC = arm-linux-gcc
LD = arm-linux-ld
AR = arm-linux-ar
OBJCOPY = arm-linux-objcopy
OBJDUMP = arm-linux-objdump
INCLUDEDIR := $(shell pwd)/include
CFLAGS := -Wall -Os -fno-builtin-printf -fno-builtin-putc //避免putc函数名冲突
CPPFLAGS := -nostdinc -I$(INCLUDEDIR)
export CC AR LD OBJCOPY OBJDUMP INCLUDEDIR CFLAGS CPPFLAGS
objs := start.o sdram.o nand.o clock.o uart.o irq.o main.o lib/libc.a
uart.bin: $(objs)
${LD} -Tuart.lds -o uart.elf $^
${OBJCOPY} -O binary -S uart.elf $@
${OBJDUMP} -D uart.elf > uart.dis
.PHONY : lib/libc.a
lib/libc.a:
cd lib; make; cd ..
%.o:%.c
${CC} $(CPPFLAGS) $(CFLAGS) -c -o $@ $<
%.o:%.S
${CC} $(CPPFLAGS) $(CFLAGS) -c -o $@ $<
clean:
make clean -C lib
rm -f uart.bin uart.elf uart.dis *.o
=====================================================================
uart.lds链接文件:
SECTIONS {
. = 0x50000000;
.text : {
start.o
clock.o
sdram.o
nand.o
* (.text)
}
. = ALIGN(4);
.rodata : {
* (.rodata)
}
. = ALIGN(4);
.data : {
* (.data)
}
. = ALIGN(4);
bss_start = .;
.bss : { *(.bss) *(COMMON) }
bss_end = .;
}
上一篇:OK6410裸机之LCD显
下一篇:OK6410裸机之中断向量控制器
推荐阅读最新更新时间:2024-03-16 16:15