Shop OBEX P1 Docs P2 Docs Learn Events
03_jm_flash_explorer.spin2 - I broke it — Parallax Forums

03_jm_flash_explorer.spin2 - I broke it

rogersydrogersyd Posts: 222
edited 2023-01-26 18:25 in PASM2/Spin2 (P2)

Hi all. I am experiencing challenges with a bit of code, hoping someone can provide a second or third set of eyes. I'm just a hack really, so excuse the crude code please :)

I am using JohnnyMac's 03_jm_flash_explorer.spin2 and have this bit of code write a block of data to the onboard flash on the P2 Edge. This code works correctly (see working.jpg):

pub writedc()|addr, t,n,x

  addr := $12_0000
  t := getct()
  addr &= $FFFFFF00
  repeat x from 0 to 1                                             ' force to page boundary
    flash.wr_page(addr+(x*256), @dc[x*256])
    repeat while flash.busy()
  t := getct() - t - 40
  term.fstr1(string("Write time: %.3fms\r\r"), t/US_001)
  term.str(string("Wrote flash at ",13))
  term.hex(addr)

However, when i try to turn "writedc" into a callable method with parameters using the code below, the data is not written completely to the flash. It appears to load the first 5 items from @dc just fine, and the rest becomes corrupt. (see broken.jpg) In this example, i have rewritten writedc to accept three parameters (the starting memory location to write to, the number of pages, the location of the data). To write a new block of data, first clearsomething wipes the block (this works), then writesomthing (this is broken), then readsomething back out (works).

pub testseq()

    clearsomething(dcID)  ' works as expected 
    waitms(100)
    writesomething(dcID,dcRepeat,@dc)   ' broken 
    waitms(100)
    readsomething(dcID,dcBytes,dclen,dccount,dcAttr)  ' works as expected 

pub writesomething(towrite,torepeat,todata)|t,n,x,addr

  addr := towrite
  t := getct()
  addr &= $FFFFFF00
  repeat x from 0 to torepeat                                            ' force to page boundary
    flash.wr_page(addr+(x*256), todata[x*256])
    repeat while flash.busy()
  t := getct() - t - 40
  term.fstr1(string("Write time: %.3fms\r\r"), t/US_001)
  term.str(string("Wrote flash at ",13))
  term.hex(addr)

The entire code is attached below. (it is really a mess sorry...) I was hoping to replace all the bespoke write functions with a single method i could just pass parameters into. I managed to get this working for the erase (clear) and read (display in terminal) functions, but the write function has me pounding my head on the table. I did try this with other blocks of data, and it yields similar results (meaning that much of data is written correctly, and then becomes janky after the first several bytes.)

If you happen to run this yourself, from the main menu, use option "2" (undocumented) to run the testseq() method.

To use the working writedc() method instead, use "g" to clear the space, "u" to right the data, and "n" to read it back.

This is not a mission critical project, but I would appreciate any advice. I could continue to write a bespoke method for every block of data i need to write, but I would prefer a general purpose function, as there will be many data types ill need to eventually write to the flash. Thanks in advance to the community for your advice (and for JohnnyMac for supplying the original code - as per usual.)

Comments

  • Reading the quickbyte again: "The 16MB Flash array is organized into 65,536 programmable pages of 256 bytes each. Up to 256 bytes can be programmed at a time. Pages can be erased in blocks of 16 (4KB) or 256 (64KB). Flash blocks must be erased before they can be programmed." I should be able to wrap my head around what is happening now that I re-read that. Read the manual much?

  • evanhevanh Posts: 15,187

    Ah, yes, the curse of EEPROMs, Flash being the most extreme of them. SD cards have a busy life hiding all this.

  • rogersydrogersyd Posts: 222
    edited 2023-01-26 18:42

    Well found a work around i guess. Probably not the most efficient way to do this but its workable, and still enables me to use a single write method, so I will take it as a win, if anyone is keeping score. Moving the repeat loop from the write method and repeating the call multiple times for each 256 byte page works, but I am still buffered while the other way didn't work. This workaround still feels like a kludge and will require more typing but whatever, Im moving on.

    pub testseq()|x
    
        clearsomething(outcomeID)
        waitms(100)
        repeat x from 0 to outcomePages
          writesomething(outcomeID+(x*256),@outcomes[x*256])
        waitms(100)
        readsomething(outcomeID,outcomelen,outcomecount,outcomeAttr)
    
    
    pub writesomething(towrite,todata)|t,n,x,addr
    
      addr := towrite
      t := getct()
      addr &= $FFFFFF00
      flash.wr_page(addr,todata)
      repeat while flash.busy()
    
  • JonnyMacJonnyMac Posts: 8,923
    edited 2023-01-27 01:43

    You have big address gaps in you data addresses. Will all of your data fit in 4K? It it will, consider reorganizing your storage so that you can read a 4K page into a RAM buffer and operate on that. It will certainly be faster. When done, erase that 4K block and then write the RAM buffer to it.

    so excuse the crude code please

    White space can be your friend. I suggest you start by redefining your memory locations. Consider something like this

    con { memory locations }
    
      TM_BASE   = $10_0000
    
      TM_ID     = TM_BASE + $0000
      TM_SHORT  = TM_BASE + $0010
      TM_NICK   = TM_BASE + $0020      
      TM_CITY   = TM_BASE + $0030
      TM_CON    = TM_BASE + $0040
      TM_DIV    = TM_BASE + $0050
    
    
      POS_BASE  = TM_BASE + $0100
    
      POS_ID    = POS_BASE + $0000
      POS_SHORT = POS_BASE + $0010 
      POS_LONG  = POS_BASE + $0020
      POS_SIDE  = POS_BASE + $0030 
    

    With the page read into RAM, you should be able to determine the array offset by subtracting TM_BASE from your named constant.

  • rogersydrogersyd Posts: 222
    edited 2023-01-27 23:41

    Thanks for the advice Jon. The C3 version of this game I am porting over to spin2 is much cleaner and better organized - I swear. I think at this point I am good to go here - thanks again for your demo code. After I integrate these methods into the old game (and update the rest of the code to spin2) I will be right back to where I was on the P1/C3 several years ago when I abandoned this project for the next shiny one. LOL. Good times.

Sign In or Register to comment.