Here's an example using the buffer ram to work with pfm sectors.
Supposedly you can use the TABLEPTR to load the ram too, but it just seems to make more sense to me to use it as ram since that's where it's located.
On the Q10 the buffer ram is a 256-byte block reserved for nvm sector operations. You can read it, change its contents, and write it pretty much like normal ram.
I tested this with a 25Q10, but it should work with the others as well. Just change the PFM_ADDR const to match (or set the variable pfmAddr)
Code: Select all
// Q10 PFM sector operations using BufferRam
device = 18F27Q10
clock = 64
include "intosc.bas"
include "usart.bas"
// 18FxxQ family nvm BufferRam definitions (from device file)
const BUF_RAM_ADDR = _nvm_bufferram_start
const BUF_RAM_SIZE = _nvm_bufferram_end - _nvm_bufferram_start + 1
dim buffer_ram(BUF_RAM_SIZE) as byte absolute (BUF_RAM_ADDR)
// NVMCON0 register bits
const
NVMEN = 7,
NVMERR = 4
// NVMCON1 register bits
const
SECER = 6,
SECWR = 5,
WR = 4,
SECRD = 1,
RD = 0
// global INTCON IE register bit
const GIE = 7
// pfm sector to test (device-dependant)
const PFM_ADDR = $10000
//---------------------------
// PFM NVM sector functions
//---------------------------
// read pfm sector at 'addr' into buffer_ram. returns state of NVMERR
public function ReadSector(addr as longword) as bit
dim t_intcon as byte ' copy of INTCON
' get current intr enable and disable interrupts
t_intcon = INTCON
INTCON.bits(GIE) = 0
' clear BufferRam so we can see results of sector read (optional)
clear(buffer_ram)
' read sector contents into BufferRam
NVMADRU = addr.byte2
NVMADRH = addr.byte1
NVMADRL = addr.byte0
' enable nvm operations
NVMCON0.bits(NVMEN) = 1
' SECRD unlock
NVMCON2 = $BB
NVMCON2 = $44
' sector read
NVMCON1.bits(SECRD) = 1
while (NVMCON1.bits(SECRD) = 1)
end while
' buffer_ram should now contain current sector data
' return state of NVMERR flag (remains set... user must clear)
result = NVMCON0.bits(NVMERR)
' disable sector operations
NVMCON0.bits(NVMEN) = 0
' restore GIE intr bit setting
if (t_intcon.bits(GIE) = 1) then
INTCON.bits(GIE) = 1
end if
end function
// erase pfm sector at 'addr'. returns state of NVMERR
public function EraseSector(addr as longword) as bit
dim t_intcon as byte ' copy of INTCON
' get current intr enable and disable interrupts
t_intcon = INTCON
INTCON.bits(GIE) = 0
' set sector addr to erase
NVMADRU = addr.byte2
NVMADRH = addr.byte1
NVMADRL = addr.byte0
' enable nvm operations
NVMCON0.bits(NVMEN) = 1
' SECER unlock
NVMCON2 = $CC
NVMCON2 = $33
' sector erase
NVMCON1.bits(SECER) = 1
while (NVMCON1.bits(SECER) = 1)
end while
' return state of NVMERR flag (remains set... user must clear)
result = NVMCON0.bits(NVMERR)
' disable sector operations
NVMCON0.bits(NVMEN) = 0
' restore GIE intr bit setting
if (t_intcon.bits(GIE) = 1) then
INTCON.bits(GIE) = 1
end if
end function
// write buffer_ram to pfm sector at 'addr'. returns state of NVMERR
public function WriteSector(addr as longword) as bit
dim t_intcon as byte ' copy of INTCON
' get current intr enable and disable interrupts
t_intcon = INTCON
INTCON.bits(GIE) = 0
' set sector addr to write
NVMADRU = addr.byte2
NVMADRH = addr.byte1
NVMADRL = addr.byte0
' enable nvm operations
NVMCON0.bits(NVMEN) = 1
' SECWR unlock
NVMCON2 = $DD
NVMCON2 = $22
' sector write
NVMCON1.bits(SECWR) = 1
while (NVMCON1.bits(SECWR) = 1)
end while
' return state of NVMERR flag (remains set... user must clear)
result = NVMCON0.bits(NVMERR)
' disable sector operations
NVMCON0.bits(NVMEN) = 0
' restore GIE intr bit setting
if (t_intcon.bits(GIE) = 1) then
INTCON.bits(GIE) = 1
end if
end function
//---------------------------
// main program
//---------------------------
dim pfmAddr as longword
dim nvmStat as bit
dim ix as byte
main:
' set nvm params
pfmAddr = PFM_ADDR
' read current sector into BufferRam
nvmStat = ReadSector(pfmAddr)
' buffer_ram should now contain current sector data
if (nvmStat = 1) then
USART.Write("ReadSector Err",13,10)
NVMCON0.bits(NVMERR) = 0 ' user must clear error flag
endif
' erase sector
nvmStat = EraseSector(pfmAddr)
if (nvmStat = 1) then
USART.Write("EraseSector Err",13,10)
NVMCON0.bits(NVMERR) = 0 ' user must clear error flag
endif
' verify erase by re-reading sector
nvmStat = ReadSector(pfmAddr)
' BufferRam should now contain sector data (all FF)
for ix = 0 to bound(buffer_ram)
if (buffer_ram(ix) <> $FF) then
USART.Write("EraseSector Verify Err",13,10)
endif
next
' fill BufferRam with contents to write (0-255 in this example)
for ix = 0 to bound(buffer_ram)
buffer_ram(ix) = ix
next
' write sector
nvmStat = WriteSector(pfmAddr)
if (nvmStat = 1) then
USART.Write("WriteSector Err",13,10)
NVMCON0.bits(NVMERR) = 0 ' user must clear error flag
endif
' verify write by re-reading sector
nvmStat = ReadSector(pfmAddr)
' BufferRam should now contain sector data (0-255)
for ix = 0 to bound(buffer_ram)
if (buffer_ram(ix) <> ix) then
USART.Write("WriteSector Verify Err",13,10)
endif
next
while (true)
end while
end