' ' SPI receiving with a smartpin works very cleanly as the number of I/O buffer stages does not affect timing. ' This is so because the SPI clock follows the same number of stages as the data does. ' ' SPI sending, on the other hand, has a problem with responding to a SPI clock input in a timely manner. ' The number of input stages and output stages both stack to make a four sysclock lag ' from SPI clock input to SPI tx data output. ' ' Here is a demo of using a full period leading SPI clock to compensate for the four sysclock lag. ' Note that this relies on the sysclock to SPI clock ratio being set to 4:1. Unsuitable for others. ' Makes use of idle-high SPI clocking. ' ' Use a digital storage oscilloscope to view the timings. ' DAT ORG 0 call #spi_init callpb #"5", #spi_command callpb #"a", #spi_tx_byte callpb #$aa, #spi_tx_byte callpb #$55, #spi_tx_byte waitse1 outh #spi_cs 'deselct SPI device jmp #$ spi_command outl #spi_cs 'select SPI device shl pb, #32-8 '8-bit word size rev pb 'make it big-endian pollse1 'clear any prior event wypin pb, #spi_tx 'write new byte to Y buffer _ret_ wypin #8, #spi_ck 'clock out 8-bit word size spi_tx_byte shl pb, #32-8 '8-bit word size rev pb 'make it big-endian waitse1 'wait for completion of prior word wypin pb, #spi_tx 'write new byte to Y buffer _ret_ wypin #8, #spi_ck 'clock out 8-bit word size spi_init wrpin #0, #spi_cs 'clear any prior spartpin mode drvh #spi_cs 'deselect SPI device fltl #spi_ck 'disable any prior spartpins for clock, tx and rx fltl #spi_tx fltl #spi_rx wrpin ##SPM_PULSES | P_OINV, #spi_ck 'SPI clock smartpin, inverted out for idle high wxpin ##RATIO | (RATIO/2)<<16, #spi_ck wrpin ##SPM_SSER_TX | BF_MINUS1NOT, #spi_tx 'SPI tx smartpin, SPI clock on B input, inverted for full period wxpin #7 | SSTX_STOP, #spi_tx '8 bits per word, stop-start mode wrpin ##SPM_SSER_RX | BF_MINUS2, #spi_rx 'SPI rx smartpin, SPI clock on B input wxpin #7, #spi_rx '8 bits per word dirh #spi_ck 'enable the smartpins for clock, tx and rx dirh #spi_tx dirh #spi_rx _ret_ setse1 #E_PIN_RISE | spi_ck 'setup event for completion of SPI clock burst CON #0, spi_cs, spi_ck, spi_tx, spi_rx RATIO = 4 'Select Event modes E_LOCK_RISE = (%01 << 4) ' hub-lock rise event trigger E_LOCK_FALL = (%10 << 4) ' hub-lock fall event trigger E_LOCK_DIFF = (%11 << 4) ' hub-lock change event trigger E_PIN_RISE = (%001 << 6) ' pin rise event trigger E_PIN_FALL = (%010 << 6) ' pin fall event trigger E_PIN_DIFF = (%011 << 6) ' pin change event trigger E_PIN_LOW = (%100 << 6) ' pin low event trigger E_PIN_HIGH = (%110 << 6) ' pin high event trigger ' Pin modes ' *********************************************************** ' ***** PIN MODES INCOMPLETE ***** ONLY HAS WHAT I USED ***** ' *********************************************************** P_REGD = (%1 << 16) ' turn on clocked digital I/O (registered pins) P_IINV = (%1 << 15) ' invert digital input P_OINV = (%1 << 14) ' invert digital output P_NFB = (%0001 << 17) ' negative feedback, in -> not out P_FLOAT = (%111111 << 8) ' float digital output P_1K5R = (%001001 << 8) ' 1.5 kiloOhm digital output P_15KR = (%010010 << 8) ' 15 kiloOhm digital output P_1mA = (%100100 << 8) ' 1 milliAmp digital output P_COGDAC = (%01 << 6) ' select a cog/streamer for DAC level, smartpin must be off P_BITDAC = (%10 << 6) ' preset for DAC level (split in revB), smartpin off (default for smartpins when DACMODE) PM_DAC = (%101 << 18) ' DAC output (with optional ADC input), preset level DAC_990 = PM_DAC |(%00 << 16) ' 990 Ohm, 3.3 Volt range DAC_124 = PM_DAC |(%10 << 16) ' 124 Ohm, 3.3 Volt range DAC_600 = PM_DAC |(%01 << 16) ' 600 Ohm, 2.0 Volt range DAC_75 = PM_DAC |(%11 << 16) ' 75 Ohm, 2.0 Volt range PM_COMPDAC = (%1100 << 17) ' Analogue comparator with DAC as preset reference PM_ADC = (%100 << 18) ' turn on custom pin ADC input ADC_GIO = PM_ADC | (%000 << 15) ADC_VIO = PM_ADC | (%001 << 15) ADC_B1 = PM_ADC | (%010 << 15) ADC_A1 = PM_ADC | (%011 << 15) ADC_A3 = PM_ADC | (%100 << 15) ADC_A10 = PM_ADC | (%101 << 15) ADC_A30 = PM_ADC | (%110 << 15) ADC_A100 = PM_ADC | (%111 << 15) AF_PLUS1 = (%0001 << 28) AF_PLUS2 = (%0010 << 28) AF_PLUS3 = (%0011 << 28) AF_MINUS1 = (%0111 << 28) AF_MINUS2 = (%0110 << 28) AF_MINUS3 = (%0101 << 28) AF_OUT = (%0100 << 28) AF_NOT = (%1000 << 28) AF_PLUS1NOT = (%1001 << 28) AF_PLUS2NOT = (%1010 << 28) AF_PLUS3NOT = (%1011 << 28) AF_MINUS1NOT = (%1111 << 28) AF_MINUS2NOT = (%1110 << 28) AF_MINUS3NOT = (%1101 << 28) AF_OUTNOT = (%1100 << 28) BF_PLUS1 = (%0001 << 24) BF_PLUS2 = (%0010 << 24) BF_PLUS3 = (%0011 << 24) BF_MINUS1 = (%0111 << 24) BF_MINUS2 = (%0110 << 24) BF_MINUS3 = (%0101 << 24) BF_OUT = (%0100 << 24) BF_NOT = (%1000 << 24) BF_PLUS1NOT = (%1001 << 24) BF_PLUS2NOT = (%1010 << 24) BF_PLUS3NOT = (%1011 << 24) BF_MINUS1NOT = (%1111 << 24) BF_MINUS2NOT = (%1110 << 24) BF_MINUS3NOT = (%1101 << 24) BF_OUTNOT = (%1100 << 24) ' Smartpin modes SP_OUT = (%1 << 6) ' enable digital output when DIR operates smartpin SPM_OFF = 0 ' smart pin off (default) SPM_REPOSITORY = %00001_0 ' long repository (P[12:10] != %101) SPM_DAC_RANDOM = %00001_0 |SP_OUT|PM_DAC ' DAC noise (P[12:10] = %101) SPM_DAC_RND = %00010_0 |SP_OUT|PM_DAC ' DAC 16-bit dither, noise (P[12:10] = %101) SPM_DAC_PWM = %00011_0 |SP_OUT|PM_DAC ' DAC 16-bit dither, PWM (P[12:10] = %101) SPM_PULSES = %00100_0 |SP_OUT ' pulse/cycle output SPM_STEPS = %00101_0 |SP_OUT ' transition output SPM_NCO_FREQ = %00110_0 |SP_OUT ' NCO frequency SPM_NCO_DUTY = %00111_0 |SP_OUT ' NCO duty SPM_PWM_TRI = %01000_0 |SP_OUT ' PWM triangle SPM_PWM_SAW = %01001_0 |SP_OUT ' PWM sawtooth SPM_PWM_SAW_FB = %01010_0 |SP_OUT ' PWM switch-mode power supply, V and I feedback SPM_CNT_QUAD = %01011_0 ' count: A-B quadrature encoder SPM_CNT_UP_ENA = %01100_0 ' count: A clock up, B enable SPM_CNT_DIR = %01101_0 ' count: A clock, B direction SPM_CNT_UP = %01110_0 ' count: (Y=%0) A clock up SPM_CNT_UP_DN = %01110_0 ' count: (Y=%1) A clock up, B clock down SPM_ACC_UP = %01111_0 ' accumulate: (Y=%0) A up SPM_ACC_UP_DN = %01111_0 ' accumulate: (Y=%1) A up, B down SPM_TIM_STEP = %10000_0 ' interval: of most recent step duration SPM_TIM_PULSE = %10001_0 ' interval: of most recent pulse duration SPM_TIM_MANY = %10010_0 ' interval: (Y=%0xx) of X number of accum/pulses/steps SPM_TIMEOUT = %10010_0 ' interval: (Y=%1xx) since most recent high/rise/edge, with X compare SPM_TIM_PULS = %10011_0 ' interval: of X number of A-B pulses/steps SPM_ACC_PULS = %10100_0 ' accumulate: pulses/steps, of X number of A-B pulses/steps SPM_TIM_OVER = %10101_0 ' interval: of A-B pulses/steps, for at least X duration SPM_ACC_OVER = %10110_0 ' accumulate: A-B pulses/steps, for at least X duration SPM_CNT_OVER = %10111_0 ' count: A-B pulses/steps, for at least X duration #ifdef PROP2_REVA SPM_USB_HOSTL = %11000_0 |SP_OUT ' USB host, low-speed (even/odd pin pair = DM/DP) SPM_USB_HOSTH = %11001_0 |SP_OUT ' USB host, high-speed (even/odd pin pair = DM/DP) SPM_USB_DEVL = %11010_0 |SP_OUT ' USB device, low-speed (even/odd pin pair = DM/DP) SPM_USB_DEVH = %11011_0 |SP_OUT ' USB device, high-speed (even/odd pin pair = DM/DP) #endif #ifdef PROP2_REVB SPM_ADC_ISINC = %11000_0 ' ADC sample/filter/capture, internally clocked SPM_ADC_ESINC = %11001_0 ' ADC sample/filter/capture, externally clocked SPM_ADC_SCOPE = %11010_0 ' ADC scope-mode, with trigger, internally clocked SPM_USB = %11011_0 |SP_OUT ' USB v1.0 host or device, (even/odd pin pair = DM/DP) #endif SPM_SSER_TX = %11100_0 |SP_OUT ' sync serial transmit (A-data, B-clock) SPM_SSER_RX = %11101_0 ' sync serial receive (A-data, B-clock) SPM_ASER_TX = %11110_0 |SP_OUT ' async serial transmit (baud) SPM_ASER_RX = %11111_0 ' async serial receive (baud) SSTX_STOP = (%1 << 5) ' sync serial transmit first bit direct when empty (start-stop mode) SSRX_LATE = (%1 << 5) ' sync serial receiver post-clock sampling