Shop OBEX P1 Docs P2 Docs Learn Events
SPI Slave implemented on prop — Parallax Forums

SPI Slave implemented on prop

pemspems Posts: 70
edited 2008-11-15 00:13 in Propeller 1
Just curious if there is any prior art for implementing an SPI Slave on a prop

In my continuing efforts to come up with a framework of marrying a prop to another MCU, i've implemented a simple yet effective SPI Slave mechanism running on one cog.
The protocol is very simple:
NSS on
1st byte: command (read or wright data)
2nd byte: register address to read/write into (i have a 0xff longs of hub ram allocated as SPI accessible registers)
next bytes: data in longs (has to be a multiple of 4 bytes of course)
NSS off

Currently it only runs at laughable "under 1Mbps", but i plan to optimize the heck out of it, to make it be able to run faster

I'll share this code soon if anyone is interested to use it or help with optimizations


Cheers

Comments

  • SeariderSearider Posts: 290
    edited 2008-11-07 18:12
    Hippy has done some work on this. You should be able to locate it in this forum using the search functon. I would also be interested in looking at your code. I was just starting to play with Hippy's version for Prop to Prop interface.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔

    Searider
  • pemspems Posts: 70
    edited 2008-11-08 22:38
    Ok here is the code. I've optimized it to run seemingly error free @ about 1.125Mhz SPI clock
    things could be unrolled further (resulting in huge mess) but i think the bottleneck will still be the wrlong/rdlong. I thought of implementing some kind of caching, but that would complicate things.

    EDIT: updated the code with jump table mechanism (for cases if more commands are needed)

    
                            org     0
    'Command jump table. Addresses of these pointers must be equal to numbers representing a command
    wrcmdptr                LONG    0                                     
    rdcmdptr                LONG    0
    
    
    entry
    
    
                            or      dira, misomask
      
                            'init pointers
                            mov     wrcmdptr, #wrdata
                            mov     rdcmdptr, #rddata
    
    
    waitnsstrans0           waitpne nssmask, nssmask
    
    
    nextcmd
            ' shift in the command 
                            mov     t1, #8 '8bits in byte
                            mov     data, #0
                            shr     jmpcmd, #8  'prepare jmpcmd for later shifting in of jump pointer address
    
    :nextbit
    :waitclktrans0           
              '              test    nssmask, ina wz
              '    if_nz     jmp     #waitnsstrans0  ' abort and wait for next nss falling edge 
                            test    clkmask, ina wz
                  if_nz     jmp     #:waitclktrans0  ' wait for clk = 0 transition
    
                            test    mosimask, ina wc
                            rcl     jmpcmd, #1 ' shift in the jump pointer address. The shifting order is LSb first
    
                            waitpeq clkmask, clkmask  ' wait for clk = 1 transition
                                                    
                            djnz    t1, #:nextbit
    
    jmpcmd                  jmp     0   'template for conditional jumping, according to the command received
                                                
                                    
    '--------------------------------------------------------------------------------------------
    wrdata
            'shift in the register address
                            mov     t1, #8 '8bits in byte
    
                            'or      outa, gmask 'test
    
    :nextbit
    :waitclktrans0           
               '             test    nssmask, ina wz
               '   if_nz     jmp     #waitnsstrans0  ' abort and wait for next nss falling edge 
                            test    clkmask, ina wz
                  if_nz     jmp     #:waitclktrans0  ' wait for clk = 0 transition
    
                            test    mosimask, ina wc
                            rcr     addr, #1 ' shift in new bit. The shifting order is LSb first
    
                            waitpeq clkmask, clkmask  ' wait for clk = 1 transition
                                                    
                            djnz    t1, #:nextbit
                            shr     addr, #24 'shift right the byte received to the bits 0-7 position
    
    wrnextdata 
                  ' now shift in the data to write
                            mov     t1, #32 '32bits in long
    
    :nextbit
    
      
    :waitclktrans0
                            test    nssmask, ina wz
                  if_nz     jmp     #waitnsstrans0  ' abort and wait for next nss falling edge 
                            test    clkmask, ina wz
                  if_nz     jmp     #:waitclktrans0  ' wait for clk = 0 transition
    
                            test    mosimask, ina wc
                            rcr    data, #1
    
    
                            waitpeq clkmask, clkmask  ' wait for clk = 1 transition
    
                            djnz    t1, #:nextbit
    
    
    
                            wrlong  data, addr  'write to hub ram at pre-specified location
                            'mov      tempreg, data 'test
                            
                            add     addr, #4 'next long
                            jmp     #wrnextdata 'write the next register
    
    
    '-------------------------------------------------------------------------------
    rddata
           ' shift in the register address
                            mov     t1, #8 '8bits in byte
                            'or      outa, amask 'test
    :nextbit
    :waitclktrans0           
             '               test    nssmask, ina wz
             '     if_nz     jmp     #waitnsstrans0  ' abort and wait for next nss falling edge 
                            test    clkmask, ina wz
                  if_nz     jmp     #:waitclktrans0  ' wait for clk = 0 transition
    
                            test    mosimask, ina wc
                            rcr     addr, #1 ' shift in new bit. The shifting order is LSb first
    
                            waitpeq clkmask, clkmask  ' wait for clk = 1 transition
                                                    
                            djnz    t1, #:nextbit
                            shr     addr, #24 'shift right the byte received to the bits 0-7 position
    
    rdnextdata
                            rdlong  data, addr 'read from hub ram at pre-specified location
                            'mov     data, tempreg 'test
                            
              ' now shift out the data 
                            mov     t1, #32 '32bits in long
    :nextbit
    
                            rcr     data, #1 wc ' shift out new bit. The shifting order is LSb first
                            muxc    outa, misomask ' shift out next out bit   
    :waitclktrans0
                            test    nssmask, ina wz
                  if_nz     jmp     #waitnsstrans0  ' abort and wait for next nss falling edge 
                            test    clkmask, ina wz
                  if_nz     jmp     #:waitclktrans0  ' wait for clk = 0 transition
    
    
                            waitpeq clkmask, clkmask  ' wait for clk = 1 transition
    
                            djnz    t1, #:nextbit
    
    
                            add     addr, #4 'next long
                            jmp     #rdnextdata 'read the next register 
                            
    
    
                                                        
    rmask               LONG 1<<15
    amask               LONG 1<<14
    gmask               LONG 1<<13
    
    nssmask                 LONG 1<<4
    clkmask                 LONG 1<<5 
    misomask                LONG 1<<6 
    mosimask                LONG 1<<7
    
    
    
    '             
    '
    ' Uninitialized data
    '
    t1                      res     1
    t2                      res     1
    t3                      res     1
    addr                    res     1
    data                    res     1
    
    
    

    Post Edited (pems) : 11/9/2008 2:35:07 AM GMT
  • SeariderSearider Posts: 290
    edited 2008-11-09 13:30
    Thanks, I'll take a look at this. Were you able to find the work that Hippie did on this subject?

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔

    Searider
  • hippyhippy Posts: 1,981
    edited 2008-11-14 23:07
    @ Searider : it was I2C Slave I worked on but the principles should apply to SPI. Perhaps easier as there's only one clock line to look for, no complicated start/stop bus transitions.

    @ Pems : You seem to be on the right track. If it's a dedicated SPI peripheral and you want even faster throughput you could use multiple Cogs - One simply catches transitions and throws them into a ring buffer, another Cog can assemble the bytes / packets and executes them. That will get the clock rate up high.
  • SeariderSearider Posts: 290
    edited 2008-11-15 00:13
    Hippy, thanks for the correction.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔

    Searider
Sign In or Register to comment.