打印
[应用相关]

VSF平台应用实例之MSCBoot

[复制链接]
1585|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
Simon21ic|  楼主 | 2014-7-24 16:03 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 Simon21ic 于 2014-7-24 16:45 编辑

MSCBoot是我以前就发布过的一个bootloader,通过在USB口上,实现MSC设备,模拟出一个FAT32的U盘,通过对U盘中firmware.bin文件的覆盖性复制,来更新固件应用程序。

VSF平台的简介,参考这里:https://bbs.21ic.com/icview-773982-1-1.html
这个做为VSF介绍的第一个实例吧,代码做过一些简化,去掉了不需要的部分。

不多说了,直接上代码:

// mal
// embedded flash
static struct embflash_param_t embflash_param =
{
    0,                            // uint8_t index;
};
static struct mal_info_t embflash_mal_info =
{
    {0, 0}, NULL, 0, 0, 0, &embflash_drv
};
static struct dal_info_t embflash_dal_info =
{
    NULL,
    &embflash_param,
    NULL,
    &embflash_mal_info,
};

// firmware, APP_CFG_FWSIZE bytes located at APP_CFG_BOOTSIZE
static struct malinmal_param_t firmware_param =
{
    &embflash_dal_info,            // struct dal_info_t *maldal;
    APP_CFG_BOOTSIZE,            // uint32_t addr;
    APP_CFG_FWSIZE,                // uint32_t size;
};
static struct mal_info_t firmware_mal_info =
{
    {0, 0}, NULL, 0, 0, 0, &malinmal_drv
};
static struct dal_info_t firmware_dal_info =
{
    NULL,
    &firmware_param,
    NULL,
    &firmware_mal_info,
};

首先,定义mal实例(mal是存储器抽象层),embflash_dal_info是把芯片内部的flash,实现为通用的mal接口。
但是,实际我们的bootlaoder也同样会占用内存flash,那就需要用到malinmal的实例,把flash中,实际应用程序使用的部分,独立抽象出一个mal。

然后,定义fakefat32(同样也是一个mal的驱动,用代码的方式,实现一个假的FAT32文件系统)
static struct fakefat32_file_t root_dir[] =
{
    {
        "MSCBoot", NULL,
        FKAEFAT32_FILEATTR_VOLUMEID,
    },
    {
        "firmware", "bin",
        FAKEFAT32_FILEATTR_ARCHIVE,
        512,
        {
            ReadFirmwareArea,
            ReadFirmwareArea_isready,
            WriteFirmwareArea,
            WriteFirmwareArea_isready
        },
    },
    {
        NULL,
    }
};
为了简化,名字为MSCBoot的根目录里,只有一个firmware.bin文件。
ReadFirmwareArea等接口,是用户实现的代码,其实只是控制firmware_mal_info,实现对固件flash空间的非阻塞的读写访问。

定义好目录结构后,就需要定义fakefat32的mal的实例了:
static struct fakefat32_param_t fakefat32_param =
{
    512,            // uint16_t sector_size;
    0x00760000,        // uint32_t sector_number;
    8,                // uint8_t sectors_per_cluster;
   
    0x0CA93E47,        // uint32_t volume_id;
    0x12345678,        // uint32_t disk_id;
    {                // struct fakefat32_file_t root;
        {
            "ROOT", NULL,
            0,
            0,
            {fakefat32_dir_read, NULL, fakefat32_dir_write, NULL},
            root_dir
        }
    }
};
static struct mal_info_t fakefat32_mal_info =
{
    {0, 0}, NULL, 0, 0, 0, &fakefat32_drv
};
static struct dal_info_t fakefat32_dal_info =
{
    NULL,
    &fakefat32_param,
    NULL,
    &fakefat32_mal_info,
};

之后是USB设备端接口的MSC类驱动相关的类实例:
struct SCSI_LUN_info_t MSCBOT_LunInfo =
{
    &fakefat32_dal_info,
    {
        true,
        {'S', 'i', 'm', 'o', 'n', ' ', ' ', ' '},
        {'M', 'S', 'C', 'B', 'o', 'o', 't', ' ',
        ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '},
        {'1', '.', '0', '0'},
        SCSI_PDT_DIRECT_ACCESS_BLOCK
    }
};
uint8_t MSCBOT_Buffer0[4096], MSCBOT_Buffer1[4096];

struct vsfusbd_MSCBOT_param_t MSCBOT_param =
{
    1,                            // uint8_t ep_out;
    1,                            // uint8_t ep_in;
   
    0,                            // uint8_t max_lun;
    &MSCBOT_LunInfo,            // struct SCSI_LUN_info_t *lun_info;
    NULL,                         // struct SCSI_handler_t *user_handlers;
   
    {
        {MSCBOT_Buffer0, sizeof(MSCBOT_Buffer0)},
        {MSCBOT_Buffer1, sizeof(MSCBOT_Buffer1)}
    },                            // struct vsf_buffer_t page_buffer[2];
};

注意,这里使用了双缓冲的方式,USB在通信的同时,另一个缓存可以用于实际mal的读写操作。
MSCBOT_LunInfo里设置了实际mal为fakefat32_dal_info,也就是虚拟FAT32的mal驱动。

接下里就是USB设备端协议栈的实例,实际描述符就直接略过了:
描述符结构
static const struct vsfusbd_desc_filter_t descriptors[] =
{
    VSFUSBD_DESC_DEVICE(0, MSCBOT_DeviceDescriptor, sizeof(MSCBOT_DeviceDescriptor), NULL),
    VSFUSBD_DESC_CONFIG(0, 0, MSCBOT_ConfigDescriptor, sizeof(MSCBOT_ConfigDescriptor), NULL),
    VSFUSBD_DESC_STRING(0, 0, MSCBOT_StringLangID, sizeof(MSCBOT_StringLangID), NULL),
    VSFUSBD_DESC_STRING(0x0409, 1, MSCBOT_StringVendor, sizeof(MSCBOT_StringVendor), NULL),
    VSFUSBD_DESC_STRING(0x0409, 2, MSCBOT_StringProduct, sizeof(MSCBOT_StringProduct), NULL),
    VSFUSBD_DESC_STRING(0x0409, 3, MSCBOT_StringSerial, sizeof(MSCBOT_StringSerial), NULL),
    VSFUSBD_DESC_NULL
};

USB接口的定义,每个接口需要设置对应的类驱动和参数。
static struct vsfusbd_iface_t ifaces[] =
{
    {(struct vsfusbd_class_protocol_t *)&vsfusbd_MSCBOT_class, (void *)&MSCBOT_param},
    {(struct vsfusbd_class_protocol_t *)NULL, (void *)NULL}
};
USB配置结构
static struct vsfusbd_config_t config0[] =
{
    {
        NULL, NULL, dimof(ifaces), (struct vsfusbd_iface_t *)ifaces,
    }
};
USB设备端的定义
struct vsfusbd_device_t usb_device =
{
    1, (struct vsfusbd_config_t *)config0,
    (struct vsfusbd_desc_filter_t *)descriptors, 0,
    (struct interface_usbd_t *)&core_interfaces.usbd,
   
    {
        NULL,            // init
        NULL,            // fini
        NULL,            // poll
        NULL,            // on_set_interface
        
        NULL,            // on_ATTACH
        NULL,            // on_DETACH
        NULL,            // on_RESET
        NULL,            // on_ERROR
        NULL,            // on_WAKEUP
        NULL,            // on_SUSPEND
        NULL,            // on_RESUME
        NULL,            // on_SOF
        
        NULL,            // on_IN
        NULL,            // on_OUT
    },            // callback
};
其中,core_interfaces.usbd定义了,这个协议栈使用的是芯片内部的USB硬件。

主函数就相当精简了:
int main(void)
{
主控芯片初始化
    interfaces->core.init(NULL);
自保护
    if (!interfaces->flash.isprotected(0))
    {
        interfaces->flash.unlock(0);
        interfaces->flash.protect(0);
        interfaces->flash.lock(0);
    }

初始化应用固件的mal,并且读取第一个block
    if (mal.init(&embflash_dal_info) ||
        (0 == embflash_mal_info.capacity.block_size) ||
        (sizeof(block_buffer) < embflash_mal_info.capacity.block_size) ||
        mal.readblock(&embflash_dal_info, APP_CFG_BOOTSIZE, block_buffer, 1))
    {
        fatal_error();
    }
    pagesize = (uint32_t)embflash_mal_info.capacity.block_size;
    pagenum = (uint32_t)embflash_mal_info.capacity.block_number;
    size = pagesize * pagenum;
   
对于Cortex芯片,第一个block里有固件的堆栈指针和复位向量地址。
    // read MSP and RST_VECT
    MSP = GET_LE_U32(&block_buffer[0]);
    RST_VECT = GET_LE_U32(&block_buffer[4]);
   
初始化按键IO,并且判断按键是否按下,如果按下的话(或者应用固件无效的话),进入Bootloader模式,否则跳转到应用:
    interfaces->gpio.init(KEY_PORT);
    interfaces->gpio.config_pin(KEY_PORT, KEY_PIN, KEY_VALID_LOW ? GPIO_INPU : GPIO_INPD);
    key_val = interfaces->gpio.get(KEY_PORT, 1 << KEY_PIN);
    if ((KEY_VALID_LOW ? key_val : !key_val) &&
        ((MSP & 0xFF000000) == 0x20000000) &&
        ((RST_VECT & 0xFF000000) == 0x08000000))
    {
跳转到应用钱,释放对应的资源。
        mal.fini(&embflash_dal_info);
        interfaces->gpio.fini(KEY_PORT);
        interfaces->core.set_stack(MSP);
        ((void (*)(void))RST_VECT)();
        while (1);
    }
fakefat32 mal的初始化
    // fakefat32 parameter init
    fakefat32_param.sector_size = pagesize;
    fakefat32_param.sector_number = 128 * 1024 * 1024 / pagesize;
    fakefat32_param.sectors_per_cluster = 1;
    mal.init(&fakefat32_dal_info);
   
是能USB上拉,是的主机可以发现本设备
    // Enable USB Pull-up
    interfaces->gpio.set(USB_PULL_PORT, 1 << USB_PULL_PIN);
   
如果初始化USB设备协议栈成功的话,就进入轮训
    if (!vsfusbd_device_init(&usb_device))
    {
        while (1)
        {
            if (vsfusbd_device_poll(&usb_device))
            {
                break;
            }
        }
    }
   
    return 0;
}

VSF的USB协议栈,确实就只需要vsfusbd_device_init和vsfusbd_device_poll 2个接口。
用户甚至不需要关心USB端口的设置,以及缓冲的分配。
用户只需关心应用部分就行。
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

个人签名:www.versaloon.com --- under construction

266

主题

2597

帖子

104

粉丝