Shop OBEX P1 Docs P2 Docs Learn Events
SPI Flash Programming in P2ASM — Parallax Forums

SPI Flash Programming in P2ASM

proppyproppy Posts: 37
edited 2025-07-12 03:16 in Propeller 2

Hello!

I been working with SPI code a bit and the onboard SPI flash for the P2 Edge. I stumbled upon this code for an SPI programming but ran it through FlexProp and got an error for this line:
https://forums.parallax.com/discussion/165060/spi-flash-programmer-code/p1

testin  #spi_do     wc

to this

testp   #spi_do     wc

However, it doesn't seem to blink anything. I was able to try some of the code for reading and changed a few things. When I Compile and Flash a program via FlexProp the program is stored. I can then read/run the program on flash. Not sure why the code in the thread does not seem to work for the writing though.

Comments

  • RaymanRayman Posts: 15,358

    testp looks right. Not sure why doesn't work... Maybe post full code?

  • RaymanRayman Posts: 15,358

    You can get the spreadsheet with all the P2 assembly instructions here:
    https://www.parallax.com/propeller-2/documentation/

  • Hey there @Rayman!

    Sure thing! Here is that complete code:

    ' Program SPI flash with signed OUTB blinker program
    ' - Connect SPI flash (M25P80 okay) with pull-ups on spi_cs and spi_ck
    ' - Blinks OUTB on boot-up
    
    CON
    
      spi_cs = 61
      spi_ck = 60
      spi_di = 59
      spi_do = 58
    
    DAT
    
    
            org
    '
    '
    ' Init SPI pins
    '
            outh    #spi_cs
    
            dirh    #spi_cs
            dirh    #spi_ck
            dirh    #spi_di
    '
    '
    ' Erase 1st $1000 bytes
    '
            call    #spi_wrena      'write enable
    
            mov cmd,cmd_erase       'sector erase
            call    #spi_cmd32
    
            call    #spi_wait       'wait for completion
    '
    '
    ' Program first $400 bytes
    '
            loc ptra,#\pgmdata      'point to program data
    
    .program    call    #spi_wrena      'write enable
    
            mov cmd,cmd_program     'page program
            or  cmd,adr
            call    #spi_cmd32
    
    .byte       rdbyte  cmd,ptra++      'get byte
    
            mov x,#8            'send byte
            shl cmd,#24
            call    #spi_out
    
            add adr,#1          'page done?
            test    adr,#$FF    wz
        if_nz   jmp #.byte
    
            call    #spi_wait       'wait for completion
    
            testb   adr,#10     wz  'another page?
        if_z    jmp #.program
    '
    '
    ' Read data back to outa for viewing on logic analyzer
    '
            mov dira,#$1FF
    
    .read1k     mov cmd,cmd_read        'start read
            call    #spi_cmd32
    
            outh    #8          'trigger signal
            outl    #8
    
            decod   y,#10           'read byte to outa
    .read       call    #spi_in
            setbyte outa,cmd,#0
            djnz    y,#.read
    
            jmp #.read1k        'loop
    '
    '
    ' SPI write enable
    '
    spi_wrena   mov cmd,#$06        'write enable
            call    #spi_cmd8
    
            ret
    '
    '
    ' SPI wait while busy
    '
    spi_wait    mov cmd,#$05
            call    #spi_cmd8
    
    .wait       call    #spi_in
            test    cmd,#$01    wc
        if_c    jmp #.wait
    
            ret
    '
    '
    ' SPI command
    '
    spi_cmd32   mov x,#32
            jmp #spi_cmd
    
    spi_cmd8    mov x,#8
            shl cmd,#24
    
    spi_cmd     outh    #spi_cs
            outl    #spi_cs
    '
    '
    ' SPI long/byte out (x=bits, cmd=msbdata)
    '
    spi_out     rep @.r,x
            shl cmd,#1      wc
            outc    #spi_di
            outh    #spi_ck
            outl    #spi_ck
    .r
            ret
    '
    '
    ' SPI byte in (cmd)
    '
    spi_in
        mov y, #8
        mov cmd, #0
    .rdloop
        outh    #spi_ck
        testp   #spi_do wc
        rcl cmd, #1
        outl    #spi_ck
        djnz    y, #.rdloop
        ret
    '
    '
    ' Data
    '
    cmd_erase   long    $20_00_00_00
    cmd_program long    $02_00_00_00
    cmd_read    long    $03_00_00_00
    adr     long    0
    '
    '
    ' Variables
    '
    cmd     res 1
    x       res 1
    y       res 1
    '
    '
    ' Program Data
    '
    ' first 20 bytes are blinker program:
    '
    '   not dirb
    '.lp    not outb
    '   waitx   ##20_000_000/4
    '   jmp #.lp
    '
    ' last 32 bytes are signature (key=0)
    '
        orgh
    
    pgmdata byte    $FB,$F7,$23,$F6,$FD,$FB,$23,$F6,$25,$26,$80,$FF,$28,$80,$66,$FD 'blinker program
        byte    $F0,$FF,$9F,$FD,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
        byte    $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
        byte    $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
        byte    $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
        byte    $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
        byte    $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
        byte    $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
        byte    $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
        byte    $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
        byte    $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
        byte    $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
        byte    $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
        byte    $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
        byte    $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
        byte    $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
        byte    $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
        byte    $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
        byte    $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
        byte    $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
        byte    $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
        byte    $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
        byte    $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
        byte    $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
        byte    $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
        byte    $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
        byte    $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
        byte    $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
        byte    $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
        byte    $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
        byte    $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
        byte    $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
        byte    $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
        byte    $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
        byte    $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
        byte    $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
        byte    $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
        byte    $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
        byte    $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
        byte    $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
        byte    $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
        byte    $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
        byte    $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
        byte    $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
        byte    $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
        byte    $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
        byte    $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
        byte    $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
        byte    $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
        byte    $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
        byte    $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
        byte    $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
        byte    $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
        byte    $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
        byte    $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
        byte    $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
        byte    $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
        byte    $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
        byte    $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
        byte    $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
        byte    $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
        byte    $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
        byte    $99,$AA,$44,$98,$86,$E2,$C8,$71,$C3,$1E,$60,$BF,$A3,$36,$19,$7A 'SHA-256/HMAC signature
        byte    $F5,$3D,$53,$97,$5C,$AF,$BA,$BB,$B7,$7F,$C3,$0A,$B4,$24,$02,$40
    

    I only changed that line in FlexProp. But even then it doesn't work as it should i think. I know it's writing something though since it overwrote the program i had in place previously on the spi Flash. I've been having a bit of trouble with this thing having the boot mode on/off. Very weird behavior at times. I got the read working from using the manual a bit and this code.

  • JonnyMacJonnyMac Posts: 9,375
    edited 2025-06-19 23:04

    Yes, testp is the correct instruction. This code is for PNut (FlexProp does inline assembly differently), but this code does work.

    pri shiftin(bits) : result | tix
    
      tix := ticks                                                  ' tix in 1/2 clock
    
      org
                    rep       #6, bits
                     testp    #SF_MISO                      wc      ' scan MISO
                     rcl      result, #1                            ' move new bit to result.0
                     drvh     #SF_SCLK                              ' clock next bit
                     waitx    tix
                     drvl     #SF_SCLK
                     waitx    tix
      end
    
  • Hello @JonnyMac!

    @JonnyMac said:
    Yes, testp is the correct instruction. This code is for PNut (FlexProp does inline assembly differently), but this code does work.

    Thank you. Okay I did get reading working in another program. I think i'll pick apart the writing part a bit under FlexProp and see what I come up with.

  • evanhevanh Posts: 16,582

    I recommend use of SPI clock mode 3 rather than 0. The shared SD card wiring conflicts much less when the clock idles high.

  • Howdy @evanh

    @evanh said:
    I recommend use of SPI clock mode 3 rather than 0. The shared SD card wiring conflicts much less when the clock idles high.

    I'll give this a shot as well in the future. Would this wiring conflict cause an SD card to randomly delete itself? I went through some SD card code and created a driver for writing which works based on the reading you had helped with before. I noticed if I ran the code a few times though it blew away the SD card once i tried to read. Off-topic but just curious.

  • evanhevanh Posts: 16,582
    edited 2025-06-20 13:53

    All it would take is the erasure of block zero to stop a SD card from mounting correctly. So, yes, routines built to write blocks can easily accidentally make the card look empty. There is no filesystem management by the card itself.

    As for SPI clock mode 0, I expect it would more likely cause lock-ups rather than erasures. But I have no specific evidence of what actually happens though.

  • evanhevanh Posts: 16,582

    Another problem I discovered recently is the historical FSRW SD card FAT filesystem for the Propellers has had deficiencies in its driver layer that did not wait for card busy condition. This is particularly bad thing when writing blocks. The chances of skipped blocks is high.

    If you've been using FSRW software then that would explain filesystem corruption.

  • Well, the CRC checksums are supposed to protect against such corruption, but SPI mode doesn't use them by default... On the P2 nothing should be stopping us from using CMD59 to enable them.

  • proppyproppy Posts: 37
    edited 2025-06-20 20:05

    @evanh said:
    Another problem I discovered recently is the historical FSRW SD card FAT filesystem for the Propellers has had deficiencies in its driver layer that did not wait for card busy condition. This is particularly bad thing when writing blocks. The chances of skipped blocks is high.

    If you've been using FSRW software then that would explain filesystem corruption.

    Thanks for this. That narrows things down a bit. I'm doing FAT32 cause that's what I'm most familiar with.

    I got a little further but I'm pretty sure the program never moves from hub ram to the flash.

    ' Program SPI flash with signed program
    
    CON
    
      spi_cs = 61
      spi_ck = 60
      spi_di = 59
      spi_do = 58
    
    DAT
        orgh
    
    pgmdata byte $02, $00, $00, $FF, $04, $00, $6C, $FC, $02, $00, $00, $FF, $48, $84, $4C, $FC
    byte $02, $00, $00, $FF, $49, $00, $4C, $FC, $02, $00, $00, $FF, $04, $02, $6C, $FC
    byte $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
    byte $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
    byte $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
    byte $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
    byte $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
    byte $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
    byte $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
    byte $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
    byte $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
    byte $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
    byte $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
    byte $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
    byte $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
    byte $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
    byte $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
    byte $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
    byte $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
    byte $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
    byte $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
    byte $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
    byte $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
    byte $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
    byte $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
    byte $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
    byte $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
    byte $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
    byte $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
    byte $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
    byte $99, $AA, $44, $98, $86, $E2, $C8, $71, $C3, $1E, $60, $BF, $A3, $36, $19, $7A  'SHA-256/HMAC signature
    byte $F5, $3D, $53, $97, $5C, $AF, $BA, $BB, $B7, $7F, $C3, $0A, $B4, $24, $02, $40
    
            org
            asmclk
    '
    '
    ' Init SPI pins
    '
            outh    #spi_cs
            dirh    #spi_cs
            dirh    #spi_ck
            dirh    #spi_di
    '
    '
    ' Erase 1st $1000 bytes
    '
            call    #spi_wrena      'write enable
    
            mov cmd,cmd_erase       'sector erase
            call    #spi_cmd32
    
            call    #spi_wait       'wait for completion
    '
    '
    ' Program first $400 bytes
    '
            loc ptra,#\pgmdata      'point to program data
    
    .program    call    #spi_wrena      'write enable
    
            mov cmd,cmd_program     'page program
            or  cmd,adr
            call    #spi_cmd32
    
    .byte       rdbyte  cmd,ptra++      'get byte
    
            mov x,#8            'send byte
            shl cmd,#24
            call    #spi_out
    
            add adr,#1          'page done?
            test    adr,#$FF    wz
        if_nz   jmp #.byte
    
            call    #spi_wait       'wait for completion
    
            cmp adr, ##$100 wz
            if_nz jmp #.program
    
    '
    '
    ' Read data back to outa for viewing on logic analyzer
    '
            mov dira,#$1FF
    
    .read1k     mov cmd,cmd_read        'start read
            call    #spi_cmd32
    
            outh    #8          'trigger signal
            outl    #8
    
            decod   y,#10           'read byte to outa
    .read       call    #spi_in
            setbyte outa,cmd,#0
            djnz    y,#.read
    
            jmp #.read1k        'loop
    '
    '
    ' SPI write enable
    '
    spi_wrena   mov cmd,#$06        'write enable
            call    #spi_cmd8
    
            ret
    '
    '
    ' SPI wait while busy
    '
    spi_wait    mov cmd,#$05
            call    #spi_cmd8
    
    .wait       call    #spi_in
            test    cmd,#$01    wc
        if_c    jmp #.wait
    
            ret
    '
    '
    ' SPI command
    '
    spi_cmd32   mov x,#32
            jmp #spi_cmd
    
    spi_cmd8    mov x,#8
            shl cmd,#24
    
    spi_cmd     outh    #spi_cs
            outl    #spi_cs
    '
    '
    ' SPI long/byte out (x=bits, cmd=msbdata)
    '
    spi_out     rep @.r,x
            shl cmd,#1      wc
            outc    #spi_di
            outh    #spi_ck
            outl    #spi_ck
    .r
            ret
    '
    '
    ' SPI byte in (cmd)
    '
    spi_in      rep @.r,#8
            outh    #spi_ck
            outl    #spi_ck
            testp   #spi_do     wc  'due to latencies, 'testin' is from 2 clocks before 'outh'
            rcl cmd,#1
    .r
            ret
    '
    '
    ' Data
    '
    cmd_erase   long    $20_00_00_00    ' Sector Erase command
    cmd_program long    $02_00_00_00    ' Page Program command
    cmd_read    long    $03_00_00_00    ' Read Data command
    adr         long    $00_00_00_00    ' 24-bit address, MSB aligned
    
    '
    '
    ' Variables
    '
    cmd     res 1
    x       res 1
    y       res 1
    '
    '
    ' Program Data
    '
    ' first 20 bytes are blinker program:
    '
    '   not dirb
    '.lp    not outb
    '   waitx   ##20_000_000/4
    '   jmp #.lp
    '
    ' last 32 bytes are signature (key=0)
    '
    

    I may plug away at understanding it a bit more later. Also, I think i might need to generate a new signature. I noticed i was using the one found in the example found here: https://forums.parallax.com/discussion/165060/spi-flash-programmer-code/p1. Though honestly it does work if run from hub ram. I kept in the testp but also replaced the testb with cmp

            cmp adr, ##$100 wz
            if_nz jmp #.program
    
  • ersmithersmith Posts: 6,184

    There's some sample flash programming code in spin2cpp; for example, in Chip's parallax file system (include/filesys/parallax/flash_fs.spin2) and in the littlefs file system code (include/filesys/littlefs/SpiFlash.spin2).

    If you're trying to learn how to write programs into the flash, the sources for loadp2 or propeller-loader would be useful. On the P2 booting from flash is a two step process: the ROM loads the first 256 bytes (or so, I may be misremembering the size) from flash into RAM, and then runs that. So the first part of the flash must be a small stand-alone program capable of loading the rest of the program into flash. Chip's code for this is the file "flash_stub.spin2" in the loadp2 source code (https://github.com/totalspectrum/loadp2).

  • Hiya @ersmith!

    Firstly, thank you for all your efforts on FlexProp.

    @ersmith said:
    If you're trying to learn how to write programs into the flash,

    Yes, exactly. I’ll have a look at this stuff before I continue. I would like to finish this before moving onto dual I/O.

  • pik33pik33 Posts: 2,413

    @evanh said:
    I recommend use of SPI clock mode 3 rather than 0. The shared SD card wiring conflicts much less when the clock idles high.

    +1 to this. Mode 3 or problems with SD cards

  • Hey all,

    I was able to work out a few things and got the results i was looking for. I decided to use the Flash 6 Click and connect it to my mikroebus adapter on the P2 Edge breakout board. I started from the ground up and worked my way through the commands. So maybe this might help someone else running into the same problem.

    Reading the JEDEC:

    CON
      _CLKFREQ  = 180_000_000
    
      ' UART on P62
      RX_PIN = 63
      TX_PIN = 62
      BAUD_RATE = 2000000
      SERIAL_CLOCK = (_CLKFREQ / BAUD_RATE)
      BIT_PERIOD = ((SERIAL_CLOCK << 16) & $FFFFFC00) + (8 - 1)
    
      ' SPI pins
      spi_cs   = 8
      spi_ck   = 9
      spi_miso = 10
      spi_mosi = 11
      spi_hld  = 4
      spi_wp   = 5
    
    DAT
    org 0
    asmclk
    
    ' ---- UART TX init ----
            wrpin   ##(P_ASYNC_TX | P_OE), #TX_PIN
            wxpin   ##BIT_PERIOD, #TX_PIN
            wypin   #1, #TX_PIN
            dirh    #TX_PIN
    
    ' ---- SPI GPIO Init ----
            outh    #spi_cs
            outh    #spi_hld
            outh    #spi_wp
    
            dirh    #spi_cs
            dirh    #spi_ck
            dirh    #spi_mosi
            dirh    #spi_hld
            dirh    #spi_wp
    
        outh    #spi_ck    ' Clock starts high
    
    ' ---- Read JEDEC ID ----
            call    #spi_jedec
    
    ' ---- Print JEDEC Information ----
            mov     result, manufacturer_id
            call    #print_hex_byte
            call    #uart_tx_space
    
            mov     result, memory_type_id1
            call    #print_hex_byte
            call    #uart_tx_space
    
            mov     result, capacity
            call    #print_hex_byte
            call    #uart_tx_space
    
            call    #uart_tx_nl
    
            jmp     #endprog
    
    ' ---- JEDEC ID/Information Read ----
    spi_jedec
            outl    #spi_cs          ' CS low
    
            mov     cmd, #$9F
            call    #spi_cmd8        
    
            call    #spi_in
            mov     manufacturer_id, cmd
    
            call    #spi_in
            mov     memory_type_id1, cmd
    
            call    #spi_in
            mov     capacity, cmd
    
            outh    #spi_cs          ' CS high
            ret
    
    ' ---- Send 8 bits (MSB first) ----
    spi_cmd8
            mov     x, #8
            shl     cmd, #24
            jmp     #spi_cmd
    
    spi_cmd
            rep     @.r, x
            shl     cmd, #1 wc
            outc    #spi_mosi
            waitx   ##45
            outl    #spi_ck          ' falling edge (sample in slave)
            waitx   ##45
            outh    #spi_ck
    .r
            ret
    
    ' ---- Read 8 bits (MSB first) ----
    spi_in
            mov     y, #8
            mov     cmd, #0
    .rdloop
            waitx   ##45
            outl    #spi_ck          ' falling edge: sample MISO
            waitx   ##10             ' setup/hold time
            testp   #spi_miso wc
            rcl     cmd, #1
            waitx   ##45
            outh    #spi_ck
            djnz    y, #.rdloop
            ret
    
    ' ---- UART hexadecimal Output ----
    print_hex_byte
            mov     temp, result
            mov     pr0, temp
            shr     pr0, #4
            and     pr0, #$F
            call    #print_nibble
            mov     pr0, temp
            and     pr0, #$F
            call    #print_nibble
            ret
    
    print_nibble
            cmp     pr0, #10 wc
      if_b  add     pr0, #"0"
      if_nc add     pr0, #"A"-10
            mov     result, pr0
            call    #uart_tx_char
            ret
    
    ' ---- UART character Output ----
    uart_tx_char
            wypin   result, #TX_PIN
    .tx
            rdpin   pr2, #TX_PIN wc
      if_c  jmp     #.tx
            ret
    
    uart_tx_space
            mov     result, #" "
            call    #uart_tx_char
            ret
    
    uart_tx_nl
            mov     result, #13
            call    #uart_tx_char
            mov     result, #10
            call    #uart_tx_char
            ret
    
    ' ---- End ----
    endprog
    
    ' ---- General Variables ----
    cmd     res 1
    x       res 1
    y       res 1
    temp    res 1
    result  res 1
    
    ' ---- Flash Variables ----
    manufacturer_id res 1
    memory_type_id1 res 1
    capacity res 1
    

    Performing the write enable

    CON
      _CLKFREQ  = 180_000_000
    
      ' UART on P62
      RX_PIN = 63
      TX_PIN = 62
      BAUD_RATE = 2000000
      SERIAL_CLOCK = (_CLKFREQ / BAUD_RATE)
      BIT_PERIOD = ((SERIAL_CLOCK << 16) & $FFFFFC00) + (8 - 1)
    
      ' SPI pins
      spi_cs   = 8
      spi_ck   = 9
      spi_miso = 10
      spi_mosi = 11
      spi_hld  = 4
      spi_wp   = 5
    
    DAT
    org 0
    asmclk
    
    ' ---- UART TX init ----
            wrpin   ##(P_ASYNC_TX | P_OE), #TX_PIN
            wxpin   ##BIT_PERIOD, #TX_PIN
            wypin   #1, #TX_PIN
            dirh    #TX_PIN
    
    ' ---- SPI Init ----
            outh    #spi_cs
            outh    #spi_hld
            outh    #spi_wp
    
            dirh    #spi_cs
            dirh    #spi_ck
            dirh    #spi_mosi
            dirh    #spi_hld
            dirh    #spi_wp
    
    ' ----  Write enable ----
            call    #spi_write_enable
    
    ' ----  Read Status Register ----
            call #spi_rdsr
    
    ' ---- Print Status Register ----
            mov     result, RDSR1
            call    #print_hex_byte
            call    #uart_tx_space
    
            call    #uart_tx_nl
    
            jmp     #endprog
    
    ' ---- Write Enable ----
    spi_write_enable
            outl    #spi_cs          ' CS low
    
            mov     cmd, #$06
            call    #spi_cmd8        
    
            outh    #spi_cs          ' CS high
            ret
    
    ' ---- READ STATUS REGISTER (RDSR) ----
    spi_rdsr
            outl    #spi_cs          ' CS low
    
            mov     cmd, #$05
            call    #spi_cmd8        
    
            call    #spi_in
            mov     RDSR1, cmd
    
            outh    #spi_cs          ' CS high
            ret
    
    ' ---- Send 8 bits (MSB first) ----
    spi_cmd8
            mov     x, #8
            shl     cmd, #24
            jmp     #spi_cmd
    
    spi_cmd
            rep     @.r, x
            shl     cmd, #1 wc
            outc    #spi_mosi
            waitx   ##45
            outl    #spi_ck          ' falling edge (sample in slave)
            waitx   ##45
            outh    #spi_ck
    .r
            ret
    
    ' ---- Read 8 bits (MSB first) ----
    spi_in
            mov     y, #8
            mov     cmd, #0
    .rdloop
            waitx   ##45
            outl    #spi_ck          ' falling edge: sample MISO
            waitx   ##10             ' setup/hold time
            testp   #spi_miso wc
            rcl     cmd, #1
            waitx   ##45
            outh    #spi_ck
            djnz    y, #.rdloop
            ret
    
    ' ---- UART hexadecimal Output ----
    print_hex_byte
            mov     temp, result
            mov     pr0, temp
            shr     pr0, #4
            and     pr0, #$F
            call    #print_nibble
            mov     pr0, temp
            and     pr0, #$F
            call    #print_nibble
            ret
    
    print_nibble
            cmp     pr0, #10 wc
      if_b  add     pr0, #"0"
      if_nc add     pr0, #"A"-10
            mov     result, pr0
            call    #uart_tx_char
            ret
    
    ' ---- UART character Output ----
    uart_tx_char
            wypin   result, #TX_PIN
    .tx
            rdpin   pr2, #TX_PIN wc
      if_c  jmp     #.tx
            ret
    
    uart_tx_space
            mov     result, #" "
            call    #uart_tx_char
            ret
    
    uart_tx_nl
            mov     result, #13
            call    #uart_tx_char
            mov     result, #10
            call    #uart_tx_char
            ret
    
    ' ---- End ----
    endprog
    
    ' ---- General Variables ----
    cmd     res 1
    x       res 1
    y       res 1
    temp    res 1
    result  res 1
    
    ' ---- Eeprom Variables ----
    RDSR1 res 1
    

    Performing a single byte write, but also the sector erase:

    CON
      _CLKFREQ  = 180_000_000
    
      ' UART on P62
      RX_PIN = 63
      TX_PIN = 62
      BAUD_RATE = 2000000
      SERIAL_CLOCK = (_CLKFREQ / BAUD_RATE)
      BIT_PERIOD = ((SERIAL_CLOCK << 16) & $FFFFFC00) + (8 - 1)
    
      ' SPI pins
      spi_cs   = 8
      spi_ck   = 9
      spi_miso = 10
      spi_mosi = 11
      spi_hld  = 4
      spi_wp   = 5
    
    DAT
    org 0
    asmclk
    
    ' ---- UART TX init ----
            wrpin   ##(P_ASYNC_TX | P_OE), #TX_PIN
            wxpin   ##BIT_PERIOD, #TX_PIN
            wypin   #1, #TX_PIN
            dirh    #TX_PIN
    
    ' ---- SPI Init ----
            outh    #spi_cs
            outh    #spi_hld
            outh    #spi_wp
    
            dirh    #spi_cs
            dirh    #spi_ck
            dirh    #spi_mosi
            dirh    #spi_hld
            dirh    #spi_wp
    
    ' ----  Write enable ----
            call #spi_write_enable
    
    ' ----  Read Status Register ----
            call #spi_rdsr
    
    ' ---- Print ----
        mov     addr, #$0         ' Pick address 0x00
    
            call    #spi_write_enable     ' Send 06h
    
        call #spi_erase_sector
    
        call #spi_write_enable
    
        mov     addr, #$0        ' Pick address 0x00
        mov data, #"A"
        call #spi_byte_write
    
        mov     result, data
        call    #print_hex_byte
            call    #uart_tx_space
    
            call    #uart_tx_nl
    
            jmp     #endprog
    
    ' ---- Write Enable ----
    spi_write_enable
            outl    #spi_cs          ' CS low
    
            mov     cmd, #$06
            call    #spi_cmd8        
    
            outh    #spi_cs          ' CS high
            ret
    
    ' ---- READ STATUS REGISTER (RDSR) ----
    spi_rdsr
            outl    #spi_cs          ' CS low
    
            mov     cmd, #$05
            call    #spi_cmd8        
    
            call    #spi_in
            mov     RDSR1, cmd
    
            outh    #spi_cs          ' CS high
            ret
    
    spi_erase_sector
            outl    #spi_cs               ' CS low
    
            mov     cmd, #$20             ' Sector Erase
            call    #spi_cmd8              ' Send command
    
            call    #spi_send_address24     ' Send address
    
            outh    #spi_cs        ' CS high
    
    .wait_busy
        call    #spi_rdsr
        testb   RDSR1, #0 wz       ' Test if all bits are 0
      if_z     jmp #.wait_busy    ' Loop again if BUSY/non-ero
      ret                ' Return only when all bits are 0
    
    spi_byte_write      
            outl    #spi_cs          ' CS low
    
            mov     cmd, #$02          ' WRITE command
            call    #spi_cmd8
    
            ' Send 24-bit address (A23-A0), top bits don't matter
            mov     cmd, addr
            shr     cmd, #16
            call    #spi_cmd8          ' A23–A16
            mov     cmd, addr
            shr     cmd, #8
            and     cmd, #$FF
            call    #spi_cmd8          ' A15–A8
            mov     cmd, addr
            and     cmd, #$FF
            call    #spi_cmd8          ' A7–A0
    
            ' Send data byte
            mov     cmd, data
            call    #spi_cmd8
    
            outh    #spi_cs          ' CS high
            ret
    
            ' ---- Send 24-bit address ----
    spi_send_address24
            mov     cmd, addr
            shr     cmd, #16
            call    #spi_cmd8      ' A23–A16
            mov     cmd, addr
            shr     cmd, #8
            and     cmd, #$FF
            call    #spi_cmd8      ' A15–A8
            mov     cmd, addr
            and     cmd, #$FF
            call    #spi_cmd8      ' A7–A0
    
            ret
    
    
    ' ---- Send 8 bits (MSB first) ----
    spi_cmd8
            mov     x, #8
            shl     cmd, #24
            jmp     #spi_cmd
    
    spi_cmd
            rep     @.r, x
            shl     cmd, #1 wc
            outc    #spi_mosi
            waitx   ##45
            outl    #spi_ck          ' falling edge (sample in slave)
            waitx   ##45
            outh    #spi_ck
    .r
            ret
    
    ' ---- Read 8 bits (MSB first) ----
    spi_in
            mov     y, #8
            mov     cmd, #0
    .rdloop
            waitx   ##45
            outl    #spi_ck          ' falling edge: sample MISO
            waitx   ##10             ' setup/hold time
            testp   #spi_miso wc
            rcl     cmd, #1
            waitx   ##45
            outh    #spi_ck
            djnz    y, #.rdloop
            ret
    
    ' ---- UART hexadecimal Output ----
    print_hex_byte
            mov     temp, result
            mov     pr0, temp
            shr     pr0, #4
            and     pr0, #$F
            call    #print_nibble
            mov     pr0, temp
            and     pr0, #$F
            call    #print_nibble
            ret
    
    print_nibble
            cmp     pr0, #10 wc
      if_b  add     pr0, #"0"
      if_nc add     pr0, #"A"-10
            mov     result, pr0
            call    #uart_tx_char
            ret
    
    ' ---- UART character Output ----
    uart_tx_char
            wypin   result, #TX_PIN
    .tx
            rdpin   pr2, #TX_PIN wc
      if_c  jmp     #.tx
            ret
    
    uart_tx_space
            mov     result, #" "
            call    #uart_tx_char
            ret
    
    uart_tx_nl
            mov     result, #13
            call    #uart_tx_char
            mov     result, #10
            call    #uart_tx_char
            ret
    
    ' ---- End ----
    endprog
    
    ' ---- General Variables ----
    cmd     res 1
    x       res 1
    y       res 1
    temp    res 1
    result  res 1
    
    ' ---- Flash Variables ----
    RDSR1 res 1
    addr    res 1
    data    res 1
    

    Doing a read of the byte that was written:

    CON
      _CLKFREQ  = 180_000_000
    
      ' UART on P62
      RX_PIN = 63
      TX_PIN = 62
      BAUD_RATE = 2000000
      SERIAL_CLOCK = (_CLKFREQ / BAUD_RATE)
      BIT_PERIOD = ((SERIAL_CLOCK << 16) & $FFFFFC00) + (8 - 1)
    
      ' SPI pins
      spi_cs   = 8
      spi_ck   = 9
      spi_miso = 10
      spi_mosi = 11
      spi_hld  = 4
      spi_wp   = 5
    
    DAT
    org 0
    asmclk
    
    ' ---- UART TX init ----
            wrpin   ##(P_ASYNC_TX | P_OE), #TX_PIN
            wxpin   ##BIT_PERIOD, #TX_PIN
            wypin   #1, #TX_PIN
            dirh    #TX_PIN
    
    ' ---- SPI Init ----
            outh    #spi_cs
            outh    #spi_hld
            outh    #spi_wp
    
            dirh    #spi_cs
            dirh    #spi_ck
            dirh    #spi_mosi
            dirh    #spi_hld
            dirh    #spi_wp
    
    ' ---- Print ----
        mov     addr, #$0         ' Pick address 0x10
        call #spi_byte_read
    
        mov     result, data
        call    #print_hex_byte
        call    #uart_tx_space
    
        mov     result, data
        call #uart_tx_char
            call    #uart_tx_space
    
            call    #uart_tx_nl
    
            jmp     #endprog
    
    spi_byte_read       
            outl    #spi_cs
    
            mov     cmd, #$03          ' READ command
            call    #spi_cmd8
    
            ' Send 24-bit address
        call #spi_send_address24
    
            ' Read data byte
            call    #spi_in
            mov     data, cmd          ' Save read byte
    
            outh    #spi_cs
            ret
    
    spi_send_address24
            mov     cmd, addr
            shr     cmd, #16
            call    #spi_cmd8      ' A23–A16
            mov     cmd, addr
            shr     cmd, #8
            and     cmd, #$FF
            call    #spi_cmd8      ' A15–A8
            mov     cmd, addr
            and     cmd, #$FF
            call    #spi_cmd8      ' A7–A0
    
            ret
    
    ' ---- Send 8 bits (MSB first) ----
    spi_cmd8
            mov     x, #8
            shl     cmd, #24
            jmp     #spi_cmd
    
    spi_cmd
            rep     @.r, x
            shl     cmd, #1 wc
            outc    #spi_mosi
            waitx   ##45
            outl    #spi_ck          ' falling edge (sample in slave)
            waitx   ##45
            outh    #spi_ck
    .r
            ret
    
    ' ---- Read 8 bits (MSB first) ----
    spi_in
            mov     y, #8
            mov     cmd, #0
    .rdloop
            waitx   ##45
            outl    #spi_ck          ' falling edge: sample MISO
            waitx   ##10             ' setup/hold time
            testp   #spi_miso wc
            rcl     cmd, #1
            waitx   ##45
            outh    #spi_ck
            djnz    y, #.rdloop
            ret
    
    ' ---- UART hexadecimal Output ----
    print_hex_byte
            mov     temp, result
            mov     pr0, temp
            shr     pr0, #4
            and     pr0, #$F
            call    #print_nibble
            mov     pr0, temp
            and     pr0, #$F
            call    #print_nibble
            ret
    
    print_nibble
            cmp     pr0, #10 wc
      if_b  add     pr0, #"0"
      if_nc add     pr0, #"A"-10
            mov     result, pr0
            call    #uart_tx_char
            ret
    
    ' ---- UART decimal Output ----
    uart_tx_char
            wypin   result, #TX_PIN
    .tx
            rdpin   pr2, #TX_PIN wc
      if_c  jmp     #.tx
            ret
    
    uart_tx_space
            mov     result, #" "
            call    #uart_tx_char
            ret
    
    uart_tx_nl
            mov     result, #13
            call    #uart_tx_char
            mov     result, #10
            call    #uart_tx_char
            ret
    
    ' ---- End ----
    endprog
    
    ' ---- General Variables ----
    cmd     res 1
    x       res 1
    y       res 1
    temp    res 1
    result  res 1
    
    ' ---- Flash Variables ----
    RDSR1 res 1
    addr    res 1
    data    res 1
    

    Reading again, but for a full page (256 bytes):

    CON
      _CLKFREQ  = 180_000_000
    
      ' UART on P62
      RX_PIN = 63
      TX_PIN = 62
      BAUD_RATE = 2000000
      SERIAL_CLOCK = (_CLKFREQ / BAUD_RATE)
      BIT_PERIOD = ((SERIAL_CLOCK << 16) & $FFFFFC00) + (8 - 1)
    
      ' SPI pins
      spi_cs   = 8
      spi_ck   = 9
      spi_miso = 10
      spi_mosi = 11
      spi_hld  = 4
      spi_wp   = 5
    
    DAT
    org 0
    asmclk
    
    ' ---- UART TX init ----
            wrpin   ##(P_ASYNC_TX | P_OE), #TX_PIN
            wxpin   ##BIT_PERIOD, #TX_PIN
            wypin   #1, #TX_PIN
            dirh    #TX_PIN
    
    ' ---- SPI Init ----
            outh    #spi_cs
            outh    #spi_hld
            outh    #spi_wp
    
            dirh    #spi_cs
            dirh    #spi_ck
            dirh    #spi_mosi
            dirh    #spi_hld
            dirh    #spi_wp
    
    ' ---- Print ----
        mov     addr, #$0         ' Pick address 0x00
        mov cnt, #0
    
        call #spi_page_read
    
            call    #uart_tx_nl
    
            jmp     #endprog
    
    spi_page_read
            outl    #spi_cs
    
            mov     cmd, #$03            ' READ command
            call    #spi_cmd8
    
            ' Send 24-bit address
            mov     cmd, addr
            shr     cmd, #16
            call    #spi_cmd8            ' A23–A16
            mov     cmd, addr
            shr     cmd, #8
            and     cmd, #$FF
            call    #spi_cmd8            ' A15–A8
            mov     cmd, addr
            and     cmd, #$FF
            call    #spi_cmd8            ' A7–A0
    
            ' Read 256 bytes
            mov     cnt, #256
    .read_loop
            call    #spi_in
            mov     result, cmd          ' Store read byte to result
    
            ' Optional:  switch between hex print or character print or both
            'call    #print_hex_byte
            call    #uart_tx_char
            call    #uart_tx_space
    
            djnz    cnt, #.read_loop
    
            outh    #spi_cs
            ret
    
    ' ---- Send 8 bits (MSB first) ----
    spi_cmd8
            mov     x, #8
            shl     cmd, #24
            jmp     #spi_cmd
    
    spi_cmd
            rep     @.r, x
            shl     cmd, #1 wc
            outc    #spi_mosi
            waitx   ##45
            outl    #spi_ck          ' falling edge (sample in slave)
            waitx   ##45
            outh    #spi_ck
    .r
            ret
    
    ' ---- Read 8 bits (MSB first) ----
    spi_in
            mov     y, #8
            mov     cmd, #0
    .rdloop
            outl    #spi_ck          ' falling edge: sample MISO
            waitx   ##10             ' setup/hold time
            testp   #spi_miso wc
            rcl     cmd, #1
            outh    #spi_ck
            djnz    y, #.rdloop
            ret
    
    ' ---- UART hexadecimal Output ----
    print_hex_byte
            mov     temp, result
            mov     pr0, temp
            shr     pr0, #4
            and     pr0, #$F
            call    #print_nibble
            mov     pr0, temp
            and     pr0, #$F
            call    #print_nibble
            ret
    
    print_nibble
            cmp     pr0, #10 wc
      if_b  add     pr0, #"0"
      if_nc add     pr0, #"A"-10
            mov     result, pr0
            call    #uart_tx_char
            ret
    
    ' ---- UART decimal Output ----
    uart_tx_char
            wypin   result, #TX_PIN
    .tx
            rdpin   pr2, #TX_PIN wc
      if_c  jmp     #.tx
            ret
    
    uart_tx_space
            mov     result, #" "
            call    #uart_tx_char
            ret
    
    uart_tx_nl
            mov     result, #13
            call    #uart_tx_char
            mov     result, #10
            call    #uart_tx_char
            ret
    
    ' ---- End ----
    endprog
    
    ' ---- General Variables ----
    cmd     res 1
    x       res 1
    y       res 1
    temp    res 1
    result  res 1
    cnt res 1
    
    ' ---- Flash Variables ----
    RDSR1 res 1
    addr    res 1
    data    res 1
    
  • Write again, but for a full page (256 bytes):

    CON
      _CLKFREQ  = 180_000_000
    
      ' UART on P62
      RX_PIN = 63
      TX_PIN = 62
      BAUD_RATE = 2000000
      SERIAL_CLOCK = (_CLKFREQ / BAUD_RATE)
      BIT_PERIOD = ((SERIAL_CLOCK << 16) & $FFFFFC00) + (8 - 1)
    
      ' SPI pins
      spi_cs   = 8
      spi_ck   = 9
      spi_miso = 10
      spi_mosi = 11
      spi_hld  = 4
      spi_wp   = 5
    
    DAT
    org 0
    asmclk
    
    ' ---- UART TX init ----
            wrpin   ##(P_ASYNC_TX | P_OE), #TX_PIN
            wxpin   ##BIT_PERIOD, #TX_PIN
            wypin   #1, #TX_PIN
            dirh    #TX_PIN
    
    ' ---- SPI Init ----
            outh    #spi_cs
            outh    #spi_hld
            outh    #spi_wp
    
            dirh    #spi_cs
            dirh    #spi_ck
            dirh    #spi_mosi
            dirh    #spi_hld
            dirh    #spi_wp
    
    ' ----  Write enable ----
            call #spi_write_enable
    
    ' ----  Read Status Register ----
            call #spi_rdsr
    
    ' ---- Print ----
        mov     addr, #$0         ' Pick address 0x00
    
            call    #spi_write_enable
    
        call #spi_erase_sector
    
        call #spi_write_enable
    
        mov     addr, #$0        ' Pick address 0x00
        mov data, #"Z"
        call #spi_byte_write
    
        mov     result, data
        call    #print_hex_byte
            call    #uart_tx_space
    
            call    #uart_tx_nl
    
            jmp     #endprog
    
    ' ---- Write Enable ----
    spi_write_enable
            outl    #spi_cs          ' CS low
    
            mov     cmd, #$06
            call    #spi_cmd8        
    
            outh    #spi_cs          ' CS high
            ret
    
    ' ---- READ STATUS REGISTER (RDSR) ----
    spi_rdsr
            outl    #spi_cs          ' CS low
    
            mov     cmd, #$05
            call    #spi_cmd8        
    
            call    #spi_in
            mov     RDSR1, cmd
    
            outh    #spi_cs          ' CS high
            ret
    
    spi_erase_sector
            outl    #spi_cs               ' CS low
    
            mov     cmd, #$20             ' Sector Erase
            call    #spi_cmd8              ' Send command
    
            call    #spi_send_address24     ' Send address
    
            outh    #spi_cs        ' CS high
    
    .wait_busy
        call    #spi_rdsr
        testb   RDSR1, #0 wz       ' Test if all bits are 0
      if_z     jmp #.wait_busy    ' Loop again if BUSY/non-ero
      ret                ' Return only when all bits are 0
    
    spi_byte_write       
            outl    #spi_cs          ' CS low
    
            mov     cmd, #$02          ' WRITE command
            call    #spi_cmd8
    
            ' Send 24-bit address (A23-A0), top bits don't matter
            mov     cmd, addr
            shr     cmd, #16
            call    #spi_cmd8          ' A23–A16
            mov     cmd, addr
            shr     cmd, #8
            and     cmd, #$FF
            call    #spi_cmd8          ' A15–A8
            mov     cmd, addr
            and     cmd, #$FF
            call    #spi_cmd8          ' A7–A0
    
            ' Send data byte
            mov     cmd, data
            call    #spi_cmd8
    
            ' Send the same byte 256 times
            mov     cnt, #256
    .page_loop
            mov     cmd, data
            call    #spi_cmd8
            djnz    cnt, #.page_loop
    
            outh    #spi_cs          ' CS high (starts write)
            ret
    
    
            ' ---- Send 24-bit address ----
    spi_send_address24
            mov     cmd, addr
            shr     cmd, #16
            call    #spi_cmd8      ' A23–A16
            mov     cmd, addr
            shr     cmd, #8
            and     cmd, #$FF
            call    #spi_cmd8      ' A15–A8
            mov     cmd, addr
            and     cmd, #$FF
            call    #spi_cmd8      ' A7–A0
    
            ret
    
    
    ' ---- Send 8 bits (MSB first) ----
    spi_cmd8
            mov     x, #8
            shl     cmd, #24
            jmp     #spi_cmd
    
    spi_cmd
            rep     @.r, x
            shl     cmd, #1 wc
            outc    #spi_mosi
            waitx   ##45
            outl    #spi_ck          ' falling edge (sample in slave)
            waitx   ##45
            outh    #spi_ck
    .r
            ret
    
    ' ---- Read 8 bits (MSB first) ----
    spi_in
            mov     y, #8
            mov     cmd, #0
    .rdloop
            outl    #spi_ck          ' falling edge: sample MISO
            waitx   ##10             ' setup/hold time
            testp   #spi_miso wc
            rcl     cmd, #1
            outh    #spi_ck
            djnz    y, #.rdloop
            ret
    
    ' ---- UART hexadecimal Output ----
    print_hex_byte
            mov     temp, result
            mov     pr0, temp
            shr     pr0, #4
            and     pr0, #$F
            call    #print_nibble
            mov     pr0, temp
            and     pr0, #$F
            call    #print_nibble
            ret
    
    print_nibble
            cmp     pr0, #10 wc
      if_b  add     pr0, #"0"
      if_nc add     pr0, #"A"-10
            mov     result, pr0
            call    #uart_tx_char
            ret
    
    ' ---- UART character Output ----
    uart_tx_char
            wypin   result, #TX_PIN
    .tx
            rdpin   pr2, #TX_PIN wc
      if_c  jmp     #.tx
            ret
    
    uart_tx_space
            mov     result, #" "
            call    #uart_tx_char
            ret
    
    uart_tx_nl
            mov     result, #13
            call    #uart_tx_char
            mov     result, #10
            call    #uart_tx_char
            ret
    
    ' ---- End ----
    endprog
    
    ' ---- General Variables ----
    cmd     res 1
    x       res 1
    y       res 1
    temp    res 1
    result  res 1
    cnt res 1
    
    ' ---- Flash Variables ----
    RDSR1 res 1
    addr    res 1
    data    res 1
    

    I decided to do a write without the erase for the spi flash just to see what the "corruption" might look like. A 41, and then a write without erase stored at 40. The Flash 6 click just happened to be the Winbond W25Q128JV. Fun stuff. Still needs some clean up.

Sign In or Register to comment.