;======================================================================= ;======================================================================= ; SERIAL PERIPHERAL INTERFACE (SPI) VIRTUAL PERIPHERALS ; DEMO3M.SRC -- Demo #3 Master SX Software ; SPIM (Authentic SPI Master) Virtual Peripheral Demo Program ; Revision 1.02, 07.21.98 ; Developed by Authentic Engineering for Scenix Semiconductor, Inc. ; Authentic Engineering // http://www.authenticeng.com // ak@silcom.com ;======================================================================= ; ; ; DEMO#3 provides an example of data transfer between two ; SX microcontrollers through the SPI data bus. ; DEMO#3 consists of two programs - DEMO3M.SRC and DEMO3S.SRC, ; which correspond to the SPI Master and SPI Slave sides accordingly. ; The are 4 signal lines that connect the Master to the Slave: ; ; Master-Out-Slave-In MOSI signal line ; Master-In-Slave_Out MISO signal line ; Serial Clock SCLK signal line ; Slave Select SS signal line ; ; The Slave Select (SS) Line from Master to Slave signals the ; latter to start sending/receiving data. The word length is set ; to 16 bits in this demo (VP permits 1 to 16 bits). ; ; Authentic SPI virtual perphirals perform shifting in and out at ; the same time, as most hardware SPI implemetations do. ; ; The demo works as follows: ; - Assuming that Slave has been initialized prior to Master, ; the Master sends The Predefined Word 256 times. ; - The Slave SX is configured to perform the loopback function, ; that is, every time Slave sends to the Master whatever it has ; received from the Master during the previous transmission. ; - After the initial 256 transmissions Master switches into ; the loopback mode. ; - The data transfer of The Predefined Word can be easily observed ; with the help of oscilloscope. ; ; SPI clock period for this demo is 900 nsec - maximum clock ; rate supported by the SPIS (SPI Slave VP). ; ; Data transfer from Master side is triggered by RTCC interrupt with ; a period of 25.6 microseconds. ; ;======================================================================= ; ; ; Authentic SPIM (SPI Master) Virtual Peripheral ; ; SPIM is a part of the Authetic SPI virtual peripherals for SX micro. ; This VP provides simple and efficient way to send/get one word of ; data to/from SPI compatible Slave device. ; ; SPIM Clock rate can be selected starting from 1.72 MHz (max). ; Corresponding minimum clock period is 580 ns. Clock period can be ; incremented with 160 nsec increment. It is possible to achive faster ; data transfer rates sacrifising the rate programmability. Maximum ; clock rate of 2.5MHz can be achived by removing part of the program, ; responsible for programmable clock rate. Minimum clock rate is ; prctically unlimited, however, for clock rates lower than 500KHz ; we recommend to use Authentic SPIML (low rate SPI Master VP). ; ; Word length can be set to anywhere from 1 to 16 bits. Longer word ; lengths could be easily implemented if needed. ; ; Clock polarity is configurable by using the appropriate command byte. ; ; Four I/O signal lines are associated with any SPI communication: ; ; Master-Out-Slave-In MOSI signal line ; Master-In-Slave_Out MISO signal line ; Serial Clock SCLK signal line ; Slave Select SS signal line ; ; SPIM does not make any diffenece between read and write cycles. ; The data is clocked in and out simultaneously. ; ; If necessary, user may want to add more sophistication to the data ; transfer by adding Read/Write and handshaking signals. All that ; can be easily implemented without affecting the core SPIM program. ; ; SPIM controlls MOSI; MISO; SCLK lines. User program must provide ; appropriate control for SS lines. ; ; Arbitrary pins of the SX-28/SX-18 can be assigned for SPIM. ; ; To initialize SPIM user must: disable the interrupts; initilize ; SX I/O ports (calling SPIM_INIT); place the outgoing data into ; the I/O buffer, set SS signal and call SPIM_EXECUTE. Since SPIM ; is not using any interrupts, it will transfer the data and return ; control to user program. ; ; The two-byte (16 bits) send/receive buffer is allocated in ; memory as SPIM_LSB and SPIM_MSB. Data are shifted starting ; from the most significant bit. ; In case of less than 16-bit long data word, the SPIM will ; automatically align the MSBit of the word to the MSBit of ; the buffer before shifting. No user intervention is required. ; The contents of SPIM_LSB and SPIM_MSB are not preserved ; during the driver operation since the bits are always shifted in. ; ; -- SPIM control, status and I/O DATA registers -- ; ; SPIM_RATE. This byte defines the clock rate. When set to 1 it ; defines maximum clock rate of 1.72 MHz (580 nsec period). ; The actual clock period can be calculated as 420 nsec plus ; 160 nsec, multiplied by the SPIM_RATE. SPIM_RATE equal to ; zero will define maximun clock period of 41.380 usec. ; ; SPIM_PORT must be defined by user to point to the SX Port ; - A,B or C, which will generate SPI Clock signal. ; For instance: spim_port = rb. ; ; SPIM_PORTA_MASK, SPIM_PORTB_MASK, SPIM_PORTC_MASK. These ; bytes are the images of SX I/O ports direction registers. ; They are written to corresponding ports direction registers ; during the initialisation of SPIM. ; ; SPIM_CLK_MASK defines the SPI Clock pin. The pin is defined by ; setting corresponding bit of SPIM_CLK_MASK. ; For instance: ; spim_portc_mask = $fd ; spim_port = rc ; spim_clk_mask = 02ドル ; will define rc.1 as SPI Clock pin. ; ; SPIM_CMD - command and configuration byte. This byte defines: ; - SPI Clock polarity ; - direction (Read/Write) ; - number of bits to send/receive ; ; SPIM supports 4 commands, specified by the 4 MSBits of the ; SPIM_CMD byte ; ; 3ドル - GET WORD in MASTER FAST mode, define FALLING edge; ; 7ドル - GET WORD in MASTER FAST mode, define RISING edge; ; $B - SEND WORD in MASTER FAST mode, define FALLING edge; ; $F - SEND WORD in MASTER FAST mode, define RISING edge. ; ; Practically there is no difference between the GET and SEND commands. ; When the I/O buffer is shifted out, the input data is always ; shifted in. The different commands are provided for user convinience ; and confusion. The contents of SPIM_LSB and SPIM_MSB are ; not preserved during the driver operation since the bits are ; always shifted in even if they don't make any sense. ; ; Four LSBits of the command byte define the word length. ; 00ドル sets the length to 16 bits ; 01ドル sets the length to 1 bit ; ... ; 0ドルF sets the length to 15 bits ; ; The SPIM_CMD byte also serves as a ready flag. SPIM will clear this ; byte upon the success of data transfer. ; ; SPIM_STATUS byte provides the error status information to the user ; program. It has 1 error flag: ; bit 4 - set to 1 when the SPIS_CMD byte contains an unsupported command ; ; -- SPIS ENTRY POINTS -- ; ; SPIM_INIT - Initialization subroutine. It provides appropriate configuration ; for SX I/O ports ports ; ; SPIM_EXECUTE - This is the actual VP entry point which may be ; called either from the interrupt service routine or from MAIN program. ; ; SPIM_SS_SET - user defined subroutine to set active level on SS pin. ; SPIM_SS_RESET - user defined subroutine to set passive level on SS pin. ; In the case of multiple devices on SPI bus, user must provide appropriate ; control over SS signals. ; ; SPIM_ORG. This is the base address of SPIM VP. Typically it will be ; next ROM location, after the user program. ; ; -- How to use SPIM from the user program -- ; ; 1. Make sure that no interrupt is allowed during execution of SPIM. ; ; 2. Verify that the execution parameters are configured properly: ; SPIM_RATE ; SPIM_PORT_A_MASK ; SPIM_PORT_B_MASK ; SPIM_PORT_C_MASK ; SPIM_PORT ; SPIM_CLK_MASK ; SPIM_CMD ; ; 3. Configure I/O ports by calling SPIM_INIT. ; ; 4. Verify that SPIM is ready for execution by testing the SPIM_CMD byte. ; ; 5. Place the outgoing data into SPIM_LSB and SPIM_MSB ; ; 6. Call SPIM_EXECUTE from the interrupt. ; ; 7. Test SPIM_CMD for completion and SPIM_STATUS for errors. ; Unload the data from SPIM_LSB and SPIM_MSB ; ; Your SPIM is now ready for reuse. Repeat from step 4. ; ;======================================================================= ;**************************** CODE START ******************************* device pins28, pages4,banks8,oschs ;This is the SX-28 device configuration device turbo, stackx, optionx ;data which should be used to run this VP id 'DEMO3M' reset reset_entry ;***************************** I/O PINS ******************************** spim_port = rb ;SPI port for clock pin spim_clk_pin = rb.0 ;SPI clock line spim_out_pin = rb.1 ;master_in slave_out line spim_in_pin = rb.2 ;master_out slave_in line spim_MCU_cs_pin = rb.3 ;slave select/slave request micro ;******************************* RAM *********************************** ;SPIS DEMO#3 Variables. org 8 sys_timer_rate ds 1 ;RTCC reload value for MAIN program spim_init_cycles ds 1 ;numder of initial cycles when SPIM ;sends to Slave prederfined SPI_DEMO_DATA spim_init_counter ds 1 ;counter of initial cycles spim_demo_rate ds 1 ;SPIM_RATE for DEMO#3 spim_demo_data_MSB ds 1 ;predefined data for SPI transfer to Slave spim_demo_data_LSB ds 1 spim_demo_cmd ds 1 ;SPIM_CMD for DEMO#3 ;************************* INTERRUPT HANDLER *************************** ;Calls the SPIM VP on every RTCC interrupt org 0 call spim_execute mov w,sys_timer_rate retiw ;************************ DEMO#3 SUBROUTINES **************************** ;user defined subroutines to generate SPI SS signal spim_SS_set clrb spim_MCU_cs_pin ;set MCU__SS active (low) ret spim_SS_reset setb spim_MCU_cs_pin ;set MCU__SS passive (high) ret ;************************ DEMO#3 MAIN PROGRAM ************************** reset_entry clr fsr ;clear RAM :loop setb fsr.4 clr ind ijnz fsr,:loop bank spim_ram_bank ;SPI_bank initialization ;Set configuration bytes for PortB and SPI Clock line mov spim_clk_mask,#01ドル ;SPI Clock line mask for SPI Port mov spim_portb_mask,#04ドル ;PortB data direction byte ;Set DEMO#3 control data mov sys_timer_rate,#-80 ;set system timer to 25.6 usec mov spim_init_cycles,#$ff ;set number of initial cycles to 255 ;set SPIM control data mov spim_demo_rate,#03ドル ;set SPI Clock period 900 nsec mov spim_demo_data_MSB,#0ドルd ;define the data to transfer mov spim_demo_data_LSB,#35ドル mov spim_demo_cmd,#$f0 ;Set SPIM_CMD to SEND RISING 16 BIT ; mov spim_demo_cmd,#$bc ;Set SPIM_CMD to SEND FALLING 12 BIT ;initialise SPIM mov spim_rate,spim_demo_rate ;set SPI Clock rate to 900 nsec call spim_init ;configure SPIM ports mov !option,#03ドル ;enable RTCC interrupt ;set RTCC prescaler rate 1:16 ;start data transfer, SPIM will be called from RTCC interrupt handler on every RTCC interrupt ;initial 255 cycles when spim_demo_data are sent to Slave mov spim_init_counter,spim_init_cycles ;spim_init_counter to $ff :spim_transfer_start test spim_cmd ;wait for SPIM to be ready jnz :spim_transfer_start ;for next transfer mov spim_msb,spim_demo_data_MSB ;initialize I/O buffer mov spim_lsb,spim_demo_data_LSB mov spim_cmd,spim_demo_cmd ;initialize SPIS_CMD djnz spim_init_counter,:spim_transfer_start ;initial 255 cycles finished main_master call :spim_transfer ;main loop jmp main_master :spim_transfer test spim_cmd ;SPIM VP access loop jnz :spim_transfer mov spim_cmd,spim_demo_cmd ret spim_org equ $ ;*********************************************************************** ;************************** Authentic SPI MASTER VP ******************** org 10h spim_ram_bank = $ ;SPIM control data spim_cmd ds 1 ;SPIM command byte fast_ON equ spim_cmd.4 ;set to 1 for SPIM mode is used master_ON equ spim_cmd.5 ;set to 1 if MASTER rising_ON equ spim_cmd.6 ;set to 1 if RISING transmit_ON equ spim_cmd.7 ;set to 1 if TRANSMIT spim_clk_mask ds 1 ;defines SPI Clock pin spim_porta_mask ds 1 ;PortA direction register image spim_portb_mask ds 1 ;PortB direction register image spim_portc_mask ds 1 ;PortC direction register image ;SPIM status data spim_status ds 1 ;SPIM status byte spim_cmd_error equ spim_status.4 ;error - unsupported comand ;SPIS I/O buffer spim_msb ds 1 ;I/O data buffer spim_lsb ds 1 ;SPIS private data spim_shift_counter ds 1 ;I/O shift counter spim_bits_total ds 1 ;number of bits to transfer spim_shifts_init ds 1 ;number of bits for initial shift spim_rate ds 1 ;clock rate factor spim_rate_counter ds 1 ;clock rate delay counter org spim_org ;********************* SPIM INITIALIZATION ROUTINE ********************* spim_init mov m,#0ドルf ;set up data direction registers mov !rb,spim_portb_mask ;configure ports mov !ra,spim_porta_mask mov !rc,spim_portc_mask ret ;************************* SPIM DATA TRANSFER ************************** spim_execute bank spim_ram_bank ;set SPIM RAM bank snb master_ON jb fast_ON,spim_cmd_proc ;begin decoding SPIM_CMD setb spim_cmd_error ;unsupported command spim_exit clr spim_cmd ;SPIM exit ret ;decode SPIM_CMD spim_cmd_proc sb rising_ON ;set the SPI_CLK polarity clrb spim_clk_pin snb rising_ON setb spim_clk_pin mov w,spim_cmd ;set number of bits to transfer and w,#0ドルf ;decode four LSBits of SPIM_CMD mov spim_bits_total,w test spim_bits_total snz mov spim_bits_total,#10ドル mov spim_shift_counter,spim_bits_total ;set shift bit counter mov spim_shifts_init,#10ドル sub spim_shifts_init,spim_bits_total ;set initial shifts counter call spim_SS_set ;activate user defined SS lines test spim_shifts_init ;initial shift needed? jz :spim ;prepare data for transfer :set_bit_position clc ;initial shift for the data < 16 bit long rl spim_lsb rl spim_msb djnz spim_shifts_init,:set_bit_position ;data transfer :spim test spim_shift_counter jz :spim_execute_exit ;shift bit out mov spim_rate_counter,spim_rate ;define transfer rate djnz spim_rate_counter,$ ;in shift data out cycle movb spim_out_pin,spim_msb.7 ;shift data out xor spim_port,spim_clk_mask ;change SPI Clock state dec spim_shift_counter rl spim_lsb rl spim_msb ;shift bit in mov spim_rate_counter,spim_rate ;define transfer rate djnz spim_rate_counter,$ ;in shift data in cycle movb spim_lsb,spim_in_pin ;shift bit in xor spim_port,spim_clk_mask ;change SPI clock state jmp :spim :spim_execute_exit call spim_SS_reset ;disable SS jmp spim_exit ;exit ret ;TO CLOSE THE LABEL SCOPE ;***************************** END OF SPIM VP **************************
.