The tcDspLvds class is used to provide an interface to an instance of the MityDSP LVDS core firmware.
For transmit, the LVDS interface utilizes a dual port RAM structure that is segmented into 3 working areas: Idle, Transmit Buffer A, and Transmit Buffer B. The sizes of these working areas may be arbitrarily set. When enabled, the interface continuously transmits the content defined as the idle message until data is made available in either transmit Buffer A or B. The design is such that there are no stalls between any packets.
For receive, properly qualified packets (including address match and valid header and checksums) are clocked into a 32-bit wide receive buffer. A "promiscuous mode" is provided to bypass these checks and qualify all packets.
Interrupt mechanisms are provided for both transmit buffer available notifications, as well as receive data status. The application may register routines to be run in ISR context to provide specific functionality for type of interrupt.
An instance of the tcDspLvds class is created by specifying the firmware base address of the core and the receive packet size to be used on the interface.
This is a simple example of tcDspLvds creation and usage:
{ SEM_handle MyClass::mhTxAAvail, MyClass::mhTxBAvail, MyClass::mhRxDataAvail; tcDspLvds *MyClass::myLvds; volatile unsigned int *MyClass::mpRxFifo; unsigned int MyClass::mnRxDepth; unsigned int MyClass::mpRxBuf[4096]; static void MyClass::myIsrCallback(tcDspLvds *apLvds, int aeLevel, void *apUser) { // do different things based on interrupt switch ((tcDspLvds::teFIFOLevelMask)aeLevel) { // one of the TX buffers has been sent... mark it as available case tcDspLvds::eeTxAEmpty: { SEM_ipost(mhTxAAvail); break; } case tcDspLvds::eeTxBEmpty: { SEM_ipost(mhTxBAvail); break; } // RX FIFO is 1/4 full, transfer data from receive buffer case tcDspLvds::eeRxOneQ: { // transfer data from RX buffer... for (int i=0; i<(mnRxDepth / 4); i++) { mpRxBuf[i] = *mpRxFifo; } // re-enable interrupt ((tcDspLvds *)apUser)->EnableInterrupts(eeRxOneQ, true); break; } } return; } void MyClass::doSomething(void) { int i; unsigned int my_base_addr = 0xA0000200; unsigned int rx_packet_nibbles = 40; // initialize semaphores mhTxAAvail = SEM_create(0, NULL); mhTxBAvail = SEM_create(0, NULL); mhRxDataAvail = SEM_create(0, NULL); // create access to the LVDS myLvds = new tcDspLvds((void *)my_base_addr, rx_packet_nibbles); // Set receive address and mask myLvds->SetRxAddress(1); myLvds->SetRxAddrMask(false); // Get receive FIFO address and size mpRxFifo = myLvds->GetRxFifoDataPtr(); mnRxDepth = myLvds->GetRxFifoSize(); // register callback when TX buffers are complete, // and when RX FIFO is 1/4 full myLvds->RegisterIsrCallback((tcDspLvds::eeRxOneQ | tcDspLvds::eeAllTxEmpty), myIsrCallback, (void *)myLvds); // enable the receive interrupt myLvds->EnableInterrupts(eeRxOneQ, true); // load idle buffer with data and activate myLvds->LoadIdleBuffer("The Idle message for this interface", 40); // enable interface myLvds->EnableLink(true); // do something for a long time... while (true) { // wait for ISR to trigger RX data available if (SEM_pend(mhRxDataAvail, 0)) { // do something application-specific : : } // wait for ISR to trigger TX A available if (SEM_pend(mhTxAAvail, 0)) { myLvds->LoadTxABuffer("A transmit message of some kind", 40); // enable the TX A empty interrupt myLvds->EnableInterrupts(eeTxAEmpty, true); } // wait for ISR to trigger TX B available if (SEM_pend(mhTxBAvail, 0)) { myLvds->LoadTxBBuffer("Another transmit message...", 40); // enable the TX B empty interrupt myLvds->EnableInterrupts(eeTxBEmpty, true); } } } }