(*  This version Willem Ouwerkerk - April 2021 - bitbang SPI driver 
    With use of some of the data from Mecrisp, but much more
    the GD32VF103 user manual V1.2  
    Please note that 27 MHz is the maximum SPI clock frequency!
        40010800 =  PORTA
        40010C00 =  PORTB
        40011000 =  PORTC
        40011400 =  PORTD
        40011800 =  PORTE
        40021000 =  RCU_CTL
        40021018 =  RCU_APB2EN
        40013000 =  SPI0_CTL0
        40013008 =  SPI0_STAT
        4001300C =  SPI0_DATA
        
\ These bits are connected to flash memory on SEEED dev. board
PA5     = SCK     - 1       40010800
PA6     = MISO    - 8
PA7     = MOSI    - 1
PC0     = CE      - 1       40011000
*)

hex
v: fresh
: SPI-SETUP         ( +n -- )
    drop                    \ Remove compatability dummy
\ AF output mode push-pull 10MHz 
    FFF00000 40010800 **bic \ Port_A CRL  Clear pins PA5,6,7
    18100000 40010800 **bis \ Port_A CRL  Set pins PA5,6,7
    40 4001080C **bis       \ Port_A OCTL PA.6 Activate pull-up
\ Output mode push-pull 10MHz 
    000000FF 40011000 **bic \ Port_C CRL  Clear pin PC0 & PC1
    00000011 40011000 **bis \ Port_C CRL  Set pin PC0 & PC1
    1 4001100C **bis        \ Port_C out  CS high
    20 4001080C **bic ;     \ Port_A OCTL PA.5  CLK = 0

false [if]  \ Clock high level version = 300 kHz, low level version = 1 MHz

: CLOCK-HI     ( -- )      20 4001080C **bis ;      \ PA5_OCTL  SPI clock
: CLOCK-LOW    ( -- )      20 4001080C **bic ;      \ PA5_OCTL  SPI clock
: CLOCK        ( -- )      clock-hi  clock-low ;
: {SPI         ( -- )      1 4001100C **bic ;       \ PC0_OCTL  SPI on, CS=low
: SPI}         ( -- )      1 4001100C **bis ;       \ PCO_OCTL  SPI off, CS=high

\ Write a bit to the SPI-bus, read abit from the SPI-bus
: WRITE-BIT    ( b -- )
    80 and if 80 4001080C **bis else 80 4001080C **bic then ; \ PA7_OCTL

: READ-BIT     ( -- 0|1 )  40 40010808 bit** 0<> 1 and ; \ PA0_STAT

[else]

code CLOCK-HI     ( -- )
    sun 4001080C li     \ PORTA_ODR  Port-A output address
    day 20 li           \ Bit-5 mask
    w sun ) .mov        \ Read Port-A
    w day .or           \ Set bit-0
    sun ) w .mov        \ Write Port-A
    next
end-code

code CLOCK-LOW    ( -- )
    sun 4001080C li     \ PORTA_ODR  Port-A output address
    day -21 li          \ Bit-5 inverted mask
    w sun ) .mov        \ Read Port-A
    w day .and          \ Clear bit-5
    sun ) w .mov        \ Write Port-A
    next
end-code

code CLOCK      ( -- )
    sun 4001080C li     \ PORTA_ODR  Port-A output address
    day 20 li           \ Bit-5 mask
    w sun ) .mov        \ Read Port-A
    w day .or           \ Set bit-0
    sun ) w .mov        \ Write Port-A
    sun ) w .mov        \ Delay a few cycles
    day -21 li          \ Bit-5 inverted mask
    w sun ) .mov        \ Read Port-A
    w day .and          \ Clear bit-5
    sun ) w .mov        \ Write Port-A
    next
end-code

code  {SPI      ( -- )
    sun 4001100C li     \ PORTC_ODR  Port-C output address
    w sun ) .mov        \ Read Port-C
    w -2 .andi          \ Clear bit-0
    sun ) w .mov        \ Write Port-C
    next
end-code

code SPI}        ( -- )
    sun 4001100C li     \ PORTC_ODR  Port-C output address
    day 1 .li           \ Bit-0 mask
    w sun ) .mov        \ Read Port-C
    w day .or           \ Set bit-0
    sun ) w .mov        \ Write Port-C
    next
end-code

code WRITE-BIT  ( b -- )
    sun 40010800 li     \ Port_A base address
    moon C sun x) .mov  \ Read Port_A OCTL register
    day -81 li          \ Prepare inverted bit mask for bit-7
    moon day .and       \ Remove bit-7 from  MOON
    day 80 li           \ Prepare bit mask for bit-7
    tos day .and        \ Leave only bit-7 from TOS
    moon tos .or        \ Add bit-7 to MOON
    C sun x) moon .mov  \ Write MOON back
    tos sp )+ .mov      \ Pop stack
    next
end-code

code READ-BIT   ( -- 0|1 )
    sp -) tos .mov
    moon 40 li          \ Bit-6 mask to MOON
    sun 40010800 li     \ Port_A base address
    tos 8 sun x) .mov   \ Read Port_A STAT register
    tos moon .and       \ Leave bit-6 only
    tos 6 .srli         \ Bit-6 to bit-0
    next
end-code

[then]

: SPI-I/O       ( b0 -- b1 )
    8 for
        dup write-bit  2*  clock-hi
        read-bit or  clock-lo
    next  FF and ;

: SPI-OUT       ( b -- )
    8 for  dup write-bit  2*  clock  next  drop ;

: SPI-IN        ( -- b )
    0  8 for  2*  clock-hi  read-bit or  clock-lo  next ;

: SPI-ON        ( -- )      1 spi-setup ;

spi-on
v: fresh  
shield spi\  freeze

\ End ;;;