QRSS Rx Network receiver. A receiver to sample a segment of RF spectrum and send this data to a server for further processing and display. NXP mbed Design Challenge entry (Honorable Mention). Published in Circuit Cellar, Feb 2012

Dependencies:   NetServices mbed DNSResolver

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers I2S_Rx.cpp Source File

I2S_Rx.cpp

00001 /*---------------------------------------------------------------------------
00002 
00003     QRSS Receiver Application
00004         
00005     by Clayton ZL3TKA/VK1TKA
00006     clayton@isnotcrazy.com
00007 
00008     I2S Hardware Driver Routines
00009 
00010 ---------------------------------------------------------------------------*/
00011 // include files
00012 
00013 #include "I2S_Rx.h"
00014 
00015 // Definitions
00016 
00017 // (bit 12) Source burst size = 1
00018 // (bit 15) Destination burst size = 1
00019 // (bit 18) Source Width = 32 bits
00020 // (bit 21) Destination Width = 32 bits
00021 // (bit 26) Source Increment
00022 // (bit 27) Destination Increment
00023 // (bit 31) enable INT
00024 #define DMA_CONTROL             ( (0x00 << 12) | (0x00 << 15) | (0x02 << 18) | (0x02 << 21) | (0 << 26) | (1 << 27) | (1U << 31) )
00025 #define DMA_TC_MASK             0xFFF
00026 
00027 // Macros
00028 
00029 // Local Data
00030 
00031 // pointer to receiver - for use by IRQ routine
00032 static TI2SReceiver * pI2SReceiver;
00033 
00034 // Global Data
00035 
00036 // Function Prototypes
00037 
00038 //---------------------------------------------------------------------------
00039 //  IRQ Routines
00040 //---------------------------------------------------------------------------
00041 
00042 //---------------------------------------------------------------------------
00043 //
00044 //  DMA Int routine - test and call the object handler if appropriate
00045 //
00046 void DMA_IRQHandler(void) 
00047 {
00048     uint32_t regVal;
00049 
00050     // read Int TC (terminal count) Status register
00051     regVal = LPC_GPDMA->DMACIntTCStat;
00052     // clear interrupts
00053     LPC_GPDMA->DMACIntTCClear |= regVal;
00054     // test for receiver DMA channel int
00055     if ( regVal&1 )
00056         pI2SReceiver->DMA_Interrupt();
00057 }
00058 
00059 //---------------------------------------------------------------------------
00060 //  I2S RECEIVER FUNCTIONS
00061 //---------------------------------------------------------------------------
00062 
00063 //---------------------------------------------------------------------------
00064 //
00065 //  TI2SReceiver constructor
00066 //
00067 TI2SReceiver::TI2SReceiver( TBufferPool &BuffPol ) :
00068             EmptyBuffersPool( BuffPol ),
00069             bRunning( false ),
00070             ulBufferCount( 0 ),
00071             ulBufferAllocations( 0 ),
00072             ulBufferFailures( 0 )
00073 {
00074     // Set up I2S pointer for the IRQ routine
00075     pI2SReceiver = this;
00076     
00077     // Enable I2S in the PCONP register (I2S is disabled on reset)
00078     LPC_SC->PCONP |= (1 << 27);
00079 
00080     // Connect the I2S sigals to port pins (P0.23 - P0.25)
00081     LPC_PINCON->PINSEL1 &= ~( (0x3<<14) | (0x3<<16) | (0x3<<18) );
00082     LPC_PINCON->PINSEL1 |=  ( (0x2<<14) | (0x2<<16) | (0x2<<18) );
00083 }
00084 
00085 //---------------------------------------------------------------------------
00086 //
00087 //  TI2SReceiver Initialise operation
00088 //
00089 void TI2SReceiver::Init()
00090 {
00091     // Enable I2S in the PCONP register (I2S is disabled on reset)
00092     LPC_SC->PCONP |= (1 << 27);
00093     
00094     // Connect the I2S sigals to port pins (P0.23 - P0.25)
00095     LPC_PINCON->PINSEL1 &= ~( (0x3<<14) | (0x3<<16) | (0x3<<18) );
00096     LPC_PINCON->PINSEL1 |=  ( (0x2<<14) | (0x2<<16) | (0x2<<18) );
00097 
00098     // Stop reception
00099     LPC_I2S->I2SDAI = 0x03 | (0x1<<3) | (0x1<<4) | (0x1<<5) | (0x1F<<6);
00100 
00101     // Disable DMA
00102     LPC_GPDMACH0->DMACCControl = 0;
00103 
00104     // Initialise DMA
00105     LPC_SC->PCONP |= (1 << 29);         // Enable GPDMA clock
00106     LPC_GPDMA->DMACConfig = 0x01;       // Enable DMA channels, little endian
00107     while ( !(LPC_GPDMA->DMACConfig & 0x01) )  ;
00108 
00109     // Set up DMA Int routine
00110     NVIC_SetVector( DMA_IRQn, (uint32_t)DMA_IRQHandler );
00111     NVIC_EnableIRQ( DMA_IRQn );
00112 }
00113 
00114 //---------------------------------------------------------------------------
00115 //
00116 //  TI2SReceiver Start operation
00117 //
00118 void TI2SReceiver::Start()
00119 {
00120     // Stop reception
00121     LPC_I2S->I2SDAI = 0x03 | (0x1<<3) | (0x1<<4) | (0x1<<5) | (0x1F<<6);
00122     LPC_GPDMACH0->DMACCConfig = 0;
00123     LPC_GPDMACH0->DMACCControl = 0;
00124     bRunning = false;
00125     LPC_GPDMA->DMACIntTCClear = 0x01;   // clear DMA0 flags
00126     LPC_GPDMA->DMACIntErrClr = 0x01;
00127 
00128     // Enable DMA
00129     // Get new buffer and set up the DMA
00130     StartDMATransfer();
00131 
00132     // Slave receive mode. 32 bit data, stereo
00133     LPC_I2S->I2SDMA1 = (0x1<<0) | (0x02<<8);        // channel 1 = Rx DMA
00134     LPC_I2S->I2SRXMODE = 0;
00135     LPC_I2S->I2SDAI = 0x03 | (0x1<<5) | (0x1F<<6);
00136     bRunning = true;
00137 }
00138 
00139 //---------------------------------------------------------------------------
00140 //
00141 //  TI2SReceiver Stop operation
00142 //
00143 void TI2SReceiver::Stop()
00144 {
00145     bRunning = false;
00146 
00147     // Stop reception
00148     LPC_I2S->I2SDMA1 = 0;
00149     LPC_I2S->I2SDAI = 0x03 | (0x1<<3) | (0x1<<4) | (0x1<<5) | (0x1F<<6);
00150     LPC_GPDMACH0->DMACCConfig = 0;
00151     LPC_GPDMACH0->DMACCControl = 0;
00152 
00153     // clear out buffers
00154     ReceivedBuffers.Flush();
00155     CurrentRxBuffer.Release();
00156 }
00157         
00158 //---------------------------------------------------------------------------
00159 //
00160 //  Debug routine - 
00161 //      Read samples from the I2S by polling it
00162 //          Returns number of samples read
00163 //
00164 int TI2SReceiver::PolledRead( int32_t *piBuffer, int iLen )
00165 {
00166     int iCnt = 0;
00167     while ( iLen>0 )
00168     {
00169         // wait for something in the FIFO
00170         if ( ((LPC_I2S->I2SSTATE>>8)&0xF)==0 )
00171             continue;
00172         // Read it out to the buffer
00173         *piBuffer = LPC_I2S->I2SRXFIFO;
00174         piBuffer++;
00175         iLen--;
00176         iCnt++;
00177     }
00178     return iCnt;
00179 }
00180 
00181 //---------------------------------------------------------------------------
00182 //
00183 //  Debug routine - 
00184 //      Read status register
00185 //
00186 uint32_t TI2SReceiver::Status()
00187 {
00188     return LPC_I2S->I2SSTATE;
00189 }
00190 //---------------------------------------------------------------------------
00191 //
00192 //  Debug routine - 
00193 //      Report Status
00194 //
00195 void TI2SReceiver::Report()
00196 {
00197     printf( "C-%d\r\n", ulBufferCount );
00198     printf( "F-%d\r\n", ulBufferFailures );
00199 /*
00200     printf( "I2S Buffers Counter - %d\r\n", ulBufferCount );
00201     printf( "I2S Buffer Failures - %d\r\n", ulBufferFailures );
00202     printf( "I2S Buffer Allocations - %d\r\n", ulBufferAllocations );
00203     printf( "I2S Status Register: 0x%08X\r\n", LPC_I2S->I2SSTATE );
00204     printf( "I2S DMA1 Register: 0x%08X\r\n", LPC_I2S->I2SDMA1 );
00205     printf( "I2S DMA2 Register: 0x%08X\r\n", LPC_I2S->I2SDMA2 );
00206     printf( "DMA Enabled Register: 0x%08X\r\n",  LPC_GPDMA->DMACEnbldChns );
00207     printf( "DMA TC Status Register: 0x%08X\r\n",  LPC_GPDMA->DMACIntTCStat );
00208     printf( "DMA Err Status Register: 0x%08X\r\n",  LPC_GPDMA->DMACIntErrStat );
00209     printf( "DMA Config Register: 0x%08X\r\n",  LPC_GPDMA->DMACConfig );
00210     printf( "DMA0 Control Register: 0x%08X\r\n",  LPC_GPDMACH0->DMACCControl );
00211     printf( "DMA0 Config Register: 0x%08X\r\n",  LPC_GPDMACH0->DMACCConfig );
00212 */
00213 }
00214 
00215 //---------------------------------------------------------------------------
00216 //
00217 //  DMA Interrupt Routine
00218 //
00219 void TI2SReceiver::DMA_Interrupt( )
00220 {
00221     // exit if receiver is not running
00222     if ( !bRunning )
00223         return;
00224 
00225     // Queue current buffer
00226     CurrentRxBuffer.SetLength( 99999 );     // set length to full buffer size
00227     ReceivedBuffers.Write( CurrentRxBuffer );
00228     ulBufferCount++;
00229 
00230     // Get new buffer and set up the DMA
00231     StartDMATransfer();
00232 }
00233 
00234 //---------------------------------------------------------------------------
00235 //
00236 //  Start a new DMA transfer
00237 //
00238 void TI2SReceiver::StartDMATransfer()
00239 {
00240     int32_t    *pDataPtr;
00241     int         iBufSize;
00242 
00243     // uses DMA0 and sets it up with new buffer (or a dummy buffer if none available)
00244     //  DMA channel 0   Source is I2S DMA1 = RX FIFO, Destination is memory
00245 
00246     // count DMA allocations
00247     ulBufferAllocations++;
00248     
00249     // get a buffer
00250     pDataPtr = NULL;
00251     if ( EmptyBuffersPool.Create(CurrentRxBuffer) )
00252     {   // got a buffer
00253         pDataPtr = (int32_t *)(CurrentRxBuffer.SamplePtr());
00254         iBufSize = CurrentRxBuffer.Size() * 2;          // size = samples*2 (samples are I/Q)
00255         CurrentRxBuffer.Timestamp( LPC_TIM2->TC );      // Set timestamp
00256     }
00257     // check for buffer
00258     if ( pDataPtr==NULL )
00259     {   // failed to get a buffer - use the dumy buffer
00260         ulBufferFailures++;
00261         pDataPtr = aulDummyBuffer;
00262         iBufSize = I2S_DUMMY_BUFFER_SIZE;
00263     }
00264 
00265     // clear any ints
00266     LPC_GPDMA->DMACIntTCClear = 0x01;   // clear DMA0 flags
00267     LPC_GPDMA->DMACIntErrClr = 0x01;
00268 
00269     // write source addr
00270     LPC_GPDMACH0->DMACCSrcAddr = (uint32_t)(&(LPC_I2S->I2SRXFIFO));
00271     
00272     // write destination
00273     LPC_GPDMACH0->DMACCDestAddr = (uint32_t)pDataPtr;
00274     
00275     // write LL address - use 0 for single transfer
00276     LPC_GPDMACH0->DMACCLLI = 0;
00277     
00278     // write control & config
00279     LPC_GPDMACH0->DMACCControl = (iBufSize & DMA_TC_MASK) | DMA_CONTROL;
00280     LPC_GPDMACH0->DMACCConfig = 0x08001 | (0x05 << 1) | (0x02 << 11);
00281 }
00282 
00283 //---------------------------------------------------------------------------
00284 //  END
00285 //---------------------------------------------------------------------------