( Spi3208Forth)
( R.J.Wilks   3rd June 2016)
( Using 8-channel 12-bit ADC chip MCP3208 on breadboard cct with SPI bus transfer)
( set address and bit positions in SPI_CS etc)

CR ." SPI3208Forth" 

HEX
( get address of CS Register - Master Controller & Status)
( eg Hex 20204000 for B+; 3F204000 for Pi2)
GPIOsel_fn 4000 + CONSTANT SPI_CS

( SPI_CS U. KEY DROP)

HEX
SPI_CS 4 + CONSTANT SPI_FIFO    ( SPI Master TX & RX FIFOs Reg)
SPI_CS 8 + CONSTANT SPI_CLK     ( SPI Master Clock Divider Reg)

00800000 CONSTANT CS_CS2    ( CSPOL2)
00400000 CONSTANT CS_CS1    ( CSPOL1)
00200000 CONSTANT CS_CS0    ( CSPOL0)

00100000 CONSTANT CS_RXFIFOFULL  ( RXF)
00080000 CONSTANT CS_RXFIFO3_4   ( RXR)
00040000 CONSTANT CS_TXFIFOSPCE  ( TXD)
00020000 CONSTANT CS_RXFIFODATA  ( RXD)
00010000 CONSTANT CS_DONE        ( DONE)

00001000 CONSTANT CS_MOSI_INPUT  ( REN)
00000800 CONSTANT CS_DEASRT_CS   ( ADCS)
00000400 CONSTANT CS_RX_IRQ      ( INTR)
00000200 CONSTANT CS_DONE_IRQ    ( INTD)
00000100 CONSTANT CS_DMA_ENABLE  ( DMAEN)

00000080 CONSTANT CS_ACTIVATE    ( TA - Transfer Active)
00000040 CONSTANT CS_POLARITY    ( CSPOL)
00000020 CONSTANT CS_CLRTXFIFO   ( CLEAR)
00000010 CONSTANT CS_CLRRXFIFO   ( CLEAR)
00000030 CONSTANT CS_CLRFIFOS    ( CLEAR)

00000008 CONSTANT CS_CLK_IDLHI   ( CPOL)
00000004 CONSTANT CS_CLK_TRANS   ( CPHA)  ( use 0)

00000000 CONSTANT CS_CHIPSEL     ( CS)    ( only 0 or 1 - 0 for channel A)
00000001 CONSTANT CS_CHIPSEL1    ( CS)

: CS_CLRALL CS_CLRFIFOS CS_DONE OR ;  ( bit pattern to clear FIFOS and DONE together)

BINARY
( start bit,no-diff input, channel 000 - 16bits - 2 bytes sent after channel no. added)
11000000000 CONSTANT command1   

DECIMAL
1000 VARIABLE Twait
1 VARIABLE channel

( Utilities)
: short_wait 0 DO I I * DROP LOOP ;   ( n...)

: dsp_SPI_CS HEX SPI_CS rd_SVCmode . CR DECIMAL ;  ( ...)

( Activate SPI pins 7 to 11 - call to GPIO module)
: set_SPIpins set_SPIForth ;   ( ...)

( ...)  ( back to GPIO pins - input)
( : unset_SPIpins   
     0 7 GPWrMode 0  8 GPWrMode 0  9 GPWrMode
     0 10 GPWrMode 0 11 GPWrMode ;)    

( Clock .. was 256, use 64 for v.fast)
256 VARIABLE CDIV     ( Clock Divider value)
: set_clock  CDIV @ SPI_CLK  wr_SVCmode ;

( FIFOs ...)
: read_FIFO   SPI_FIFO rd_SVCmode 255 AND ;  ( ... value)
: write_FIFO  255 AND SPI_FIFO wr_SVCmode ;  ( value ...)

( Setup SPI bus - FIFOs cleared and 'DONE' to zero)
: setup_spi   ( ...)
   set_clock
   CS_CLRALL SPI_CS wr_SVCmode
   CS_DONE   SPI_CS wr_SVCmode ;

: clr_TA  SPI_CS rd_SVCmode CS_ACTIVATE XOR SPI_CS wr_SVCmode ; ( ...)

: test_bitz   ( bit code, addr ..... flg)
  rd_SVCmode  ( bit code,reg value ...)  ( in SVC mode)
  AND         ( n ...)            ( n>0 if reg has a 1 in this bit position)
  0= 0=       ( flg...)           ( 0/1 flg - '1' if bit=1 in reg)
  ?Esc OR
;

: wait_done   ( ...)   ( wait for SPI to be ready - about 16 microsec)
   BEGIN
     CS_DONE SPI_CS  test_bitz  ( rd_SVCmode AND)
   UNTIL ;


( Read ADC)
: read_adc   ( ch no...value)
   ( 500 short_wait)   ( to ensure chip select is high for a short while)
   CS_CHIPSEL  CS_ACTIVATE OR SPI_CS wr_SVCmode  ( use CS0 and set activate bit)
   ( now write the command into the FIFO - 2 x 8-bit words) ( Differs from 3002 & 3008!!)
   command1 SWAP 6 << OR          ( channel no. included in 2 bytes)
   DUP 8 >>  write_FIFO           ( top byte: 5 x 0's,start bit,nondiffl,top bit of ch no.)
   255 AND   write_FIFO           ( remaining 2 bits of ch no. + 6x0's)
   0 write_FIFO             ( dummy)
   wait_done                ( wait until ready - DONE bit)
   clr_TA                   ( TA=0 to stop transfers)
   read_FIFO DROP           ( 1st byte is garbage)
   read_FIFO read_FIFO      ( read 2 bytes from ADC and put on stack)
   ( 2DUP . .)
   SWAP 15 AND 8 <<
   OR ;                     ( combine to 12-bit value)

: ADCsetup_general   ( ...)
  set_SPIpins setup_spi ;

: ADC   ( ch no...)
  0 7 confine        ( channel 0 to 7 only)
  ( ADCsetup_general)       ( already called - not needed)
  ( loop and display)
  CR ." ADC Values:" CR
  DUP read_adc DROP  ( discard first reading)
  0 TIME=
  100 0 DO DUP read_adc . LOOP DROP
  ( unset_SPIForth )        ( Forth version***)  (  not needed)
   TIME ." csec= " .
;

: qadc channel @ read_adc . ;    ( test system)

ADCsetup_general
