\ ********************************************************************* 
\ Words to drive the SPI module on the ATmega2560 
\    Filename:      spi-base-avr-v2.txt 
\    PJ 31-Jan-2016: initial listing spi-base-avr.txt 
\    adaptation MP 04-nov-2019 
\    Date:          18/11/2019 
\    MCU:           ARDUINO all models 
\    GNU General Public License 
\ ********************************************************************* 
 
-spi-base 
marker -spi-base 
 
\ Registers of interest 
$24 constant DDRB       \ Port B Data Direction Register 
$25 constant PORTB      \ Port B Data Register 
 
$4c constant SPCR       \ SPI Control Register 
$4d constant SPSR       \ SPI Status Register 
$4e constant SPDR       \ SPI Data Register 
 
\ bit masks for ARDUINO MEGA 
%00000001 constant mSS1   ( PB0 )   \ -> CS 
%00000010 constant mSCK   ( PB1 )   \ -> CLK 
%00000100 constant mMOSI  ( PB2 )   \ -> DIN 
%00001000 constant mMISO  ( PB3 ) 
\ %00010000 constant mRST   ( PB4 ) 
$80 constant mSPIF      \ SPI Interrupt Flag 
$40 constant mWCOL      \ Write Collision Flag 
 
: slave.select ( mSSx -- )     \ select slave x in mSSx constant 
    dup DDRB  mset      \ SS as output 
        PORTB mclr      \ deselect 
  ; 
: slave.deselect ( mSSx -- )   \ unselect slave 
    dup DDRB  mset      \ SS as output 
        PORTB mset      \ deselect 
  ; 
 
%01000000 constant SPCR_SPE     \ SPI Enable 
: spi.enable ( ---) 
    SPCR_SPE SPCR mset ; 
: spi.disable ( ---) 
    SPCR_SPE SPCR mclr ; 
 
%00100000 constant SPCR_DORD \ Data Order 
: LSB.first ( --- )     \ select LOW Signifiant Bit first 
    SPCR_DORD SPCR mset ; 
: MSB.first ( --- )     \ select MOST Signifiant Bit first 
    SPCR_DORD SPCR mclr ; 
 
%00010000 constant SPCR_MSTR    \ Master/Slave Select 
: Master.mode 
    SPCR_MSTR SPCR mset ; 
: Slave.mode 
    SPCR_MSTR SPCR mclr ; 
 
\ SPI mode 
%00000100 constant SPCR_CPHA    \ Clock Phase 
%00001000 constant SPCR_CPOL    \ Clock Polarity 
: Mode0 
    SPCR_CPHA SPCR mclr   \ Idle CLK = 0 
    SPCR_CPOL SPCR mclr  \ Sample on leading edge 
  ; 
: Mode1 
    SPCR_CPHA SPCR mclr   \ Idle CLK = 0 
    SPCR_CPOL SPCR mset    \ Sample on trailing edge 
  ; 
: Mode2 
    SPCR_CPHA SPCR mset     \ Idle CLK = 1 
    SPCR_CPOL SPCR mclr    \ Sample on trailing edge 
  ; 
: Mode3 
    SPCR_CPHA SPCR mset     \ Idle CLK = 1 
    SPCR_CPOL SPCR mset    \ Sample on leading edge 
  ; 
 
\ SPI clock speed 
%00000010 constant SPCR_SPR1    \ SPI Clock Rate Selects 
%00000001 constant SPCR_SPR0    \ SPI Clock Rate Selects 
%00000001 constant SPSR_SPI2x   \ Double SPI Speed 
: spi2X.off ( --- ) 
    SPSR_SPI2x SPSR mclr 
  ; 
: spi2X.on  ( --- ) 
    SPSR_SPI2x SPSR mset 
  ; 
: fosc/4 
    SPCR_SPR1  SPCR mclr 
    SPCR_SPR0  SPCR mclr 
    spi2X.off 
  ; 
: fosc/16      
    SPCR_SPR1  SPCR mclr 
    SPCR_SPR0  SPCR mset 
    spi2X.off 
  ; 
: fosc/64      
    SPCR_SPR1  SPCR mset 
    SPCR_SPR0  SPCR mclr 
    spi2X.off 
  ; 
: fosc/128     
    SPCR_SPR1  SPCR mset 
    SPCR_SPR0  SPCR mset 
    spi2X.off 
  ; 
 
: spi.init ( -- )  
    mSCK  DDRB  mset            \ SCK as output 
    mSCK  PORTB mclr            \ clock idles low 
    mMOSI DDRB  mset            \ MOSI as output 
    mMISO DDRB  mclr            \ MISO as input 
    mMISO PORTB mset            \ activate pull-up on MISO 
    mSS1  DDRB  mset            \ SS as output 
    mSS1  PORTB mset            \ deselect 
        spi.enable 
        Master.mode 
        Mode0 
        fosc/64 
    SPSR c@ drop SPDR c@ drop   \ will clear SPIF 
; 
 
: spi.close ( -- ) 
    $00 SPCR c! 
  ; 
: spi.wait ( -- ) 
    begin  
        mSPIF SPSR mtst  
    until 
  ; 
: spi.cexch ( c1 -- c2 ) 
    SPDR c!  
    spi.wait  
    SPDR c@ 
  ; 
: spi.csend ( c1 -- ) 
    spi.cexch drop 
  ; 
 
 
\ : spi.test ( -- )  
\     mSS1 slave.select 
\     spi.init 
\     $1c spi.csend   \ an arbitrary byte 
\     mSS1 slave.deselect 
\     spi.close 
\   ;