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
Diff: I2S_Rx.cpp
- Revision:
- 0:82ff15078322
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/I2S_Rx.cpp Wed Jan 25 20:32:53 2012 +0000 @@ -0,0 +1,285 @@ +/*--------------------------------------------------------------------------- + + QRSS Receiver Application + + by Clayton ZL3TKA/VK1TKA + clayton@isnotcrazy.com + + I2S Hardware Driver Routines + +---------------------------------------------------------------------------*/ +// include files + +#include "I2S_Rx.h" + +// Definitions + +// (bit 12) Source burst size = 1 +// (bit 15) Destination burst size = 1 +// (bit 18) Source Width = 32 bits +// (bit 21) Destination Width = 32 bits +// (bit 26) Source Increment +// (bit 27) Destination Increment +// (bit 31) enable INT +#define DMA_CONTROL ( (0x00 << 12) | (0x00 << 15) | (0x02 << 18) | (0x02 << 21) | (0 << 26) | (1 << 27) | (1U << 31) ) +#define DMA_TC_MASK 0xFFF + +// Macros + +// Local Data + +// pointer to receiver - for use by IRQ routine +static TI2SReceiver * pI2SReceiver; + +// Global Data + +// Function Prototypes + +//--------------------------------------------------------------------------- +// IRQ Routines +//--------------------------------------------------------------------------- + +//--------------------------------------------------------------------------- +// +// DMA Int routine - test and call the object handler if appropriate +// +void DMA_IRQHandler(void) +{ + uint32_t regVal; + + // read Int TC (terminal count) Status register + regVal = LPC_GPDMA->DMACIntTCStat; + // clear interrupts + LPC_GPDMA->DMACIntTCClear |= regVal; + // test for receiver DMA channel int + if ( regVal&1 ) + pI2SReceiver->DMA_Interrupt(); +} + +//--------------------------------------------------------------------------- +// I2S RECEIVER FUNCTIONS +//--------------------------------------------------------------------------- + +//--------------------------------------------------------------------------- +// +// TI2SReceiver constructor +// +TI2SReceiver::TI2SReceiver( TBufferPool &BuffPol ) : + EmptyBuffersPool( BuffPol ), + bRunning( false ), + ulBufferCount( 0 ), + ulBufferAllocations( 0 ), + ulBufferFailures( 0 ) +{ + // Set up I2S pointer for the IRQ routine + pI2SReceiver = this; + + // Enable I2S in the PCONP register (I2S is disabled on reset) + LPC_SC->PCONP |= (1 << 27); + + // Connect the I2S sigals to port pins (P0.23 - P0.25) + LPC_PINCON->PINSEL1 &= ~( (0x3<<14) | (0x3<<16) | (0x3<<18) ); + LPC_PINCON->PINSEL1 |= ( (0x2<<14) | (0x2<<16) | (0x2<<18) ); +} + +//--------------------------------------------------------------------------- +// +// TI2SReceiver Initialise operation +// +void TI2SReceiver::Init() +{ + // Enable I2S in the PCONP register (I2S is disabled on reset) + LPC_SC->PCONP |= (1 << 27); + + // Connect the I2S sigals to port pins (P0.23 - P0.25) + LPC_PINCON->PINSEL1 &= ~( (0x3<<14) | (0x3<<16) | (0x3<<18) ); + LPC_PINCON->PINSEL1 |= ( (0x2<<14) | (0x2<<16) | (0x2<<18) ); + + // Stop reception + LPC_I2S->I2SDAI = 0x03 | (0x1<<3) | (0x1<<4) | (0x1<<5) | (0x1F<<6); + + // Disable DMA + LPC_GPDMACH0->DMACCControl = 0; + + // Initialise DMA + LPC_SC->PCONP |= (1 << 29); // Enable GPDMA clock + LPC_GPDMA->DMACConfig = 0x01; // Enable DMA channels, little endian + while ( !(LPC_GPDMA->DMACConfig & 0x01) ) ; + + // Set up DMA Int routine + NVIC_SetVector( DMA_IRQn, (uint32_t)DMA_IRQHandler ); + NVIC_EnableIRQ( DMA_IRQn ); +} + +//--------------------------------------------------------------------------- +// +// TI2SReceiver Start operation +// +void TI2SReceiver::Start() +{ + // Stop reception + LPC_I2S->I2SDAI = 0x03 | (0x1<<3) | (0x1<<4) | (0x1<<5) | (0x1F<<6); + LPC_GPDMACH0->DMACCConfig = 0; + LPC_GPDMACH0->DMACCControl = 0; + bRunning = false; + LPC_GPDMA->DMACIntTCClear = 0x01; // clear DMA0 flags + LPC_GPDMA->DMACIntErrClr = 0x01; + + // Enable DMA + // Get new buffer and set up the DMA + StartDMATransfer(); + + // Slave receive mode. 32 bit data, stereo + LPC_I2S->I2SDMA1 = (0x1<<0) | (0x02<<8); // channel 1 = Rx DMA + LPC_I2S->I2SRXMODE = 0; + LPC_I2S->I2SDAI = 0x03 | (0x1<<5) | (0x1F<<6); + bRunning = true; +} + +//--------------------------------------------------------------------------- +// +// TI2SReceiver Stop operation +// +void TI2SReceiver::Stop() +{ + bRunning = false; + + // Stop reception + LPC_I2S->I2SDMA1 = 0; + LPC_I2S->I2SDAI = 0x03 | (0x1<<3) | (0x1<<4) | (0x1<<5) | (0x1F<<6); + LPC_GPDMACH0->DMACCConfig = 0; + LPC_GPDMACH0->DMACCControl = 0; + + // clear out buffers + ReceivedBuffers.Flush(); + CurrentRxBuffer.Release(); +} + +//--------------------------------------------------------------------------- +// +// Debug routine - +// Read samples from the I2S by polling it +// Returns number of samples read +// +int TI2SReceiver::PolledRead( int32_t *piBuffer, int iLen ) +{ + int iCnt = 0; + while ( iLen>0 ) + { + // wait for something in the FIFO + if ( ((LPC_I2S->I2SSTATE>>8)&0xF)==0 ) + continue; + // Read it out to the buffer + *piBuffer = LPC_I2S->I2SRXFIFO; + piBuffer++; + iLen--; + iCnt++; + } + return iCnt; +} + +//--------------------------------------------------------------------------- +// +// Debug routine - +// Read status register +// +uint32_t TI2SReceiver::Status() +{ + return LPC_I2S->I2SSTATE; +} +//--------------------------------------------------------------------------- +// +// Debug routine - +// Report Status +// +void TI2SReceiver::Report() +{ + printf( "C-%d\r\n", ulBufferCount ); + printf( "F-%d\r\n", ulBufferFailures ); +/* + printf( "I2S Buffers Counter - %d\r\n", ulBufferCount ); + printf( "I2S Buffer Failures - %d\r\n", ulBufferFailures ); + printf( "I2S Buffer Allocations - %d\r\n", ulBufferAllocations ); + printf( "I2S Status Register: 0x%08X\r\n", LPC_I2S->I2SSTATE ); + printf( "I2S DMA1 Register: 0x%08X\r\n", LPC_I2S->I2SDMA1 ); + printf( "I2S DMA2 Register: 0x%08X\r\n", LPC_I2S->I2SDMA2 ); + printf( "DMA Enabled Register: 0x%08X\r\n", LPC_GPDMA->DMACEnbldChns ); + printf( "DMA TC Status Register: 0x%08X\r\n", LPC_GPDMA->DMACIntTCStat ); + printf( "DMA Err Status Register: 0x%08X\r\n", LPC_GPDMA->DMACIntErrStat ); + printf( "DMA Config Register: 0x%08X\r\n", LPC_GPDMA->DMACConfig ); + printf( "DMA0 Control Register: 0x%08X\r\n", LPC_GPDMACH0->DMACCControl ); + printf( "DMA0 Config Register: 0x%08X\r\n", LPC_GPDMACH0->DMACCConfig ); +*/ +} + +//--------------------------------------------------------------------------- +// +// DMA Interrupt Routine +// +void TI2SReceiver::DMA_Interrupt( ) +{ + // exit if receiver is not running + if ( !bRunning ) + return; + + // Queue current buffer + CurrentRxBuffer.SetLength( 99999 ); // set length to full buffer size + ReceivedBuffers.Write( CurrentRxBuffer ); + ulBufferCount++; + + // Get new buffer and set up the DMA + StartDMATransfer(); +} + +//--------------------------------------------------------------------------- +// +// Start a new DMA transfer +// +void TI2SReceiver::StartDMATransfer() +{ + int32_t *pDataPtr; + int iBufSize; + + // uses DMA0 and sets it up with new buffer (or a dummy buffer if none available) + // DMA channel 0 Source is I2S DMA1 = RX FIFO, Destination is memory + + // count DMA allocations + ulBufferAllocations++; + + // get a buffer + pDataPtr = NULL; + if ( EmptyBuffersPool.Create(CurrentRxBuffer) ) + { // got a buffer + pDataPtr = (int32_t *)(CurrentRxBuffer.SamplePtr()); + iBufSize = CurrentRxBuffer.Size() * 2; // size = samples*2 (samples are I/Q) + CurrentRxBuffer.Timestamp( LPC_TIM2->TC ); // Set timestamp + } + // check for buffer + if ( pDataPtr==NULL ) + { // failed to get a buffer - use the dumy buffer + ulBufferFailures++; + pDataPtr = aulDummyBuffer; + iBufSize = I2S_DUMMY_BUFFER_SIZE; + } + + // clear any ints + LPC_GPDMA->DMACIntTCClear = 0x01; // clear DMA0 flags + LPC_GPDMA->DMACIntErrClr = 0x01; + + // write source addr + LPC_GPDMACH0->DMACCSrcAddr = (uint32_t)(&(LPC_I2S->I2SRXFIFO)); + + // write destination + LPC_GPDMACH0->DMACCDestAddr = (uint32_t)pDataPtr; + + // write LL address - use 0 for single transfer + LPC_GPDMACH0->DMACCLLI = 0; + + // write control & config + LPC_GPDMACH0->DMACCControl = (iBufSize & DMA_TC_MASK) | DMA_CONTROL; + LPC_GPDMACH0->DMACCConfig = 0x08001 | (0x05 << 1) | (0x02 << 11); +} + +//--------------------------------------------------------------------------- +// END +//---------------------------------------------------------------------------