I2SSlave

LPC17xx architecture

The mbed is capable of a lot of things, many of which have not yet been published on the internet. One of those things is that the mbed possesses a high quality audio port called an I2S port. This supports various sampling frequencies, word sizes, wiring layouts, master/slave configurations, mono/stereo output, clocking speeds etc. So it’s highly flexible and most of all enables us to add an entirely new dimension to the mbed libraries.

The I2S port also supports interrupts and DMA requests. I’ve chosen to supply a class with just the interrupts, since mbed does not yet supply any DMA functionality to any of its classes. Otherwise check out Andy Kirkham’s DMA library. For the really keen, why not try and write your own abstraction libraries? It’s a fantastic way to really understand how some of the mbed libraries work!

How to use the API

As the library name suggests, this is only for a slave configuration on both transmit and receive channels, hence no frequency() function.

Information

The format() function invokes reset and initialisation, so just call this to reinitialise the class at any point.

Pinout

tx_sda - p5
tx_ws - p6
tx_clk - p7
rx_sda - p8/p17
rx_ws - p29/p16

How to use it

I2S can get really tricky if you don't lay out your code systematically. So, it is extremely important to think about what you want to do, before you jump in. The API works in two ways, (1) raw input/output to the FIFOs and (2) interrupt handlers. Method (2) is really both (1) and (2) together.

Method (1)

You can simply write data to the I2STXFIFO via the write() function and read data into a temporary buffer rxBuffer using the read() function. *rxBuffer is a pointer to this temporary buffer, which is 4 x 32-bit words deep and it is necessary to call read() to empty the I2SRXFIFO so that more data can be read into it.

Method (2)

Attach a function to the interrupt handler via the attach() function, be careful to know what sort of function you're attaching. If it's a function without a class, or a static member function (i.e. a function defined within a class but there is only ever one instance of it because it is declared with the static label) then use:

myI2s.attach(&myFunction);   
//OR
myi2S.attach(&myClass::myStaticMemberFunction);

If, however, the function belongs to a class and it is 'normal' in the sense that it is not defined with the static qualifier use:

myI2S.attach(&myObject, &myClass::myNonstaticMemberFunction);

To start interrupts simply call the start() function, which accepts a parameter to define the type of interrupt you wish to receive, namely, NONE (not useful), RECEIVE, TRANSMIT, BOTH. I suggest you do not use BOTH, because you then have to figure out which FIFO triggered it, via the status() function and it usually turns out that if you're taking data from the I2SRXFIFO DSP-ing it and then sticking it on the I2STXFIFO, you're generating the majority of the interrupts just by placing data in the I2STXFIFO. The receive FIFO triggers at a depth of 4 words, the transmit, when it's empty.

To stop interrupts, call stop().

API

Import library

Public Member Functions

I2SSlave (PinName tx_sda, PinName tx_ws, PinName clk, PinName rx_sda, PinName rx_ws)
Create an I2S object.
void format (int bit, bool mode)
Set the data transmission format.
void write (int *buffer, int from, int length)
Write a buffer to the I2S port.
void start (int mode)
Activate I2S port for data streaming.
void stop (void)
Deactivate I2S port from data streaming.
void read (void)
Load receive FIFO data into receiver buffer.
void attach (void(*fptr)(void))
Attach a void/void function or void/void static memeber function to an interrupt generated by the I2SxxFIFOs.
template<typename T >
void attach (T *tptr, void(T::*mptr)(void))
Attach a nonstatic void/void member function to an interrupt generated by the I2SxxFIFOs.
int status (void)
Return contents of I2S status register.

What you may want to do...

example program flow

Projects

To check out some exciting projects, which you can follow yourself, check out my post on the TLV320AIC23B Audio CODEC.


1 comment on I2SSlave:

17 Sep 2011

Hello,
Thank you for your nice library.
I'm using your library for my mbed audio sampler project.

I think it, register initialization is not expected.
I modified the code as follows.

before

      :
void I2SSlave::format_(int bit, bool mode){
    uint32_t bps= ((bit+1)*8)-1;
    LPC_I2S->I2SDAO &= (0x00 << 6);   <== HERE
    LPC_I2S->I2SDAO |= (bps << 6);
    //set bit length
    switch(bit){
        case 8:
            LPC_I2S->I2SDAO &= 0xfffffffc;
            break;
        case 16:
            LPC_I2S->I2SDAO &= (0 << 1);   <== HERE
            LPC_I2S->I2SDAO |= (1 << 0);
      :

after

      :
    LPC_I2S->I2SDAO &= ~(0x1ff << 6);
      :
            LPC_I2S->I2SDAO &= ~(1 << 1);
      :

* Other places as well.

For example,

LPC_I2S->I2SDAO &= (0 << 1);
-> (0 << 1) = 0
-> LPC_I2S->I2SDAO &= 0;
-> LPC_I2S->I2SDAO = LPC_I2S->I2SDAO & 0;
-> clear all bits!?

New code,

LPC_I2S->I2SDAO &= ~(1 << 1);
-> ~(1 << 1) = ~2 = 0xfffffffd
-> LPC_I2S->I2SDAO &= 0xfffffffd;
-> LPC_I2S->I2SDAO = LPC_I2S->I2SDAO & 0xfffffffd;
-> clear bit 1 :)

Please log in to post comments.