⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 main.c

📁 ZLG的SMARTARM2300的IAP_Program
💻 C
字号:
/****************************************Copyright (c)**************************************************
**                               Guangzou ZLG-MCU Development Co.,LTD.
**                                      graduate school
**                                 http://www.zlgmcu.com
**
**--------------File Info-------------------------------------------------------------------------------
** File name:			main.c
** Last modified Date:  2004-09-16
** Last Version:		1.0
** Descriptions:		The main() function example template
**
**------------------------------------------------------------------------------------------------------
** Created by:			Chenmingji
** Created date:		2004-09-16
** Version:				1.0
** Descriptions:		The original version
**
**------------------------------------------------------------------------------------------------------
** Modified by:			LinEnqiang
** Modified date:		2006-12-1
** Version:				
** Descriptions:		Test
**
********************************************************************************************************/
#include "config.h"
#include "IAP.h"
#include "GPIO.h"
#include "string.h"
#include "VIC.h"
#include "User.h"

#define	LOW				0x00008000		// LOW区首地址
#define	HIGH			0x00010000		// HIGH区首地址
#define	Flag			0x00003000		// 用户程序标志区,0x55-运行LOW区代码,0xaa-运行HIGH区代码
#define	LED1			(1 << 15)		// P0.15控制LED1
#define	UserISP			(1 <<  6)		// 用户ISP跳线,P0.6。上电为低时,进入用户ISP代码区域

#define	RxHardFIFO_Size	8
#define	User_Flag		0x00004000		// 用户程序标志区
										// 0x10000	 -HIGH区,0x10000
										// 0xffffffff-LOW区 ,0x8000
										// 0x8000    -LOW区 ,0x8000
#define	Ethernet_RAM	0x7FE00000		// 以太网RAM起始地址
#define	User_LOW		0x00008000		// 用户程序低区入口
#define	User_HIGH		0x00010000		// 用户程序高区入口

__align(4)	uint8	IAP_Tmp[4096];		// 定义4K空间,编程Flash时使用
uint8   *RcvData   = (uint8 *)Ethernet_RAM;		// 接收数据缓冲区
uint32	*FlagPoint = (uint32 *)User_Flag;		// 用户程序标志指针
volatile uint32 RcvCount;				// 接收字节数
volatile uint8  RcvOver;				// 接收完成标志 1:表示完成
/*********************************************************************************************************
** 函数名称:UART0_ISR
** 函数功能:串口中断服务函数。
********************************************************************************************************/
 void __irq UART0_ISR(void)
{
	volatile uint8 i;
	T0TCR |= 0x02;				// 定时器复位
	T0TCR  = 0x01;
    do
	{
	    switch (U0IIR & 0x0e)
		{
			case  0x04:			// 接收中断,FIFO满中断
				for (i = 0; i < RxHardFIFO_Size - 1; i++)
				{
					RcvData[RcvCount++] = U0RBR;
				}
				break;
			case  0x0c:    		// 接收超时中断
			   	while ((U0LSR & 0x01) != 0)	
				{
					RcvData[RcvCount++] = U0RBR;
				}
				RcvOver = 1;	// 接收完成
				break;
			case  0x02:			// 发送中断
				break;
			case  0x06:
				i = U0LSR;
				break;
			default:
				break;
		}
	}while ((U0IIR & 0x01) == 0);
	VICVectAddr = 0x00;
}

/*********************************************************************************************************
** 函数名称: UART_SendData
** 功能描述: UART发送函数。
** 入口参数: SendBuf	发送缓冲区
**			 len		发送字节数
** 出口参数: 无
********************************************************************************************************/
void UART0_SendData(uint8 *SendBuf, uint32 len)
{
	while (len != 0)
	{
		U0THR = *SendBuf++;			// 发送数据
		U0TER = 0x80;
		while ((U0LSR & 0x20) == 0);// 等待数据发送完毕
		len --;
	}
}

/*********************************************************************************************************
** 函数名称: uint8	T0MAT_Init
** 功能描述: 定时器0匹配模式初始化
** 入口参数: time		匹配时间,该值会直接写入到匹配寄存器中
**			 PR_data	预分频寄存器的值
**			 T_MODE		匹配控制模式
**						0:匹配时,定时器复位
**						1:匹配时,定时器停止
**			 EXT_MODE	匹配时,外部输出控制
**						0:不执行任何动作
**						1:外部匹配输出0
**  					2:外部匹配输出1
**						3:外部匹配输出翻转
**			 MATn		匹配通道选择,0~3
**			 Int_En		中断使能
**						0:发生匹配事件时,不产生中断
**						1:发生匹配事件时,产生中断
** 出口参数: 0 :初始化失败
**         	 1 :初始化成功
** 调试说明:调用前,要设置相关的引脚
********************************************************************************************************/
uint8  T0MAT_Init(uint32 time, uint32 PR_data, uint8 T_MODE, uint8 EXT_MODE, uint8 MATn, uint8 Int_En)
{
	if ((T_MODE > 1) || (EXT_MODE > 3) || (MATn > 3) || (Int_En > 1))
	{
		return (0);						// 参数不合理,直接返回
	}
	T0TCR = 0x03;						// 在设置之前,先将定时器复位
	T0IR  = T0IR | (1 << MATn);			// 清除中断标志位
	T0PR  = PR_data;					// 设置预分频器 
	/* 设置匹配寄存器 */
	switch(MATn)						
	{
		case 0:
			T0MR0 = time;
			break;
		case 1:
			T0MR1 = time;
			break;
		case 2:
			T0MR2 = time;
			break;
		case 3:
			T0MR3 = time;
			break;
		default:
			break;
	}
	T0MCR = T0MCR & (~(7 << (MATn * 3))) | (1 << (MATn * 3 + 1 + T_MODE)) | (Int_En << (MATn * 3));
	T0EMR = T0EMR & (~(3 << (MATn * 2 + 4))) | (EXT_MODE << (MATn * 2 + 4));
	T0TCR = 0x01;						// 重新启动定时器
	return (1);
}

/*********************************************************************************************************
** 函数名称: UART0_Init
** 功能描述: 对UART0进行初始化
** 入口参数: baud 	串口通信波特率
** 出口参数: 无
********************************************************************************************************/
void UART0_Init(uint32 baud)
{
	PCONP  |= (1 << 3);
	
	/* 设置UART0引脚,且不影响其它引脚 */
	PINSEL0 = (PINSEL0 & (~(0x0f << 4))) | (1 << 4) | (1 << 6);		
	
	/* 设置串口波特率 */
	U0LCR = 0x80;		
	U0DLM = ((Fpclk / 16) / baud) / 256;
	U0DLL = ((Fpclk / 16) / baud) % 256;	
	
	/* 设置串口模式:8位数据位、1位停止位、无奇偶校验位 */
	U0LCR = 0x03;			
	U0FCR = 0x81;		// FIFO触发点为8个字节
	U0IER = 0x01;		// 接收中断使能
	IRQ_Init(UART0_INT, 0, (uint32)UART0_ISR);	// 初始化UART IRQ中断信息
}

/*********************************************************************************************************
** 函数名称: SendMessage
** 功能描述: 发送提示信息。
** 入口参数: 无
** 出口参数: 无
********************************************************************************************************/
void SendMessage(void)
{
	volatile uint8 tmp;							// 用来清除UART中断标志
	if (*FlagPoint == 0x10000)					// 当前程序运行在HIGH区,需要对LOW区进行升级
	{ 							
		UART0_SendData((uint8 *)("当前程序运行在HIGH区,只能对LOW区进行升级 "), strlen("当前程序运行在HIGH区,只能对LOW区进行升级 "));				
	}
	else 
	{
		if (*FlagPoint == 0x8000)				// 当前程序运行在HIGH区,需要对LOW区进行升级
		{
			UART0_SendData((uint8 *)("当前程序运行在LOW区,只能对HIGH区进行升级 "), strlen("当前程序运行在LOW区,只能对HIGH区进行升级 "));
		}
		else									// 当前程序运行在HIGH区,需要对LOW区进行升级
		{
			UART0_SendData((uint8 *)("当前程序运行在固件区,只能对HIGH区进行升级 "), strlen("当前程序运行在固件区,只能对HIGH区进行升级 "));
		}
	}
	tmp = U0IIR;	
}

/*********************************************************************************************************
** 函数名称: ProgramUserData
** 功能描述: 编程用户代码区
** 入口参数: 无
** 出口参数: 无
********************************************************************************************************/
void ProgramUserData(void)
{
	uint32  Addr;								// Addr:字节偏移量
	uint32  ProgramCount;						// ProgramCount:编程到Flash扇区的字节数
	if (*FlagPoint == 0x10000)		            // 当前程序运行在HIGH区,需要对LOW区进行升级
	{ 	
		SelSector  (8, 8);			            // 选择LOW扇区
		EraseSector(8, 8);			            // 擦除LOW扇区				
	}
	else							            // 当前程序运行在LOW区固件区 ,需要对HIGH区进行升级
	{
		SelSector  (9, 9);			            // 选择HIGH扇区
		EraseSector(9, 9);			            // 擦除HIGH扇区
	}
	
	Addr = 0;						            // 字节偏移量清0
	while (RcvCount != 0)
	{			
		if (RcvCount > (1024 * 4))	            // 一次最多写入4K代码量
		{
			memcpy(IAP_Tmp , RcvData + Addr, 1024 * 4);
			RcvCount -= (1024 * 4);
			ProgramCount = 1024 * 4;
		}		
		else
		{
			memcpy(IAP_Tmp , RcvData + Addr, RcvCount);
			ProgramCount = RcvCount;	
			RcvCount = 0;
			if ((ProgramCount == 256) || (ProgramCount == 512) || (ProgramCount == 1024) || (ProgramCount == 4096))
			{
				goto ProgramFlash;
			}
			/* 满足编程字节数的要求,256、512、1024等 */
			if (ProgramCount < 256)
			{
				ProgramCount = 256;					
				goto ProgramFlash;
			}
			if (ProgramCount < 512)
			{
				ProgramCount = 512;
				goto ProgramFlash;
			}
			if (ProgramCount < 1024)
			{
				ProgramCount = 1024;
				goto ProgramFlash;
			}
			if (ProgramCount < 4096)
			{
				ProgramCount = 4096;
				goto ProgramFlash;
			}
		}
ProgramFlash:
		/* 升级用户程序空间 */
		if (*FlagPoint == 0x10000)			// 当前程序运行在HIGH区,需要对LOW区进行升级
		{
			SelSector(8, 8);				// 选择LOW扇区
			RamToFlash(User_LOW + Addr, (uint32)IAP_Tmp, ProgramCount);	// 写数据到FLASH
			Addr += ProgramCount;
		}
		else								// 当前程序运行在LOW区,需要对HIGH区进行升级
		{
			SelSector(9, 9);				// 选择HIGH扇区
			RamToFlash(User_HIGH + Addr, (uint32)IAP_Tmp, ProgramCount);// 写数据到FLASH
			Addr += ProgramCount;
		}
	}//end of while(RcvCount != 0)
}

/*********************************************************************************************************
** 函数名称: UpdateUserFlag
** 功能描述: 更新用户程序标志区
** 入口参数: 无
** 出口参数: 无
********************************************************************************************************/
void UpdateUserFlag(void)
{
	uint32  *Data32Point;
	
	/* 更新用户程序标志空间0x4000 */
	memset(IAP_Tmp, 0xff, 256);						// 临时缓冲区清空
	Data32Point = (uint32 *)IAP_Tmp;
	if (*FlagPoint == 0x10000)
	{
		*Data32Point = 0x8000;
	}
	else
	{
		*Data32Point = 0x10000;
	}
	SelSector  (4, 4);								// 选择扇区
	EraseSector(4, 4);								// 擦除扇区
	SelSector  (4, 4);								// 选择扇区
	RamToFlash(User_Flag, (uint32)IAP_Tmp, 256);	// 编程FLASH
}

/*********************************************************************************************************
** 函数名称:main
** 函数功能:在线升级函数Boot代码
** 调试说明:在Flash中调试
********************************************************************************************************/
int main (void)
{	
	void (*UserProgram)();   					 	//函数指针
	uint32  dly;
	
	PCONP |= (1 << 30);
	UART0_Init(9600);								// 初始化UART0	
	GPIO0_Init(LED1, 1);						
	GPIO0_Init(UserISP, 0);							// 输入模式
	SendMessage();									// 发送提示信息
	memset(IAP_Tmp, 0, 4096);						// 缓冲区清零
	memset((char *)RcvData, 0, 1024 * 8);		

	if ((Read_P0() & UserISP) == 0)		
	{
		/* 进入升级阶段 */
		T0MAT_Init(Fpclk * 30, 0, 1, 0, 0, 1);		// 30秒钟定时
		RcvOver  = 0;
		RcvCount = 0;
		while (RcvOver == 0)
		{	
			if ((T0IR & 0x01) != 0)
			{
				T0IR     = 0x01;				    // 清除中断标志					
				RcvCount = 0;
				break;							    // 时间到,退出接收程序
			}			
		}
		if (RcvCount != 0)						    // 升级用户代码
		{
			IRQDisable(); 
			ProgramUserData();					    // 编程用户代码区
			UpdateUserFlag();					    // 更新用户程序标志区
			IRQEnable();
		}
	}
	
	/* 运行用户程序 */
	if (*FlagPoint == HIGH)
	{
		UserProgram = (void (*)()) (HIGH);
	}
	else 
	{
		if (*FlagPoint == LOW)
		{
			UserProgram = (void (*)()) (LOW);
		}
		else
		{
			while (1)
			{
				P0_GPIOClr(LED1);
				for (dly = 5000000 ; dly != 0; dly --);
				P0_GPIOSet(LED1);
				for (dly = 5000000 ; dly != 0; dly --);
			}		
		}
	}
	(*UserProgram)();							    // 启动程序
    return (0);
}
/*********************************************************************************************************
**                            End Of File
********************************************************************************************************/

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -