Storing data in flash memory

Thread Starter

RG23

Joined Dec 6, 2010
304
I am using PIC18f controller to display the signal waveform on a graphic display using four rows B1, B2, B3, B4(eight pixels each) of the display and it works fine.

Now I want to capture the signal data and store it in flash memory and later read the same

I am trying to capture the data every 60 seconds interval and then erase the flash memory storing that data and start storing new data.

There are 122 columns in the display and I am using 32 pixels (8 pixels in each row) to represent the amplitude of the signal;

So there will be in all 122*4*60 = 29280 memory locations required

I tried the write to flash subroutine in the datasheet but didn't work.

It says that the memory should be erased (1024 bytes)
Honestly it looks complicated to me and I could not figure it out.

All I want to do is assign a table pointer to a particular memory location
Move signal data to that location
Keep incrementing table pointer and moving data for every 60 seconds.

If anybody worked on this before, your input will be highly appreciated.

Thanks
 

JohnInTX

Joined Jun 26, 2012
4,787
First, you have to specify which 18f you are using. Different ones have different write block sizes.

Yes, you have to erase any existing data in a block before you can write new data. That's just the nature of flash. The erase block size may be different than the write block size depending on the chip. On the 18F4520, you erase a 64 byte block and write two 32 byte blocks in sequence. On the 18F4685, you erase and write 64 byte blocks. Check the datasheet.

You can't have any interrupts running because there is a time-sensitive set of instructions you need to execute to enable writing to the flash.

When writing, TBLPTR is used to fill a (not visable to the programmer) buffer of 32 or 64 bytes which is then written as a block to flash. Keep in mind that the PIC will STALL for 2-3ms while writing a block; it will not process any instructions or interrupts during that time.
From some 18F4685 code:

The general sequence to erase a block is:
set TBLPTR to the first address of the block to erase before write.
set up EECON1 to access flash, enable write and enable row erase
Disable interrupts
Write 55h then aah to ECON2
set the WR bit.
the CPU will stall for 2-3 ms.
re-enable interrupts

To write a block from RAM to Flash:
Use an FSR to point at the data in RAM
set TBLPTR to first the address in a block if it has been changed since erase
copy RAM to the Flash holding registers (32 or 64 bytes or whatever the write block size is) using TBLWT *+ in the copy loop.
set up EECON1 to write to flash
disable interrupts
do the access sequence (write 55h then aah to EECON2)
set EECON1,WR
the CPU will stall for another 2-3ms.
re-enable interrupts

Note that if the write block is smaller than the erase block (as in the 4520) you'll repeat the write twice for each erase.

I've used the flash lots and it works fine for often read, infrequently written tables etc. There is a limit to how many times flash can be written and since it stalls the CPU while writing, it might not be an optimum choice for a RAM replacement. Depends on your application.

If you are using C, the compiler likely has some library routines to make it simpler. I've only used assembler on it.

Have fun.
 

joeyd999

Joined Jun 6, 2011
5,283
It says that the memory should be erased (1024 bytes)...
This sounds like you are trying to write to the program flash memory, using the tblwrt instruction, yes?

This can be done, but there are at least two caveats:

1. The CPU stalls during program memory writes. Anything you are trying to run in the background will halt till the write operation completes.

2. Program memory flash has a much lower write endurance than data flash. I think (without referring to a datasheet) it is on the order of 10,000 write operations. After that, your pic will become useless.

You say writing to flash did not work. Can you post your code and tell us how it did not work?
 

JohnInTX

Joined Jun 26, 2012
4,787
I am using PIC 18f67J90

As per the memory usage gauge

Program memory used: 25671 / 65532
So.. you'll erase in blocks of 1024 and have to program the each block in 64 byte increments i.e. erase once, program 16*64 bytes. The erase blocks must be aligned on even 1024 byte boundaries AND the write blocks must be on 64 byte boundaries within the 1024 so some absolute addressing (away from your code of course) is in order.

What language are you developing in and what debugger are you using? You can use MPSIM but you'll have to add a workaround to the code.
 
Last edited:

Thread Starter

RG23

Joined Dec 6, 2010
304
So.. you'll erase in blocks of 1024 and have to program the each block in 64 byte increments i.e. erase once, program 16*64 bytes. The erase blocks must be aligned on even 1K boundaries so some absolute addressing (away from your code of course) is in order.

What language are you developing in and what debugger are you using? You can use MPSIM but you'll have to add a workaround to the code.
________________________________________________________________

I have a subroutine which runs every one second and updates the signal data
I display 122 columns of data every one second.
Each column has 4 row data in it (32 bits).So out of 32 I have to tranfer each 8 bit data to a memory location
After 60 seconds I have to erase all the contents and start recording the new 60 second interval data

I am actually not clear with the concept of the block of 1024 and 64byte increment

What language are you developing in and what debugger are you using?

I am using assembly language and Pickit2 as debugger
 
Last edited:

joeyd999

Joined Jun 6, 2011
5,283
Maybe this will help (though I hope it doesn't confuse you further). This is a code snippet that copies some off-board UNI/O flash data into program flash.

It performs multiple 1024 byte block erases, each subsequently followed by multiple 64 byte writes.

The following instructions are macros:

movlf, movdf, and djnz are macros for "move literal to file register", "move double literal to file registers", and "decrement file register and jump if not zero".

Ask questions about anything you do not understand.


Rich (BB code):
;*****************************************************
;** RDSENP -- Read Sensor UNI/O into Program Memory **
;*****************************************************	

rdsenp	call	unistat			;ensure last write complete

	movlf	tblptrl,low hmstadd	;set starting address
	movlf	tblptrh,high hmstadd

	movlf	temp5,hmblks		;number of 1K blocks
	movdf	temp10,ufcalmc		;start of program record in uni/o (including checksums)

;1st, erase a full row (1024 bytes) at tblptr

rdlp0
	bsf	eecon1,wren		; enable write to memory
	bsf	eecon1,free		; enable Row Erase operation
	movlf	eecon2,0x55		; write 55h
	movlf	eecon2,0xAA		; write 0AAh		
	bsf	eecon1,wr		; start erase (CPU stall)

	tblrd	*-			;point to first byte of block -1

;2nd, read 16*64 bytes into write buffer

	movlf	temp4,16		;number of 64 byte pages/block

rdlp1	call	unir64			;get 64 bytes from UNI/O

	movlw	64
	movwf	bitcnt			;preload # bytes to copy
	addwf	temp10,f		;and update UNI/O address holder
	clrw
	addwfc	temp11,f

	lfsr	0,unibuf		;point to UNI/O buffer

rdlp2	movff	postinc0,tablat		;copy byte program memory buffer
	tblwt	+*			;do short write
	djnz	bitcnt,rdlp2		;do for 64 bytes

;3rd preform a long write

	movlf	eecon2,0x55		; write 55h
	movlf	eecon2,0xAA		; write 0AAh		
	bsf	eecon1,wr		; start write (CPU stall)

	djnz	temp4,rdlp1		;do for full block

	tblrd	*+			;point to first byte of next block

	djnz	temp5,rdlp0		;do for all blocks 

	return
 
Last edited:

JohnInTX

Joined Jun 26, 2012
4,787
Rich (BB code):
I am actually not clear with the concept of the block of 1024 and 64byte increment
I think you are misunderstanding what the flash can do. You can't write it by individual bytes, you have to have 64 bytes of data read and buffered in RAM to write anything. That's just the way it is.

Since, unlike RAM or EEPROM, the flash must be erased before rewriting data you have that to do as well. Since the flash erases in 1K blocks (minimum) you have to be ready to lose that data and replace it with 1K of new data written in 64 byte pages. That will take 16 writes of 64 bytes to do. No way around it.

A further complication is that according to parameter D130 Cell Endurance, you are only guaranteed 10K writes to the flash before it may start not holding data. That's why I indicated that flash storage is not a good replacement for temporary data. Its best used to generate tables and lists a few times then be read many times.

Can you use RAM (the chip has 3.9K of it) to store your 1K of data? If not, I would recommend you look at some of the external serial RAMs that uCHIP and other's offer.

If you want to play with the flash anyway, start by ORG'ing a 1K space near the end of the program ROM, paying attention to any reserved by the PK2. At that location, use the dt directive to put some data there by default i.e.
ORG 7000h
dt "HELLO"
Open a PROGRAM MEMORY window at 7000h and you'll see HELLO in the ASCII dump.
Get the erase to work .. call erase then read the chip and examine program memory. It should be blank. Then write a 64 byte block, you can just increment TABLAT to generate unique data. Read the chip and see what you get.

PK2 may not have all the features you need but should get close. You won't be able to step through the critical section, break just before and after it.

If using MPSIM, clear PIR1, 2 and 3 before reenabling interrupts. Unless they have fixed it, a bug in MPSIM will cause a crash if IEs are reenabled with any pending interrupts. That said, MPSIM is probably easier to deal with to debug flash writes since you don't have to read the chip to see what the results of the code are.

All of that said, if I understand what you are trying to do, using flash for temp storage/buffering probably won't do.
 

Thread Starter

RG23

Joined Dec 6, 2010
304
Now I am using indirect addressing
I am using LFSR h'100' as the starting point

I store 488 data points in those locations and display them correctly.

Then I pause the signal data.

Now when I try to shift each point to the right I am not getting the data moving correctly.

To test it I used two switches

When I press the first switch it should dispay all the data points

When I press the second switch it should move those data points to the right
 
Last edited:
Top