dm3730之支持Peripheral 启动系统

开发板:DM3730
虚拟机:ubuntu 14.04
编译器:arm-none-linux-gnueabi
uboot:U-Boot 2010.06-00166-gbf92a97
开发板内核:Linux-2.6.37
文件系统:ext3

一般芯片的启动机制都在芯片手册上有讲解 比如我这款a8的dm3730的启动机制大致如下
romcode->x-load(MLO)->u-boot.bin->uImage->rootfs
u-boot我选择的是用uart的方式启动 因为usb启动的话需要usb是host并且满足一下的协议才能发送相应的image
这里写图片描述
uart启动uboot的协议如上
具体的ASCI ID
这里写图片描述
先是ROMCODE发送ASIC ID给host 然后host接受到后就发送Boot message 和size of image ,image
协议看似复杂 其实用工具就可以实现 我们可以使用两个tools就是peserial,ukermit
使用方法是 调好sys_boot[4:0]然后上电下载就好了

也可以自行去分析在pserial和ukermit里怎么实现传输文件的 在这里简单的分析下pserial协议下载

//pserial.c
int main(int argc, char **argv)
{
    signed char ret = 0;
    unsigned char buff[MAX_BUF];
    /* 0xF0030002表示继续从uart或者usb启动 */
    unsigned int download_command = 0xF0030002;
    char *port = NULL;
    char *second_file = NULL;
    char *appname = argv[0];
    int c;
    int read_size = 0;
    unsigned int asic_id = 0;
    char verbose = 0;
    /* Option validation */
    opterr = 0;
    /* 分析参数 给相关的变量赋值 */
    while ((c = getopt(argc, argv, PORT_ARG ":" SEC_ARG ":" VERBOSE_ARG)) !=
            -1)
        switch (c) {
        case VERBOSE_ARG_C:
            verbose = 1;
            break;
        case PORT_ARG_C:
            port = optarg;
            break;
        case SEC_ARG_C:
            second_file = optarg;
            break;
        case '?':
            if ((optopt == SEC_ARG_C) || (optopt == PORT_ARG_C)) {
                APP_ERROR("Option -%c requires an argument.\n",
                      optopt)
            } else if (isprint(optopt)) {
                APP_ERROR("Unknown option `-%c'.\n", optopt)
            } else {
                APP_ERROR("Unknown option character `\\x%x'.\n",
                      optopt)
            }
            usage(appname);
            return 1;
        default:
            abort();
        }
    if ((port == NULL) || (second_file == NULL)) {
        APP_ERROR("Error: Not Enough Args\n")
            usage(appname);
        return -1;
    }
    /* 打开端口 也就是/dev/ttyUSB0等 */
    /* Setup the port */
    ret = s_open(port);
    if (ret != SERIAL_OK) {
        APP_ERROR("serial open failed\n")
            return ret;
    }
    /* 根据uart需求来配置端口 这里设置115200 偶校验 等 */
    ret = s_configure(115200, EVENPARITY, ONE_STOP_BIT, 8);
    if (ret != SERIAL_OK) {
        s_close();
        APP_ERROR("serial configure failed\n")
            return ret;
    }

    /* Read ASIC ID */
    /* 读取ASIC ID 开发板上电 ROMCODE回发送ASIC ID到此 这里接受到后分析数据 */
    printf("Waiting For Device ASIC ID: Press Ctrl+C to stop\n");
    while (!ret) {
        ret = s_read(buff, 1);
        if (buff[0] != 0x04)
            ret = 0;
    }

    ret = 0;
    while (!ret) {
        ret = s_read(buff, ASIC_ID_SIZE);
        if ((ret != ASIC_ID_SIZE)) {
            APP_ERROR("Did not read asic ID ret = %d\n", ret)
                s_close();
            return ret;
        }
    }
    if (verbose) {
        int i = 0;
        for (i = 0; i < ASIC_ID_SIZE; i++)
            printf("[%d] 0x%x[%c]\n", i, buff[i], buff[i]);
    }
    asic_id = (buff[3] << 8) + buff[4];
    switch (asic_id) {
    case ASIC_ID_OMAP4430:
        printf("ASIC ID Detected: OMAP 4430 with ROM Version"
            " 0x%02x%02x\n", buff[5], buff[6]);
        read_size = 59;
        break;
    case ASIC_ID_OMAP3430:
    case ASIC_ID_OMAP3630:
        printf("ASIC ID Detected: OMAP %04x with ROM Version"
            " 0x%02x%02x\n", asic_id, buff[5], buff[6]);
        read_size = 50;
        break;
    default:
        printf("ASIC ID Detected: 0x%02x 0x%02x 0x%02x 0x%02x\n",
            buff[3], buff[4], buff[5], buff[6]);
        read_size = 50;
        break;
    }

    ret = 0;
    while (!ret) {
        ret = s_read(buff, read_size);
        if ((ret != read_size)) {
            APP_ERROR("Did not read asic ID ret = %d\n", ret)
                s_close();
            return ret;
        }
    }

    if (verbose) {
        int i = 0;
        for (i = 0; i < read_size; i++)
            printf("[%d] 0x%x[%c]\n", i, buff[i], buff[i]);
    }
    /* 发送boot message */
    /* Send the Download command */
    printf("Sending 2ndFile:\n");
    ret =
        s_write((unsigned char *)&download_command,
            sizeof(download_command));
    if (ret != sizeof(download_command)) {
        APP_ERROR("oppps!! did not actually manage to send command\n")
            return -1;
    }
    /* 发送image size 和image */
    if (send_file(second_file) != 0) {
        APP_ERROR("send file failed!\n")
    }
    /* 关闭端口 */
    ret = s_close();
    if (ret != SERIAL_OK) {
        APP_ERROR("serial close failed\n")
            return ret;
    }
    printf("\nFile download completed.\n");

    return ret;
}

整个程序就是根据手册上的协议来接受或者发送

接着就是kermit下载uboot到x-load接收 不过这个太复杂了 我可分析不了 我只是个做底层的 没太多精力放在协议上哈哈
接着是启动后的uboot要用到usb启动内核和文件系统 那么首先就是要uboot里先扫描到usb设备 才能读写
具体的验证方法是usb start命令
这个命令也就是调用usb_init()这个函数同样也可以走马观花的大概分析下

int usb_init(void)
{
    int result;

    running = 0;
    dev_index = 0;
    asynch_allowed = 1;
    usb_hub_reset();
    /* init low_level USB */
    printf("USB:   ");
    /* usb相关控制器的初始化 */
    result = usb_lowlevel_init();
    /* if lowlevel init is OK, scan the bus for devices
     * i.e. search HUBs and configure them */
    if (result == 0) {
        printf("scanning bus for devices... ");
        running = 1;
        /* 扫描设备 */
        usb_scan_devices();
        usb_started = 1;
        return 0;
    } else {
        printf("Error, couldn't init Lowlevel part\n");
        usb_started = 0;
        return -1;
    }
}

usb_lowlevel_init()函数就是初始化相关的控制器 基本都是在手册上的寄存器之类的 比如我这里使用的就是musb otg 所以就是初始化otg controler之类的寄存器
然后就是设备扫描部分

void usb_scan_devices(void)
{
    int i;
    struct usb_device *dev;

    /* first make all devices unknown */
    /* 将usb_device结构体清零 也就是把数据擦除 */
    for (i = 0; i < USB_MAX_DEVICE; i++) {
        memset(&usb_dev[i], 0, sizeof(struct usb_device));
        usb_dev[i].devnum = -1;
    }
    dev_index = 0;
    /* device 0 is always present (root hub, so let it analyze) */
    /*  */
    /* 初始化usb_device */
    dev = usb_alloc_new_device();
    /* 这里才是真正去扫描 */
    if (usb_new_device(dev))
        printf("No USB Device found\n");
    else
        printf("%d USB Device(s) found\n", dev_index);
    /* insert "driver" if possible */
#ifdef CONFIG_USB_KEYBOARD
    drv_usb_kbd_init();
    USB_PRINTF("scan end\n");
#endif
}
int usb_new_device(struct usb_device *dev)
{
    int addr, err;
    int tmp;
    unsigned char tmpbuf[USB_BUFSIZ];

    /* We still haven't set the Address yet */
    addr = dev->devnum;
    dev->devnum = 0;

#ifdef CONFIG_LEGACY_USB_INIT_SEQ
    /* this is the old and known way of initializing devices, it is
     * different than what Windows and Linux are doing. Windows and Linux
     * both retrieve 64 bytes while reading the device descriptor
     * Several USB stick devices report ERR: CTL_TIMEOUT, caused by an
     * invalid header while reading 8 bytes as device descriptor. */
    dev->descriptor.bMaxPacketSize0 = 8;        /* Start off at 8 bytes  */
    dev->maxpacketsize = PACKET_SIZE_8;
    dev->epmaxpacketin[0] = 8;
    dev->epmaxpacketout[0] = 8;

    err = usb_get_descriptor(dev, USB_DT_DEVICE, 0, &dev->descriptor, 8);
    if (err < 8) {
        printf("\n      USB device not responding, " \
               "giving up (status=%lX)\n", dev->status);
        return 1;
    }
#else
    /* This is a Windows scheme of initialization sequence, with double
     * reset of the device (Linux uses the same sequence)
     * Some equipment is said to work only with such init sequence; this
     * patch is based on the work by Alan Stern:
     * http://sourceforge.net/mailarchive/forum.php?
     * thread_id=5729457&forum_id=5398
     */
     /* 发送要获取64字节usb描述符类的请求 */
    struct usb_device_descriptor *desc;
    int port = -1;
    struct usb_device *parent = dev->parent;
    unsigned short portstatus;

    /* send 64-byte GET-DEVICE-DESCRIPTOR request.  Since the descriptor is
     * only 18 bytes long, this will terminate with a short packet.  But if
     * the maxpacket size is 8 or 16 the device may be waiting to transmit
     * some more, or keeps on retransmitting the 8 byte header. */

    desc = (struct usb_device_descriptor *)tmpbuf;
    dev->descriptor.bMaxPacketSize0 = 64;       /* Start off at 64 bytes  */
    /* Default to 64 byte max packet size */
    dev->maxpacketsize = PACKET_SIZE_64;
    dev->epmaxpacketin[0] = 64;
    dev->epmaxpacketout[0] = 64;

    err = usb_get_descriptor(dev, USB_DT_DEVICE, 0, desc, 64);
    if (err < 0) {
        USB_PRINTF("usb_new_device: usb_get_descriptor() failed\n");
        return 1;
    }

    dev->descriptor.bMaxPacketSize0 = desc->bMaxPacketSize0;

    /* find the port number we're at */
    if (parent) {
        int j;

        for (j = 0; j < parent->maxchild; j++) {
            if (parent->children[j] == dev) {
                port = j;
                break;
            }
        }
        if (port < 0) {
            printf("usb_new_device:cannot locate device's port.\n");
            return 1;
        }

        /* reset the port for the second time */
        err = hub_port_reset(dev->parent, port, &portstatus);
        if (err < 0) {
            printf("\n     Couldn't reset port %i\n", port);
            return 1;
        }
    }
#endif

    dev->epmaxpacketin[0] = dev->descriptor.bMaxPacketSize0;
    dev->epmaxpacketout[0] = dev->descriptor.bMaxPacketSize0;
    switch (dev->descriptor.bMaxPacketSize0) {
    case 8:
        dev->maxpacketsize  = PACKET_SIZE_8;
        break;
    case 16:
        dev->maxpacketsize = PACKET_SIZE_16;
        break;
    case 32:
        dev->maxpacketsize = PACKET_SIZE_32;
        break;
    case 64:
        dev->maxpacketsize = PACKET_SIZE_64;
        break;
    }
    dev->devnum = addr;

    err = usb_set_address(dev); /* set address */

    if (err < 0) {
        printf("\n      USB device not accepting new address " \
            "(error=%lX)\n", dev->status);
        return 1;
    }

    wait_ms(10);    /* Let the SET_ADDRESS settle */

    tmp = sizeof(dev->descriptor);

    err = usb_get_descriptor(dev, USB_DT_DEVICE, 0,
                 &dev->descriptor, sizeof(dev->descriptor));
    if (err < tmp) {
        if (err < 0)
            printf("unable to get device descriptor (error=%d)\n",
                   err);
        else
            printf("USB device descriptor short read " \
                "(expected %i, got %i)\n", tmp, err);
        return 1;
    }
    /* correct le values */
    le16_to_cpus(&dev->descriptor.bcdUSB);
    le16_to_cpus(&dev->descriptor.idVendor);
    le16_to_cpus(&dev->descriptor.idProduct);
    le16_to_cpus(&dev->descriptor.bcdDevice);
    /* only support for one config for now */
    /*  */
    usb_get_configuration_no(dev, &tmpbuf[0], 0);
    usb_parse_config(dev, &tmpbuf[0], 0);
    usb_set_maxpacket(dev);
    /* we set the default configuration here */
    if (usb_set_configuration(dev, dev->config.desc.bConfigurationValue)) {
        printf("failed to set default configuration " \
            "len %d, status %lX\n", dev->act_len, dev->status);
        return -1;
    }
    USB_PRINTF("new device strings: Mfr=%d, Product=%d, SerialNumber=%d\n",
           dev->descriptor.iManufacturer, dev->descriptor.iProduct,
           dev->descriptor.iSerialNumber);
    memset(dev->mf, 0, sizeof(dev->mf));
    memset(dev->prod, 0, sizeof(dev->prod));
    memset(dev->serial, 0, sizeof(dev->serial));
    if (dev->descriptor.iManufacturer)
        usb_string(dev, dev->descriptor.iManufacturer,
               dev->mf, sizeof(dev->mf));
    if (dev->descriptor.iProduct)
        usb_string(dev, dev->descriptor.iProduct,
               dev->prod, sizeof(dev->prod));
    if (dev->descriptor.iSerialNumber)
        usb_string(dev, dev->descriptor.iSerialNumber,
               dev->serial, sizeof(dev->serial));
    USB_PRINTF("Manufacturer %s\n", dev->mf);
    USB_PRINTF("Product      %s\n", dev->prod);
    USB_PRINTF("SerialNumber %s\n", dev->serial);
    /* now prode if the device is a hub */
    usb_hub_probe(dev, 0);
    return 0;
}

其实最终都是要到usb驱动里 根据usb设备的发包或者信息之类的传输 来确认usb的设备信息 具体的原理我也不甚了解 大概也就懂的大部分要做的事~

这里的dm3730用的是musb otg所以就在otg接口插上u盘然后 usb start扫描 然后扫描到设备后通过fatload命令下载内核到ram中然后bootm ,bootm的实现原理看我的上一篇转载的文章 讲的挺全的
uboot启动内核和文件系统 其实就是两件事
1.u盘启动盘的制作
2.uboot中环境变量的设置

还有一点特别需要注意的是usb otg是分为host 和 gadget模式的

.usb 有host和otg之分,host只能当主控来用,即去识别u盘;

而otg既可以当主控来用,也可以当从来用。

当otg当主的时候,就主动去之别u盘;当otg当从的时候,有以下几种种功能:

                1.打开 Serial Gadget (with CDC ACM and CDC OBEX support) ,这个时候选用 mv_gadget.c   pxa_comp.c   serial.c  ,把核心盘模拟成usbclient,把设备当成一个串口来用。 会在/dev/下生成一个设备节点,/dev/ttyGS0.通过映射之后,用getty /dev/ttyGS0 115200 ,这样就可以在pc上看到我们的串口,其实就是把我们的串口映射到pc上;

另外,当我们把usbmMode设为client之后,就可以在pc上安装驱动,这样就会在pc端被模拟成串口,这个时候就可以用串口工具进行通讯了。

   设备端建议采用minicomm测试,而不是用cat

              2.打开File-backed Storage Gadget ,这个时候选择mv_gadget.c  pxa_comp.c   file_storage.c,这个时候,其实是把核心板模拟成upan,具体做法如下;

                         1.生成文件 dd if=/dev/zero of=./vfat.bin bs=1M count=10
                         2.格式化./newfs_msdos -F 32 ./vfat.bin
                         3.建立目录 mkdir vfat_mount
                         4.挂载目录mount -t vfat vfat.bin ./vfat_mount/    
                         5.加载驱动 insmod g_file_storage.ko file=./vfat.bin stall=0 removable=1
                         6.cd vfat_mount  ,写一个文件,sync  ,插拔usb先,pc上可以看到实时看到设备上写的新东西。
                         7.电脑上些东西 ,设备端sync ,然后 umount ./vfat_mount/   mount -t vfat ./vfat.bin ./vfat_mount/,这样就可以在设备端实时看到pc端更新的东西
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值