📄 isp.c
字号:
/* execute update code,the address is maybe 0xe000 */
#include "LPC23xx.h"
#include "type.h"
#include "target.h"
#include "irq.h"
#include "uart.h"
#define IAP_LOCATION 0x7FFFFFF1 //IAP入口地址定义
//IAP命令
//指令 参数
#define IAP_CMD_PREPARE 50 //选择扇区 【起始扇区号、结束扇区号】
#define IAP_CMD_COPY 51 //拷贝数据 【FLASH目标地址、RAM源地址、写入字节数、系统时钟频率】
#define IAP_CMD_ERASE 52 //擦出扇区 【起始扇区号、结束扇区号、系统时钟频率】
#define IAP_CMD_CHECK 53 //查空扇区 【起始扇区号、结束扇区号】
#define IAP_CMD_ID 54 //读器件ID 【无】
#define IAP_CMD_VERSION 55 //读BOOT版本号 【无】
#define IAP_CMD_COMPARE 56 //比较命令 【FLASH起始地址、RAM起始地址、需要比较的字节数】
#define ISP_PC_NOUPDATE 0x20
#define ISP_PC_UPDATE 0x21
#define ISP_PC_DOWNLOAD 0x22
#define ISP_PC_FILE_LEN 0x23
#define ISP_MCU_UPDATE_OK 0x24
#define ISP_MCU_UPDATE_FAIL 0x25
//IAP返回状态字
#define IAP_RET_CMD_SUCCESS 0
#define IAP_RET_INVALID_COMMAND 1
#define IAP_RET_SRC_ADDR_ERROR 2
#define IAP_RET_DST_ADDR_ERROR 3
#define IAP_RET_SRC_ADDR_NOT_MAPPED 4
#define IAP_RET_DST_ADDR_NOT_MAPPED 5
#define IAP_RET_COUNT_ERROR 6
#define IAP_RET_INVALID_SECTOR 7
#define IAP_RET_SECTOR_NOT_BLANK 8
#define IAP_RET_SECTOR_NOT_PREPARED_FOR_WRITE_OPERATION 9
#define IAP_RET_COMPARE_ERROR 10
#define IAP_RET_BUSY 11
// 定义CCLK值大小,单位为KHz
#define IAP_FCCLK 12000
volatile DWORD UART0Status, UART1Status;
volatile BYTE UART0TxEmpty = 1;
volatile BYTE *UART0Buffer;
volatile DWORD UART0Count = 0;
// 定义函数指针
void (*IAP_Entry)(DWORD param_tab[], DWORD result_tab[]);
DWORD command[8]; // IAP入口参数缓冲区
DWORD result[8]; // IAP出口参数缓冲区
void LedPort(char state)
{
PINSEL7 &= 0xFF00FFFF; //config P3.24-P3.27 as GPIO
FIO3DIR |= 0x0F000000; //make P3.24-P3.27 as output
FIO3MASK &= ~(0xF << 24);
FIO3PIN = (FIO3PIN & 0xF0FFFFFF)|(state &0x0F)<<24 ;
FIO3MASK |= 0xF << 24;
}
/*
*********************************************************************************************************
** 函数名称:SelSector()
** 函数功能:IAP操作扇区选择,命令代码50。
** 入口参数:sec1 起始扇区
** sec2 终止扇区
** 出口参数:IAP操作状态码
** IAP返回值(result缓冲区)
*******************************************************************************************************
*/
DWORD SelSector(BYTE sec1, BYTE sec2)
{
command[0] = IAP_CMD_PREPARE; // 设置命令字
command[1] = sec1; // 设置参数
command[2] = sec2;
(*IAP_Entry)(command, result); // 调用IAP服务程序
return(result[0]); // 返回状态码
}
/*
*******************************************************************************************************
** 函数名称:RamToFlash()
** 函数功能:复制RAM的数据到FLASH,命令代码51。
** 入口参数:dst 目标地址,即FLASH起始地址。以512字节为分界
** src 源地址,即RAM地址。地址必须字对齐
** no 复制字节个数,为512/1024/4096/8192
** 出口参数:IAP操作状态码
** IAP返回值(result缓冲区)
*******************************************************************************************************
*/
DWORD RamToFlash(DWORD dst, DWORD src, DWORD no)
{
command[0] = IAP_CMD_COPY; // 设置命令字
command[1] = dst; // 设置参数
command[2] = src;
command[3] = no;
command[4] = IAP_FCCLK;
(*IAP_Entry)(command, result); // 调用IAP服务程序
return(result[0]); // 返回状态码
}
/*
*******************************************************************************************************
** 函数名称:EraseSector()
** 函数功能:扇区擦除,命令代码52。
** 入口参数:sec1 起始扇区
** sec2 终止扇区
** 出口参数:IAP操作状态码
** IAP返回值(result缓冲区)
*******************************************************************************************************
*/
DWORD EraseSector(BYTE sec1, BYTE sec2)
{
command[0] = IAP_CMD_ERASE; // 设置命令字
command[1] = sec1; // 设置参数
command[2] = sec2;
command[3] = IAP_FCCLK;
(*IAP_Entry)(command, result); // 调用IAP服务程序
return(result[0]); // 返回状态码
}
/*
*******************************************************************************************************
** 函数名称:BlankCHK()
** 函数功能:扇区查空,命令代码53。
** 入口参数:sec1 起始扇区
** sec2 终止扇区
** 出口参数:IAP操作状态码
** IAP返回值(result缓冲区)
*******************************************************************************************************
*/
DWORD BlankCHK(BYTE sec1, BYTE sec2)
{
command[0] = IAP_CMD_CHECK; // 设置命令字
command[1] = sec1; // 设置参数
command[2] = sec2;
(*IAP_Entry)(command, result); // 调用IAP服务程序
return(result[0]); // 返回状态码
}
/*
*******************************************************************************************************
** 函数名称:ReadParID()
** 函数功能:扇区查空,命令代码53。
** 入口参数:无
** 出口参数:IAP操作状态码
** IAP返回值(result缓冲区)
*******************************************************************************************************
*/
DWORD ReadParID(void)
{
command[0] = IAP_CMD_ID; // 设置命令字
(*IAP_Entry)(command, result); // 调用IAP服务程序
return(result[0]); // 返回状态码
}
/*
*******************************************************************************************************
** 函数名称:Compare()
** 函数功能:校验数据,命令代码56。
** 入口参数:dst 目标地址,即RAM/FLASH起始地址。地址必须字对齐
** src 源地址,即FLASH/RAM地址。地址必须字对齐
** no 复制字节个数,必须能被4整除
** 出口参数:IAP操作状态码
** IAP返回值(result缓冲区)
*******************************************************************************************************
*/
DWORD Compare(DWORD dst, DWORD src, DWORD no)
{
command[0] = IAP_CMD_COMPARE; // 设置命令字
command[1] = dst; // 设置参数
command[2] = src;
command[3] = no;
(*IAP_Entry)(command, result); // 调用IAP服务程序
return(result[0]); // 返回状态码
}
int main(void)
{
DWORD err;
BYTE fileCount0;
BYTE fileCount1;
BYTE fileCount2;
BYTE fileCount3;
DWORD fileCount;
//1. 确定更新的情况下,擦除对应代码区域
IAP_Entry = (void(*)())IAP_LOCATION; //初始化函数指针
SelSector(0x1,0x1); // 选择扇区1
EraseSector(0x1,0x1); // 擦除扇区1 (4k)
BlankCHK(0x1,0x1) ; // 查空扇区
//2. 发送0x22准备字节给PC
U0IER = IER_THRE | IER_RLS; // 发送时disable RBR
while(!(UART0TxEmpty & 0x01));
U0THR = ISP_PC_DOWNLOAD; // 0x22 means bootloader is ready to update
UART0Count = 0;
U0IER = IER_THRE | IER_RLS | IER_RBR; // REenable RBR
//3. 发送0x23表示请求PC发送文件的长度,DWORD
U0IER = IER_THRE | IER_RLS; // 发送时disable RBR
while(!(UART0TxEmpty & 0x01));
U0THR = ISP_PC_FILE_LEN; // 0x23 means order PC to confirm the fileLen
UART0Count = 0;
U0IER = IER_THRE | IER_RLS | IER_RBR; // REenable RBR
//4. 接收文件长度
while(UART0Count < 5)
{
if(UART0Count == 4)
{
fileCount0 = *(volatile BYTE*)(DWORD)(&UART0Buffer);
fileCount1 = *(volatile BYTE*)((DWORD)(&UART0Buffer)+1);
fileCount2 = *(volatile BYTE*)((DWORD)(&UART0Buffer)+2);
fileCount3 = *(volatile BYTE*)((DWORD)(&UART0Buffer)+3);
UART0Count = 5;
}
}
UART0Count = 0;
fileCount = (fileCount0 << 24) + (fileCount1 << 16) + (fileCount2 << 8) + (fileCount3); //fileCount is the the length of the HEX file
//5.等待PC发送的文件到on-chip RAM
while(UART0Count < fileCount) //等待数据传输完毕
{
if(UART0Count != 0)
{
U0IER = IER_THRE | IER_RLS;
while(!(UART0TxEmpty & 0x01));
U0IER = IER_THRE | IER_RLS | IER_RBR;
}
}
UART0Count = 0;
//6.从RAM写入FLASH的指定扇区
SelSector(0x1,0x1); // 选择扇区1
RamToFlash(0x00001000, (DWORD)&UART0Buffer, (UART0Count/512)*512+512);
err = Compare(0x00001000,(DWORD)&UART0Buffer,(UART0Count/512)*512+512);
//7.想串口发送更新操作结果,0x24表示成功,0x25表示失败
if(err == IAP_RET_CMD_SUCCESS)
{
U0IER = IER_THRE | IER_RLS; // 发送时disable RBR
while(!(UART0TxEmpty & 0x01));
U0THR = ISP_MCU_UPDATE_OK; // 0x24 means bootloader has finished the update process
UART0Count = 0;
U0IER = IER_THRE | IER_RLS | IER_RBR;
}
else
{
U0IER = IER_THRE | IER_RLS; // 发送时disable RBR
while(!(UART0TxEmpty & 0x01));
U0THR = ISP_MCU_UPDATE_OK; // 0x25 means bootloader is failed to update
UART0Count = 0;
U0IER = IER_THRE | IER_RLS | IER_RBR;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -