/*
 * W_BEE.c
 *
 *  Created on: 2016-4-19
 *      Author: Administrator
 */

#include "main.h"

unsigned int 	BEE_BUFFER[BEE_BUFFER_MAX];
unsigned int    BEE_READ_BUF;	   //当单字读函数使用非全嵌汇编模式时，使用该值获取读取结果R7 R6构成的值


/***********************************************************************************
 * 函数名     ：BEE_READ_ONE
 * 函数功能：以设定地址开始，读取一个数的BEE数据并返回结果
 * 入口参数：起始地址
 * 返回          ：无
 **********************************************************************************/
unsigned int BEE_READ_ONE(unsigned int address)
{
#if  1  	// 1 选用C语言表达  0 选用嵌汇编表达，嵌汇编效率更高，但提示传递参数未使用和函数无返回，可以忽略

	// BEE_READ_BUF;  需要定义全局的该变量，获取R7 R6的值用于返回，或直接使用
	//; 参数的使用
	BADDRH=(unsigned char)(address>>8);
	BADDRL=(unsigned char)address;
	__asm
		;//备份中断使能寄存器
			BANKSEL _INTCTL
			MOV		R1,_INTCTL
		;//关闭中断，BEE操作不可打断
			CLR		_INTCTL,_AIE
			JNB		_INTCTL,_AIE
			JMP		$-2
		;//时钟频率备份及降频操作BEE,建议降频到1M,此时中断已被关
			MOV		R0,#0x30
			MOV		R2,_OSCCTL
			MOV		_OSCCTL,R0
//		;//硬件使能读操作
			BANKSEL _EECTL1
			MOV 	R5,#0x81
			MOV 	_EECTL1,R5
			NOPZ
			NOPZ
			NOPZ
			NOPZ
			NOPZ
			NOPZ
			NOPZ
			NOPZ
			NOPZ
			NOPZ
//		;//时钟与中断使能的还原
			MOV		_OSCCTL,R2
			AND 	R1,#0xC0	;//中断使能仅关系高2位
			ORL 	INTCTL,R1
//		;//操作结果赋值到变量，用于返回
			BANKSEL _BEE_READ_BUF
			MOV R0,BDATAL
			MOV (_BEE_READ_BUF),R0
			MOV R0,BDATAH
			MOV (_BEE_READ_BUF+1),R0
	__endasm;
	return 	BEE_READ_BUF;
#else
	// 参数的传递使用  编译器自动变量 STK00  和 R0 ，其中R0为高位，返回使用STK00  和 R0 ，其中R0为高位
	__asm
	;//传递操作地址
		BANKSEL _BADDRH
		MOV		_BADDRH,R0
		BANKSEL STK00
		MOV		R0,STK00
		BANKSEL _BADDRL
		MOV		_BADDRL,R0
	;//备份中断使能寄存器
		BANKSEL _INTCTL
		MOV		R1,_INTCTL
	;//关闭中断，BEE操作不可打断
		CLR		_INTCTL,_AIE
		JNB		_INTCTL,_AIE
		JMP		$-2
	;//时钟频率备份及降频操作BEE,建议降频到1M,此时中断已被关
		MOV		R0,#0x30
		MOV		R2,_OSCCTL
		MOV		_OSCCTL,R0
	;//硬件使能读操作
		BANKSEL _EECTL1
		MOV 	R5,#0x81
		MOV 	_EECTL1,R5
		NOPZ
		NOPZ
		NOPZ
		NOPZ
		NOPZ
		NOPZ
		NOPZ
		NOPZ
		NOPZ
		NOPZ
	;//时钟与中断使能的还原
		MOV		_OSCCTL,R2
		AND 	R1,#0xC0	;//中断使能仅关系高2位
		ORL 	_INTCTL,R1
	;//操作结果提供形式 整型数据返回结果使用  编译器自动变量 STK00  和 R0 ，其中R0为高位
		BANKSEL STK00
		MOV		STK00,R6
		MOV		R0,R7
	__endasm;
#endif

}

///***********************************************************************************
// * 函数名     ：BEE_READ_FUN
// * 函数功能：以设定地址开始，读取一定个数的BEE数据放置到数值BEE_BUFFER[x]中
// * 入口参数：起始地址，操作个数
// * 返回          ：无
// **********************************************************************************/
void BEE_READ_FUN(unsigned int address,unsigned char length)
{
#if 1  	   //  1时效率比0小   1 使用传递参数   0 按编译器全嵌汇编实现，但编译提示参数未使用，可以忽略
	//; 参数的使用
	BADDRH=(unsigned char) (address>>8);
	BADDRL=address;

	__asm
	;//备份中断使能寄存器
		BANKSEL _INTCTL
		MOV		R1,_INTCTL
	;//关闭中断，BEE操作不可打断
		CLR		_INTCTL,_AIE
		JNB		_INTCTL,_AIE
		JMP		$-2
	;//时钟频率备份及降频操作BEE,建议降频到1M,此时中断已被关
		MOV		R0,#0x30
		MOV		R2,_OSCCTL
		MOV		_OSCCTL,R0
	;//读取结果的存放起始RAM地址，即数组缓存区  BEE_BUFFER[x]
		MOV		R3,#_BEE_BUFFER
	__endasm;

	while(length--)	// 仅使用R0，不改变R1
	{
		__asm
		;//硬件读
		BANKSEL _EECTL1
		MOV 	R5,#0x81
		MOV 	_EECTL1,R5
		NOPZ
		NOPZ
		NOPZ
		NOPZ
		;//读结果处理
		BANKSEL _BEE_BUFFER
//		ST		[R3],R6
		MOV     R0,BDATAL
		ST		[R3],R0
		INC		R3
		MOV     R0,BDATAH
		ST		[R3],R0
//		ST		[R3],R7
		INC		R3
		;//指向下一操作地址，建议每次操作内容在一个块中，此时不需要处理_BADDRL进位的_BADDRH+1操作
		BANKSEL _BADDRL
		INC		_BADDRL
		JNB		_PSW,_Z
		INC		_BADDRH
		__endasm;
	}

	__asm
		;//时钟与中断使能的还原
		MOV		_OSCCTL,R2
		AND 	R1,#0xC0	;//中断使能仅关系高2位
		ORL 	_INTCTL,R1
	__endasm;
#else
	// 参数1的传递使用  编译器自动变量 STK00  和 R0 ，其中R0为高位
	// 参数2的传递使用  编译器自动变量 STK01
	// 整体实现的嵌汇编会提示参数未被使用，可以忽略
__asm
	;//传递操作地址
	BANKSEL _BADDRH
	MOV		_BADDRH,R0
	BANKSEL STK00
	MOV		R0,STK00
	BANKSEL _BADDRL
	MOV		_BADDRL,R0
	;//备份中断使能寄存器
	BANKSEL _INTCTL
	MOV		R1,_INTCTL
	;//关闭中断，BEE操作不可打断
	CLR		_INTCTL,_AIE
	JNB		_INTCTL,_AIE
	JMP		$-2
	;//时钟频率备份及降频操作BEE,建议降频到1M,此时中断已被关
	MOV		R0,#0x30
	MOV		R2,_OSCCTL
	MOV		_OSCCTL,R0
	;//读取结果的存放起始RAM地址，即数组缓存区  BEE_BUFFER[x]
	MOV		R0,#_BEE_BUFFER

BEE_READ_FUN_LOOP:
	;//硬件读
	BANKSEL _EECTL1
	MOV 	R5,#0x81
	MOV 	_EECTL1,R5
	NOPZ
	NOPZ
	NOPZ
	NOPZ
	;//读结果处理
	BANKSEL _BEE_BUFFER
	ST		[R0],R6
	INC		R0
	ST		[R0],R7
	INC		R0
	;//指向下一操作地址，建议每次操作内容在一个块中，此时不需要处理_BADDRL进位的_BADDRH+1操作
	BANKSEL _BADDRL
	INC		_BADDRL
	JNB		_PSW,_Z
	INC		_BADDRH
	;//读数量的判断
	BANKSEL STK01
	DECJZ	STK01
	JMP		BEE_READ_FUN_LOOP

	;//时钟与中断使能的还原
	MOV		_OSCCTL,R2
	AND 	R1,#0xC0	;//中断使能仅关系高2位
	ORL 	_INTCTL,R1
__endasm;
#endif
}

/***********************************************************************************
 * 函数名     ：BEE_WRITE_FUN
 * 函数功能：按块或按页写入数据到BEE，个数参数只能为 4 8 12 16 ，地址必须为块的首地址 如十六进制下末位 0  4  8  C
 * 			如果地址不是页的首地址，必须确定后续块结果为0xFFFF，或前面操作过块首写，使后续块值被0xFFFF，否则写结果异常。
 * 入口参数：待写地址，待写地址的数据
 * 返回          ：无
 * 写时间说明：除去代码，以整页BEE为例，操作完第一块需要4ms，另外3块需要2ms。即第一块执行整页的擦除后写自身块，其他块直接写。
 **********************************************************************************/
void BEE_WRITE_FUN(unsigned int address,unsigned char length)
{
#if 1  	   //  1时效率比0小   1 使用传递参数   0 按编译器全嵌汇编实现，但编译提示参数未使用，可以忽略
	//; 参数的使用
	BADDRH=(unsigned char) (address>>8);
	BADDRL=address;

	__asm
	;//备份中断使能寄存器
		BANKSEL _INTCTL
		MOV		R1,_INTCTL
	;//关闭中断，BEE操作不可打断
		CLR		_INTCTL,_AIE
		JNB		_INTCTL,_AIE
		JMP		$-2
	;//时钟频率备份及降频操作BEE,建议降频到1M,此时中断已被关
		MOV		R0,#0x30
		MOV		R2,_OSCCTL
		MOV		_OSCCTL,R0
	;//读取结果的存放起始RAM地址，即数组缓存区  BEE_BUFFER[x]
		MOV		R3,#_BEE_BUFFER
	__endasm;

	while(length--)		// 仅使用R0，不改变R1
	{
		__asm
		;//加载待写数据
		BANKSEL _BEE_BUFFER
//		LD		R6,[R3]
		LD		R0,[R3]
		MOV		BDATAL,R0
		INC		R3
//		LD		R7,[R3]
		LD		R0,[R3]
		MOV		BDATAH,R0
		INC		R3
		;//硬件写
		MOV 	R5 ,#0x84
		MOV 	_EECTL1,R5
		MOV 	R5,#0x69
		MOV 	_EECTL2,R5
		MOV 	R5,#0x96
		MOV 	_EECTL2,R5
		SET 	_EECTL1 , 1	;// 写存在高压，高压还原添加空指令确保后续运行正常
		NOPZ
		NOPZ
		NOPZ
		NOPZ
		NOPZ
		NOPZ						;// 至少10条
		NOPZ
		NOPZ
		NOPZ
		NOPZ
		MOV 	R5,#0X80
		MOV 	EECTL1,R5
		;//指向下一操作地址，这里不考虑高位，BEE特性要求只能操作一页内的数据，不能跨页
		BANKSEL _BADDRL
		INC		_BADDRL
		__endasm;
	}
	__asm
		;//时钟与中断使能的还原
		MOV		_OSCCTL,R2
		AND 	R1,#0xC0	;//中断使能仅关系高2位
		ORL 	_INTCTL,R1
	__endasm;
#else
	// 参数1的传递使用  编译器自动变量 STK00  和 R0 ，其中R0为高位
	// 参数2的传递使用  编译器自动变量 STK01
	// 整体实现的嵌汇编会提示参数未被使用，可以忽略
__asm
	;//传递操作的地址(块首)
	BANKSEL _BADDRH
	MOV		_BADDRH,R0
	BANKSEL STK00
	MOV		R0,STK00
	BANKSEL _BADDRL
	MOV		_BADDRL,R0
	;//备份中断使能寄存器
	BANKSEL	_INTCTL
	MOV		R1,_INTCTL
	;//关闭中断，BEE操作不可打断
	CLR		_INTCTL,_AIE
	JNB		_INTCTL,_AIE
	JMP		$-2
	;//时钟频率备份及降频操作BEE,建议降频到1M,此时中断已被关
	MOV		R0,#0x30
	MOV		R2,_OSCCTL
	MOV		_OSCCTL,R0
	;//待写数据的存放起始RAM地址，即数组缓存区  BEE_BUFFER[x]
	MOV		R0,#_BEE_BUFFER

BEE_WRITE_PAGE_LOOP:
	;//加载待写数据
	BANKSEL _BEE_BUFFER
	LD		R6,[R0]
	INC		R0
	LD		R7,[R0]
	INC		R0
	;//硬件写
	MOV 	R5 ,#0x84
	MOV 	_EECTL1,R5
	MOV 	R5,#0x69
	MOV 	_EECTL2,R5
	MOV 	R5,#0x96
	MOV 	_EECTL2,R5
	SET 	_EECTL1 , 1	;// 写存在高压，高压还原添加空指令确保后续运行正常
	NOPZ
	NOPZ
	NOPZ
	NOPZ
	NOPZ
	NOPZ						;// 至少10条
	NOPZ
	NOPZ
	NOPZ
	NOPZ
	MOV 	R5,#0X80
	MOV 	EECTL1,R5
	;//指向下一操作地址，这里不考虑高位，BEE特性要求只能操作一页内的数据，不能跨页
	BANKSEL _BADDRL
	INC		_BADDRL

	BANKSEL STK01
	DECJZ	STK01
	JMP		BEE_WRITE_PAGE_LOOP

	;//时钟与中断使能的还原
	MOV		_OSCCTL,R2
	AND 	R1,#0xC0	;//中断使能仅关系高2位
	ORL 	_INTCTL,R1
__endasm;
#endif
}

/***********************************************************************************
 * 函数名     ：BEE_WRITE_ONE
 * 函数功能：向某一地址写入一个字，不建议使用，实际执行从页首读出，经对应地址的缓存修改，在页起始回写，因此地址与页首偏移量需要数组大小满足需求。
 * 			如当你BEE_BUFFER_MAX为4时，操作地址十六进制下的末尾必须只能是0 1 2 3
 * 建议：         可采用BEE_WRITE_FUN的传递个数为4 8 12 16 对应连续操作地址开始的第一块 第二块 第三块 第四块
 * 			 但地址必须是某块的开始
 * 入口参数：待写地址，待写地址的数据
 * 返回          ：无
 **********************************************************************************/
void BEE_WRITE_ONE(unsigned int address,unsigned int value)
{
	// 读出当前页到数据缓存，要求缓存大小必须满足写地址的偏移量要求
	BEE_READ_FUN(address&0xFFF0,BEE_BUFFER_MAX);
	// 修改待写数据在按照页排序中位置数据结果
	BEE_BUFFER[address&0xF] = value;
	// 整页数据回写
	BEE_WRITE_FUN(address&0xFFF0,BEE_BUFFER_MAX);
}
