【飞思卡尔 MC9S12】BootLoader 上位机
本篇讲述BootLoader上位机开发。
Bootloader上位机、下位机以及用户App 范例源码:https://gitee.com/beatfan/freescale_mc9s12xep100_-bootloader.git
此上位机采用WPF框架,C#语言开发,支持周立功的CAN设备和ValueCAN。
由于手头上暂时没有硬件,无法实际演示,大家先凑合看示例图。
注意,有很多人操作误区在于,将S19文件选择成了Bootloader,这里应该选择app,就是你自己的应用程序。
Bootloader与App分别占用2个非分页区。
Bootloader: 0xC000-0xFFFF(实际到0xF7FF,保留一个sector给vector table)
Application: 0x4000-0x7FFF,加上其它分页区(转换成全局地址为0x7F4000-0x7FFFF)
若是不知道怎么写App,可参考范例


BootloaderPage.xaml -- Bootloader刷写界面
S19ParseWithText -- 为S19文件解析查看界面,仅用于查看数据,与刷写无关
ClassBootloaderForCAN -- 协议封包解包在
CANCommon -- 通用的CAN连接断开、发送接收的类(实际收发在CANDevices类库,大家也可以添加自己手上以后的CAN设备的API,以便于支持)
VAlueCAN和ZlgCAN.xaml -- CAN配置控件,用于设置各个不同的CAN配置参数,方便转换成通用的例如波特率的参数。

/// <summary>
/// 更新进度
/// </summary>
void UpdateProgress()
{
double percentNoDiv100 = m_CmdCount.SendFrameCount * 100.00 / m_CANSendFrameCount;// e.ProgressPercentage;// m_CmdCount.SendFrameCount * 1.0 / m_CANdataList.Count;
double usedTime = DateTime.Now.Subtract(m_SendDataSartTime).TotalSeconds;
double leftTime = usedTime / percentNoDiv100 * (100 - percentNoDiv100);
//TextBlockChangeMsg("发送进度", "已发送帧数:" + m_CmdCount.SendFrameCount.ToString(), System.Windows.Media.Brushes.Gray);
TextBlockChangeMsg("刷写进度", "已刷写帧数: " + m_CmdCount.ReceiveFrameCount.ToString() + " ,已用时间:" + usedTime.ToString("0.00") + " s ,剩余时间:" + leftTime.ToString("0.00") + " s", System.Windows.Media.Brushes.Gray);
ProcessUpdate(percentNoDiv100);
}
/// <summary>
/// 开始烧录
/// </summary>
void TryBurnS19()
{
//SendData();
//return;
DateTime startTime;
ProcessUpdate(0); //进度清零
TextBlockAddMsg("检查是否已擦除Flash", System.Windows.Media.Brushes.Black);
m_Mtcl1DevelopCmd.SendNormalBytes(m_UpdateAppSendCmdCANID, GetCurrentCANIndex(),m_CanDataParse.CanErasePackage(m_ValidMinGlobalAddr, m_ValidMaxGlobalAddr));
startTime = DateTime.Now; //开始计时
while (m_McuState != McuState.McuFlashErased)
{
uint count = 0;
while (count < 100000)
count++;
if (DateTime.Now.Subtract(startTime).TotalSeconds > 10) //是否超过10s没有接收到
break;
}
if (m_McuState != McuState.McuFlashErased)
{
TextBlockAddMsg("擦除超时", System.Windows.Media.Brushes.Red, 1);
BurnHex();
return;
}
string ts = DateTime.Now.Subtract(startTime).TotalSeconds.ToString();
TextBlockAddMsg("擦除完毕!,总耗时:" + ts + "s", System.Windows.Media.Brushes.Blue);
TextBlockAddMsg("开始发送数据,CAN帧数;" + m_CANSendFrameCount.ToString(), System.Windows.Media.Brushes.Black);
//m_UpdateProgressTimer.Start(); //定时更新UI
SendData(); //发送数据
//m_UpdateProgressTimer.Stop(); //关闭定时更新UI
UpdateProgress();
TextBlockAddMsg("发送数据结束,耗时: " + DateTime.Now.Subtract(m_SendDataSartTime).TotalSeconds.ToString("0.00") + "s", System.Windows.Media.Brushes.Black);
m_Mtcl1DevelopCmd.SendNormalBytes(m_UpdateAppSendCmdCANID, GetCurrentCANIndex(), m_CanDataParse.g_DataEndCmd); //数据结束命令
BurnHex();
}
/// <summary>
/// 发送后检查是否超时或错误
/// </summary>
/// <returns></returns>
bool CheckAfterSend()
{
if (!SendDataCheck_Wait(ref m_CmdCount.SendFrameCount, ref m_CmdCount.ReceiveFrameCount, 2000)) //发送中断
{
TextBlockAddMsg("发送超时 ", System.Windows.Media.Brushes.Red);
return false;
}
if (m_ReponseState != ClassBootloaderForCAN.ReponseState.CmdRunOK)
return false;
return true;
}
/// <summary>
/// 发送数据
/// </summary>
private void SendData()
{
m_CmdCount.SendLineCount = 0;
m_CmdCount.SendFrameCount = m_CmdCount.ReceiveFrameCount = 0;
m_SendDataSartTime = DateTime.Now; //开始计时
bool isNotBreak = true;
//发送数据
for (int i = 0; i < m_CANAddrList.Count && isNotBreak; i++)
{
m_Mtcl1DevelopCmd.SendNormalBytes(m_UpdateAppSendCmdCANID, GetCurrentCANIndex(), m_CANAddrList[i]); //发送地址命令
m_CmdCount.SendLineCount++;
m_CmdCount.SendFrameCount++;
if (!CheckAfterSend() ) //发送中断
{
isNotBreak = false;
break;
}
for (int j=0;j<m_CANdataListList[i].Count && isNotBreak; j++)
{
m_Mtcl1DevelopCmd.SendNormalBytes(m_UpdateAppSendDataCANID, GetCurrentCANIndex(), m_CANdataListList[i][j]); //发送数据
m_CmdCount.SendFrameCount++;
if (!CheckAfterSend()) //发送中断
{
isNotBreak = false;
break;
}
}
if(m_CmdCount.SendLineCount%10==0)
UpdateProgress();
}
}
/// <summary>
/// 检查接收情况
/// </summary>
/// <returns></returns>
bool CheckReceive(ref byte[] datas)
{
m_ReponseState = ProcessReponseState(ref datas); //获取返回状态
switch (m_ReponseState)
{
case ClassBootloaderForCAN.ReponseState.AddressChecksumError:
case ClassBootloaderForCAN.ReponseState.AddressOverRange:
case ClassBootloaderForCAN.ReponseState.DataChecksumError:
case ClassBootloaderForCAN.ReponseState.EraseFailed:
case ClassBootloaderForCAN.ReponseState.FlashProgramFailed:
TextBlockAddMsg("错误: " + Enum.GetName(typeof(ClassBootloaderForCAN.ReponseState), m_ReponseState), System.Windows.Media.Brushes.Red);
return false;
default: break;
}
return true;
}
/// <summary>
/// 获取返回数据的状态
/// </summary>
/// <param name="datas"></param>
/// <returns></returns>
private ClassBootloaderForCAN.ReponseState ProcessReponseState(ref byte[] datas)
{
return (ClassBootloaderForCAN.ReponseState)(datas[1]);
}
/// <summary>
/// 接收数据,回调函数
/// </summary>
private void ReceiveData(uint canId, string canIndex,byte[] datas)
{
if (canId==m_UpdateAppReceiveCmdCANID) //命令id
{
if (!CheckReceive(ref datas)) //收到错误报告
return;
//判断回馈类型
ClassBootloaderForCAN.CmdType cmdType = m_CanDataParse.ReceiveDataParse(ref datas);
//TextBlockAddMsg("ReceiveData:"+BitConverter.ToString(datas), System.Windows.Media.Brushes.DarkOrange);
switch (cmdType)
{
case ClassBootloaderForCAN.CmdType.EntryBootloader: //已经入Bootloader
if (m_McuState == McuState.WaitForBootloader)
m_McuState = McuState.InBootloader;
BootloaderIndicator(true);
TextBlockAddMsg("成功进入Bootloader," + datas[2].ToString() + "s内无操作进入用户程序!", System.Windows.Media.Brushes.Blue);
break;
case ClassBootloaderForCAN.CmdType.CheckBootloader: //检查是否处于Bootloader
if (m_McuState == McuState.WaitForBootloader)
m_McuState = McuState.InBootloader;
BootloaderIndicator(true);
//TextBlockAddMsg("成功进入Bootloader," + datas[2].ToString() + "s内无操作进入用户程序!", System.Windows.Media.Brushes.Blue);
break;
case ClassBootloaderForCAN.CmdType.LeaveBootloader: //离开Bootloader
//m_McuState = McuState.BurnEnd;
BootloaderIndicator(false);
TextBlockAddMsg("Bootloader已断开", System.Windows.Media.Brushes.Blue);
break;
case ClassBootloaderForCAN.CmdType.Reset:
//m_McuState = McuState.BurnEnd;
BootloaderIndicator(false);
TextBlockAddMsg("重启!", System.Windows.Media.Brushes.Blue);
break;
case ClassBootloaderForCAN.CmdType.Erase:
if (m_McuState == McuState.InBootloader)
m_McuState = McuState.McuFlashErased;
break;
case ClassBootloaderForCAN.CmdType.SendAddress:
m_CmdCount.ReceiveFrameCount++;
break;
case ClassBootloaderForCAN.CmdType.DataEnd:
if (m_McuState == McuState.Burnning)
m_McuState = McuState.BurnEnd;
//m_CmdCount.ReceiveFrameCount++;
TextBlockAddMsg("用户程序刷新完毕!", System.Windows.Media.Brushes.Blue);
break;
case ClassBootloaderForCAN.CmdType.Other:
TextBlockAddMsg("Receive Other: " + BitConverter.ToString(datas), System.Windows.Media.Brushes.DarkOrange);
break;
default: break;
}
}
else //返回数据回应
{
//判断回馈类型
if(m_CanDataParse.ReceiveDataParse(ref datas)==ClassBootloaderForCAN.CmdType.SendData)
{
if (m_McuState == McuState.McuFlashErased)
m_McuState = McuState.Burnning;
m_CmdCount.ReceiveFrameCount++;
}
}
}
浙公网安备 33010602011771号