您的位置:首页 > 其它

bootloader---19.usb下载之设备枚举

2016-08-29 13:58 447 查看
    在实现了读取内核并引导内核之后,下一步要实现的功能是内核下载。内核下载可以通过网络和usb下载,正好最近学习了usb的一些东东,现在就把usb下载的功能加入到myboot中,这样myboot看起来就像是那么回事了,呵呵。

    usb主机要与usb设备进行通信,这儿要完成的是usb设备部分,那么usb主机部分肿么办呢?windows下的dnw没有代码的,而且还老蓝屏,但是linux下有基于libusb的源程序(dnw2)。 usb主机部分临时先用这个代码,等把usb设备完成之后,再自己动手写一下这个dnw2的代码,这样上下位机咱就都会了。

    下面说一下思路,usb 设备部分主要实现如下功能:

1.实现usb的枚举
   a. 以前代码中没有用到中断,所以这儿要实现中断
       a.1 建立arm的中断向量表 (start.S中添加)

当发生 irq中断时,mcu跳到中断向量表的irq入口处,执行ldr pc, _irq命令。
因为定义了 _irq: .word irq, 所以程序跳到irq函数去执行。

点击(此处)折叠或打开

_start:

    b reset

    ldr pc, _undefined_instruction

    ldr pc, _software_interrupt

    ldr pc, _prefetch_abort

    ldr pc, _data_abort 

    ldr pc, _not_used

    ldr pc, _irq

    ldr pc, _fiq

_undefined_instruction:

    .word undefined_instruction

_software_interrupt:

    .word software_interrupt

_prefetch_abort:

    .word prefetch_abort

_data_abort:

    .word data_abort

_not_used:

    .word not_used

_irq:

    .word irq

_fiq:

    .word fiq

       a.2 arm的中断服务程序,这儿只用到了irq (start.S中添加)

点击(此处)折叠或打开

undefined_instruction:

    nop

software_interrupt:

    nop

prefetch_abort:

    nop

data_abort:

    nop

not_used:

nop

irq:

    sub lr, lr, #4 
@ the return address

    ldr sp, IRQ_STACK_START 
@ the stack for irq @在完成保存堆栈的操作后,跳到中断处理函数IRQ_Handle中。

    stmdb { r0-r12,lr} 
@ save registers

    ldr lr, =int_return 
@ set the return addr

    ldr pc, =irq_handle 
@ call the isr

int_return:

    ldmia { r0-r12,pc }^ 
@ return from interrupt

fiq:

nop

.globl IRQ_STACK_START

IRQ_STACK_START:

    .word 0x33FF7000

      a.3 irq的中断服务程序

点击(此处)折叠或打开

void (*isr_handle_array[50])(void);

void irq_handle(void)

{

    unsigned long oft = INTOFFSET; 

    SRCPND = 1<<oft;

    INTPND = 1<<oft;

    (isr_handle_array[oft])();

    return ;

}

      a.4 初始化irq的中断向量表

点击(此处)折叠或打开

//这里只用usb中断和dma2

void Isr_Init(void)

{

    u32 i = 0;

    for(i=0; i<sizeof(isr_handle_array); i++)

    {

        isr_handle_array[i] = Dummy_isr;

    }

    

    //将所有中断设为IRQ模式,并屏闭所有中断

    INTMOD = 0x0; 

    INTMSK = BIT_ALLMSK;

    isr_handle_array[ISR_USBD_OFT] = IsrUsbd;

    isr_handle_array[ISR_DMA2_OFT] = IsrDma2;

    ClearPending(BIT_DMA2);

    ClearPending(BIT_USBD);

    return ;

}

     a.5 最关键的一步,打开irq中断,重启复位时默认进入0xd3模式,并不开启irq中断。

点击(此处)折叠或打开

开启irq中断

void enable_irq(void) 

{

    asm volatile 

    (

        "mrs r4,cpsr\n\t"

        "bic r4,r4,#0x80\n\t"

        "msr cpsr,r4\n\t"

        :::"r4"

    );

}

   b. irq中断这条路己经通了,当有usb中断时就会进入usb中断服务程序,这一步要实现产生usb中断的所有准备
      b.1 配置usb寄存器, 让usb设备工作起来

点击(此处)折叠或打开

void Init_Usb_Reg(void)

{

// *** End point
information ***

// EP0: control

// EP1: bulk in end point

// EP2: not used

// EP3: bulk out end point

// EP4: not used

    #define PWR_REG_DEFAULT_VALUE (DISABLE_SUSPEND)

    PWR_REG=PWR_REG_DEFAULT_VALUE;    //disable
suspend mode //0x00

    INDEX_REG=0;

    MAXP_REG=FIFO_SIZE_8;     //EP0
max packit size = 8 //datasheet:For EP1~4, MAXP=64 is recommended.

    EP0_CSR_IN_CSR1_REG=EP0_SERVICED_OUT_PKT_RDY|EP0_SERVICED_SETUP_END; //EP0_CSR
EP0:clear OUT_PKT_RDY & SETUP_END

    INDEX_REG=1;

    MAXP_REG=FIFO_SIZE_32;    //EP1:max
packit size = 32

    EP0_CSR_IN_CSR1_REG=EPI_FIFO_FLUSH|EPI_CDT;

    IN_CSR2_REG=EPI_MODE_IN|EPI_IN_DMA_INT_MASK|EPI_BULK; //IN mode, IN_DMA_INT=masked

    OUT_CSR1_REG=EPO_CDT;

    OUT_CSR2_REG=EPO_BULK|EPO_OUT_DMA_INT_MASK;

    INDEX_REG=2;

    MAXP_REG=FIFO_SIZE_64;    //EP2:max
packit size = 64

    EP0_CSR_IN_CSR1_REG=EPI_FIFO_FLUSH|EPI_CDT|EPI_BULK;

    IN_CSR2_REG=EPI_MODE_IN|EPI_IN_DMA_INT_MASK; //IN mode, IN_DMA_INT=masked

    OUT_CSR1_REG=EPO_CDT;

    OUT_CSR2_REG=EPO_BULK|EPO_OUT_DMA_INT_MASK;

    INDEX_REG=3;

    MAXP_REG=FIFO_SIZE_32;    //EP3:max
packit size = 32

    EP0_CSR_IN_CSR1_REG=EPI_FIFO_FLUSH|EPI_CDT|EPI_BULK;

    IN_CSR2_REG=EPI_MODE_OUT|EPI_IN_DMA_INT_MASK; //OUT
mode, IN_DMA_INT=masked

    OUT_CSR1_REG=EPO_CDT;

    //clear OUT_PKT_RDY, data_toggle_bit.

    //The data toggle bit should be cleared when initialization.

    OUT_CSR2_REG=EPO_BULK|EPO_OUT_DMA_INT_MASK;

    INDEX_REG=4;

    MAXP_REG=FIFO_SIZE_64;    //EP4:max
packit size = 64

    EP0_CSR_IN_CSR1_REG=EPI_FIFO_FLUSH|EPI_CDT|EPI_BULK;

    IN_CSR2_REG=EPI_MODE_OUT|EPI_IN_DMA_INT_MASK; //OUT
mode, IN_DMA_INT=masked

    OUT_CSR1_REG=EPO_CDT;

        //clear OUT_PKT_RDY, data_toggle_bit.

    //The data toggle bit should be cleared when initialization.

    OUT_CSR2_REG=EPO_BULK|EPO_OUT_DMA_INT_MASK;

    EP_INT_REG=EP0_INT|EP1_INT|EP2_INT|EP3_INT|EP4_INT;

    USB_INT_REG=RESET_INT|SUSPEND_INT|RESUME_INT;

    //Clear all usbd pending bits

    //EP0,1,3 & reset
interrupt are enabled

    EP_INT_EN_REG=EP0_INT|EP1_INT|EP3_INT;

    USB_INT_EN_REG=RESET_INT;

    //ep0State=EP0_STATE_INIT;

}

     b.2 产生usb复位信号,进入usb枚举过程

点击(此处)折叠或打开

void usb_reconnect(void)

{

    //tq2440: 在USB设备的信号线D+上接了一个1.5K的一个上拉电阻,这个上拉电阻是由usb_en控制的,当GPG12输出高电平的时候,主机的集线器才能检测到设备,从而给复位信号

    //GPG12-->usb_en

    GPGCON |= (OUTPUT_PIN<<24); //set GPG12
output

    GPGDAT |= (1<<12);            //enable
USB Device

}

    b.3 usb中断最关键的一步

点击(此处)折叠或打开

INTMSK &= ~(BIT_USBD); //打开usb中断

   c. 产生了usb中断了,但是usb中断服务程序还没有完成,马上。
注意: usb枚举过程是有时间限制的,如果printf打印的太多,会导致枚举失败。

点击(此处)折叠或打开

void IsrUsbd(void)

{

    u8 usbdIntpnd,epIntpnd;

    u8 saveIndexReg=INDEX_REG;

    usbdIntpnd=USB_INT_REG;

    epIntpnd=EP_INT_REG;

    //uart_printf( "[INT:EP_I=%x,USBI=%x]",epIntpnd,usbdIntpnd );

    if(usbdIntpnd&SUSPEND_INT)        //出现suspend_int中断之后,直接清中断

    {

        USB_INT_REG=SUSPEND_INT;    //向寄存器写1,清除该位

    //    uart_puts( "<sus]\n");

    }

    if(usbdIntpnd&RESUME_INT)        //出现resume_int中断之后,直接清中断

    {

        USB_INT_REG=RESUME_INT;        //向寄存器写1,清除该位

    //    uart_puts("<rsm]\n");

    }

    if(usbdIntpnd&RESET_INT)        //出现reset_int中断之后,复位usb

    {

        //uart_puts( "<rst]
init_usb_reg\n");

        //ResetUsbd();

        Init_Usb_Reg();

        USB_INT_REG=RESET_INT; //clear
RESET_INT

       // PrepareEp1Fifo();

    }

    if(epIntpnd&EP0_INT)

    {

     EP_INT_REG=EP0_INT;        //向寄存器写1,清除该位

        Ep0Handler();

    }

    if(epIntpnd&EP1_INT)

    {

        EP_INT_REG=EP1_INT;        //向寄存器写1,清除该位

        Ep1Handler();

    }

    if(epIntpnd&EP2_INT)

    {

        EP_INT_REG=EP2_INT;        //向寄存器写1,清除该位

        uart_puts("<2:TBD]\n"); //not implemented
yet

        //Ep2Handler();

    }

    if(epIntpnd&EP3_INT)

    {

        EP_INT_REG=EP3_INT;

        Ep3Handler();

    }

    if(epIntpnd&EP4_INT)

    {

        EP_INT_REG=EP4_INT;

        uart_puts("<4:TBD]\n"); //not implemented
yet

        //Ep4Handler();

    }

    ClearPending(BIT_USBD);

    INDEX_REG=saveIndexReg;

}

   d.
   e.
   f.
2.实现数据的收取 

   a.
   b.
   c.
   d.
   e.
   f.

参考文章:

1. s3c2440的USB主机控制器

http://blog.csdn.net/zhaocj/article/details/6083162

2. S3C2440之USB设备篇

http://blog.csdn.net/xuxg2005/article/details/6172412

3. S3C2440 USB设备控制器

http://blog.csdn.net/yaozhenguo2006/article/details/7405825
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: