VS-MFC:LPC2000-uart-isp软件源码分析(含UU编码)

源码:https://gitee.com/huangweide001/lpc_-uart_-isp

0.前言

这是一个基于MFC的LPC21xx系列ARM7单片机的烧录程序的源码。原来是用VC6.0开发,现在使用VS2017重新编译。年代比较久远,公开给有需要的人参考。
在这里插入图片描述

1. 几个关于LPC2000系列芯片UART ISP的基础知识

1.1 hex格式转化为bin格式

这个知识大家都知道,多数单片机都是由相应的编译器生成hex文件用于烧录器使用。

1.2 UU编码

UU编码:将3字节的数据编码成4字节的可打印的ASCII码,用于将二进制文件转换为可打印的ASCII码字符集。
下面以实例来说明编码原理:(使用0x14,0xFF,0xA7三个字节进行UU编码)
编码过程:
在这里插入图片描述
因此,UU编码后的数据范围是0x21~0x60的可打印字符,属于ASCII码字符集内;这个转换过程也意味着 uuencoded 文件要比原文件大三分之一。
UU编码的C代码:

void	Uue (unsigned char chasc[3],unsigned char chuue[4])
{//	chasc:未编码的二进制代码;chuue:编码过的Uue代码
	int i,k=2;
	unsigned char t=NULL;
	for(i=0;i<3;i++) 
	{
		*(chuue+i)=*(chasc+i)>>k;
		*(chuue+i)|=t;
		if(*(chuue+i)==NULL)	*(chuue+i)+=96;
		else					*(chuue+i)+=32;
		t=*(chasc+i)<<(8-k);
		t>>=2;
		k+=2;
	}
	*(chuue+3)=*(chasc+2)&63;
	if(*(chuue+3)==NULL) *(chuue+3)+=96;
	else				*(chuue+3)+=32;
}

1.3 在NXP的LPC21XX、LPC22XX中,规定“中断向量表中所有数据32位累加和为0,否则程序不能脱机运行。”

flash地址内容
0x0000 0000LDR PC, ResetAddr
0x0000 0004LDR PC, UndefinedAddr
0x0000 0008LDR PC, SWI_Addr
0x0000 000CLDR PC, PrefetchAddr
0x0000 0010LDR PC, DataAbortAddr
0x0000 0014检查字,使这个表中8个字的累加和为0
0x0000 0018LDR PC, IRQ_Addr
0x0000 001CLDR PC, FIQ_Addr

由于这个检查字的存在,我们在读入hex文件后,要把其他7个字相加为sum,再用0-sum得到检查字。

	//	必须将下面四个字节(检查字)改变,才能正确运行	
	data[0x14] =	data[0x15] = 	data[0x16] = 	data[0x17] = 0;
	UINT* pTemp=(UINT*)data;//	data是由hex文件转换为bin数据
	UINT Sum=0;
	for (i=0;i<8;i++)
	{
		Sum += pTemp[i];
	}
	pTemp[5]=0-Sum;

2. ISP命令及应答

2.1 命令格式

命令名称命令代码命令格式
ISP_SYNCHRONIZEd‘?’自动波特率程序同步指令
CMD_UNLOCKED‘U’解锁 <解锁代码>
CMD_SET_BAUDRATE‘B’置波特率 <波特率> <停止位>
CMD_ECHO‘A’回声 <设定>
CMD_WRITE_RAM‘W’写RAM <起始地址> <字节数>
CMD_READ_FLASH‘R’读存储器 <地址> <字节数>
CMD_GO‘G’运行 <地址> <模式>
CMD_ERASE‘E’擦除扇区 <起始扇区号> <结束扇区号>
CMD_CHECK_BLANK‘I’扇区查空 <起始扇区号> <结束扇区号>
CMD_COMPARE‘M’比较 <地址1> <地址2> <字节数>
CMD_READ_CHIP_ID‘J’读器件ID
CMD_PREPARE_WRITE‘P’准备写操作的扇区 <起始扇区号> <结束扇区号>
CMD_RAM_COPY_TO_FLASH‘C’将RAM 内容复制到Flash <Flash 地址> <RAM 地址> <字节数>
CMD_READ_BOOT_VERSION‘K’读Boot 代码版本

2.2 应答参数

应答名称应答代码含义
RSP_SUCCESS0命令被成功执行。只有当主机发出的命令被成功执行完毕后,才由ISP 处理程序发送。
RSP_INVALID_COMMAND1无效命令
RSP_SRC_ADDR_ERROR2源地址没有以字为边界
RSP_DST_ADDR_ERROR3目标地址的边界错误
RSP_SRC_ADDR_NOT_MAPPED4源地址没有位于存储器映射中。计数值必须考虑可用性。
RSP_DST_ADDR_NOT_MAPPED5目的地址没有位于存储器映射中。计数值必须考虑可用性。
RSP_COUNT_ERROR6字节计数值不是4 的倍数或是一个非法值。
RSP_INVALID_SECTOR7扇区号无效或结束扇区号大于起始扇区号。
RSP_SECTOR_NOT_BLANK8扇区非空
RSP_SECTOR_NOT_PREPARED_WRITE9为写操作准备扇区命令未执行 。
RSP_COMPARE_ERROR10源和目标数据不相等。
RSP_BUSY_FLASH11编程硬件接口忙
RSP_PARAM_ERROR12参数不足或无效参数
RSP_ADDR_ERROR13地址没有以字为边界
RSP_ADDR_NOT_MAPPED14地址没有位于存储器映射中。计数值必须考虑可用性。
RSP_CMD_LOCKED15命令被锁定
RSP_INVALID_CODE16解锁代码无效
RSP_INVALID_BAUD_RATE17无效波特率设定
RSP_INVALID_STOP_BIT18无效停止位设定
RSP_CODE_READ_PROTECTION_ENABLE19代码读保护使能

3. 烧录主流程

读入hex或者bin文件
发送?--握手指令尝试与和芯片建立联系
发送U --flash解锁指令
发送P --准备写入Flash
发送E --擦除Flash
发送W --数据写入RAM
发送C --将数据从RAM拷贝flash
发送M --比较数据

源码:

void CArmISPV1_0Dlg::OnUploadFlash() 
{	
	int		i,nSendLen,nEndBase,nBaseCount;
	CString	strResult;
	i = nSendLen = nEndBase	=nBaseCount=0;
	UpdateData(TRUE);
	//复位状态
	m_nPromgrammingStatus = enuStatus_NothingDone;
	memset(binBuf,0,sizeof(binBuf));
	if (g_hexFileName.Find(".bin") != -1){	//	bin File
		FILEReadByName(g_hexFileName,binBuf,&g_nBinTotalLen);
	}else{									//	hex File
		if(!OpenHexFile(g_hexFileName,binBuf,g_nBinTotalLen))	{		
			strResult = "打开HEX文件出错!";		
			goto	OVER;	
		}
	}
	
	i = g_nBinTotalLen%4;
	if(i)		g_nBinTotalLen += (4 - i);
	nEndBase = g_nBinTotalLen/4096;	
	if(!GetFlashSector(m_nStartSector,m_nEndSector,g_nStartBase,g_nEndEraseSector,g_nBinTotalLen))		
	{	
		MessageBox("扇区号输入有问题,Sector Number wrong!"); 
		strResult = "扇区号输入有问题,Sector Number wrong!";
		goto	OVER;
	}
	m_ProgressBar.SetRange ((unsigned short)0,(unsigned short)MAX_RANGE);
	m_ProgressBar.SetPos (0);
	if (!(ISPSynchroniz()))//m_nPromgrammingStatus||
	{		strResult = "芯片握手失败";		goto	OVER;	}	

	if(!ChangeFlash(CMD_UNLOCKED,0,0))
	{		strResult = "解锁失败!";		goto	OVER;	}
	
	if(m_nPromgrammingStatus < enuStatus_Echo)
		ChangeFlash(CMD_ECHO,0,0);
	if (!ChangeFlash(CMD_PREPARE_WRITE,g_nStartBase,g_nEndEraseSector))
	{		strResult = "准备擦除Flash失败!";		goto	OVER;	}
	
	strResult = "正在擦除Flash...";
	GetDlgItem(IDC_COM_OPEN_STATUS)->SetWindowText(strResult);
	if(!ChangeFlash(CMD_ERASE,g_nStartBase,g_nEndEraseSector))
	{		strResult = "擦除Flash失败!";		goto	OVER;	}
	
	strResult = "擦除Flash成功,开始写Flash...";
	GetDlgItem(IDC_COM_OPEN_STATUS)->SetWindowText(strResult);
	g_dwStart = GetTickCount();
	for (nBaseCount=0;nBaseCount<nEndBase;nBaseCount++)
	{
		i=3;
		while (i)
		{	
			i--;
			if(Send2RamAndCopy2Flash(4096,binBuf+4096*nBaseCount,nBaseCount,TODO_COPY))	
				break;
		}
		if(i==0)
		{			strResult = "下载Flash失败!";			goto	OVER;		}
	}
	i=3;
	while (i)
	{
		i--;
		if(Send2RamAndCopy2Flash(g_nBinTotalLen-4096*nBaseCount,
								binBuf+4096*nBaseCount,
								nBaseCount,TODO_COPY))	
								break;
	}
	if(i==0)		{	strResult = "下载Flash失败!";	goto	OVER;	}
	else			strResult = "下载Flash成功。";
	m_nPromgrammingStatus = enuStatus_FlashLoad;
	if (m_CheckAfterLoad.GetCheck ())
	{
		if(!m_bCheckComOpen.GetCheck())
			OnComOpen();
		OnCheckData ();
		goto	END_ALL;
	}
OVER:
	GetDlgItem(IDC_COM_OPEN_STATUS)->SetWindowText(strResult);
END_ALL:
	OnComClose() ;
}

4. 编译方法

使用VS2017打开项目/解决方案 《armISPV1_0.sln》。
选择自己windows中的SDK和工具集。

5. 使用说明

和官方的烧写软件使用方法几乎相同。增加一个功能:将汉字库《hzk16.bin》写入到LPC2138偏移量为128kB起始的空间。《hzk16.bin》大小约为260kB。

7ee7da2d-dde0-4b21-aa41-37bc654fb190

posted @ 2023-03-21 17:03  汉塘阿德  阅读(83)  评论(0编辑  收藏  举报  来源