采用UDP协议的PIC32MZ ethernet bootloader
了解更多关于bootloader 的C语言实现,请加我QQ: 1273623966 (验证信息请填 bootloader),欢迎咨询或定制bootloader(在线升级程序)。
经过千辛万苦,今天终于完工PIC32MZ EC Starter Kit的ethernet bootloader项目。我将整个项目, 命名为PhnBootloader。它分为两个部分。第一个部分是PC 端的host程序PhnLoader_v3.0。另一部分是单片机端boot程序PhnBoot_v3.0,是从Microchip AN1388 ethernet bootloader移植过来的。整个移植过程碰到很多困难,主要是由于ethernet bootloader使用到Microchip 的TCP/IP Stack,但是TCP/IP Stack不支持PIC32MZ。 这里我列出移植需要注意的地方:
1. PIC32MZ默认enable cache.
2. PIC32MZ ethernet module ports mapping
3. PIC32MZ EC Starter Kit的external PHY的LEDs和Start Kit的LED1,LED2复用
4. PIC32MZ EC Starter Kit的ethernet module有些port复用AN功能。
5. ethernet bootloader download完application后,跳转到application前 ,注意要清零所有使用到的register,包括disable interrupt。
PhnLoader_v3.0和PhnBoot_v3.0之间采用UDP协议通信,通信数据包格式采用以下协定:
<STX><CMD><ADDRL><ADDRH><ADDRU><ADDRM><LEN><DATA>...<DATA><ETX>
STX - Start of packet indicator
ETX - End of packet indicator
LEN - The length of true data
DATA - General data 16 bytes, only first LEN of datas are true
CMD - Base command
ADDR - Address up to 32 bits ( ADDRL , ADDRH , ADDRH, ADDRM)
具体有以下Base command:
RD-VER: 0x00 -- Read Version Information (最终版本未实现)
RD_MEM: 0x01 -- Read Program Memory (最终版本未实现)
ER_MEM: 0x03 -- Erase Program Memory
WR_MEM: 0x02 -- Write Program Memory
WR_CFG: 0x04 -- Write Configuration Registers (最终版本未实现)
PhnLoader_v3.0
PhnLoader_v3.0 是PC端host 程序。
运行环境:Window + .NET Framework 4.5
开发语言:C#
通信类型:UDP Server
IP 地址: 192.168.1.105
端口号: 8720
UI 如下图:
C#源代码主要部分:
try
{
while (loaderReader.Peek() >= 0)
{
pBarLoading.PerformStep();
recordLine = loaderReader.ReadLine(); if (recordLine.Contains(EXTEND_TOKEN) == true)
{
if (recordLine.Contains(USER_ID_TOKEN) == true)
{
isNextLineUserID = true;
continue;
}
//else if (recordLine.Contains(CONFIG_BITS_TOKEN) == true)
//{
// const int ADDR_U_START_INDEX = 9;
// const int ADDR_U_LENGTH = 4;
// string addrU = recordLine.Substring(ADDR_U_START_INDEX, ADDR_U_LENGTH);
// loaderUpperAddr = Convert.ToInt32(addrU, 16) << 16;
// isNextLineConfigBits = true;
// continue;
//}
else if (recordLine.Contains(PIC32_CONFIG_BITS_TOKEN) == true)
{
const int ADDR_U_START_INDEX = 9;
const int ADDR_U_LENGTH = 4;
string addrU = recordLine.Substring(ADDR_U_START_INDEX, ADDR_U_LENGTH);
loaderUpperAddr = Convert.ToInt32(addrU, 16) << 16;
isNextLineConfigBits = true;
continue;
}
else
{
const int ADDR_U_START_INDEX = 9;
const int ADDR_U_LENGTH = 4;
string addrU = recordLine.Substring(ADDR_U_START_INDEX, ADDR_U_LENGTH);
loaderUpperAddr = Convert.ToInt32(addrU, 16) << 16;
continue;
}
}
else if (recordLine.Contains(END_OF_HEX_FILE_TOKEN) == true)
{
break;
}
if (isNextLineUserID)
{
isNextLineUserID = false;
// do nothing;
}
else if (isNextLineConfigBits)
{
//if (!DownloadConfigLine(recordLine))
//{
// Debug.WriteLine("Error found during configuration bits programming");
// loaderReader.Close();
// loaderServer.Close();
// btnDownload.Enabled = true;
// return;
//}
DownloadConfigLine(recordLine);
isNextLineConfigBits = false;
}
else
{
if (!DownloadDataLine(recordLine))
{
Debug.WriteLine("Error found during data programming");
loaderReader.Close();
loaderServer.Close();
btnDownload.Enabled = true;
return;
}
}
}
}
catch (Exception ex)
{
Debug.WriteLine("Error: " + ex.Message);
textBoxStatus.ForeColor = Color.Red;
textBoxStatus.AppendText("Downloading failed\r\n");
textBoxStatus.ForeColor = Color.Black;
loaderServer.Close();
loaderReader.Close();
btnDownload.Enabled = true;
return;
}
PhnBoot_v3.0
PhnBoot_v3.0 是单片机端Boot 程序。
运行环境:PIC32MZ EC Starter Kit
开发语言:C 语言 (Microchip XC32编译)
通信类型:UDP Client
IP 地址: 192.168.1.123
端口号: 8740
主要代码段:
switch (GenUDPSt)
{
case SM_HOME:
ARPResolve(&ServerNode.IPAddr);
startTime = TickGet();
GenUDPSt++;
break;
case SM_ARP:
if (TickGet() - startTime < 5*TICK_SECOND)
{
if (ARPIsResolved(&ServerNode.IPAddr,&ServerNode.MACAddr))
{
MySock = UDPOpen(LOCAL_CLIENT_PORT,&ServerNode,REMOTE_SERVER_PORT);
startTime = TickGet();
GenUDPSt++;
}
}
else
{
GenUDPSt = SM_HOME;
}
break;
case SM_UDPOPEN:
if (TickGet() - startTime < TICK_SECOND)
{
if (MySock != INVALID_UDP_SOCKET)
{
startTime = TickGet();
GenUDPSt++;
}
}
else
{
GenUDPSt = SM_HOME;
}
break;
case SM_UDPPUT:
if (TickGet() - startTime < 5*TICK_SECOND)
{
if (UDPIsPutReady(MySock) > BUFFER_MAX)
{
UDPPutString(ok);
UDPFlush();
GenUDPSt++;
}
}
else
{
GenUDPSt = SM_CLOSE;
}
break;
case SM_UDPGET:
if (TickGet() - startTime < 5*TICK_SECOND)
{
udpPackets = UDPIsGetReady(MySock);
if (udpPackets >= BUFFER_MAX)
{
UDPGetArray(frameBuffer, BUFFER_MAX);
UDPDiscard();
if (frameBuffer[0] == STX && frameBuffer[BUFFER_MAX - 1] == ETX)
{
Uart_Putc('.');
for(i=0;i<BUFFER_MAX;i++)
{
printf("%02x",frameBuffer[i]);
}
printf("%02x",frameBuffer[CMD_INDEX]);
printf("\r\n");
switch (frameBuffer[CMD_INDEX])
{
case WR_MEM:
//printf("<");
SourceAddr.byte.LB = frameBuffer[ADDRL_INDEX];
SourceAddr.byte.HB = frameBuffer[ADDRH_INDEX];
SourceAddr.byte.UB = frameBuffer[ADDRU_INDEX];
SourceAddr.byte.MB = frameBuffer[ADDRM_INDEX];
int ix;
for (ix=0;ix<frameBuffer[LEN_INDEX];)
{
pData.byte.LB = frameBuffer[LEN_INDEX+1+ix++];
pData.byte.HB = frameBuffer[LEN_INDEX+1+ix++];
pData.byte.UB = frameBuffer[LEN_INDEX+1+ix++];
pData.byte.MB = frameBuffer[LEN_INDEX+1+ix++];
NVMWriteWord(SourceAddr.Val, pData.Val);
SourceAddr.Val += 4;
}
break;
case WR_CFG:
break;
case ER_MEM:
for (EraseAddr.Val = ERASE_FLASH_BASE_ADDRESS; EraseAddr.Val < ERASE_FLASH_END_ADDRESS;)
{
NVMErasePage(EraseAddr.Val);
EraseAddr.Val += PAGE_SIZE;
}
break;
case RUN_APP:
GenUDPSt = SM_CLOSE;
break;
default:
break;
}
startTime = TickGet();
if (GenUDPSt == SM_UDPGET) GenUDPSt = SM_RESPONCE;
}
}
}
else
{
GenUDPSt = SM_CLOSE;
}
break;
case SM_RESPONCE:
if (TickGet() - startTime < 10*TICK_SECOND)
{
if (UDPIsPutReady(MySock) >= BUFFER_MAX)
{
UDPPutArray(frameBuffer, BUFFER_MAX);
UDPFlush();
}
startTime = TickGet();
GenUDPSt = SM_UDPGET;
}
else
{
printf("xx"); // for debug
GenUDPSt = SM_CLOSE;
}
break;
case SM_CLOSE:
printf("done\r\n"); // for debug
UDPClose(MySock);
MySock = INVALID_UDP_SOCKET;
GenUDPSt = SM_HOME;
TRISCSET = 0x2000; // RC13 Input
LATCCLR = 0x6000; // Clear LATC
LATHCLR = (1<<2);
TRISHSET = (1<<2);
INTDisableInterrupts();
T1CON = 0;
ETHCON1 = 0;
ETHCON2 = 0;
CoreT_DelayMs(1);
U1MODE = 0x0;
U1STA = 0x0;
(*((void(*)(void))USER_APP_RESET_ADDRESS))();
break;
}
如何使用PhnLoader_v3.0和PhnBoot_v3.0
1. 使用XC32编译PhnBoot_v3.0(编译前,需先修改linker script)。
2. 使用pickit3烧录PhnBoot_v3.0的Hex文件到目标板中。
3. 拔除pickit3烧录器
4. 连接目标板和PC到同一局域网,设置PC的IP地址,打开PhnLoader_v3.0,选择UDP协议,端口号,IP地址。
5. 点击PhnLoader_v3.0用户界面上的“.."按钮加载需要烧录的应用程序Hex文件(编译前,需先修改linker script)
6. 重启目标板,等到LED3 灯亮了,立刻在PhnLoader_v3.0界面上点击Download按钮。如果超时未点击Download按钮,会自动跳转到上次烧录的应用程序中去。
7. 烧录完毕,再次重启目标板, 数秒后目标板开始正常运行应用程序。
之后每次更新应用程序,只需重复步骤 4 ~ 7 就可以了。注意,整个烧录过程未能实现User ID/Configuration Bits的烧写,所以需要保持应用程序的Configuration Bits和Bootloader的Configuration Bits一致。
采用UDP协议的PIC32MZ ethernet bootloader的更多相关文章
- 采用TCP协议的PIC32MZ ethernet bootloader
了解更多关于bootloader 的C语言实现,请加我QQ: 1273623966 (验证信息请填 bootloader),欢迎咨询或定制bootloader(在线升级程序). 趁热打铁,在上一PIC ...
- 采用UDP协议实现PIC18F97J60 ethernet bootloader
了解更多关于bootloader 的C语言实现,请加我QQ: 1273623966 (验证信息请填 bootloader),欢迎咨询或定制bootloader(在线升级程序). TCP/IP Stac ...
- 采用TCP协议实现PIC18F97J60 ethernet bootloader
了解更多关于bootloader 的C语言实现,请加我QQ: 1273623966 (验证信息请填 bootloader),欢迎咨询或定制bootloader(在线升级程序). TCP/IP Stac ...
- 在网络7层协议中,如果想使用UDP协议达到TCP协议的效果,可以在哪层做文章?(QQ 为什么采用 UDP 协议,而不采用 TCP 协议实现?)
为了解决这题,可以具体看看下面这个讨论. 解灵运工程师 185 人赞同 某次架构师大会上那个58同城做即时通信的人说:原因是因为当时没有epoll这种可以支持成千上万tcp并发连接的技术,所以他们使用 ...
- Java开发笔记(一百一十六)采用UDP协议的Socket通信
前面介绍了如何通过Socket接口传输文本与文件,在示例代码中,Socket客户端得先调用connect方法连接服务端,确认双方成功连上后才能继续运行后面的代码,这种确认机制确保客户端与服务端的的确确 ...
- QQ--基于TCP/UDP协议的通讯原理
QQ是一个基于TCP/UDP协议的通讯软件 发送消息的时候是UDP打洞,登陆的时候使用HTTP~因为登陆服务器其实就是一个HTTP服 务器,只不过不是常用的那些,那个服务器是腾讯自行开发的! 一 ...
- QQ 为什么以 UDP 协议为主,以 TCP 协议为辅?
QQ既有UDP也有TCP!不管UDP还是TCP,最终登陆成功之后,QQ都会有一个TCP连接来保持在线状态.这个TCP连接的远程端口一般是80,采用UDP方式登陆的时候,端口是8000. UDP协议是无 ...
- java ->网络通信协议(UDP协议、TCP协议)
网络通信协议 通过计算机网络可以使多台计算机实现连接,位于同一个网络中的计算机在进行连接和通信时需要遵守一定的规则,这就好比在道路中行驶的汽车一定要遵守交通规则一样.在计算机网络中,这些连接和通信的规 ...
- 接口与协议学习笔记-Ethernet UDP通信协议(一)
总线(BUS,即公共汽车,数据的公共传输路线)分类的方式有很多,如被分为外部和内部总线.系统总线和非系统总线等等,下面是几种最常用的分类方法.另外,总线的传输核心思想是多路复用:时分多路复用-TDMA ...
随机推荐
- PHP常用的文件操作函数集锦
以下是个人总结的PHP文件操作函数.当然,这只是部分,还有很多,我没有列出来. 一 .解析路径: 1 获得文件名:basename();给出一个包含有指向一个文件的全路径的字符串,本函数返回基本的文件 ...
- css3 animation-fill-mode 对布局的影响
问题描述:在小米手机上,animation-fill-mode设置为 both时,在手机上的web页面会超出屏幕宽度,出现滚动条. 解决方法:animation-fill-mode设为none. .p ...
- Saying that Java is nice because it works on every OS is like saying that anal sex is nice because it works on every gender.
Saying that Java is nice because it works on every OS is like saying that anal sex is nice because i ...
- Android数据库的运用
很简单的应用,所以我直接简单明了. android中数据库的运用: 1.定义类继承SQLiteOpenHelper ps: public class DBHelper exten ...
- 工程中建立多个src目录
android 工程下可以有多个源代码的目录,不一定都要放到src下面.可以在 .classpath 文件中添加. 默认是这样的: <classpath> <classpathent ...
- Elasticsearch mysql 增量同步 三表联合 脚本
在上一篇中简略的说了一下es同步数据脚本的大致情况,但是实际情况里肯定不会像上一篇里面的脚本那么简单.比如目前我就有三张表,两张实体表,一张关联表.大致实现如下: bin目录建立一个statefile ...
- ( C++) Access the hard drive.
// Open up the volume HANDLE hVolume = CreateFile(wstrPath, GENERIC_READ, FILE_SHARE_READ | FILE_SHA ...
- html中空格转义字符
记录一下,空格的转义字符分为如下几种: 平时一般用的是 1. &160#;不断行的空白(1个字符宽度) 2. &8194#;半个空白(1个字符宽度) 3. &8195# ...
- vue.js 2.0开发(2)
如果我们想实时的显示我们todos的长度这个业务逻辑可以这样: <h1>{{message}} ({{todos.length}})</h1> 直接展示todos的length ...
- 使用Jenkins可持续集成maven项目
首先下载最新的Jenkins的war包,放在tomcat的webapps的目录下,然后运行,例如: http://121.42.62.45:8080/jenkins/ 然后按照一步步的提示,下载相关的 ...