-- -------------------------------------------------------------------------- -- MAX522_demo.jal - demonstrate that the MAX522 Dual DAC is working -- $Id: MAX522_demo.jal,v 1.2 2003/03/19 00:19:52 jerry Exp $ -- $Source: /home/cvsroot/projectsTop/picProjectBoard/examples/MAX522_demo.jal,v $ -- -------------------------------------------------------------------------- -- -- Requirements: -- - Output a triangular wave signal on both DAC channels -- -- Approach: -- - Use a counter to ramp up and down. -- - Write the count to both DAC channels at the same time -- - Ramp as quickly as possible -- -- Procedures that need to be written: -- There are no pre-existing SPI routines in the JAL libaries and the -- IO pins and registers are not defined. -- -- - define registers and pins using structures and names similar to -- those used in the jpic.jal library. -- -- spi_wait - wait for the spi_word to be transmitted. This routine will -- loop waiting for the BF bit (bit 0) in the SPPSTAT -- register to transistion from 0 to 1. -- -- No other sub-programs are needed because using the SPI interface -- is mainly the process of writing to the SPPBUF register. -- -- Reading the SPI interface is not necessary because the MAX522 is a -- write-only device. The SPI input pin (RC4/SDI/SDA) will not be -- enabled as an SPP input. -- -- The chip select for the MAX522 is RD7. It will be held low for -- two SPI write cycles because the MAX522 expects a 16 bit word and -- SPI output buffer on the PIC is 8-bits. -- -- The MAX522 samples the serial data on the rising edge of the clock. -- So the SPI will be configured to output data on the falling edge, -- and the idle state for the clock will be 'low'. -- -- The PIC SPI transmits the MSB first which means that the MAX522 -- control word should be loaded in the ouput buffer with UB1 in the -- MSB and LA in the LSB. The MAX522 should be loaded in the output -- buffer with B7 (MSB) loaded in the MSB and B0 (LSB) in the LSB. -- -- Overall structure: -- Initialize I/O ports: -- RD7, ouput, initially high so that the MAX522 is not selected -- RC3, ouput, this will be the serial clock (SCLK). Note that -- RC3 is also connected to LED D4, initial low. -- RC5, ouput, this will be the serial data out to the MAX522 (SDO) -- -- RC0-2, outputs, LEDs D1-D3 for diagnostics. Initial value should -- be 1 so that the LEDs are off. -- -- Initialize registers: -- SSPCON -- SSPSTAT -- -- Assumptions and Limitations: -- - Assuming a write to the SSPBUF register will set the SDO pin to -- the state of the first bit so that the data to the MAX522 will -- be valid on the first rising edge of the clock. -- -- - The code has been optimized and now assumes that Fosc = 20MHz and -- that the SPI clock is run at it's highest frequency (Fosc/4 = -- 5Mhz). The optimization was to replace the spi_wait procedure -- with 8 nop instructions. -- -- Development time: -- Preliminary Investigation - 39min -- Reading spec sheets, coming up with a concept. -- -- Design - 47min -- Most of the comments above -- -- Coding - 52min -- -- Debugging - 62min -- Code worked the first time! So most of this time was spent making -- measurements and then speeding up the code. The spi_wait -- procedure was replaced with assembly nop instructions to double the -- update rate. This optimization was done after I found that the -- while loop in the spi_wait function was never being called. -- -- - The test time went up from 48min to 62min while I was doing the -- documentation. While reading the code I noticed that when -- I optimized the code I eliminated the delay that would -- allow the data to be clocked out to the MAX522. That seemed -- wrong, and I had not compared the MAX522 CS signal to the -- SPI clock. So I went back, instrumented the code and measured -- only to find that there was no problem. The write to max522_cs -- takes enough time that the data has time to clock out. There is -- 500ns between the falling clock and max522_cs going high. -- -- - Measured values before optimization: -- Loop time = 34.5uS -- Triangle wave frequency = ~55.6Hz (18ms/cycle) -- -- - Measured values after optimization: -- Loop time = 15.4uS -- Triangle wave frequency = ~128.2Hz (7.8ms/cycle) -- -- All times were measured with an 150MHz analog oscilloscope. -- -- Documentation - 39min -- Updating these comments, commiting to CVS, and final build and -- test. -- -- Total Development Time = 3hr 59min -- -------------------------------------------------------------------------- include f877_20 include jlib -- -------------------------------------------------------------------------- -- Define special function registers for SSP -- -------------------------------------------------------------------------- var volatile byte sspbuf at 0x_13 var volatile byte sspcon at 0x_14 var volatile byte sspstat at 0x_94 -- sspcon associated bits var volatile bit sspcon_wcol at sspcon : 7 var volatile bit sspcon_sspov at sspcon : 6 var volatile bit sspcon_sspen at sspcon : 5 var volatile bit sspcon_ckp at sspcon : 4 var volatile bit sspcon_sspm3 at sspcon : 3 var volatile bit sspcon_sspm2 at sspcon : 2 var volatile bit sspcon_sspm1 at sspcon : 1 var volatile bit sspcon_sspm0 at sspcon : 0 -- sspstat associated bits var volatile bit sspstat_smp at sspstat : 7 var volatile bit sspstat_cke at sspstat : 6 var volatile bit sspstat_da at sspstat : 5 var volatile bit sspstat_p at sspstat : 4 var volatile bit sspstat_s at sspstat : 3 var volatile bit sspstat_rw at sspstat : 2 var volatile bit sspstat_ua at sspstat : 1 var volatile bit sspstat_bf at sspstat : 0 -- -------------------------------------------------------------------------- -- setup I/O ports and define variables -- -------------------------------------------------------------------------- disable_a_d_functions pin_d7 = high pin_d7_direction = output var volatile bit max522_cs is pin_d7 pin_c3 = low pin_c3_direction = output pin_c5 = low pin_c5_direction = output pin_c0 = high pin_c1 = high pin_c2 = high pin_c0_direction = output pin_c1_direction = output pin_c2_direction = output var byte count = 0 var byte interval = 1 const byte max522_control = 0b_0010_0011 -- |||| |||+- LA - 1 = load DAC A -- |||| ||+-- LB - 1 = load DAC B -- |||| |+--- UB4 - unused -- |||| +---- SA - 0 = DAC A enabled -- |||+------ SB - 0 = DAC B enabled -- ||+------- UB3 - unused, but 1 in data sheet -- |+-------- UB2 - unused -- +--------- UB1 - unused -- -------------------------------------------------------------------------- -- spi_wait - wait for the SPI transmit to complete -- -- SPI tranmsit and receive are simultaneous, so we can look at the -- receive buffer full bit to determine when the buffer is full -- -------------------------------------------------------------------------- procedure spi_wait is pin_c0 = high bank_1 while ( sspstat_bf == false ) loop -- nothing to do but wait -- toggle pin c1 so that we can see if the while loop is -- active bank_0 pin_c1 = ! pin_c1 bank_1 end loop bank_0 pin_c0 = low end procedure -- -------------------------------------------------------------------------- -- Main loop -- -------------------------------------------------------------------------- forever loop bank_1 sspstat = 0b_0100_0000 -- |||| |||+- BF - buffer full status bit, 0 = SSPBUF empty -- |||| ||+-- UA - Update address, n/a SPI -- |||| |+--- RW - Read/Write, n/a SPI -- |||| +---- S - Start, n/a SPI -- |||+------ P - Stop, n/a SPI -- ||+------- DA - Data/Address, n/a SPI -- |+-------- CKE - SPI clock edge, 1 = rising edge -- +--------- SMP - SPI sample time, 0 = middle bank_0 sspcon = 0b_0010_0000 -- |||| ++++-- 0000 = SPI Master, clock = (Fosc/4) -- |||+------- 0 = CKP, SPI clock idle state = low -- ||+-------- 1 = SSPEN, SPI enabled -- |+--------- SSPOV, 0 = clear receive overflow -- +---------- WCOL, 0 = no collision count = count + interval if ( count == 255 ) then interval = -1 elsif ( count == 0 ) then interval = 1 end if -- select the MAX522 max522_cs = low -- write the control word sspbuf = max522_control -- Wait for the control word to be transmitted. -- spi_wait replaced by 8 nop instructions. -- Each nop instruction takes one CPU cycle (cycle = Fosc/4) assembler nop nop nop nop nop nop nop nop end assembler -- write the data to the MAX522 sspbuf = count -- Wait for the data word to be transmitted. -- spi_wait eliminated after measurements showed that -- the code to set max522_cs high took more time than -- clocking the data. -- de-select the MAX522 which causes the data to be written to the -- DACs max522_cs = high end loop