Not able to read i2s registers

16 Nov 2010

I am able to read all other registers but not the i2s. I am wondering if the i2s module is disabled on my embed.

 regVal = *((unsigned int *)(0x400a8034));    // Does not work. Looks like it causes an exception.
   
 fprintf(fp, "\n regVal <0x%x> \n", regVal);

Need help ...

16 Nov 2010

Did you remember to switch on the peripheral?

PCONP set PCI2S   : LPC_SC->PCONP |= (1UL << 27);

Also, clock needs setting: PCLKSEL1 : PCLK_I2S

// CCLK / 4 (the default)
LPC_SC->PCLKSEL1 &= ~(3UL << 22); 

// Then, if a different F then:-
LPC_SC->PCLKSEL1  |= 1UL << 22; // For CCLK /1 
LPC_SC->PCLKSEL1  |= 2UL << 22; // For CCLK /2 
LPC_SC->PCLKSEL1  |= 3UL << 22; // For CCLK /8
16 Nov 2010

Oh, and by the way, you can save yourself a lot of trouble. You wrote:-

regVal = *((unsigned int *)(0x400a8034)); 

Better to use :-

regVal = LPC_I2C1->I2SRXMODE;

or

regVal = LPC_I2C2->I2SRXMODE;

See http://mbed.org/projects/libraries/svn/mbed/trunk/LPC1768/LPC17xx.h#L411

The LPC17xx.h header file is a life saver :)

 

17 Nov 2010

Hi Andy,

  Thx a lot. I am able to read the registers now. I have another problem now. I am not getting interrupts.

  I have set up the i2s as a master receiver operating at a very low data rate (375 bits/sec). I verified the clock and ws signals using a scope.

 I can see the rx FIFO level increase and cross the threshold (4) but no interrupt !! 

 

I am pasting the code below. Once the i2s port is setup, the code polls the status reg in a loop for about 2 seconds before exiting.

 

 

extern "C" void I2S_IRQHandler(void);

volatile unsigned int i2sIntCnt = 0;

void I2S_IRQHandler(void)
{
   NVIC_DisableIRQ(I2S_IRQn);
   i2sIntCnt ++;
}

LocalFileSystem local("local"); 
FILE *fp;

int main()
{
   unsigned int regVal;
  
   
   fp = fopen("/local/i2s.dat", "w"); 
   if (fp == NULL)
       return 1; 
   
  
   fprintf(fp, "\n i2s interface test .... \n");   
 
   fprintf(fp, "\n PCONP<0x%x> \n", (LPC_SC->PCONP));
   
   LPC_SC->PCONP |= (1UL << 27);
  
   fprintf(fp, "\n PCONP<0x%x> \n", (LPC_SC->PCONP));
  
   /*
    * Pins: Select I2S pins and their modes in PINSEL0 to PINSEL4 and
    * PINMODE0 to PINMODE4 (see Section 8.5).
    */
   // CCLK / 4 (the default)
   LPC_SC->PCLKSEL1 &= ~(3UL << 22);    // 96 Mhz / 8 -> 12 Mhz
   LPC_SC->PCLKSEL1  |= 3UL << 22;
   fprintf(fp, "\n LPC_PINCON @ <0x%x> is <0x%x> \n",
           &(LPC_PINCON->PINSEL0), LPC_PINCON->PINSEL0);     
          
   LPC_PINCON->PINSEL0 = 0x1550;       
  
   fprintf(fp, "\n LPC_PINCON @ <0x%x> is <0x%x> \n",
           &(LPC_PINCON->PINSEL0), LPC_PINCON->PINSEL0);       
   
   
   LPC_I2S->I2SRXRATE = 0x01fa;  // X is 1 and Y is 250  // 0x1096; // 0x0106;  // 0x40bb;   // X is 1 and Y is 3
   LPC_I2S->I2SRXBITRATE = 63;  // MCLK / 64 ->> Bit clock is 375
   LPC_I2S->I2SRXMODE = 0;
   LPC_I2S->I2SDAI = 0x1cc;
   wait_ms(100);
   LPC_I2S->I2SDAI = 0x1c4;
   LPC_I2S->I2SIRQ =  0x1 | (4<<8);
   NVIC_EnableIRQ(I2S_IRQn);
   
   // Loop
   int idx;
   for (idx=0;idx<20;idx++)
   {
     wait_ms(100);
     fprintf(fp, "\n Int-Cnt <%u> \n", i2sIntCnt);
     fprintf(fp, "\n I2SSTATE @ <0x%x> is <0x%x> \n", &(LPC_I2S->I2SSTATE), LPC_I2S->I2SSTATE);
   }
  
   NVIC_DisableIRQ(I2S_IRQn);
  
   fclose(fp);
}

17 Nov 2010

Your ISR disables future intterupts after the first one. Why?

Also, why are you banging teh registers rather than using teh API?

For example:-

LPC_I2S->I2SRXRATE = 0x01fa;  // X is 1 and Y is 250  // 0x1096; // 0x0106;  // 0x40bb;   // X is 1 and Y is 3
LPC_I2S->I2SRXBITRATE = 63;  // MCLK / 64 ->> Bit clock is 375

What's wrong with frequency ?

17 Nov 2010

Hi Andy,

     I think I was getting an exception so I thought maybe I was getting repeated interrupts so I disable the interrupt in the handler. Then i2sIntCnt should be at least show 1.  I am just trying to get a working system. I will clean up the code later.

I did not get your question about the frequency.

Thx

Ram

17 Nov 2010 . Edited: 17 Nov 2010

Follow the link. There's an API that sets things like the bit clock without you having to bash the registers directly. I haven't read through your code to look for errors or as to why it may not be working, mainly because your are bashing the registers and that makes working it out take longer than if you used the API.

Also, decalre your ISR like this:-

volatile unsigned int i2sIntCnt = 0;

extern "C" void I2S_IRQHandler(void) __irq {
i2sIntCnt ++;
}

 

Ah, I think I spot it now:- LPC_I2S->I2SIRQ =  0x1 | (4<<8);

(4 << 8)  <-- You have set the level of the fifo before it generates an interrupt. But you only interrupt once because you then switch it off in the ISR

edit: erm... maybe not, teh IRQ has to fire at least once to switch it off. Hmm, if only I had some hardware. I may look at doing a "loopback" test later this evening.

17 Nov 2010

oh, and I also just noticed too this is I2S and not I2C. I will have a play later with all this after my kids are mbed (ah hem, "in bed" lol) and get back to you

18 Nov 2010

Hi Andy,

 It works now. I just read the receive FIFO when I get the interrupt to clear the event which causes the interrupt otherwise it keeps interrupting and mbed drive becomes non accessible.

Thx a lot

Ram

 

18 Nov 2010

hey, thats good. Hope things work out. :)