前言
最近需要做个从emmc启动的程序测试,实际应用中,emmc的数据内容肯定是从tcp传输过来,不多说,往下看了。
一、前期准备
板子使用原子哥的领航者V1,在vivado中勾选SD1,保存设计后执行“Generate Output Products”导出export hardware并导入SDK,SDK中创建应用工程,NEW一个新的Appliation Project,选择lwip echo的示例,并在BSP下的Board Support Package Sttings下勾选xilffs(emmc需要使用到),并且修改lwip的设置:大致如下:
保存,选择OK,等待更新完毕。
二、软件
1.大致思路
对于emmc,先初始化以及挂载成功,此部分这里省略。 对于lwip,它的官方例程可以直接拿来使用,把轮询模式修改为中断接收数据模式,然后在回调函数中做相应的数据处理即可。 由于实际应用中,tcp客户端需要不断的和服务端通讯,主程序收到客户端的命令不可能在中断回调中完成(影响效率),所以只在中断回调函数中做简单的数据处理,命令的实际处理放在主程序中执行。
2.部分代码
typedef struct _Head{
unsigned short uHeader;
unsigned short uHeader1;
unsigned short uCmd;
unsigned short uCmdReverse;
unsigned int nLenth;
}Head_T;
err_t recv_callback(void *arg, struct tcp_pcb *tpcb,struct pbuf *p, err_t err)
{
int nLen = 0,i = 0;
char *pRev = NULL;
static int nSumLen = 0;
struct pbuf *q;
char cCopyflag = FALSE;
pRev = (char *)RECEIVE_BUF;
if(!cCopyflag)
{
nLen = 4;
uint16_t *pHead =(unsigned short *)&tCmdHead;
while(nLen--)
{
*(pHead + i) = *((unsigned short *)(p->payload)+i);
i++;
}
tCmdHead.wLenthInt = *((int *)(p->payload)+2);
}
if(cCopyflag)
{
memcpy((uint8_t *)(pLinuxRev+nSumLen), p->payload, p->len);
nSumLen += p->len;
}
if((tCmdHead.uCmd == 0x01) && (cCopyflag == FALSE) && (wLwipCmdState == NULL_CMD)){
cCopyflag = TRUE;
memcpy((uint8_t *)(pLinuxRev+nSumLen), ((unsigned short *)(p->payload+6)), (p->len - 12));
nSumLen += (p->len-12);
}
if(nSumLen == tCmdHead.wLenthInt)
{
cCopyflag = FALSE;
nSumLen = 0;
wLwipCmdState = NEW_CMD;
}
tcp_recved(tpcb, p->len);
}
void main(void)
{
char *pRev = NULL;
if(wLwipCmdState == NEW_CMD)
{
switch(tCmdHead.uCmd)
{
case 0x01:
pRev = (char *)RECEIVE_BUF;
eMMCWrite("program",(u32)pRev,tCmdHead.wLenthInt);
wLwipCmdState = NULL_CMD;
tCmdHead.uCmd = 0;
break;
default: Aprintf("ERROR CMD!!!\r\n");break;
}
}
}
验证的时候,SDK用FSBL生成bin文件,然后用UltraEdit工具的十六进制编辑模式,把数据头添加进bin文件中,如图 程序烧写至开发板,这里不做过多说明 然后用网络调试助手,连接好TCP客户端 选择打开文件数据源,选择bin文件,点击发送,即可实现远程更新emmc程序
总结
用emmc启动还是很实用的
|