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
=====================================================================
lcd.c源碼:
#define GPECON (*((volatile unsigned long *)0x7F008080))
#define GPEDAT (*((volatile unsigned long *)0x7F008084))
#define GPFCON (*((volatile unsigned long *)0x7F0080A0))
#define GPFDAT (*((volatile unsigned long *)0x7F0080A4))
#define GPICON (*((volatile unsigned long *)0x7F008100))
#define GPJCON (*((volatile unsigned long *)0x7F008120))
// display controller
#define MIFPCON (*((volatile unsigned long *)0x7410800C))
#define SPCON (*((volatile unsigned long *)0x7F0081A0))
#define VIDCON0 (*((volatile unsigned long *)0x77100000))
#define VIDCON1 (*((volatile unsigned long *)0x77100004))
#define VIDTCON0 (*((volatile unsigned long *)0x77100010))
#define VIDTCON1 (*((volatile unsigned long *)0x77100014))
#define VIDTCON2 (*((volatile unsigned long *)0x77100018))
#define WINCON0 (*((volatile unsigned long *)0x77100020))
#define VIDOSD0A (*((volatile unsigned long *)0x77100040))
#define VIDOSD0B (*((volatile unsigned long *)0x77100044))
#define VIDOSD0C (*((volatile unsigned long *)0x77100048))
#define VIDW00ADD0B0 (*((volatile unsigned long *)0x771000A0))
#define VIDW00ADD1B0 (*((volatile unsigned long *)0x771000D0))
#define VIDW00ADD2 (*((volatile unsigned long *)0x77100100))
#define VSPW 9
#define VBPD 1
#define LINEVAL 271
#define VFPD 1
#define HSPW 40
#define HBPD 1
#define HOZVAL 479
#define HFPD 1
#define LeftTopX 0
#define LeftTopY 0
#define RightBotX 479
#define RightBotY 271
#define FRAME_BUFFER 0x54000000
unsigned int fb_base_addr;
unsigned int bpp;
unsigned int xsize;
unsigned int ysize;
void lcd_init(void)
{
// 1. 設置相關GPIO引腳用于LCD
GPICON = 0xaaaaaaaa; // gpi0~gpi15用作lcd_vd[0~15]
GPJCON = 0xaaaaaaa; // gpj0~gpi11用作lcd
GPFCON &= ~(0x3<<28);
GPFCON |= (1<<28); // GPF14用作背光使能信號
GPECON &= ~(0xf);
GPECON |= (0x1); // GPE0用作LCD的on/off信號
// 2. 初始化6410的display controller
// 2.1 hsync,vsync,vclk,vden的極性和時間參數
// 2.2 行數、列數(分辨率),象素顏色的格式
// 2.3 分配顯存(frame buffer),寫入display controller
MIFPCON &= ~(1<<3); // Normal mode
SPCON &= ~(0x3);
SPCON |= 0x1; // RGB I/F style
#if 0
VIDCON0 &= ~((3<<26) | (3<<17) | (0xff<<6)); // RGB I/F, RGB Parallel format,
// vclk== 27MHz Ext Clock input / (CLKVAL+1) = 27/3 = 9MHz
VIDCON0 |= ((2<<6) | (1<<4) | (0x3<<2));
#else
VIDCON0 &= ~((3<<26) | (3<<17) | (0xff<<6) | (3<<2)); // RGB I/F, RGB Parallel format,
VIDCON0 |= ((14<<6) | (1<<4) ); // vclk== HCLK / (CLKVAL+1) = 133/15 = 9MHz
#endif
VIDCON1 &= ~(1<<7); // 在vclk的下降沿獲取數據
VIDCON1 |= ((1<<6) | (1<<5)); // HSYNC高電平有效, VSYNC高電平有效,
VIDTCON0 = (VBPD << 16) | (VFPD << 8) | (VSPW << 0);
VIDTCON1 = (HBPD << 16) | (HFPD << 8) | (HSPW << 0);
VIDTCON2 = (LINEVAL << 11) | (HOZVAL << 0);
WINCON0 &= ~(0xf << 2);
WINCON0 |= (0xb<<2); // unpacked 24 BPP (non-palletized R:8-G:8-B:8 )
VIDOSD0A = (LeftTopX<<11) | (LeftTopY << 0);
VIDOSD0B = (RightBotX<<11) | (RightBotY << 0);
//bpp=24,但是我們用4個字節即32位表示一個像素,(LINEVAL+1) * (HOZVAL+1) * 4,
//因為單位是word,故為(LINEVAL+1) * (HOZVAL+1)
VIDOSD0C = (LINEVAL + 1) * (HOZVAL + 1);
VIDW00ADD0B0 = FRAME_BUFFER; //顯存基地址/首地址
VIDW00ADD1B0 = (((HOZVAL + 1)*4 + 0) * (LINEVAL + 1)) & (0xffffff); //顯存結束地址的低24位
// VBASEL = VBASEU + (LINEWIDTH+OFFSIZE) x (LINEVAL+1)
// = 0 + (480*4 + 0) * 272
// =
//VIDW00ADD2 = HOZVAL + 1;
fb_base_addr = FRAME_BUFFER;
xsize = HOZVAL + 1;
ysize = LINEVAL + 1;
bpp = 24;
}
void backlight_enable(void)
{
GPFDAT |= (1<<14);
}
void backlight_disable(void)
{
GPFDAT &= ~(1<<14);
}
void lcd_on(void)
{
GPEDAT |= (1<<0);
// 等待10 frame
}
void lcd_off(void)
{
GPEDAT &= ~(1<<0);
}
void displaycon_on(void)
{
VIDCON0 |= 0x3;
WINCON0 |= 1; //6410的lcd控制器有多個窗口,這里只使能了一個窗口
}
void displaycon_off(void)
{
VIDCON0 &= ~0x3;
WINCON0 &= ~1; //6410的lcd控制器有多個窗口,這里只使能了一個窗口
}
void lcd_enable(void)
{
// 打開背光
// 使能LCD本身
// 使能display controller
}
void lcd_disable(void)
{
// 關閉背光
// 關閉LCD本身
// 關閉display controller
}
void draw_line(void)
{
DrawLine(0,0, 0,271, 0xff0000);
DrawLine(0,0, 479,0, 0x00ff00);
DrawLine(0,0, 479,271, 0x0000ff);
DrawLine(0,271, 479,0, 0x00ffff);
DrawLine(0,271, 479,271, 0xff00ff);
DrawLine(479,271, 479,0, 0xffff00);
DrawLine(0,136, 479,136, 0x0123ff);
DrawLine(240,0, 240,271, 0x0567ff);
}
void display_red(void)
{
volatile unsigned long *p = (volatile unsigned long *)FRAME_BUFFER;
int x, y;
int cnt = 0;
unsigned long colors[] = {0xff0000, 0x00ff00, 0x0000ff, 0, 0xffffff};
static int color_idx = 0;
for (y = 0; y <= LINEVAL; y++)
{
for (x = 0; x <= HOZVAL; x++)
{
p[cnt++] =colors[color_idx] ; // red
}
}
color_idx++;
if (color_idx == 5)
color_idx = 0;
}
void lcd_test(void)
{
unsigned char c;
static int lcdon = 0;
static int blon = 0;
static int dispon = 0;
lcd_init();
while (1)
{
printf("********LCD TEST MENU********\n\r");
printf("[L] enable/disable LCD\n\r");
printf("[B] enable/disable back light\n\r");
printf("[C] enable/disable s3c6410 display controller\n\r");
printf("[D] display color\n\r");
printf("[I] draw line\n\r");
printf("[Q] quit\n\r");
do {
c = getc();
if (c == '\n' || c == '\r')
{
printf("\n\r");
}
else
{
putc(c);
}
} while (c == '\n' || c == '\r');
switch (c) {
case 'l':
case 'L':
{
if (lcdon)
{
lcd_off();
printf("LCD off\n\r");
}
else
{
lcd_on();
printf("LCD on\n\r");
}
lcdon = !lcdon;
break;
}
case 'b':
case 'B':
{
if (blon)
{
backlight_disable();
printf("Backlight off\n\r");
}
else
{
backlight_enable();
printf("Backlight on\n\r");
}
blon = !blon;
break;
}
case 'c':
case 'C':
{
if (dispon)
{
displaycon_off();
printf("Display controller off\n\r");
}
else
{
displaycon_on();
printf("Display controller on\n\r");
}
blon = !blon;
break;
}
case 'd':
case 'D':
{
display_red();
break;
}
case 'i':
case 'I':
{
draw_line();
break;
}
case 'q':
case 'Q':
{
return ;
break;
}
}
}
}
=====================================================================
framebuffer.c源碼:
// FILE: framebuffer.c
// 實現在framebuffer上畫點、畫線、畫同心圓、清屏的函數
#include "types.h"
#include "framebuffer.h"
extern unsigned int fb_base_addr;
extern unsigned int bpp;
extern unsigned int xsize;
extern unsigned int ysize;
//typedef UINT32 FB_24BPP[272][480];
// 畫點
// 輸入參數:
// x、y : 象素坐標
// color: 顏色值
// 對于16BPP: color的格式為0xAARRGGBB (AA = 透明度),
// 需要轉換為5:6:5格式
// 對于8BPP: color為調色板中的索引值,
// 其顏色取決于調色板中的數值
void PutPixel(UINT32 x, UINT32 y, UINT32 color)
{
UINT8 red,green,blue;
switch (bpp){
case 24:
{
//bpp=24位,但是為了對齊會浪費一個字節,一共4字節32位
UINT32 *addr = (UINT32 *)fb_base_addr + (y * xsize + x);
*addr = color;
break;
}
case 16:
{
UINT16 *addr = (UINT16 *)fb_base_addr + (y * xsize + x);
red = (color >> 19) & 0x1f;
green = (color >> 10) & 0x3f;
blue = (color >> 3) & 0x1f;
color = (red << 11) | (green << 5) | blue; // 格式5:6:5
*addr = (UINT16) color;
break;
}
case 8:
{
UINT8 *addr = (UINT8 *)fb_base_addr + (y * xsize + x);
*addr = (UINT8) color;
break;
}
default:
break;
}
}
// 畫線
// 輸入參數:
// x1、y1 : 起點坐標
// x2、y2 : 終點坐標
// color : 顏色值
// 對于16BPP: color的格式為0xAARRGGBB (AA = 透明度),
// 需要轉換為5:6:5格式
// 對于8BPP: color為調色板中的索引值,
// 其顏色取決于調色板中的數值
void DrawLine(int x1,int y1,int x2,int y2,int color)
{
int dx,dy,e;
dx=x2-x1;
dy=y2-y1;
if(dx>=0)
{
if(dy >= 0) // dy>=0
{
if(dx>=dy) // 1/8 octant
{
e=dy-dx/2;
while(x1<=x2)
{
PutPixel(x1,y1,color);
if(e>0){y1+=1;e-=dx;}
x1+=1;
e+=dy;
}
}
else // 2/8 octant
{
e=dx-dy/2;
while(y1<=y2)
{
PutPixel(x1,y1,color);
if(e>0){x1+=1;e-=dy;}
y1+=1;
e+=dx;
}
}
}
else // dy<0
{
dy=-dy; // dy=abs(dy)
if(dx>=dy) // 8/8 octant
{
e=dy-dx/2;
while(x1<=x2)
{
PutPixel(x1,y1,color);
if(e>0){y1-=1;e-=dx;}
x1+=1;
e+=dy;
}
}
else // 7/8 octant
{
e=dx-dy/2;
while(y1>=y2)
{
PutPixel(x1,y1,color);
if(e>0){x1+=1;e-=dy;}
y1-=1;
e+=dx;
}
}
}
}
else //dx<0
{
dx=-dx; //dx=abs(dx)
if(dy >= 0) // dy>=0
{
if(dx>=dy) // 4/8 octant
{
e=dy-dx/2;
while(x1>=x2)
{
PutPixel(x1,y1,color);
if(e>0){y1+=1;e-=dx;}
x1-=1;
e+=dy;
}
}
else // 3/8 octant
{
e=dx-dy/2;
while(y1<=y2)
{
PutPixel(x1,y1,color);
if(e>0){x1-=1;e-=dy;}
y1+=1;
e+=dx;
}
}
}
else // dy<0
{
dy=-dy; // dy=abs(dy)
if(dx>=dy) // 5/8 octant
{
e=dy-dx/2;
while(x1>=x2)
{
PutPixel(x1,y1,color);
if(e>0){y1-=1;e-=dx;}
x1-=1;
e+=dy;
}
}
else // 6/8 octant
{
e=dx-dy/2;
while(y1>=y2)
{
PutPixel(x1,y1,color);
if(e>0){x1-=1;e-=dy;}
y1-=1;
e+=dx;
}
}
}
}
}
// 繪制同心圓
void Mire(void)
{
UINT32 x,y;
UINT32 color;
UINT8 red,green,blue,alpha;
for (y = 0; y < ysize; y++)
for (x = 0; x < xsize; x++){
color = ((x-xsize/2)*(x-xsize/2) + (y-ysize/2)*(y-ysize/2))/64;
red = (color/8) % 256;
green = (color/4) % 256;
blue = (color/2) % 256;
alpha = (color*2) % 256;
color |= ((UINT32)alpha << 24);
color |= ((UINT32)red << 16);
color |= ((UINT32)green << 8 );
color |= ((UINT32)blue );
PutPixel(x,y,color);
}
}
// 將屏幕清成單色
// 輸入參數:
// color: 顏色值
// 對于16BPP: color的格式為0xAARRGGBB (AA = 透明度),
// 需要轉換為5:6:5格式
// 對于8BPP: color為調色板中的索引值,
// 其顏色取決于調色板中的數值
void ClearScr(UINT32 color)
{
UINT32 x,y;
for (y = 0; y < ysize; y++)
for (x = 0; x < xsize; x++)
PutPixel(x, y, color);
}
====================================================================
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
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 lcd.o framebuffer.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 $@ $< -fno-builtin-putc
%.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裸機之串口發送中斷
推薦閱讀
史海拾趣