Storing data in flash memory

Discussion in 'Embedded Systems and Microcontrollers' started by RG23, May 6, 2013.

  1. RG23

    Thread Starter Active Member

    Dec 6, 2010
    301
    2
    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
     
  2. MrChips

    Moderator

    Oct 2, 2009
    12,446
    3,362
    How much memory space do you have?
     
  3. JohnInTX

    Moderator

    Jun 26, 2012
    2,347
    1,029
    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.
     
  4. RG23

    Thread Starter Active Member

    Dec 6, 2010
    301
    2
    I am using PIC 18f67J90

    As per the memory usage gauge

    Program memory used: 25671 / 65532
     
  5. joeyd999

    AAC Fanatic!

    Jun 6, 2011
    2,686
    2,748
    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?
     
  6. RG23

    Thread Starter Active Member

    Dec 6, 2010
    301
    2
    Yes I am using tblwrt instruction
     
  7. JohnInTX

    Moderator

    Jun 26, 2012
    2,347
    1,029
    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: May 6, 2013
  8. RG23

    Thread Starter Active Member

    Dec 6, 2010
    301
    2
    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: May 6, 2013
  9. joeyd999

    AAC Fanatic!

    Jun 6, 2011
    2,686
    2,748
    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.


    Code ( (Unknown Language)):
    1.  
    2. ;*****************************************************
    3. ;** RDSENP -- Read Sensor UNI/O into Program Memory **
    4. ;***************************************************** 
    5.  
    6. rdsenp  call    unistat         ;ensure last write complete
    7.  
    8.     movlf   tblptrl,low hmstadd ;set starting address
    9.     movlf   tblptrh,high hmstadd
    10.  
    11.     movlf   temp5,hmblks        ;number of 1K blocks
    12.     movdf   temp10,ufcalmc      ;start of program record in uni/o (including checksums)
    13.  
    14. ;1st, erase a full row (1024 bytes) at tblptr
    15.  
    16. rdlp0
    17.     bsf eecon1,wren     ; enable write to memory
    18.     bsf eecon1,free     ; enable Row Erase operation
    19.     movlf   eecon2,0x55     ; write 55h
    20.     movlf   eecon2,0xAA     ; write 0AAh       
    21.     bsf eecon1,wr       ; start erase (CPU stall)
    22.  
    23.     tblrd   *-          ;point to first byte of block -1
    24.  
    25. ;2nd, read 16*64 bytes into write buffer
    26.  
    27.     movlf   temp4,16        ;number of 64 byte pages/block
    28.  
    29. rdlp1   call    unir64          ;get 64 bytes from UNI/O
    30.  
    31.     movlw   64
    32.     movwf   bitcnt          ;preload # bytes to copy
    33.     addwf   temp10,f        ;and update UNI/O address holder
    34.     clrw
    35.     addwfc  temp11,f
    36.  
    37.     lfsr    0,unibuf        ;point to UNI/O buffer
    38.  
    39. rdlp2   movff   postinc0,tablat     ;copy byte program memory buffer
    40.     tblwt   +*          ;do short write
    41.     djnz    bitcnt,rdlp2        ;do for 64 bytes
    42.  
    43. ;3rd preform a long write
    44.  
    45.     movlf   eecon2,0x55     ; write 55h
    46.     movlf   eecon2,0xAA     ; write 0AAh       
    47.     bsf eecon1,wr       ; start write (CPU stall)
    48.  
    49.     djnz    temp4,rdlp1     ;do for full block
    50.  
    51.     tblrd   *+          ;point to first byte of next block
    52.  
    53.     djnz    temp5,rdlp0     ;do for all blocks
    54.  
    55.     return
    56.  
    57.  
     
    Last edited: May 6, 2013
    Eric007 likes this.
  10. JohnInTX

    Moderator

    Jun 26, 2012
    2,347
    1,029
    Code ( (Unknown Language)):
    1. 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.
     
  11. RG23

    Thread Starter Active Member

    Dec 6, 2010
    301
    2
    Thank you John and joey

    I will try out your suggestions and let you know

    Thanks again
     
  12. RG23

    Thread Starter Active Member

    Dec 6, 2010
    301
    2
    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: May 8, 2013
Loading...