datasheet

Tiny210裸板IIS之WM8960声卡操作

2018-10-12来源: eefocus关键字:Tiny210裸板  WM8960  声卡操作

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 = .;

}


关键字:Tiny210裸板  WM8960  声卡操作

编辑:什么鱼 引用地址:http://www.eeworld.com.cn/mcu/2018/ic-news101241710.html
本网站转载的所有的文章、图片、音频视频文件等资料的版权归版权所有人所有,本站采用的非本站原创文章及图片等内容无法一一联系确认版权者。如果本网所选内容的文章作者及编辑认为其作品不宜公开自由传播,或不应无偿使用,请及时通过电子邮件或电话通知我们,以迅速采取适当措施,避免给双方造成不必要的经济损失。

上一篇:S3C2440和S5PV210的声卡对比
下一篇:自己写bootloader倒计时启动内核

关注eeworld公众号 快捷获取更多信息
关注eeworld公众号
快捷获取更多信息
关注eeworld服务号 享受更多官方福利
关注eeworld服务号
享受更多官方福利

推荐阅读

Tiny4412和Tiny210裸板程序烧写比较

disk # 同步文件syncrm bl2.bin##################################### Message Display echo "---------------------------------------"echo "source file image is fused successfully."echo "Eject SD card and insert it to Exynos 4412 board again."故Tiny4412是把裸板固件放在SD卡BL2地址处运行。2、Tiny210
发表于 2018-10-14

Tiny210和Tiny4412裸板程序烧写比较

disk # 同步文件syncrm bl2.bin##################################### Message Display echo "---------------------------------------"echo "source file image is fused successfully."echo "Eject SD card and insert it to Exynos 4412 board again."故Tiny4412是把裸板固件放在SD卡BL2地址处运行。2、Tiny210
发表于 2018-10-12

S3C2440裸板WM8976声卡驱动实现

= I2SLRCK, GPE1 = I2SSCLK, GPE3 = I2SSDI, GPE4 = I2SSDO, GPE2 = CDCLK  //-------------------------------------------------------------  void Play_WAV(void)  {      Printf("[ IIS test using WM8976 CODEC ]/r/n");      IIS_PortSetting();      Init8976
发表于 2018-07-24

AM335x(TQ335x)学习笔记——WM8960声卡驱动移植

经过一段时间的调试,终于调好了TQ335x的声卡驱动。TQ335x采用的Codec是WM8960,本文来总结下WM8960驱动在AM335x平台上的移植方法。Linux声卡驱动架构有OSS和ALSA两种架构,目前最常用的架构是ALSA,本文也使用ALSA架构对WM8960驱动进行移植。 ASoC是对ALSA驱动架构的进一步封装。ASoC将ALSA驱动中的各模块抽象为三部分:Platform、Codec和Machine。Platform主要是平台硬件驱动,包括SoC的IIS模块、DMA等,在本文中就是指AM335x的McASP模块及AM335x用于音频读写操作的EDMA。Codec是编解码芯片驱动,在本文中就是WM8960
发表于 2015-08-19

去整合化大势:音频芯片的独立革命

)与接收路径(Rx)噪声消减技术功能,可使噪声分别降低32dB和20 dB。当这些特性结合在一起时,最终可使背景噪声减少高达90%,再与其它额外的特点相结合,包括宽频带语音、多种麦克风波束形成、风噪抑制以及其它可编程滤波器等,WM5110即使在最嘈杂的环境中也可实现无比清澈而干脆的语音通话、一种真正的多媒体声效体验、出色的音频捕获与回放、以及丰富和自然听觉的会议电话。 便携产品应用中的新标准     WM5110可提供超乎寻常的110 dB信噪比,和极快速的600 MIPS处理能力,每个MIPS瓦数消耗是最小的,并且可以提供最完整的音频处理解决方案。     欧胜
发表于 2012-06-04
去整合化大势:音频芯片的独立革命

基于WM2002设计的立体声耳机驱动方案

本文介绍了WM2002主要特性,方框图,典型应用框图以及推荐外接元件数值和DC1升压转换器和电荷泵外接元件数值。Wolfson 公司的WM2002是采用Wolfson myZoneTM环境噪音消(ANC)除技术的立体声耳机驱动器,可采用单端或BTL输出配置,支持模拟播放或语音输入,模拟或数字麦克风。WM2002集成了功率管理,包括DC/DC转换器,电荷泵和LDO稳压器,采用单节AAA电池供电。环境噪音可降低25dB(典型值),降噪带宽(40Hz -4kHz) ,BTL驱动的THD+N可达-80dB。主要用在带ANC的手机,耳机以及蓝牙单声道/立体声手机。WM2002应用:“Pod-style” stereo ear-buds
发表于 2012-04-12
基于WM2002设计的立体声耳机驱动方案

小广播

何立民专栏

单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号 电信业务审批[2006]字第258号函 京公海网安备110108001534 Copyright © 2005-2019 EEWORLD.com.cn, Inc. All rights reserved