工程师,您好!
我们现在想要实现的一个功能是从 6678每次启动后通过网络下载程序,如果成功下载到程序,将程序写入flash覆盖之前的程序,并从flash启动程序,如果没有下载到程序,则从flash启动之前加载的程序。我看到c6678的ibl可以通过tftp下载程序,我就想每次通过ibl从网络启动,连接tftp服务器,从服务器下载程序,并将下载好的程序写入flash,并启动程序。如果没有下载到程序,就直接从flash启动。
现在遇到的问题是,1、我看ibl源码的时候对ibl网络启动的启动流程看不明白;2、ibl通过网络连接到tftp服务器后下载到的文件存放在了哪个位置?3、ibl源码中nor/nand flash驱动都只提供了读的api,没有写的api;4、关于启动文件格式,ccs中建立工程时,选择elf格式,则生成的.out文件为elf格式,我看到网上有些资料中写到,可以直接将.out文件改名为.bin文件,ibl就可以直接识别启动了,而ethbot函数中.bin文件对应的是blob格式,那这种操作方式正确吗?通过device.h中设置启动文件格式时有blob和elf两种,我应该如何设置。
另外官方是否有关于这方面的资料,能否提供一下,谢谢
void iblEthBoot(Int32 eIdx)
{
NET_DRV_DEVICE nDevice;
Uint32 nl;
Uint32 entry;
Int32n;
Int32dataSize;
Int32format;
void(*exit)();
uint8buf[16];
char*ext;
unsigned int i, j;
//给网络启动相关设备上电、配置网络启动相关设备
/* Power up the device. No action is taken if the device is already powered up */
if (devicePowerPeriph(TARGET_PWR_ETH(ibl.bootModes[eIdx].port)) < 0)
return;
/* Do any mdio configuration */
if (ibl.mdioConfig.nMdioOps > 0)
hwMdio(ibl.mdioConfig.nMdioOps, ibl.mdioConfig.mdio,
ibl.mdioConfig.mdioClkDiv, ibl.mdioConfig.interDelay);
for (j = 0; j < 0x100; j++)
for (i = 0; i < 0x1000000; i++);
/* SGMII configuration. If sgmii is not present this statement is defined* to void in target.h */
for (n = 0; n < ibl_N_ETH_PORTS; n++) {
if (ibl.sgmiiConfig[n].configure == TRUE)
hwSgmiiConfig(n, &ibl.sgmiiConfig[n]);
}
#ifdef DEVICE_CPSW
/* On chip switch configuration */
hwCpswConfig(targetGetSwitchCtl(), targetGetSwitchMaxPktSize());
#endif
#ifdef DEVICE_QM
/* Queue manager configuration */
hwQmSetup((qmConfig_t *)(targetGetQmConfig()));
targetInitQs();
#endif
#ifdef DEVICE_CPDMA
/* Cpdma configuration. */
hwCpdmaRxConfig((cpdmaRxCfg_t *)targetGetCpdmaRxConfig());
hwCpdmaTxConfig((cpdmaTxCfg_t *)targetGetCpdmaTxConfig());
#endif
#ifdef DEVICE_PA
/* Packet accelerator configuration. If PA is not present this statement is defined* to void in target.h */
targetPaConfig(ibl.bootModes[eIdx].u.ethBoot.ethInfo.hwAddress);
#endif
#ifdef DEVICE_SS
/* Streaming switch configuration. If not present this statement is defined to void* in target.h. If present this is usually defined to a series of register writes */
hwConfigStreamingSwitch();
#endif
nDevice.port_num = ibl.bootModes[eIdx].port;
//驱动初始化、参数从主机字节序转换为网络字节序
/* Simple transation to initialize the driver */
netMemcpy(nDevice.mac_address, ibl.bootModes[eIdx].u.ethBoot.ethInfo.hwAddress, sizeof(nDevice.mac_address));
nl = FORM_IPN(ibl.bootModes[eIdx].u.ethBoot.ethInfo.ipAddr);
if (ibl.bootModes[eIdx].u.ethBoot.doBootp == TRUE)
nDevice.ip_address = 0;
else
nDevice.ip_address = htonl(nl);
nl = FORM_IPN(ibl.bootModes[eIdx].u.ethBoot.ethInfo.netmask);
nDevice.net_mask = htonl(nl);
nl = FORM_IPN(ibl.bootModes[eIdx].u.ethBoot.ethInfo.serverIp);
nDevice.server_ip = htonl(nl);
nDevice.use_bootp_server_ip = ibl.bootModes[eIdx].u.ethBoot.useBootpServerIp;
/* Note - the file name structure in nDevice is only 64 bytes, but 128 in ethInfo */
netMemcpy(nDevice.file_name, ibl.bootModes[eIdx].u.ethBoot.ethInfo.fileName, sizeof(nDevice.file_name));
nDevice.use_bootp_file_name = ibl.bootModes[eIdx].u.ethBoot.useBootpFileName;
nDevice.start = cpmac_drv_start;
nDevice.stop = cpmac_drv_stop;
nDevice.send = cpmac_drv_send;
nDevice.receive = cpmac_drv_receive;
/* have_params will be set to true in the tftp call back. It must be* set to false before opening the module, since the call back will* be from the open call if bootp is not used */
have_params = FALSE;
//开启网络设备
/* Open the network device */
if ((*net_boot_module.open) ((void *)&nDevice, ibl_rec_params) != 0)
return;
//等待从网络启动参数中获取将要下载的文件名
/* Wait for the callback with the requested filename */
while (have_params == FALSE) {
if ((*net_boot_module.peek) ((uint8 *)&nl, sizeof(nl)) < 0) {
(*net_boot_module.close)();
return;
}
}
//从网络启动参数中获取启动文件格式
format = ibl.bootModes[eIdx].u.ethBoot.bootFormat;
//根据启动文件名的后缀判断启动格式
/* If the data format was based on the name extension, determine* the boot data format */
if (format == ibl_BOOT_FORMAT_NAME) {
ext = strrchr(iblStatus.ethParams.fileName, '.');
if (ext != NULL) {
if (!strcmp(ext, ".bis"))
format = ibl_BOOT_FORMAT_BIS;
else if (!strcmp(ext, ".ais"))
format = ibl_BOOT_FORMAT_BIS;
else if (!strcmp(ext, ".out"))
format = ibl_BOOT_FORMAT_COFF;
else if (!strcmp(ext, ".coff"))
format = ibl_BOOT_FORMAT_COFF;
else if (!strcmp(ext, ".btbl"))
format = ibl_BOOT_FORMAT_BTBL;
else if (!strcmp(ext, ".bin"))
format = ibl_BOOT_FORMAT_BBLOB;
else if (!strcmp(ext, ".blob"))
format = ibl_BOOT_FORMAT_BBLOB;
}
/* Name match failed it didn't change */
if (format == ibl_BOOT_FORMAT_NAME) {
iblStatus.nameDetectFailCnt += 1;
/* Close up the peripheral */
(*net_boot_module.close)();
return;
}
}
//调用iblboot启动,iblboot返回程序入口地址
entry = iblBoot(&net_boot_module, format, &ibl.bootModes[eIdx].u.ethBoot.blob);
//读取启动文件到RAM
/* Before closing the module read any remaining data. In the coff boot mode the boot may* detect an exit before the entire file has been read. Read the rest of the file* to make the server happy */
do {
dataSize = (*net_boot_module.query)(); /* Will return -1 when the data is done */
if (dataSize > 0) {
while (dataSize > 0) {
n = MIN(dataSize, sizeof(buf));
(*net_boot_module.read)(buf, n);
dataSize = dataSize - n;
}
/* Do not peek if the data size returned in the query was > 0 */
}
else if (dataSize == 0) {
(*net_boot_module.peek)(buf, 1);
}
} while (dataSize >= 0);
//关闭网络
/* Close up the peripheral */
(*net_boot_module.close)();
#ifdef DEVICE_PA
hwPaDisable();
#endif
#ifdef DEVICE_CPDMA
/* Cpdma configuration. */
hwCpdmaRxDisable((cpdmaRxCfg_t *)targetGetCpdmaRxConfig());
hwCpdmaTxDisable((cpdmaTxCfg_t *)targetGetCpdmaTxConfig());
#endif
#ifdef DEVICE_QM
targetFreeQs();
/* Queue manager configuration */
hwQmTeardown();
#endif
//入口地址非空,则跳转到相应地址,启动完成
if (entry != 0) {
iblStatus.exitAddress = entry;
exit = (void(*)())entry;
(*exit)();
}
}
Uint32 iblBoot(BOOT_MODULE_FXN_TABLE *bootFxn, Int32 dataFormat, void *formatParams)
{
Uint32 entry = 0;
Uint32 value32;
Uint8dataBuf[4];
Uint16 value16;
//判断启动格式
/* Determine the data format if required */
if (dataFormat == ibl_BOOT_FORMAT_AUTO) {
(*bootFxn->peek)(dataBuf, sizeof(dataBuf));
value32 = (dataBuf[0] << 24) | (dataBuf[1] << 16) | (dataBuf[2] << 8) | (dataBuf[3] << 0);
value16 = (dataBuf[0] << 8) | (dataBuf[1] << 0);
/* BIS */
#ifndef EXCLUDE_BIS
if (value32 == BIS_MAGIC_NUMBER)
dataFormat = ibl_BOOT_FORMAT_BIS;
#endif
#ifndef EXCLUDE_COFF
if (iblIsCoff(value16))
dataFormat = ibl_BOOT_FORMAT_COFF;
#endif
#ifndef EXCLUDE_ELF
if (iblIsElf(dataBuf))
dataFormat = ibl_BOOT_FORMAT_ELF;
#endif
if (dataFormat == ibl_BOOT_FORMAT_AUTO) {
iblStatus.autoDetectFailCnt += 1;
return (0);
}
}
//激活相应文件格式
iblStatus.activeFileFormat = dataFormat;
//根据文件格式调用相应函数启动
/* Invoke the parser */
switch (dataFormat) {
#ifndef EXCLUDE_BIS
case ibl_BOOT_FORMAT_BIS:
iblBootBis(bootFxn, &entry);
break;
#endif
#ifndef EXCLUDE_COFF
case ibl_BOOT_FORMAT_COFF:
iblBootCoff(bootFxn, &entry);
break;
#endif
case ibl_BOOT_FORMAT_BTBL:
iblBootBtbl(bootFxn, &entry);
break;
#ifndef EXCLUDE_BLOB
case ibl_BOOT_FORMAT_BBLOB:
iblBootBlob(bootFxn, &entry, formatParams);
break;
#endif
#ifndef EXCLUDE_ELF
case ibl_BOOT_FORMAT_ELF:
iblBootElf(bootFxn, &entry);
break;
#endif
default:
iblStatus.invalidDataFormatSpec += 1;
break;
}
//返回函数入口地址
return (entry);
}
上述是ethboot、iblboot函数内容,中文注释是我对ethboot和iblboot的理解,按照我的理解,我找不到,ibl网络启动中是从哪里开始访问tftp服务器的。
希望工程师能够做出解答。谢谢。
zy979228369:
回复 Ryan BL:
您好,感谢您的回复,我也是最近才接触DSP,之前没有这方面的开发经验,而我们的项目时间又很紧,我想问一下您有什么bootloader开发的资料吗?如果可以的话,您能否将您的boot loader分享给我学习一下呢?我的邮箱是zy979228369@hotmail.com。非常感谢。
zy979228369:
回复 Ryan BL:
您好,我想问一下您自己写bootloader是在什么环境下编写的?如果是ccs的话,编译后的.out文件是无法直接烧写进eeprom被rbl识别的,需要转化,那么转化的工具链在哪里有呢?如果是其他环境下编写的,那么是在什么环境下编写的呢?编写后的ibl又有什么步骤能够让rbl识别运行呢?希望您能点拨一下,万分感谢。
Ryan BL:
回复 zy979228369:
e2echina.ti.com/…/159230
好像你已经看到了呢,这个是另外一个项目给FPGA转的bin(DSP的flash使用挂在fpga上面的);dsp自己固化,直接转出来烧写到对应位置就ok了。
zy979228369:
回复 Ryan BL:
非常感谢
TI中文支持网



