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
I2S_Rx.cpp@0:82ff15078322, 2012-01-25 (annotated)
- Committer:
- claytong
- Date:
- Wed Jan 25 20:32:53 2012 +0000
- Revision:
- 0:82ff15078322
1.0 (initial public release)
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
claytong | 0:82ff15078322 | 1 | /*--------------------------------------------------------------------------- |
claytong | 0:82ff15078322 | 2 | |
claytong | 0:82ff15078322 | 3 | QRSS Receiver Application |
claytong | 0:82ff15078322 | 4 | |
claytong | 0:82ff15078322 | 5 | by Clayton ZL3TKA/VK1TKA |
claytong | 0:82ff15078322 | 6 | clayton@isnotcrazy.com |
claytong | 0:82ff15078322 | 7 | |
claytong | 0:82ff15078322 | 8 | I2S Hardware Driver Routines |
claytong | 0:82ff15078322 | 9 | |
claytong | 0:82ff15078322 | 10 | ---------------------------------------------------------------------------*/ |
claytong | 0:82ff15078322 | 11 | // include files |
claytong | 0:82ff15078322 | 12 | |
claytong | 0:82ff15078322 | 13 | #include "I2S_Rx.h" |
claytong | 0:82ff15078322 | 14 | |
claytong | 0:82ff15078322 | 15 | // Definitions |
claytong | 0:82ff15078322 | 16 | |
claytong | 0:82ff15078322 | 17 | // (bit 12) Source burst size = 1 |
claytong | 0:82ff15078322 | 18 | // (bit 15) Destination burst size = 1 |
claytong | 0:82ff15078322 | 19 | // (bit 18) Source Width = 32 bits |
claytong | 0:82ff15078322 | 20 | // (bit 21) Destination Width = 32 bits |
claytong | 0:82ff15078322 | 21 | // (bit 26) Source Increment |
claytong | 0:82ff15078322 | 22 | // (bit 27) Destination Increment |
claytong | 0:82ff15078322 | 23 | // (bit 31) enable INT |
claytong | 0:82ff15078322 | 24 | #define DMA_CONTROL ( (0x00 << 12) | (0x00 << 15) | (0x02 << 18) | (0x02 << 21) | (0 << 26) | (1 << 27) | (1U << 31) ) |
claytong | 0:82ff15078322 | 25 | #define DMA_TC_MASK 0xFFF |
claytong | 0:82ff15078322 | 26 | |
claytong | 0:82ff15078322 | 27 | // Macros |
claytong | 0:82ff15078322 | 28 | |
claytong | 0:82ff15078322 | 29 | // Local Data |
claytong | 0:82ff15078322 | 30 | |
claytong | 0:82ff15078322 | 31 | // pointer to receiver - for use by IRQ routine |
claytong | 0:82ff15078322 | 32 | static TI2SReceiver * pI2SReceiver; |
claytong | 0:82ff15078322 | 33 | |
claytong | 0:82ff15078322 | 34 | // Global Data |
claytong | 0:82ff15078322 | 35 | |
claytong | 0:82ff15078322 | 36 | // Function Prototypes |
claytong | 0:82ff15078322 | 37 | |
claytong | 0:82ff15078322 | 38 | //--------------------------------------------------------------------------- |
claytong | 0:82ff15078322 | 39 | // IRQ Routines |
claytong | 0:82ff15078322 | 40 | //--------------------------------------------------------------------------- |
claytong | 0:82ff15078322 | 41 | |
claytong | 0:82ff15078322 | 42 | //--------------------------------------------------------------------------- |
claytong | 0:82ff15078322 | 43 | // |
claytong | 0:82ff15078322 | 44 | // DMA Int routine - test and call the object handler if appropriate |
claytong | 0:82ff15078322 | 45 | // |
claytong | 0:82ff15078322 | 46 | void DMA_IRQHandler(void) |
claytong | 0:82ff15078322 | 47 | { |
claytong | 0:82ff15078322 | 48 | uint32_t regVal; |
claytong | 0:82ff15078322 | 49 | |
claytong | 0:82ff15078322 | 50 | // read Int TC (terminal count) Status register |
claytong | 0:82ff15078322 | 51 | regVal = LPC_GPDMA->DMACIntTCStat; |
claytong | 0:82ff15078322 | 52 | // clear interrupts |
claytong | 0:82ff15078322 | 53 | LPC_GPDMA->DMACIntTCClear |= regVal; |
claytong | 0:82ff15078322 | 54 | // test for receiver DMA channel int |
claytong | 0:82ff15078322 | 55 | if ( regVal&1 ) |
claytong | 0:82ff15078322 | 56 | pI2SReceiver->DMA_Interrupt(); |
claytong | 0:82ff15078322 | 57 | } |
claytong | 0:82ff15078322 | 58 | |
claytong | 0:82ff15078322 | 59 | //--------------------------------------------------------------------------- |
claytong | 0:82ff15078322 | 60 | // I2S RECEIVER FUNCTIONS |
claytong | 0:82ff15078322 | 61 | //--------------------------------------------------------------------------- |
claytong | 0:82ff15078322 | 62 | |
claytong | 0:82ff15078322 | 63 | //--------------------------------------------------------------------------- |
claytong | 0:82ff15078322 | 64 | // |
claytong | 0:82ff15078322 | 65 | // TI2SReceiver constructor |
claytong | 0:82ff15078322 | 66 | // |
claytong | 0:82ff15078322 | 67 | TI2SReceiver::TI2SReceiver( TBufferPool &BuffPol ) : |
claytong | 0:82ff15078322 | 68 | EmptyBuffersPool( BuffPol ), |
claytong | 0:82ff15078322 | 69 | bRunning( false ), |
claytong | 0:82ff15078322 | 70 | ulBufferCount( 0 ), |
claytong | 0:82ff15078322 | 71 | ulBufferAllocations( 0 ), |
claytong | 0:82ff15078322 | 72 | ulBufferFailures( 0 ) |
claytong | 0:82ff15078322 | 73 | { |
claytong | 0:82ff15078322 | 74 | // Set up I2S pointer for the IRQ routine |
claytong | 0:82ff15078322 | 75 | pI2SReceiver = this; |
claytong | 0:82ff15078322 | 76 | |
claytong | 0:82ff15078322 | 77 | // Enable I2S in the PCONP register (I2S is disabled on reset) |
claytong | 0:82ff15078322 | 78 | LPC_SC->PCONP |= (1 << 27); |
claytong | 0:82ff15078322 | 79 | |
claytong | 0:82ff15078322 | 80 | // Connect the I2S sigals to port pins (P0.23 - P0.25) |
claytong | 0:82ff15078322 | 81 | LPC_PINCON->PINSEL1 &= ~( (0x3<<14) | (0x3<<16) | (0x3<<18) ); |
claytong | 0:82ff15078322 | 82 | LPC_PINCON->PINSEL1 |= ( (0x2<<14) | (0x2<<16) | (0x2<<18) ); |
claytong | 0:82ff15078322 | 83 | } |
claytong | 0:82ff15078322 | 84 | |
claytong | 0:82ff15078322 | 85 | //--------------------------------------------------------------------------- |
claytong | 0:82ff15078322 | 86 | // |
claytong | 0:82ff15078322 | 87 | // TI2SReceiver Initialise operation |
claytong | 0:82ff15078322 | 88 | // |
claytong | 0:82ff15078322 | 89 | void TI2SReceiver::Init() |
claytong | 0:82ff15078322 | 90 | { |
claytong | 0:82ff15078322 | 91 | // Enable I2S in the PCONP register (I2S is disabled on reset) |
claytong | 0:82ff15078322 | 92 | LPC_SC->PCONP |= (1 << 27); |
claytong | 0:82ff15078322 | 93 | |
claytong | 0:82ff15078322 | 94 | // Connect the I2S sigals to port pins (P0.23 - P0.25) |
claytong | 0:82ff15078322 | 95 | LPC_PINCON->PINSEL1 &= ~( (0x3<<14) | (0x3<<16) | (0x3<<18) ); |
claytong | 0:82ff15078322 | 96 | LPC_PINCON->PINSEL1 |= ( (0x2<<14) | (0x2<<16) | (0x2<<18) ); |
claytong | 0:82ff15078322 | 97 | |
claytong | 0:82ff15078322 | 98 | // Stop reception |
claytong | 0:82ff15078322 | 99 | LPC_I2S->I2SDAI = 0x03 | (0x1<<3) | (0x1<<4) | (0x1<<5) | (0x1F<<6); |
claytong | 0:82ff15078322 | 100 | |
claytong | 0:82ff15078322 | 101 | // Disable DMA |
claytong | 0:82ff15078322 | 102 | LPC_GPDMACH0->DMACCControl = 0; |
claytong | 0:82ff15078322 | 103 | |
claytong | 0:82ff15078322 | 104 | // Initialise DMA |
claytong | 0:82ff15078322 | 105 | LPC_SC->PCONP |= (1 << 29); // Enable GPDMA clock |
claytong | 0:82ff15078322 | 106 | LPC_GPDMA->DMACConfig = 0x01; // Enable DMA channels, little endian |
claytong | 0:82ff15078322 | 107 | while ( !(LPC_GPDMA->DMACConfig & 0x01) ) ; |
claytong | 0:82ff15078322 | 108 | |
claytong | 0:82ff15078322 | 109 | // Set up DMA Int routine |
claytong | 0:82ff15078322 | 110 | NVIC_SetVector( DMA_IRQn, (uint32_t)DMA_IRQHandler ); |
claytong | 0:82ff15078322 | 111 | NVIC_EnableIRQ( DMA_IRQn ); |
claytong | 0:82ff15078322 | 112 | } |
claytong | 0:82ff15078322 | 113 | |
claytong | 0:82ff15078322 | 114 | //--------------------------------------------------------------------------- |
claytong | 0:82ff15078322 | 115 | // |
claytong | 0:82ff15078322 | 116 | // TI2SReceiver Start operation |
claytong | 0:82ff15078322 | 117 | // |
claytong | 0:82ff15078322 | 118 | void TI2SReceiver::Start() |
claytong | 0:82ff15078322 | 119 | { |
claytong | 0:82ff15078322 | 120 | // Stop reception |
claytong | 0:82ff15078322 | 121 | LPC_I2S->I2SDAI = 0x03 | (0x1<<3) | (0x1<<4) | (0x1<<5) | (0x1F<<6); |
claytong | 0:82ff15078322 | 122 | LPC_GPDMACH0->DMACCConfig = 0; |
claytong | 0:82ff15078322 | 123 | LPC_GPDMACH0->DMACCControl = 0; |
claytong | 0:82ff15078322 | 124 | bRunning = false; |
claytong | 0:82ff15078322 | 125 | LPC_GPDMA->DMACIntTCClear = 0x01; // clear DMA0 flags |
claytong | 0:82ff15078322 | 126 | LPC_GPDMA->DMACIntErrClr = 0x01; |
claytong | 0:82ff15078322 | 127 | |
claytong | 0:82ff15078322 | 128 | // Enable DMA |
claytong | 0:82ff15078322 | 129 | // Get new buffer and set up the DMA |
claytong | 0:82ff15078322 | 130 | StartDMATransfer(); |
claytong | 0:82ff15078322 | 131 | |
claytong | 0:82ff15078322 | 132 | // Slave receive mode. 32 bit data, stereo |
claytong | 0:82ff15078322 | 133 | LPC_I2S->I2SDMA1 = (0x1<<0) | (0x02<<8); // channel 1 = Rx DMA |
claytong | 0:82ff15078322 | 134 | LPC_I2S->I2SRXMODE = 0; |
claytong | 0:82ff15078322 | 135 | LPC_I2S->I2SDAI = 0x03 | (0x1<<5) | (0x1F<<6); |
claytong | 0:82ff15078322 | 136 | bRunning = true; |
claytong | 0:82ff15078322 | 137 | } |
claytong | 0:82ff15078322 | 138 | |
claytong | 0:82ff15078322 | 139 | //--------------------------------------------------------------------------- |
claytong | 0:82ff15078322 | 140 | // |
claytong | 0:82ff15078322 | 141 | // TI2SReceiver Stop operation |
claytong | 0:82ff15078322 | 142 | // |
claytong | 0:82ff15078322 | 143 | void TI2SReceiver::Stop() |
claytong | 0:82ff15078322 | 144 | { |
claytong | 0:82ff15078322 | 145 | bRunning = false; |
claytong | 0:82ff15078322 | 146 | |
claytong | 0:82ff15078322 | 147 | // Stop reception |
claytong | 0:82ff15078322 | 148 | LPC_I2S->I2SDMA1 = 0; |
claytong | 0:82ff15078322 | 149 | LPC_I2S->I2SDAI = 0x03 | (0x1<<3) | (0x1<<4) | (0x1<<5) | (0x1F<<6); |
claytong | 0:82ff15078322 | 150 | LPC_GPDMACH0->DMACCConfig = 0; |
claytong | 0:82ff15078322 | 151 | LPC_GPDMACH0->DMACCControl = 0; |
claytong | 0:82ff15078322 | 152 | |
claytong | 0:82ff15078322 | 153 | // clear out buffers |
claytong | 0:82ff15078322 | 154 | ReceivedBuffers.Flush(); |
claytong | 0:82ff15078322 | 155 | CurrentRxBuffer.Release(); |
claytong | 0:82ff15078322 | 156 | } |
claytong | 0:82ff15078322 | 157 | |
claytong | 0:82ff15078322 | 158 | //--------------------------------------------------------------------------- |
claytong | 0:82ff15078322 | 159 | // |
claytong | 0:82ff15078322 | 160 | // Debug routine - |
claytong | 0:82ff15078322 | 161 | // Read samples from the I2S by polling it |
claytong | 0:82ff15078322 | 162 | // Returns number of samples read |
claytong | 0:82ff15078322 | 163 | // |
claytong | 0:82ff15078322 | 164 | int TI2SReceiver::PolledRead( int32_t *piBuffer, int iLen ) |
claytong | 0:82ff15078322 | 165 | { |
claytong | 0:82ff15078322 | 166 | int iCnt = 0; |
claytong | 0:82ff15078322 | 167 | while ( iLen>0 ) |
claytong | 0:82ff15078322 | 168 | { |
claytong | 0:82ff15078322 | 169 | // wait for something in the FIFO |
claytong | 0:82ff15078322 | 170 | if ( ((LPC_I2S->I2SSTATE>>8)&0xF)==0 ) |
claytong | 0:82ff15078322 | 171 | continue; |
claytong | 0:82ff15078322 | 172 | // Read it out to the buffer |
claytong | 0:82ff15078322 | 173 | *piBuffer = LPC_I2S->I2SRXFIFO; |
claytong | 0:82ff15078322 | 174 | piBuffer++; |
claytong | 0:82ff15078322 | 175 | iLen--; |
claytong | 0:82ff15078322 | 176 | iCnt++; |
claytong | 0:82ff15078322 | 177 | } |
claytong | 0:82ff15078322 | 178 | return iCnt; |
claytong | 0:82ff15078322 | 179 | } |
claytong | 0:82ff15078322 | 180 | |
claytong | 0:82ff15078322 | 181 | //--------------------------------------------------------------------------- |
claytong | 0:82ff15078322 | 182 | // |
claytong | 0:82ff15078322 | 183 | // Debug routine - |
claytong | 0:82ff15078322 | 184 | // Read status register |
claytong | 0:82ff15078322 | 185 | // |
claytong | 0:82ff15078322 | 186 | uint32_t TI2SReceiver::Status() |
claytong | 0:82ff15078322 | 187 | { |
claytong | 0:82ff15078322 | 188 | return LPC_I2S->I2SSTATE; |
claytong | 0:82ff15078322 | 189 | } |
claytong | 0:82ff15078322 | 190 | //--------------------------------------------------------------------------- |
claytong | 0:82ff15078322 | 191 | // |
claytong | 0:82ff15078322 | 192 | // Debug routine - |
claytong | 0:82ff15078322 | 193 | // Report Status |
claytong | 0:82ff15078322 | 194 | // |
claytong | 0:82ff15078322 | 195 | void TI2SReceiver::Report() |
claytong | 0:82ff15078322 | 196 | { |
claytong | 0:82ff15078322 | 197 | printf( "C-%d\r\n", ulBufferCount ); |
claytong | 0:82ff15078322 | 198 | printf( "F-%d\r\n", ulBufferFailures ); |
claytong | 0:82ff15078322 | 199 | /* |
claytong | 0:82ff15078322 | 200 | printf( "I2S Buffers Counter - %d\r\n", ulBufferCount ); |
claytong | 0:82ff15078322 | 201 | printf( "I2S Buffer Failures - %d\r\n", ulBufferFailures ); |
claytong | 0:82ff15078322 | 202 | printf( "I2S Buffer Allocations - %d\r\n", ulBufferAllocations ); |
claytong | 0:82ff15078322 | 203 | printf( "I2S Status Register: 0x%08X\r\n", LPC_I2S->I2SSTATE ); |
claytong | 0:82ff15078322 | 204 | printf( "I2S DMA1 Register: 0x%08X\r\n", LPC_I2S->I2SDMA1 ); |
claytong | 0:82ff15078322 | 205 | printf( "I2S DMA2 Register: 0x%08X\r\n", LPC_I2S->I2SDMA2 ); |
claytong | 0:82ff15078322 | 206 | printf( "DMA Enabled Register: 0x%08X\r\n", LPC_GPDMA->DMACEnbldChns ); |
claytong | 0:82ff15078322 | 207 | printf( "DMA TC Status Register: 0x%08X\r\n", LPC_GPDMA->DMACIntTCStat ); |
claytong | 0:82ff15078322 | 208 | printf( "DMA Err Status Register: 0x%08X\r\n", LPC_GPDMA->DMACIntErrStat ); |
claytong | 0:82ff15078322 | 209 | printf( "DMA Config Register: 0x%08X\r\n", LPC_GPDMA->DMACConfig ); |
claytong | 0:82ff15078322 | 210 | printf( "DMA0 Control Register: 0x%08X\r\n", LPC_GPDMACH0->DMACCControl ); |
claytong | 0:82ff15078322 | 211 | printf( "DMA0 Config Register: 0x%08X\r\n", LPC_GPDMACH0->DMACCConfig ); |
claytong | 0:82ff15078322 | 212 | */ |
claytong | 0:82ff15078322 | 213 | } |
claytong | 0:82ff15078322 | 214 | |
claytong | 0:82ff15078322 | 215 | //--------------------------------------------------------------------------- |
claytong | 0:82ff15078322 | 216 | // |
claytong | 0:82ff15078322 | 217 | // DMA Interrupt Routine |
claytong | 0:82ff15078322 | 218 | // |
claytong | 0:82ff15078322 | 219 | void TI2SReceiver::DMA_Interrupt( ) |
claytong | 0:82ff15078322 | 220 | { |
claytong | 0:82ff15078322 | 221 | // exit if receiver is not running |
claytong | 0:82ff15078322 | 222 | if ( !bRunning ) |
claytong | 0:82ff15078322 | 223 | return; |
claytong | 0:82ff15078322 | 224 | |
claytong | 0:82ff15078322 | 225 | // Queue current buffer |
claytong | 0:82ff15078322 | 226 | CurrentRxBuffer.SetLength( 99999 ); // set length to full buffer size |
claytong | 0:82ff15078322 | 227 | ReceivedBuffers.Write( CurrentRxBuffer ); |
claytong | 0:82ff15078322 | 228 | ulBufferCount++; |
claytong | 0:82ff15078322 | 229 | |
claytong | 0:82ff15078322 | 230 | // Get new buffer and set up the DMA |
claytong | 0:82ff15078322 | 231 | StartDMATransfer(); |
claytong | 0:82ff15078322 | 232 | } |
claytong | 0:82ff15078322 | 233 | |
claytong | 0:82ff15078322 | 234 | //--------------------------------------------------------------------------- |
claytong | 0:82ff15078322 | 235 | // |
claytong | 0:82ff15078322 | 236 | // Start a new DMA transfer |
claytong | 0:82ff15078322 | 237 | // |
claytong | 0:82ff15078322 | 238 | void TI2SReceiver::StartDMATransfer() |
claytong | 0:82ff15078322 | 239 | { |
claytong | 0:82ff15078322 | 240 | int32_t *pDataPtr; |
claytong | 0:82ff15078322 | 241 | int iBufSize; |
claytong | 0:82ff15078322 | 242 | |
claytong | 0:82ff15078322 | 243 | // uses DMA0 and sets it up with new buffer (or a dummy buffer if none available) |
claytong | 0:82ff15078322 | 244 | // DMA channel 0 Source is I2S DMA1 = RX FIFO, Destination is memory |
claytong | 0:82ff15078322 | 245 | |
claytong | 0:82ff15078322 | 246 | // count DMA allocations |
claytong | 0:82ff15078322 | 247 | ulBufferAllocations++; |
claytong | 0:82ff15078322 | 248 | |
claytong | 0:82ff15078322 | 249 | // get a buffer |
claytong | 0:82ff15078322 | 250 | pDataPtr = NULL; |
claytong | 0:82ff15078322 | 251 | if ( EmptyBuffersPool.Create(CurrentRxBuffer) ) |
claytong | 0:82ff15078322 | 252 | { // got a buffer |
claytong | 0:82ff15078322 | 253 | pDataPtr = (int32_t *)(CurrentRxBuffer.SamplePtr()); |
claytong | 0:82ff15078322 | 254 | iBufSize = CurrentRxBuffer.Size() * 2; // size = samples*2 (samples are I/Q) |
claytong | 0:82ff15078322 | 255 | CurrentRxBuffer.Timestamp( LPC_TIM2->TC ); // Set timestamp |
claytong | 0:82ff15078322 | 256 | } |
claytong | 0:82ff15078322 | 257 | // check for buffer |
claytong | 0:82ff15078322 | 258 | if ( pDataPtr==NULL ) |
claytong | 0:82ff15078322 | 259 | { // failed to get a buffer - use the dumy buffer |
claytong | 0:82ff15078322 | 260 | ulBufferFailures++; |
claytong | 0:82ff15078322 | 261 | pDataPtr = aulDummyBuffer; |
claytong | 0:82ff15078322 | 262 | iBufSize = I2S_DUMMY_BUFFER_SIZE; |
claytong | 0:82ff15078322 | 263 | } |
claytong | 0:82ff15078322 | 264 | |
claytong | 0:82ff15078322 | 265 | // clear any ints |
claytong | 0:82ff15078322 | 266 | LPC_GPDMA->DMACIntTCClear = 0x01; // clear DMA0 flags |
claytong | 0:82ff15078322 | 267 | LPC_GPDMA->DMACIntErrClr = 0x01; |
claytong | 0:82ff15078322 | 268 | |
claytong | 0:82ff15078322 | 269 | // write source addr |
claytong | 0:82ff15078322 | 270 | LPC_GPDMACH0->DMACCSrcAddr = (uint32_t)(&(LPC_I2S->I2SRXFIFO)); |
claytong | 0:82ff15078322 | 271 | |
claytong | 0:82ff15078322 | 272 | // write destination |
claytong | 0:82ff15078322 | 273 | LPC_GPDMACH0->DMACCDestAddr = (uint32_t)pDataPtr; |
claytong | 0:82ff15078322 | 274 | |
claytong | 0:82ff15078322 | 275 | // write LL address - use 0 for single transfer |
claytong | 0:82ff15078322 | 276 | LPC_GPDMACH0->DMACCLLI = 0; |
claytong | 0:82ff15078322 | 277 | |
claytong | 0:82ff15078322 | 278 | // write control & config |
claytong | 0:82ff15078322 | 279 | LPC_GPDMACH0->DMACCControl = (iBufSize & DMA_TC_MASK) | DMA_CONTROL; |
claytong | 0:82ff15078322 | 280 | LPC_GPDMACH0->DMACCConfig = 0x08001 | (0x05 << 1) | (0x02 << 11); |
claytong | 0:82ff15078322 | 281 | } |
claytong | 0:82ff15078322 | 282 | |
claytong | 0:82ff15078322 | 283 | //--------------------------------------------------------------------------- |
claytong | 0:82ff15078322 | 284 | // END |
claytong | 0:82ff15078322 | 285 | //--------------------------------------------------------------------------- |