Shop OBEX P1 Docs P2 Docs Learn Events
FSRW & safe_spi.spin — Parallax Forums

FSRW & safe_spi.spin

BTXBTX Posts: 674
edited 2010-09-10 17:51 in Propeller 1
Hi all.
I need some help to achieve this here.
What I want is to get out each byte that I read from a SD card file, I'm using FSRW26 with safe_spi, well this is not so simple for me, what I want is to catch those bytes into the own safe_spi code, once at a time (or a long at a time), and send those bytes out of the pchip.

I assume that my first step to do, is to locate inside the safe_spi code, where it is getting the bytes read from the SD.
I suppose that it's happening into the: read_single_block loop. is it right ?
And more, is "readback" the variable who contains a long, with four bytes of data read ?

Could I lose some time after get that variable, to send it out of the pchip, before execute the: djnz ops_left,#:read_loop ?, or this will affect the code logic ?

The idea with this is, to get those bytes out the pchip and catch them with a cpld (this is for my Prop2Cpld board). I presume that this will be more fast and efficient, that cath the bytes from the read buffer, and then send them out, using another cog to drive the data out for the cpld.

Comments

  • MicrocontrolledMicrocontrolled Posts: 2,461
    edited 2010-09-01 10:58
    I don't quite understand what you are trying to accomplish. If you want to read the SD bytes and send them out of the Pchip as serial data, you would use the SPIN code function pgetc from the FSRW program and use the TX spin routine from the FullDuplexSerial object to send them out.
    Like this:
    PUB Main | temp
    
       sd.popen(string("File.txt"),"r")
       repeat
          temp := sd.pgetc
          if temp == -1
            quit
          else
            ser.tx(temp) 
    
    

    I don't know if this is what you want, but I wouldn't mess with the PASM in the safe_spi object if I where you, as it could mess up the timing and give you false bytes. Just my opinion.
  • BTXBTX Posts: 674
    edited 2010-09-01 13:18
    I don't quite understand what you are trying to accomplish. If you want to read the SD bytes and send them out of the Pchip as serial data, you would use the SPIN code function pgetc from the FSRW program and use the TX spin routine from the FullDuplexSerial object to send them out.
    Like this:
    PUB Main | temp
    
       sd.popen(string("File.txt"),"r")
       repeat
          temp := sd.pgetc
          if temp == -1
            quit
          else
            ser.tx(temp) 
    
    

    I don't know if this is what you want, but I wouldn't mess with the PASM in the safe_spi object if I where you, as it could mess up the timing and give you false bytes. Just my opinion.

    Thank you Microcontrolled, but that is not what I want to do, and sorry, maybe I can't explain it very well in English.
    I will try to explain again it with an example.
    Until now, I'm reading the file in the SD using *pread* function, then I save that data in a big buffer, (all the file content). After that, I'm sending out the big buffer data content with another cog (ASM code) in parallel mode by 16 pins (two bytes of the buffer at a time).

    What I thought is, send out the data by the same 16 pins, but in the exact momment that the safe_spi read them from the SD card. So, my big buffer dispears, and I could get a fast throughput of the data out. The main reason is so, speed up my task.
    I hope it is clear now. :)
  • BTXBTX Posts: 674
    edited 2010-09-03 05:08
    Hey guys, anybody could help me on this ?
    Where are you lonesock and rokicki ??
  • lonesocklonesock Posts: 917
    edited 2010-09-03 07:56
    Sorry for the delay.

    In the latest FSRW (2.6), the block driver is reading a block ahead (512 bytes), and storing that in a buffer in the cog. To take maximum advantage of that, simply use pread( @buffer, 512 ), to get 512 bytes into a buffer of your choice. Then send that buffer out over the serial port (you may want to modify your serial engine to send a block of bytes, instead of using .tx to send a char at a time...SPIN becomes the bottleneck in that case). While you are sending your buffer, the block driver cog is busy reading the next sequential block of 512 bytes, so when you request the next block of 512 bytes via pread, the odds are good that the data is already in the cog, and just gets copied into your buffer, and the whole things starts again.

    Jonathan
  • BTXBTX Posts: 674
    edited 2010-09-03 10:20
    Thank you Jonathan.
    But, didn't you read my above posts ? ;)
    I don't want to send any by serial, just in parallel mode type " mov outa,somedata "
    I'm doing exactly what you suggest until now, but I need more efficient code and speed up it.
    I think to put that "mov" instruction into the same read loop of the SD, into each of the 512 bytes block.
    What you say is fine, but when I get again the data from the buffer in asm code, I'm loosing time in the rdlong instruction.
    Please read my first post in this thread to know it.
    If my questions are not clear, I will try to do them again. Thank you so much again.
  • lonesocklonesock Posts: 917
    edited 2010-09-03 11:00
    Ah, my fault, sorry.

    Yes, you _could_ put your mov outa,data code directly into the read_single_block routine. You would want to place your code directly after I stop the clock and read in the last bit. However you would have to handle the following:

    * the bytes come in big-endian (so the safe_spi reads each byte backwards, then reverses all four bytes in the long at once)
    * you would not want your output whenever FSRW is reading the FAT table (which happens whenever you open a file, or everytime you switch to a new cluster)

    The pread code in FSRW does some overhead, and then copies the data buffer into an intermediate 512-byte buffer, before passing it back to you. If you want to go a bit faster, you can make sure your files are contiguous on the SD card, use FSRW to open the file, get the block ID (address) of the first chunk, then use the safe_spi block layer directly to read each subsequent block of data directly into your own buffer. This cuts out quite a bit of overhead, and gives a decent speedup (25-50%?)...you just *must* make sure that your files are all stored in sequential blocks.

    If you want to go the harder route and modify safe_spi directly, let me know...I can help, but my free time is limited.

    Jonathan
  • BTXBTX Posts: 674
    edited 2010-09-03 14:14
    Thnak you so much Jonathan !!!!!
    Yes, yes, you give me another idea too, it is not a problem for me to read data where files are contiguous on the SD card !!
    But I'm sure I will need a more detailed help of how to modified code. Simply some recognition of where are the parts of the code to get out. I will analize it, and then I will ask again.
    Do you prefeer, I'll do in this thread, or private ?

    About the another method, I should put a flag to advice me when the block read is for FAT, or part of the file read....thought.

    PS:
    I mean that I need help, because there are somethings that I can't finish to understand, as a "mov 0:0,readback" or a mov to a label ??...like "movd :store_read_long,#speed_buf"
  • BTXBTX Posts: 674
    edited 2010-09-08 07:46
    Hi.
    Jonathan are you there ?
    I did all modifications in the fsrw, and in the safe_spi code succesufully. although I can't get a fast data transfer, comparing it, with my last working code.
    Maybe be it's due my new added code is taking about 54 clk cycles to achieve it's data transfer to the CPLD of the board, all this each four bytes of the long read in the readback variable.
    It's working fine but it is not usefull for my purposes so.

    What I want to try, is what you suggest before to me, but I can't finish to understand how to do that, just only read contiguous blocks and use another cog to transfer them, but what I need is that the read blocks get faster read that in the original safe_spi code.
  • lonesocklonesock Posts: 917
    edited 2010-09-08 08:17
    Hi, Alberto.

    What speed do you need? (In terms of raw speed reading with safe_spi, I can usually get about 900,000 bytes per second, with periodic card hiccups included) Can you give me any information on your setup (like which pins are connected to your CPLD, and how you transfer data across, and which pins & cog are driving the SD card)? There are faster versions of the spi code, but you have to be careful which pins & cog you use for the block driver code (and to some extent the routing of the clock and data lines).

    If you want, we can continue this via email: same username at gmail.com, or we can keep it on the thread.

    Jonathan
  • BTXBTX Posts: 674
    edited 2010-09-08 09:07
    lonesock wrote: »
    Hi, Alberto.

    What speed do you need? (In terms of raw speed reading with safe_spi, I can usually get about 900,000 bytes per second, with periodic card hiccups included) Can you give me any information on your setup (like which pins are connected to your CPLD, and how you transfer data across, and which pins & cog are driving the SD card)? There are faster versions of the spi code, but you have to be careful which pins & cog you use for the block driver code (and to some extent the routing of the clock and data lines).

    If you want, we can continue this via email: same username at gmail.com, or we can keep it on the thread.

    Jonathan

    Hi Jonathan.
    It's ok here for me if you want. Some info could be usefull for anyone too. (I will send to you "hot comments" if needed by email).

    OK my MicroSd card is mounted at: pin 0.
    Then the pchip is sending the data to the CPLD by P8-P15 in 16 bits wide data bus.
    I've reserved P4-P7 to let me clk the data, and for some handshaking wires between the CPLD and the pchip. (I know, I know, better I should used P0-P15 for data bus...sorry, it is late now). :(

    What speed I need ? As fast as possible, 1500KBps or 2000KBps, would be better but could be great for me to achieve about 4000KBps (just a dream...impossible in SPI mode).
    read_single_block
            ' where am I sending the data?
            movd :store_read_long,#speed_buf
            mov ops_left,#128
            ' wait until the card is ready
            mov tmp1,N_in8_500ms
    :get_resp
            call #in8
            cmp readback,#$FE wz        
    if_nz   djnz tmp1,#:get_resp
    if_nz   neg user_cmd,#ERR_ASM_NO_READ_TOKEN  
    if_nz   jmp #read_single_block_ret
            ' set DI high
            neg phsa,#1
            ' read the data
            mov ops_left,#128
    :read_loop        
            mov tmp1,#4
            movi phsb,#%011_000000
    :in_byte        
            ' Start my clock
            movi frqb,#%001_000000
            ' keep reading in my value, BACKWARDS!  (Brilliant idea by Tom Rokicki!)
            test maskDO,ina wc
            rcl readback,#8
            test maskDO,ina wc
            muxc readback,#2
            test maskDO,ina wc
            muxc readback,#4
            test maskDO,ina wc
            muxc readback,#8
            test maskDO,ina wc
            muxc readback,#16
            test maskDO,ina wc
            muxc readback,#32
            test maskDO,ina wc
            muxc readback,#64
            test maskDO,ina wc
            mov frqb,#0 ' stop the clock
            muxc readback,#128
            ' go back for more
            djnz tmp1,#:in_byte
            ' make it...NOT backwards [8^)
            rev readback,#0
    :store_read_long
            mov 0-0,readback       ' due to some counter weirdness, we need this mov
            cmp bet_flag, #1  wz  ' This flag is set high in another part of the safe_spi code.
    if_z    call #my_code        
            
            add :store_read_long,const512
            djnz ops_left,#:read_loop
    
            ' set DI low
            mov phsa,#0
            
            ' now read 2 trailing bytes (CRC)
            call #in8      ' out8 is 2x faster than in8
            call #in8      ' and I'm not using the CRC anyway
            ' give an extra 8 clocks in case we pause for a long time
            call #in8       ' in8 looks like out8($FF)
            
            ' all done successfully
            mov idle_time,#0
            mov user_cmd,#0               
    read_single_block_ret
            ret          
    
    my_code
                       or  dira,direction
                       mov     tempo,readback
                       and     tempo,maskb1
                       shl     tempo,#8
                       mov     outa,tempo
                       or      outa,clockPin     'Clock in this data into CPLD
                       andn    outa,clockPin
    
                       mov     tempo,readback
                       and     tempo,maskb2
                       shr     tempo,#8
                       mov     outa,tempo
                       or      outa,clockPin     'Clock in this data into CPLD
                       andn    outa,clockPin
                       and     dira,ndirection
    my_code_ret
            ret
    
    'These are the dir pins & masks:
    'direction          long    %00000000_11111111_11111111_10010000   '
    'ndirection         long    %11111111_00000000_00000000_01101111   '
    'ClockPin           long    %00000000_00000000_00000000_10000000
    'maskb1             long    %00000000_00000000_11111111_11111111
    'maskb2             long    %11111111_11111111_00000000_00000000
    
    

    As I said before, don't care if I enter in the code with the block address to read from the SD card, then I should read about 1200 blocks, and I could be sending them out to the CPLD with another cog, (as I did until now ), the SD read speed is my bottleneck now for me.
  • lonesocklonesock Posts: 917
    edited 2010-09-08 09:23
    As a quick test, try using the mb_rawb_spi.spin block driver. Since you are using pins 0..3, it would be best if you had the block driver running in cog 0 (your load code can transition itself into cog 1 then spin forever, then modify start_explicit to coginit into cog 0 which would overwrite the spinning cog). You only need one copy of the block driver running, correct?

    I usually get speeds of ~ 1.8 MB/s with this setup (raw reads, not going through FSRW). I have also tested it at 100 MHz without problems giving a 25% speed increase. You could easily use a 6MHz crystal or similar to get a speed bump, if you haven't already.

    Jonathan
  • BTXBTX Posts: 674
    edited 2010-09-08 14:04
    lonesock wrote: »
    As a quick test, try using the mb_rawb_spi.spin block driver. Since you are using pins 0..3, it would be best if you had the block driver running in cog 0 (your load code can transition itself into cog 1 then spin forever, then modify start_explicit to coginit into cog 0 which would overwrite the spinning cog). You only need one copy of the block driver running, correct?

    I usually get speeds of ~ 1.8 MB/s with this setup (raw reads, not going through FSRW). I have also tested it at 100 MHz without problems giving a 25% speed increase. You could easily use a 6MHz crystal or similar to get a speed bump, if you haven't already.

    Jonathan

    Yes, I only need one copy of the block driver running.
    I will try with mb_rawb_spi.spin...but I can't understand how I use it avoiding fsrw (raw reads) ??. If use a 6Mhz xtal is safe, I will too.
  • lonesocklonesock Posts: 917
    edited 2010-09-08 14:56
    To use raw access, knowing your file is continuous, I would do something like this:
    OBJ
      sdfat:        "fsrw"
      block:        "safe_spi" ' or use mb_rawb_spi, whichever is used inside fsrw
    
    ' you need to have mounted sdfat already
    
    PUB raw_demo | idx
      ' open the file using FSRW
      sdfat.popen(string("speed.tst"),"r")
      ' find out which data block we just opened
      idx:=sdfat.datablock
      ' now use raw reading direct from the block layer
      ' into a 512-byte, long-aligned buffer
      repeat 1000
        block.readblock( idx++, @buffer )
        ' do something with the buffer
    
    Jonathan
  • BTXBTX Posts: 674
    edited 2010-09-08 15:30
    OK, thank you Jonathan, I'll try all of you valuable suggest, and then I'll post again with results.
  • BTXBTX Posts: 674
    edited 2010-09-10 14:13
    Hi Jonathan.
    I've tested your suggest of read raw contiguous data using your example (by using mb_rawb_spi), and I found surprised that it works a bit slowly than before using pread with safe_spi.spin. :(

    I also tried to use mb_rawb_spi.spin, instead safe_spi with my original code, and it wont work.
    Any ideas why ?
  • lonesocklonesock Posts: 917
    edited 2010-09-10 14:54
    Would you be willing to archive your code project and email it to me? I'd be happy to look at it. (standard free time disclaimer [8^)

    Jonathan
  • BTXBTX Posts: 674
    edited 2010-09-10 17:51
    Ok Thank you Jonathan, I will prepair a special version for you.
Sign In or Register to comment.