NXP-UU编码
2.UU编码方案
UUencode是源自UNIX环境的二进制到ASCII编码的一种形式。
UUencode取一个8位值,并将其转换为ASCII等效值。UUencode在三个8位数据字节的组上工作。如果数据字节不在三个一组中,必须添加填充字节。可以编码的最大数据字节数在一条数据线中是45个数据字节。每条数据行不能超过61个字符。
UUencode数据的数据行使用以下格式:
-
<字符长度><格式化字符><换行符>
-
- <字符长度>是一个字符,指示在线字符长度是通过在数据字节数上加32来计算的在编码发生之前传输。
- <格式化字符>是编码的数据字节。
- <换行符>指示数据字节的结束。新行用、回车和换行。
3.UUencode转换
UUencode转换的流程如下:
- 数据被细分为3字节组,形成24比特流
- 然后将24比特流细分为6比特组
- 值0x20被添加到6位组
- 如果6位组的值为0x00,则会将值0x60添加到其中
- 计算数据字节数并将其转换为ASCII等效值
如果字节数不是三的倍数,则添加填充字节以创建三的倍数。填充的字节可以是任何值,因为解码过程丢弃填充的字节。建议使用0x00的值。例如,对于由4个字节组成的有效载荷,添加两个填充字节以创建6个字节的有效载荷。每个Uuencode行不能超过61个字符/45个数据字节。
3.1 UUencode示例–三字节数据
此示例描述如何转换由0x14、0x0F和0xA8转换为UUencode流。
第一步是将数据字节转换为24比特流。
24比特流被细分为6比特组。
将值0x20添加到6位值。结果是ASCII表中的一个字符。
对于值为0x00的6位数据,与0x20相反,将值0x60添加到其中。
使用ASCII表确定与编码值关联的ASCII字符。
计算要传输的字节数,然后将其转换为ASCII相等的数据字节由3个字节组成:0x14、0x0F和0xA8。角色长度是通过在数据字节数上加32来确定的。 对于本例字符长度为“#”。
- 3 + 32 = 35 = 0x23 = “#”
发送到NXP控制器的线路为:
- #%`^H<CR><LF>
3.2. UUencode示例–4字节数据
此示例描述如何转换由0x14、0x0F、0xA8和0x17转换为UUencode流。
UUencode期望数据是3的倍数。4个字节的数据用2填充0x00的数据字节,因此它是3的倍数。
第一步是将数据字节转换为24比特流。
24比特流被细分为6比特组。
将值0x20添加到6位值。结果是ASCII表中的一个字符。
对于值为0x00的6位数据,与0x20相反,将值0x60添加到其中。
使用ASCII表确定与编码值关联的ASCII字符。
计算要传输的字节数,然后将其转换为ASCII相等的数据字节由四个字节组成,即0x14、0x0F、0xA8和0x17。这个字符长度是通过在数据字节数上加32来确定的。为此
例如,字符长度为“$”。
- 4 + 32 = 36 = 0x24 = “$”
- x(字符的长度) + 0x20 = 字符长度
发送到NXP控制器的线路为:
- $%`^H%P``
4.计算校验和
校验和是传输字节的总和。读/写时需要校验和发出命令。要发送到控制器的校验和为十进制形式。
例如,如果由0x14、0x0F和0xA8组成的数据字节要发送到
NXP控制器,校验和为:
- 0x14 + 0x0F + 0xA8 = 0xCB
0xCB的十进制等效值为203。编号203被发送到NXP控制器,作为校验和。
发送到NXP控制器的线路为:
- 203<CR><LF>
5. UART ISP示例
- 对于以下ISP示例,使用的主机是运行TeraTerm的Windows 7系统。
- UART端口设置为9600,8,N,1,XON/XOFF。
- 所使用的测试板是带有LCP1114/302的LPCXpresso基板。
- 所有UART ISP命令都应作为单个ASCII字符串发送。字符串需要以回车(CR)和换行(LF)控制字符终止。额外并且忽略<LF>字符。所有ISP响应均发送为终止ASCII字符串。数据以UU编码格式发送和接收。所有其他命令和响应采用ASCII格式。
5.1. ISP初始化
控制器必须首先进入ISP模式。对于LCP1114,这是通过在复位期间使PIO0_1引脚接地。ISP模式初始化后,主机准备用于ISP控制的控制器。
步骤如下:
- 主机发送ASCII字符“?”
- 控制器响应“已同步”
- 主机用“已同步”来确认这一点
- 控制器响应“OK”
- 主机现在发送晶体的频率(kHz)。例如发送“12000”对于12 MHz的晶体
- 控制器响应“OK”
- 如果需要,主机现在可以设置新的波特率
图. UART ISP初始化
5.2. 阅读记忆
从RAM/闪存中读取的命令格式如下:
-
R<地址><字节数>
-
- <地址>是所需的十进制地址。地址必须是单词边界。
- <字节数>是所需的字节。字节数必须是4的倍数。
当发出读取时,控制器用请求的数据进行响应,该数据编码在UUencode格式以及所请求数据的校验和。
校验和是在发送请求量的数据或20 UU编码后发送的行,以先到者为准。校验和是通过将原始数据(之前UU编码)字节,并且在发送20个UU编码行之后被重置。的长度任何UU编码行不应超过61个字符(字节),即它可以容纳45个数据字节。当数据适合小于20个UU编码行时,校验和为实际发送的字节数。
例如,要从地址0x10000000读取4个字节的数据,请执行以下操作顺序发生:
- 主机发送命令“R 268435456 4”
- 控制器通过返回代码、数据和校验和进行响应
- 如果校验和正确,主机将发送“OK”。如果校验和不正确,则发出“RESEND”命令,以便控制器可以重新发送数据
图. UART ISP从内存读取
5.3. 写入RAM
写入RAM的命令格式如下:
-
W<起始地址><字节数>
-
- <起始地址>是所需的十进制地址。地址必须是单词边界。
- <字节数>是所需的字节。字节数必须是4的倍数。
例如,将0x14、0x0F、0xA8和0x17的值写入0x10000000,则出现以下顺序:
- 主机发送命令“W 268435456 4”
- 控制器以返回代码进行响应
- 主机以UUencode格式发送数据,“$%`^H%P``”
- 主机发送校验和“226”
- 如果校验和与数据匹配,控制器将以“OK”作为响应。如果校验和不匹配,则向主机发回“RESEND”
图. UART ISP写入RAM
5.4.将RAM复制到闪存
将数据从RAM复制到闪存的命令格式如下:
-
C<闪存地址><RAM地址><字节数>:
-
- <闪存地址>是十进制的目标地址。目标地址应是256字节的边界。
- <RAM地址>是以十进制表示的源地址。
- <字节数>是所需的字节。有效值为256、512、1024和4096。
写入闪存时,以下限制适用:
- 将RAM复制到闪存可以写入闪存的最小数据量命令为256字节(等于一页)。
- 一页由16个快闪字(行)组成修改的每次闪存写入是一个闪存字(一行)。此限制来自ECC在闪存写入操作中的应用。
- 为了避免写入干扰(闪存固有的机制)应在同一页内连续写入16次之后执行。请注意,擦除操作会擦除整个扇区。
备注:一旦一个页面被写入16次,仍然可以写入其他页面在不执行扇区擦除的情况下(假设页面先前已被擦除)。
例如,为了在0x10000000处从RAM复制256个字节到0x00处的闪存出现以下顺序:
- 主机发送解锁命令“U 23130”
- 控制器以返回代码进行响应
- 主机发送Prepare Sector for write命令“P 0 0”
- 控制器以返回代码进行响应
- 主机发送复制命令“C 0 268435456 256 ”
- 控制器以返回代码进行响应
图.UART ISP将RAM复制到闪存
6. 提示和提示
UART ISP命令控制器默认情况下会回显接收到的数据。最大化UART传输的速度,回声功能可以关闭。这是通过向控制器发送a 0的命令来完成。
对于读取操作,将在每20行UUencode之后发送一个校验和。主机ISP代码应该说明这一点。对于写入操作,必须在每20个UU编码行。
RAM由ISP控制器在ISP模式下使用。避免在中使用这部分RAM ISP(如果可能的话)。请参阅控制器的用户手册,以确定RAM的块在ISP中使用。
在ISP模式下,闪存编程命令使用RAM的前32个字节。这个最大堆栈使用量为256字节,并且向下增长。
必须在进行任何闪存操作之前发出Unlock(解锁)命令。
在将RAM复制到闪存和擦除之前,必须执行“准备扇区”命令扇区命令。
7.额外资源
- 利用mbed平台在LPC1768上实现UART ISP http://mbed.org/cookbook/lpc-bootloader
- 用于LPC1100/LPC1300/LPC1700的UART ISP/LPC2000 http://sourceforge.net/projects/lpc21isp/
- Linux平台的UART ISP http://code.google.com/p/lpcflash/
- 用Python编写的UART ISP http://sourceforge.net/projects/nxpprog/
- 用Python为LPC2000系列编写的UART ISP http://sourceforge.net/projects/pylpctools/
8.程序设计
/**
* ********************************************************************************************************
* 简 述 : UU编码,将原始数据进行封装
* _pbuf : 原始缓冲数据
* _len : 数据长度
* _pcode : 发送编码函数
* 返 回 值 : 校验值
* ********************************************************************************************************
*/
uint32_t ulUUencode_Package(const uint8_t *_pbuf, uint16_t _len, void (*_pcode)(uint8_t *,uint16_t) )
{
uint8_t TxBuff[64];
uint16_t x = 0;
uint8_t y = 0;
uint8_t z = 0;
uint8_t k = 0;
uint8_t num = 0;
uint32_t check_data = 0;
for( x=0; x<_len; x+=45 )
{
k = 0;
/* 45字节 */
if( _len - x >= 45 ) num = 45;
else num = _len - x;
TxBuff[k++] = num + 32; /* 校验数据 */
for( y=0; y<num; y+=3 )
{
TxBuff[k++] = (((_pbuf[x+y]>>2) & 0x3F) + ' ') & 0x7F;
TxBuff[k++] = ((((_pbuf[x+y]<<4) & 0x30) | ((_pbuf[x+y+1] >> 4) & 0x0F)) + ' ') & 0x7F;
TxBuff[k++] = ((((_pbuf[x+y+1]<<2) & 0x3C) | ((_pbuf[x+y+2] >> 6) & 0x03)) + ' ') & 0x7F;
TxBuff[k++] = ((_pbuf[x+y+2] & 0x3F) + ' ') & 0x7F;
for( z=1; z<=4; z++)
{
if( TxBuff[k-z] == ' ' ) TxBuff[k-z] = '`';
}
}
TxBuff[k++] = '\r';
TxBuff[k++] = '\n';
_pcode( TxBuff, k );
// HAL_Delay(1);
delay_us( 750 );
}
for( x=0; x<_len; x++)
{
check_data += _pbuf[x];
}
return check_data;
}