芯片平台:PIC18F26K40
软件版本:MPLAB X IDE v5.20
在使用MPLAB X编译器的过程中,使用自带的MCC代码生成工具,加入memory模块生成的flash读写接口,对单个地址读写时没有问题,但是在进行连续区域地址读写时,就会出现数据读写异常的情况,比如要进行bootloader程序的设计,使用memory的flash读写函数就会出现问题。经过一番摸索,发现使用MCC代码生成工具里面的bootloader模块,里面的flash读写接口是可以正常使用的,为了便于使用,对这个flash读写接口进行了修改,代码如下:
/**
Section: Macro Declarations
*/
#define WRITE_FLASH_BLOCKSIZE 32
#define ERASE_FLASH_BLOCKSIZE 32
#define END_FLASH 0x010000
// *****************************************************************************
#include "flash.h"
// To be device independent, these are set by mcc in memory.h
#define LAST_WORD_MASK (WRITE_FLASH_BLOCKSIZE - 1)
// Force variables into Unbanked for 1-cycle accessibility
uint8_t EE_Key_1 __at(0x0);
uint8_t EE_Key_2 __at(0x1);
void StartWrite();
// *****************************************************************************
// Read Flash
// *****************************************************************************
uint8_t Read_Flash(uint32_t flashAddr, uint8_t *data, uint16_t data_len)
{
if (data == NULL)
return 0;
TBLPTRU = (uint8_t)((flashAddr & 0x00FF0000) >> 16);
TBLPTRH = (uint8_t)((flashAddr & 0x0000FF00)>> 8);
TBLPTRL = (uint8_t)(flashAddr & 0x000000FF);
NVMCON1 = 0x80;
for (uint16_t i = 0; i < data_len; i ++)
{
asm("TBLRD *+");
data[i] = TABLAT;
}
return (data_len);
}
// *****************************************************************************
// Write Flash
// data_len <= WRITE_FLASH_BLOCKSIZE
// *****************************************************************************
uint8_t Write_Flash(uint32_t flashAddr, uint8_t *data, uint16_t data_len)
{
if (data == NULL)
return 0;
uint8_t GIEBitValue = INTCONbits.GIE; // Save interrupt enable
INTCONbits.GIE = 0; // Disable interrupts
EE_Key_1 = 0x55; // write EE Keys
EE_Key_2 = 0xAA;
TBLPTRU = (uint8_t)((flashAddr & 0x00FF0000) >> 16);
TBLPTRH = (uint8_t)((flashAddr & 0x0000FF00)>> 8);
TBLPTRL = (uint8_t)(flashAddr & 0x000000FF);
NVMCON1 = 0xA4; // Setup writes
for (uint16_t i = 0; i < data_len; i ++)
{
TABLAT = data[i];
if (TBLPTR >= END_FLASH)
{
return (0);
}
asm("TBLWT *+");
if (((TBLPTRL & LAST_WORD_MASK) == 0x00)
|| (i == data_len - 1))
{
asm("TBLRD *-");
StartWrite();
asm("TBLRD *+");
}
}
EE_Key_1 = 0x00; // erase EE Keys
EE_Key_2 = 0x00;
INTCONbits.GIE = GIEBitValue; // Restore interrupt enable
return (1);
}
// *****************************************************************************
// Erase Program Memory
// Erases data_length rows from program memory
// *****************************************************************************
uint8_t Erase_Flash (uint32_t flashAddr, uint16_t data_len)
{
uint8_t GIEBitValue = INTCONbits.GIE; // Save interrupt enable
INTCONbits.GIE = 0; // Disable interrupts
EE_Key_1 = 0x55; // write EE Keys
EE_Key_2 = 0xAA;
TBLPTRU = (uint8_t)((flashAddr & 0x00FF0000) >> 16);
TBLPTRH = (uint8_t)((flashAddr & 0x0000FF00)>> 8);
TBLPTRL = (uint8_t)(flashAddr & 0x000000FF);
for (uint16_t i=0; i < data_len; i++)
{
if (TBLPTR >= END_FLASH)
{
return (0);
}
NVMCON1 = 0x94; // Setup writes
StartWrite();
TBLPTR += ERASE_FLASH_BLOCKSIZE;
}
EE_Key_1 = 0x00; // erase EE Keys
EE_Key_2 = 0x00;
INTCONbits.GIE = GIEBitValue; // Restore interrupt enable
return (1);
}
// *****************************************************************************
// Unlock and start the write or erase sequence.
// *****************************************************************************
void StartWrite()
{
__asm ("banksel NVMCON2");
__asm ("movf _EE_Key_1, w, c");
__asm ("movwf NVMCON2, b");
__asm ("movf _EE_Key_2, w, c");
__asm ("movwf NVMCON2, b");
__asm ("bsf NVMCON1,1"); // Start the write
NOP();
NOP();
return;
}