The tcDspOutputLatch class provides an abstract digital latch interface for I/O controller classes (e.g., tcDspDac7616) that require access to FPGA specific registers. This class allows such interfaces to be abstracted from the controller implementation.
The code snippet below illustrates a typical use for the tcDspOutputLatch abstract interface. The MityDSP application here contains two I/O devices, an tcDspDac7616 4 channel Digital to Analog converter and a tcDspTlv254x 8 channel Analog to Digital converter. Both devices interface to separate McBSP interfaces, and have control lines (1 chip select each, and an addition LDAC line in the case of the tcDspDac7616 device) that are routed to the MityDSP FPGA and controlled via a simple register interface.
Here, the user creates an FPGA class (tcFPGA) which manages the application specific FPGA interfaces - including the chip select control lines. This class derives from the tcDspOutputLatch and provides appropriate interfaces to the CS lines such that (as shown in the main routine) the A/D and D/A converter objects have the necessary control...
{ // This class controls the MityDSP FPGA, and provides // register interfaces for CS control lines, etc. This // class is generally specific to a MityDSP application. class tcFPGA : public tcDspOutputLatch { ... public: typedef enum { ... eeDAC_CS, eeDAC_LDAC1, eeADC_CS, ... } teOutputs; // This method manages the CS output latch for various devices virtual int SetOuput(unsigned int ID, unsigned int Value); ... } tcFPGA::SetOutput(unsigned int ID, unsigned int Value) { int retval = 0; unsigned int mask = 0; // load the latch register unsigned int regdata = *FPGA_DACCTRL_ADDR; switch(ID) { case eeDAC_CS: mask = FPGA_DACCTRL_CS; break; case eeDAC_LDAC: mask = FPGA_DACCTRL_LDAC; break; case eeADC_CS: mask = FPGA_ADCCTRL_CS; break; ... default: retval = gnBAD_ID; break; } // if request is to set the output if (Value) { regdata |= mask; } else // else clear it { regdata &= ~mask; } // set the latch register on the FPGA *FPGA_DACCTRL_ADDR = regdata; return retval; } // Example main, putting it all together... int main (int argc, char *argv[]) { tcFPGA FPGA; tcDspMcbsp MCBSP(0x018C0000, DATA_DELAY1, // rx_data_delay WORD_LENGTH_16, // rx_word_len RXJUST_RJZF, // rx_justify DATA_DELAY1, // tx_data_delay WORD_LENGTH_16, // tx_word_len FSYNC_MODE_EXT, // rx_fsync FSYNC_MODE_INT, // tx_fsync CLK_MODE_INT, // rx_clock CLK_MODE_INT, // tx_clock FSYNC_POL_HIGH, // rx_fsync_polarity FSYNC_POL_HIGH, // tx_fsync_polarity CLKR_POL_FALLING, // rx_clock_polarity CLKX_POL_RISING, // tx_clock_polarity CSTOP_DISABLED); // clock_stop tuCfrReg config; config.mnWord = 0; config.msBits.REF_VOLTb = REF_2V; config.msBits.REF_SELb = REF_INT; tcDspTlv254x ADC(&MCBSP,config,&FPGA,tcFPGA::eeADC_CS); ADC.request_data(0); // select channel 0 TSK_sleep(1); // provide time to sample unsigned short adc_value = ADC.read_data(); // read channel 0 sample tcDspMcbsp MCBSP_1(0x01900000, DATA_DELAY1, // rx_data_delay WORD_LENGTH_16, // rx_word_len RXJUST_RJZF, // rx_justify DATA_DELAY1, // tx_data_delay WORD_LENGTH_16, // tx_word_len FSYNC_MODE_EXT, // rx_fsync FSYNC_MODE_INT, // tx_fsync CLK_MODE_INT, // rx_clock CLK_MODE_INT, // tx_clock FSYNC_POL_HIGH, // rx_fsync_polarity FSYNC_POL_LOW, // tx_fsync_polarity CLKR_POL_FALLING, // rx_clock_polarity CLKX_POL_FALLING, // tx_clock_polarity CSTOP_NODELAY); // clock_stop tcDspDac7616 DAC(&MCBSP_1,&FPGA,tcFPGA::eeDAC_CS,tcFPGA::eeDAC_LDAC1); ... // Set DAC A output to mid range... DAC.update(DAC_A_ADDRESS, 2048); } }