start.S源码:
.global _start
_start:
ldr sp, =0xD0030000 // 初始化栈,因为后面要调用C函数
bl clock_init // 初始化时钟
bl ddr_init // 初始化内存
bl nand_init // 初始化NAND
ldr r0, =0x36000000 // 要拷贝到DDR中的位置
ldr r1, =0x0 // 从NAND的0地址开始拷贝
ldr r2, =bss_start // BSS段的开始地址
sub r2,r2,r0 // 要拷贝的大小
bl nand_read // 拷贝数据
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:
mrs r0, cpsr
bic r0,r0,#0x1f // 清M4~M0
orr r0,r0,#0x12
msr cpsr,r0 // 进入irq
ldr sp, =0x3e000000 // 初始化普通中断模式的栈,指向内存
bl irq_init
mrs r0, cpsr
bic r0,r0,#0x9f // 开总的中断开关,清M4~M0
orr r0,r0,#0x10
msr cpsr,r0 // 进入user mode
ldr sp, =0x3f000000 // 初始化用户模式的栈,指向内存
ldr pc, =main
halt:
b halt
.global key_IRQ
key_IRQ:
sub lr, lr, #4 // 1.计算返回地址
stmdb sp!, {r0-r12, lr} // 2.保护现场
// 3. 处理异常
bl do_irq
// 4. 恢复现场
ldmia sp!, {r0-r12, pc}^ // ^表示把spsr恢复到cpsr
==================================================================
clock.c源码:
#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);
}
=================================================================
nand.c源码:
#define NFCONF (*(volatile unsigned int *)0xB0E00000)
#define NFCONT (*(volatile unsigned int *)0xB0E00004)
#define NFCMMD (*(volatile unsigned char *)0xB0E00008)
#define NFADDR (*(volatile unsigned char *)0xB0E0000C)
#define NFDATA (*(volatile unsigned char *)0xB0E00010)
#define NFSTAT (*(volatile unsigned int *)0xB0E00028)
#define MP0_3CON (*(volatile unsigned int *)0xE0200320)
#define MP0_1CON (*(volatile unsigned int *)0xE02002E0)
#define PAGE_SIZE 2048
#define NAND_SECTOR_SIZE_LP 2048
void wait_idle(void)
{
int i;
while(!(NFSTAT&(1<<0)));
for(i=0; i<10; i++);
}
void nand_select_chip(void)
{
int i;
NFCONT &= ~(1<<1);
for(i=0; i<10; i++);
}
void nand_deselect_chip(void)
{
NFCONT |= (1<<1);
}
void write_cmd(int cmd)
{
NFCMMD = cmd;
}
void write_addr(unsigned int addr)
{
int i;
NFADDR = (addr>>0) & 0xFF;
wait_idle();
NFADDR = (addr>>8) & 0x7;
wait_idle();
NFADDR = (addr>>11) & 0xFF;
wait_idle();
NFADDR = (addr>>19) & 0xFF;
wait_idle();
NFADDR = (addr>>27) & 0x1;
wait_idle();
}
unsigned char read_data(void)
{
return NFDATA;
}
static void nand_reset(void)
{
nand_select_chip();
write_cmd(0xff); // 复位命令
wait_idle();
nand_deselect_chip();
}
void nand_init(void)
{
// 设置时间参数(HCLK_PSYS = 667MHz/5 = 133MHz)
// TACLS[15:12]: TACLS = 1 1/133Mhz = 7.5ns
// TWRPH0[11:8]: TWRPH0 = 1 7.5ns * 2 = 15ns
// TWRPH1 [7:4]: TWRPH1 = 1 7.5ns * 2 = 15ns
// AddrCycle[1]: 1 = 指明地址周期为5次,这个是和2440的区别
NFCONF |= 1<<12 | 1<<8 | 1<<4;
NFCONF |= 1<<1;
// 使能NAND控制器
// 关闭片选信号
NFCONT |= (1<<0)|(1<<1);
// 设置相应管脚用于Nand Flash控制器
MP0_3CON = 0x22222222;
// 复位NAND Flash
nand_reset();
return;
}
// 读ID
void nand_read_id(char id[])
{
int i;
nand_select_chip();
write_cmd(0x90);
write_addr(0x00);
for (i = 0; i < 5; i++)
id[i] = read_data();
nand_deselect_chip();
}
// 读一页的函数
void nand_read(unsigned char *buf, unsigned long start_addr, int size)
{
int i, j;
// 选中芯片
nand_select_chip();
for(i=start_addr; i < (start_addr + size);)
{
// 发出READ0命令
write_cmd(0);
// Write Address
write_addr(i);
write_cmd(0x30);
wait_idle();
for(j=0; j < NAND_SECTOR_SIZE_LP; j++, i++)
{
*buf = read_data();
buf++;
}
}
// 取消片选信号
nand_deselect_chip();
}
void nand_write(int sdram_addr, int nand_addr, int size)
{
}
===================================================================
irq.c源码:
#include "lib.h"
#define VIC0INTSELECT (*(volatile unsigned int *)0xF200000C)
#define VIC1INTSELECT (*(volatile unsigned int *)0xF210000C)
#define VIC2INTSELECT (*(volatile unsigned int *)0xF220000C)
#define VIC3INTSELECT (*(volatile unsigned int *)0xF230000C)
#define VIC0INTENABLE (*(volatile unsigned int *)0xF2000010)
#define VIC0INTENCLEAR (*(volatile unsigned int *)0xF2000014)
#define VIC1INTENCLEAR (*(volatile unsigned int *)0xF2100014)
#define VIC2INTENCLEAR (*(volatile unsigned int *)0xF2200014)
#define VIC3INTENCLEAR (*(volatile unsigned int *)0xF2300014)
#define VIC0ADDRESS (*(volatile unsigned int *)0xF2000F00)
#define VIC1ADDRESS (*(volatile unsigned int *)0xF2100F00)
#define VIC2ADDRESS (*(volatile unsigned int *)0xF2200F00)
#define VIC3ADDRESS (*(volatile unsigned int *)0xF2300F00)
#define VIC1VECTADDR14 (*(volatile unsigned int *)0xF2100138)
#define VIC1INTENABLE (*(volatile unsigned int *)0xF2100010)
extern void key_IRQ(void);
void irq_init(void)
{
// 设置为IRQ中断
VIC1INTSELECT &= ~(1<<14);
// 使能中断(中断控制器里面的)
VIC1INTENABLE |= 1<<14;
// 设置中断向量
VIC1VECTADDR14 = (int)key_IRQ;
}
==================================================================
I2C.c源码:
#include "lib.h"
// GPIO
#define GPD1CON (*(volatile unsigned int *)0xE02000C0)
#define GPD1PUD (*(volatile unsigned int *)0xE02000C8)
// IIC
#define IICCON (*(volatile unsigned int *)0xE1800000)
#define IICSTAT (*(volatile unsigned int *)0xE1800004)
#define IICDS (*(volatile unsigned int *)0xE180000C)
#define VIC0ADDRESS (*(volatile unsigned int *)0xF2000F00)
#define VIC1ADDRESS (*(volatile unsigned int *)0xF2100F00)
#define VIC2ADDRESS (*(volatile unsigned int *)0xF2200F00)
#define VIC3ADDRESS (*(volatile unsigned int *)0xF2300F00)
void Delay(int time);
#define WRDATA (1)
#define RDDATA (2)
typedef struct tI2C {
unsigned char *pData; // 数据缓冲区
volatile int DataCount; // 等待传输的数据长度
volatile int Status; // 状态
volatile int Mode; // 模式:读/写
volatile int Pt; // pData中待传输数据的位置
}t210_I2C, *pt210_I2C;
static t210_I2C g_t210_I2C;
void i2c_init(void)
{
// 选择引脚功能:GPE15:IICSDA, GPE14:IICSCL
GPD1CON |= 0x22;
GPD1PUD |= 0x5;
// bit[7] = 1, 使能ACK
// bit[6] = 0, IICCLK = PCLK/16
// bit[5] = 1, 使能中断
// bit[3:0] = 0xf, Tx clock = IICCLK/16
// PCLK = 66.7MHz, IICCLK = 4.1MHz
IICCON = (1<<7) | (0<<6) | (1<<5) | (0xf); // 0xaf
IICSTAT = 0x10; // I2C串行输出使能(Rx/Tx)
}
// 主机发送
// slvAddr : 从机地址,buf : 数据存放的缓冲区,len : 数据长度
void i2c_write(unsigned int slvAddr, unsigned char *buf, int len)
{
g_t210_I2C.Mode = WRDATA; // 写操作
g_t210_I2C.Pt = 0; // 索引值初始为0
g_t210_I2C.pData = buf; // 保存缓冲区地址
g_t210_I2C.DataCount = len; // 传输长度
IICDS = slvAddr;
IICSTAT = 0xf0; // 主机发送,启动
// 等待直至数据传输完毕
while (g_t210_I2C.DataCount != -1);
}
// 主机接收
// slvAddr : 从机地址,buf : 数据存放的缓冲区,len : 数据长度
void i2c_read(unsigned int slvAddr, unsigned char *buf, int len)
{
g_t210_I2C.Mode = RDDATA; // 读操作
g_t210_I2C.Pt = -1; // 索引值初始化为-1,表示第1个中断时不接收数据(地址中断)
g_t210_I2C.pData = buf; // 保存缓冲区地址
g_t210_I2C.DataCount = len; // 传输长度
IICDS = slvAddr;
IICSTAT = 0xb0; // 主机接收,启动
// 等待直至数据传输完毕
while (g_t210_I2C.DataCount != 0);
}
//----------IIC中断服务函数----------
void do_irq(void)
{
unsigned int iicSt,i;
wy_printf("do_irq \n");
iicSt = IICSTAT;
if(iicSt & 0x8){ wy_printf("Bus arbitration failed\n"); }
switch (g_t210_I2C.Mode)
{
case WRDATA:
{
if((g_t210_I2C.DataCount--) == 0)
{
// 下面两行用来恢复I2C操作,发出P信号
IICSTAT = 0xd0;
IICCON = 0xaf;
Delay(10000); // 等待一段时间以便P信号已经发出
break;
}
IICDS = g_t210_I2C.pData[g_t210_I2C.Pt++];
// 将数据写入IICDS后,需要一段时间才能出现在SDA线上
for (i = 0; i < 10; i++);
IICCON = 0xaf; // 恢复I2C传输
break;
}
case RDDATA:
{
if (g_t210_I2C.Pt == -1)
{
// 这次中断是发送I2C设备地址后发生的,没有数据
// 只接收一个数据时,不要发出ACK信号
g_t210_I2C.Pt = 0;
if(g_t210_I2C.DataCount == 1)
IICCON = 0x2f; // 恢复I2C传输,开始接收数据,接收到数据时不发出ACK
else
IICCON = 0xaf; // 恢复I2C传输,开始接收数据
break;
}
g_t210_I2C.pData[g_t210_I2C.Pt++] = IICDS;
g_t210_I2C.DataCount--;
if (g_t210_I2C.DataCount == 0)
{
// 下面两行恢复I2C操作,发出P信号
IICSTAT = 0x90;
IICCON = 0xaf;
Delay(10000); // 等待一段时间以便P信号已经发出
break;
}
else
{
// 接收最后一个数据时,不要发出ACK信号
if(g_t210_I2C.DataCount == 1)
IICCON = 0x2f; // 恢复I2C传输,接收到下一数据时无ACK
else
IICCON = 0xaf; // 恢复I2C传输,接收到下一数据时发出ACK
}
break;
}
default:
break;
}
// 清中断向量
VIC0ADDRESS = 0x0;
VIC1ADDRESS = 0x0;
VIC2ADDRESS = 0x0;
VIC3ADDRESS = 0x0;
}
// 延时函数
void Delay(int time)
{
for (; time > 0; time--);
}
unsigned char at24cxx_read(unsigned char address)
{
unsigned char val;
wy_printf("at24cxx_read address = %d\r\n", address);
i2c_write(0xA0, &address, 1);
wy_printf("at24cxx_read send address ok\r\n");
i2c_read(0xA0, (unsigned char *)&val, 1);
wy_printf("at24cxx_read get data ok\r\n");
return val;
}
void at24cxx_write(unsigned char address, unsigned char data)
{
unsigned char val[2];
val[0] = address;
val[1] = data;
i2c_write(0xA0, val, 2);
}
void wm8960_write(unsigned int slave_addr, int addr, int data)
{
unsigned char val[2];
val[0] = addr<<1 | ((data>>8) & 0x0001);
val[1] = (data & 0x00FF);
i2c_write(slave_addr, val, 2);
}
==================================================================
IIS.c源码:
// GPIO
#define GPICON (*(volatile unsigned int *)0xE0200220) //IIS Signals
// IIS
#define IISCON (*(volatile unsigned int *)0xEEE30000) //IIS Control
#define IISMOD (*(volatile unsigned int *)0xEEE30004) //IIS Mode
#define IISFIC (*(volatile unsigned int *)0xEEE30008) //IIS FIFO Control
#define IISPSR (*(volatile unsigned int *)0xEEE3000C) //IIS Prescaler
#define IISTXD (*(volatile unsigned int *)0xEEE30010) //IIS TXD DATA
#define IISRXD (*(volatile unsigned int *)0xEEE30014) //IIS RXD DATA
#define IISFICS (*(volatile unsigned int *)0xEEE30018) //IIS FIFO Control
//CLCK
#define EPLL_CON0 (*(volatile unsigned int *)0xe0100110)
#define EPLL_CON1 (*(volatile unsigned int *)0xe0100114)
#define CLK_SRC0 (*(volatile unsigned int *)0xE0100200)
#define CLK_CON (*(volatile unsigned int *)0xEEE10000)
void IIS_init(void)
{
// 设置对应GPIO用于IIS
GPICON = 0x22222222;
// 设置锁相环
// SDIV [2:0] : SDIV = 0x3
// PDIV [13:8] : PDIV = 0x3
// MDIV [24:16]: MDIV = 0x43
// LOCKED [29]: 1 = 使能锁
// ENABLE [31]: 1 = 使能锁相环
//
// Fout = (0x43+0.7)*24M / (3 * 2^3) = 67.7*24M/24 = 67.7Mhz
EPLL_CON0 = 0xa8430303; // MPLL_FOUT = 67.7Mhz
EPLL_CON1 = 0xbcee; // K = 0xbcee
// 时钟源的设置
// 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 = 0x10001111;
// 时钟源的进一步设置(AUDIO SUBSYSTEMCLK SRC)
// bit[3:2]: 00 = MUXi2s_a_out来源于Main CLK
// bit[0] : 1 = Main CLK来源于FOUT_EPLL
CLK_CON = 0x1;
// 由于AUDIO SUBSYSTEMCLK DIV寄存器使用的是默认值,故分频系数为1
// IISCDCLK 11.289Mhz = 44.1K * 256fs
// IISSCLK 1.4112Mhz = 44.1K * 32fs
// IISLRCLK 44.1Khz
// 预分频值
// bit[13:8] : N = 5
// bit[15] : 使能预分频
IISPSR = 1<<15 | 5<<8;
// 设置IIS控制器
// bit[0]: 1 = 使能IIS
IISCON |= 1<<0 | (unsigned)1<<31;
// 设置各个时钟输出
// bit[2:1]:IISSCLK(位时钟) 44.1K * 32fs = 1.4112Mhz
// bit[3:4]:IISCDCLK(系统时钟) 44.1K * 256fs = 11.289Mhz
// bit[9:8]:10 = 既可以发送又可以接收
// bit[10] :0 = PCLK is internal source clock for IIS
IISMOD = 1<<9 | 0<<8 | 1<<10;
}
=====================================================================
command.c源码:
#include "lib.h"
#include "nand.h"
#include "i2c.h"
#define IISCON (*(volatile unsigned int *)0xEEE30000) //IIS Control
#define IISTXD (*(volatile unsigned int *)0xEEE30010) //IIS TXD DATA
extern short *p;
extern int offset;
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");
wy_printf("nand read - nand read sdram_addr nand_addr size\n");
wy_printf("nand write - nand write sdram_addr nand_addr size\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;
}
int nand(int argc, char *argv[])
{
int nand_addr, sdram_addr;
unsigned int size;
if (argc < 5)
{
wy_printf("nand read sdram_addr nand_addr size\n");
wy_printf("nand write sdram_addr nand_addr size\n");
return 0;
}
sdram_addr = atoi(argv[2]);
nand_addr = atoi(argv[3]);
size = atoi(argv[4]);
wy_printf("do_command 《%s》 \n", argv[0]);//实际为"
wy_printf("sdram 0x%x, nand 0x%x, size 0x%x\n", sdram_addr, nand_addr, size);
if (strcmp(argv[1], "read") == 0)
nand_read((unsigned char *)sdram_addr, nand_addr, size);
if (strcmp(argv[1], "write") == 0)
nand_write(sdram_addr, nand_addr, size);
wy_printf("nand %s finished!\n", argv[1]);
return 0;
}
int i2c(int argc, char *argv[])
{
int addr, data;
int temp;
addr = atoi(argv[2]);
data = atoi(argv[3]);
wy_printf("do_command 《%s》 \n", argv[0]);
wy_printf("addr 0x%x, data 0x%x\n", addr, data);
if (strcmp(argv[1], "read") == 0)
{
temp = at24cxx_read(addr);
wy_printf("addr 0x%x`s data 0x%x\n", addr, temp);
}
if (strcmp(argv[1], "write") == 0)
at24cxx_write(addr, data);
wy_printf("i2c %s finished!\n", argv[1]);
return 0;
}
int play(int argc, char *argv[])
{
int time, i = 0;
if (argc != 2)
{
wy_printf("play times(such as : 3)\n");
return 0;
}
time = atoi(argv[1]);
wy_printf("loading wav...\n",time);
nand_read((unsigned char *)0x23000000, 0x1000000, 0x200000);
wy_printf("play %d times...\n",time);
while(1)
{
// polling Primary Tx FIFO0 full status indication.
while((IISCON & (1<<8)) == (1<<8));
IISTXD = *(p+offset);
offset++;
if (offset > (882046-0x2e) /2) // 882046 is file size
{
offset = 0x2E; // replay from wav data offset
i++;
if(i == time)
return;
}
}
}
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 (strcmp(argv[0], "i2c") == 0)
{
i2c(argc, argv);
return;
}
if (strcmp(argv[0], "play") == 0)
{
play(argc, argv);
return;
}
if (strcmp(argv[0], "nand") == 0)
nand(argc, argv);
if(argc >= 1)
wy_printf("Unknown command '%s' - try 'help' \n",argv[0]);
return;
}
====================================================================
main.c源码:
#include "command.h"
#include "clock.h"
#include "led.h"
#include "uart.h"
#include "lib.h"
#include "nand.h"
#include "i2c.h"
#include "iis.h"
#define CFG_PROMPT "WY_BOOT # " // Monitor Command Prompt
#define CFG_CBSIZE 256 // Console I/O Buffer Size
#define WM8960_DEVICE_ADDR 0x34
int offset = 0x2E; // wav文件头部的大小
short *p = (short *)0x23000000;
char *argv[10];
void WM8960_init(void)
{
// 复位,让其他所有的寄存器恢复到默认值
wm8960_write(WM8960_DEVICE_ADDR, 0xf, 0x0);
// 打开电源,使用fast start-up模式
wm8960_write(WM8960_DEVICE_ADDR, 0x19, 1<<8 | 1<<7 | 1<<6);
// 任然是打开电源
wm8960_write(WM8960_DEVICE_ADDR, 0x1a, 1<<8 | 1<<7 | 1<<6 | 1<<5 | 1<<4 | 1<<3);
// 左右声道输出使能
wm8960_write(WM8960_DEVICE_ADDR, 0x2F, 1<<3 | 1<<2);
// 设置时钟,使用的都是默认值
wm8960_write(WM8960_DEVICE_ADDR, 0x4, 0x0);
// 关键是将R5寄存器的bit[3]清零,关闭静音功能
wm8960_write(WM8960_DEVICE_ADDR, 0x5, 0x0);
// 设置通信协议方式:如数据是24位,即IIS,左右声道时钟电平是否反转
wm8960_write(WM8960_DEVICE_ADDR, 0x7, 0x2);
// 设置左右声道输出的音量
wm8960_write(WM8960_DEVICE_ADDR, 0x2, 0xFF | 0x100);// 控制左声道的
wm8960_write(WM8960_DEVICE_ADDR, 0x3, 0xFF | 0x100);// 控制右声道的
wm8960_write(WM8960_DEVICE_ADDR, 0xa, 0xFF | 0x100);// 控制左声道的
wm8960_write(WM8960_DEVICE_ADDR, 0xb, 0xFF | 0x100);// 控制右声道的
// 使能通道,否则会静音
wm8960_write(WM8960_DEVICE_ADDR, 0x22, 1<<8 | 1<<7);// 控制左声道的
wm8960_write(WM8960_DEVICE_ADDR, 0x25, 1<<8 | 1<<7); // 控制右声道的
return;
}
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);
wy_printf("%s",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("\nThis bootloader support some command to test peripheral:\n");
wy_printf("Such as: LCD, IIS, BUZZER \n");
wy_printf("Try 'help' to learn them \n\n");
}
int main(void)
{
char buf[6];
int argc = 0;
int i = 0;
led_init(); // 设置对应管脚为输出
uart_init(); // 初始化UART0
nand_read_id(buf);
i2c_init(); // 初始化IIC
WM8960_init();
IIS_init();
wy_printf("\n**********************************************************\n");
wy_printf(" wy_bootloader\n");
wy_printf(" vars: %d \n",2012);
wy_printf(" nand id:");
putchar_hex(buf[0]);
putchar_hex(buf[1]);
putchar_hex(buf[2]);
putchar_hex(buf[3]);
putchar_hex(buf[4]);
wy_printf("\n**********************************************************\n");
while (1)
{
argc = readline (CFG_PROMPT);
if(argc == 0 && i ==0)
{
message();
i=1;
}
run_command(argc, argv);
}
return 0;
}
=====================================================================
Makefile文件:
uart.bin:start.s main.c uart.c clock.c led.c lib.c command.c nand.c mem_setup.S irq.c i2c.c iis.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-gcc -nostdlib -c nand.c -o nand.o
arm-linux-gcc -nostdlib -c irq.c -o irq.o
arm-linux-gcc -nostdlib -c i2c.c -o i2c.o
arm-linux-gcc -nostdlib -c iis.c -o iis.o
arm-linux-gcc -nostdlib -c mem_setup.S -o mem_setup.o
arm-linux-ld -T bootloader.lds start.o main.o uart.o lib.o clock.o led.o command.o nand.o mem_setup.o irq.o i2c.o iis.o -o uart_elf
arm-linux-objcopy -O binary -S uart_elf uart.bin
clean:
rm -rf *.o *.bin uart_elf *.dis
=====================================================================
bootloader.lds链接文件:
SECTIONS {
. = 0x36000010;
.text : {
* (.text)
}
. = ALIGN(4);
.rodata : {
* (.rodata)
}
. = ALIGN(4);
.data : {
* (.data)
}
. = ALIGN(4);
bss_start = .;
.bss : { *(.bss) *(COMMON) }
bss_end = .;
}
『本文转载自网络,版权归原作者所有,如有侵权请联系删除』