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.
The format() function invokes reset and initialisation, so just call this to reinitialise the class at any point.
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.
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.
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:
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().
|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.
Deactivate I2S port from data streaming.
Load receive FIFO data into receiver buffer.
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.
Return contents of I2S status register.
What you may want to do...
To check out some exciting projects, which you can follow yourself, check out my post on the TLV320AIC23B Audio CODEC.