i2S with AIC23 using Mark B's ported Keil code hangs...

29 Aug 2010 . Edited: 29 Aug 2010

Hi all, I'm trying to interface the mbed with a TLV320AIC23B (audio codec) via I2S.  I'm using Mark B's ported Keil code: http://mbed.org/users/macaba/programs/i2s/600c5.  It seems to work well in that it compiles and runs, but it hangs at the line

    while ( !I2SDMA0Done || !I2SDMA1Done );

I believe this means that the DMA_IRQhandler never gets triggered.  I don't know why this is but my hunch is that it has to do with how I am wiring to the AIC23B.  Specifically, I believe the AIC23B supports two I2S connections (CLK, WS, SDA), in addition to an SPI or 2-wire interface for doing actual control.  I don't have the latter hooked up because it's not clear how to do so, or how it's being used in the Keil code.  Any tips?  My notebook page which describes my wiring setup, and more, in detail is here:

http://mbed.org/users/expanoncolin/notebook/i2s-with-aic23b/

Thanks for any help,

-Colin

29 Aug 2010

And, just a note that if I change line 14 in i2s.h from

#define I2S_DMA_ENABLED        1
to

#define I2S_DMA_ENABLED        0
it runs the I2S code instead (starting on line 56), but also hangs at this line:

    while ( !I2SRXDone || !I2STXDone );

Which again likely implies that the interrupt never gets triggered...

-Colin

29 Aug 2010

Edit i2s.h to read:

extern "C" void I2S_IRQHandler( void );
This should make the linker put the handler into the vector table.

29 Aug 2010

I actually did try that!  I should have mentioned.  Unfortunately, it still hangs up in the same location.  This is true if I declare the DMA IRQ Handler as extern "C" as well.

-Colin

29 Aug 2010

Also, just a note that even with the AIC23 completely out of the circuit (just took it out from the breadboard) this is the line it gets stuck at.  In other words, I think that this line is the first that requires any interaction with the AIC23, and the interaction is not happening with the way I have the circuit hooked up!

-Colin

29 Aug 2010

Maybe put some led writes in the IRQ handler to see if it's called at all.

29 Aug 2010

Good idea.  I put some code to turn an LED on at the top of the IRQ handler function and it never turns on, so I think the function doesn't get called.  Putting it at the top of I2SStart DOES turn it on.  So yeah, with almost utmost certainty I can say that the interrupt never gets triggered, and my strong hunch is that it's a hardware problem as I am not confident at all in how I have it wired up - the AIC23B and LPC1768 datasheets use different nomenclature for I2S.

-Colin

29 Aug 2010 . Edited: 29 Aug 2010

Hi,

now i can read write audio form aic23 but without DMA. My sugestions :

1) with TWI configure chip registers (i do this yob with uart terminal and use Linear input, linear output)

  • Reset
  • Pwr on
  • Digital audio interface (16bit or 24bit, i2s)
  • Audio sampling rate (SR0,SR1,SR2)
  • Digital interface activate
  • Linear input unmute
  • Analog audio patch - Bypass( in audio chip connecting input to output), DAC select

if reset chip and power on to all peripials aic23 must send linear input to linear output.

2) Next connect i2s hardware.  DIN-p5; LRCIN-p6; BCLK-p15; LRCOUT-p16; Dout-p17 and MCLK (osscilator to aic23) solder wire to P4[28] pin on MCU

3) I2S configuartion :

void vfAudioInit(void)
{

// Switch power on I2S
LPC_SC->PCONP |= (1 << 27);                    
LPC_SC->PCLKSEL1 &= ~(PCLK_I2S_MASK);
LPC_SC->PCLKSEL1 |=  (0x2 << PCLK_I2S);        // PCLK_periph = CCLK/2 -->48MHz

//48MHz/2=24   MCLK=12.288  --> (48*64/125)/2=12.88MHz
LPC_I2S->I2SRXRATE = (64<<8) | (125);

//DIP-30 --> P0.4 = I2SRX_CLK - receive clock
//LPC_PINCON->PINSEL0 |= (1<<8);
//DIP-15 --> P0.23 = I2SRX_CLK - receive clock
LPC_PINCON->PINSEL1 &= ~(3<<14);
LPC_PINCON->PINSEL1 |= (2<<14);

//DIP-29 --> P0.5 = I2SRX_WS  - receive word clock
//LPC_PINCON->PINSEL0 |= (1<<10);
//DIP-16 --> P0.24 = I2SRX_WS  - receive word clock
LPC_PINCON->PINSEL1 &= ~(3<<16);
LPC_PINCON->PINSEL1 |= (2<<16);

//DIP-08 --> P0.6 = I2SRX_SDA - receive data
//LPC_PINCON->PINSEL0 |= (1<<12);
//DIP-17 --> P0.25 = I2SRX_SDA - receive data
LPC_PINCON->PINSEL1 &= ~(3<<18);
LPC_PINCON->PINSEL1 |= (2<<18);


//DIP-07 --> P0.7 = I2STX_CLK - transmit clock
//LPC_PINCON->PINSEL0 &= ~(3<<14);
//LPC_PINCON->PINSEL0 |= (1<<14);
//DIP-06 --> P0.8 = I2STX_WS - transmit word clock
LPC_PINCON->PINSEL0 &= ~(3<<16);
LPC_PINCON->PINSEL0 |= (1<<16);    
//DIP-05 --> P0.9 = I2STX_SD - transmit data to codec
LPC_PINCON->PINSEL0 &= ~(3<<18);
LPC_PINCON->PINSEL0 |= (1<<18);
//RX_MCLK pin
LPC_PINCON->PINSEL9 &= ~(3<<24);
LPC_PINCON->PINSEL9 |= (1<<24);


// Switch on the RX MCLK
LPC_I2S->I2SRXMODE = (1<<3);
// and make TX MCLK sourced from RX MCLK
LPC_I2S->I2STXMODE = 0x2;
// 256/4 = 64 bits per frame
LPC_I2S->I2STXBITRATE = 4-1;
LPC_I2S->I2SRXBITRATE = 4-1;

// RESET I2S
LPC_I2S->I2SDAO = (1<<4) | (1<<3);
LPC_I2S->I2SDAI = (1<<4) | (1<<3);

// CS codec works in 32-bit mode.
LPC_I2S->I2SDAI =0x3 | (0x1f<<6);
LPC_I2S->I2SDAO = 0x3 | (0x1f<<6);

// Turn on I2S interrupts in NVIC
// rx int, rx depth 4, tx depth 4
LPC_I2S->I2SIRQ = (1<<0) | (4<<8) | (4<<16);
NVIC_EnableIRQ(I2S_IRQn);  

}

 

4) and make intrreupt declerating how Igor show :

extern "C" void I2S_IRQHandler( void );

 

void  I2S_IRQHandler(void)
{
int Temp
Temp=(LPC_I2S->I2SRXFIFO)<<8; //AIC23 24bit ADC
LPC_I2S->I2STXFIFO = Temp>>8;

}

29 Aug 2010 . Edited: 29 Aug 2010

Thanks for responding!  Can you explain step 1 in more detail?  I did not do any register configuration on the AIC23.  So, you are editing the registers with I2C?  Do you have any code/connections for this?  Also, why do you use pins 15, 16, and 17 - I didn't think they had any special peripheral.  And finally, do you think there's a way to do it without soldering to the MCU?

-Colin

29 Aug 2010

Can you explain step 1 in more detail?  I did not do any register configuration on the AIC23.  I'm not sure what you mean by "with TWI"
AIC23 use 2-wire or SPI interface to write registers (TWI- two wire interface or I2C), without register configuartion nothing work if you read tlv320aic23B datasheet must anderstud.

Also, why do you use pins 15, 16, and 17 - I didn't think they had any special peripheral. 
in mbed libary not I2S interface .If you open LPC1768 datasheet and med lpc1768 board schematic  ther can find pin description and functions.

And finaly if not use RX_MCK AIC23 must set in master mode (dosn`t work for me).

29 Aug 2010 . Edited: 30 Aug 2010

OK, thanks, I will do some reading and see what I come up with.  Did you write any code for the I2C (TWI) setting of registers?

-Colin

04 Jan 2011

Hi again all, sorry to resurrect this old thread, I can start a new one if necessary.  After some months of hiatus, I am back at this I2S project, and have written code to set the AIC23B's registers correctly.  All of the I2C writes to the AIC23B come back with status OK, and I've checked my register values with some other code that has been written since then, so I think that part of it is good.  However, it still hangs without getting any interrupts (DMA or IRQ).  At this point, I'm thinking it's because I'm setting up the AIC23B as master, but either the LPC1768 is not configured to reflect this, or my hookup is wrong.  In i2s.cpp, the lines

  /* Audio output is the master, audio input is the slave, */
  /* 16 bit data, stereo, reset, master mode, not mute. */
  DAOValue = LPC_I2S->I2SDAO;
  DAIValue = LPC_I2S->I2SDAI;
  LPC_I2S->I2SDAO = DAOValue & (~((0x01 << 4)|(0x01 <<3)));
  /* 16 bit data, stereo, reset, slave mode, not mute. */
  LPC_I2S->I2SDAI = DAIValue & (~((0x01 << 4)|(0x01 <<3)));
  return;
define the master/slave configuration.  Should both be master?  I can't find the relevant sections in the LPC1768 datasheet, so any help there would be appreciated.  Also, is my hookup correct between the LPC1768 and AIC23B?

Name(s) AIC23B Pin mbed Pin
TX_SDA/DIN 4 5
TX_WS/LRCIN 5 6
TX_CLK/BCLK 3 7
RX_SDA/DOUT 6 8
RX_WS/LRCOUT 7 29
RX_CLK/BCLK 3 30

 

Any help is appreciated, I think a number of people got I2S working since I tried this so any tips would be appreciated.

22 Feb 2011

I've got a simpler setup that's not even all wired yet, but watching the signals on the scope I can see it appears to work, yet it hangs always except for the first run after powering down and up. I can see from the LEDs that it hangs in my FIFO-feeding (no DMA) loop, with the FIFO level never decreasing.

What in I2S could one possibly be setting up (unaware) that's dependent on an initial condition which is given after power-up, but not given after a reset? It's not even a single run of this program causing it, as I can run something else, then program this one, reset, and it will hang. Power down/up, it will run once, then hang on subsequent resets.

Background:

I'm using the MAX5556 DAC that's generally easier to deal with (no registers) but it requires the entire I2S interface, i.e. MCLK (pin 85) needs to be wired up.

I haven't done that yet, so I'm only watching the signals on a scope, where they look nearly correct. The sample frequency is measured by the scope (not a freq. counter, so it's based on period) to be 41666 instead of 44100 - could that be an artifact of large values in the fractional divider registers? (The 96MHz systme clock doesn't lend itself to producing clean 44100 Hz fs.)

23 Feb 2011

Hi Benedikt, I'm afraid I can't help with that rather bizarre problem but I would suggest starting a new thread - this one is quite old now.

23 Feb 2011

Yes, but the problems may be related. I've measured some more, and have realized that actualy, all my I2S signal relate together the way I intended to set them up, EXCEPT the basic division from PCLK divider to fractional divider and then /2 again looks as if my odd-numbered, fairly-near-1:1 fractional divider settings are completely ignored, as if I'd set them to 1:1. There does not seem to be a setting to have it ignored, so that is quite odd. I'm assuming 96MHZ is the default system clock, right?

Meanwhile, the hanging at all times except the first run after power-up still stands.

23 Feb 2011

Colin, do you have the LPC1768's MCLK pin or an oscillator connected to the AIC23B's MCLK pin?

25 Feb 2011

I'm generating a 12MHz clock with the LPC1768's PWM.

    // Need to create PWM clock for AIC23B
    LPC_PWM1->TCR = (1 << 1);               // Reset counter, disable PWM
    LPC_SC->PCLKSEL0 &= ~(0x3 << 12);  
    LPC_SC->PCLKSEL0 |= (1 << 12);          // Set peripheral clock divider to /1, i.e. system clock
    LPC_PWM1->MR0 = 7;                      // Match Register 0 is shared period counter for all PWM1
    LPC_PWM1->MR6 = 9;                      // Pin 21 is PWM output 6, so Match Register 6
    LPC_PWM1->LER |= 1;                     // Start updating at next period start
    LPC_PWM1->TCR = (1 << 0) || (1 << 3);   // Enable counter and PWM

Not sure if this works or is a good idea. My code still doesn't really work!

27 Feb 2011

I don't really have a clue about the LPC1768 being a slave and/or receiving I2S data (I've only done uC master sending I2S to DAC slave), but since you're doing something along those lines,

does the 1768 as slave/as receiver perhaps require an MCLK *input*?

The MAX5556 I use will make up its own bitclock (!) if there is none, but shuts down the output if the MCLK/bitclock relationship isn't one of 3 it deigns to accept. (Incidentally, I'm rid of my mystery hanging problem, after starting from scratch after I realized that the published I2S library I was partially using, despite being described as usable, had many odd errors in register-bit math (trying to OR a 0 into a number, hidden among ORing 1s), as though it was purposely made to frustrate fellow contestants. - but I fill the FIFO manually, after checking the level, so I don't know about interrupts)

28 Feb 2011

I'm not sure. My code doesn't really work either way.

-Colin