I do not understand properly how to actually use the I2S example provided with the SDK for the LPC55S69 EVK board.
Once an I2S transfer has occurred, the function TxCallback is called. In the example software, within TxCallback, the following code is called:
i2s_transfer_t *transfer = (i2s_transfer_t *)userData;
I2S_TxTransferNonBlocking(base, handle, *transfer);
Stepping through from this point in the debugger then brings us to
I2S_TxHandleIRQ() within fsl_i2s.c. We do not come back into TxCallback until a transfer has completed, and we do not exit I2S_TxHandleIRQ() until this point either.
My question is - where am I supposed to do other processing? Since I am attempting to read data bytes from an SD card, and then send these to I2S sample by sample via arrays, (in a custom ping-pong style arrangement), I do not understand whereabouts I am meant to perform these reads. At the end of my main code, I have a while() loop, which is true always. If I have a breakpoint within TxCallback, and another within this while loop, the program will never enter the while loop upon subsequent runs, but if I remove the breakpoint from TxCallback, it will enter the while loop, multiple times.
Does anyone understand how to use this and to set this up for audio transfer from an sd card?
Cheers
Rory##
Solved! Go to Solution.
Hi, Rory,
I suppose that you use the ..._i2s_interrupt_transfer example to have a test, for the example, I think this is the the architecture of the example.
First of all, a handler is declared as static i2s_handle_t s_TxHandle; for i2s transmitter, the s_TxHandle->i2sQueue[handle->queueDriver] is a component with structure i2s_transfer_t, it contains the sample pointer and data size.
The example use interrupt mechanism to transfer sample to I2S transmitter FIFO, so in the ISR void I2S_TxHandleIRQ(I2S_Type *base, i2s_handle_t *handle) is called. NOTE the I2S_TxHandleIRQ() not exact ISR, it is called by real ISR of FC7. when a bunch of data defined in the s_TxHandle->i2sQueue[handle->queueDriver] is completed, the callback function static void TxCallback(I2S_Type *base, i2s_handle_t *handle, status_t completionStatus, void *userData) is called. in the TxCallback() function, you need fill NEW data, the NEW data will update the s_TxHandle->i2sQueue[handle->queueDriver] structure.
In conclusion, you are required to just write the callback function TxCallback(), it is okay.
For your application, this is the pseudo code:
assume the data size is 100
uint8_t sample[100]
uint32_t data_size=100;
static void TxCallback(I2S_Type *base, i2s_handle_t *handle, status_t completionStatus, void *userData)
{
//read data from file
read(filePointer, &sample[0],data_size);
/* Enqueue the same original s_Buffer all over again */
i2s_transfer_t *transfer;
transfer->data=sample
transfer->dataSize=100;
I2S_TxTransferNonBlocking(base, handle, *transfer);
}
Hope it can help you
BR
XiangJun Rong
Hi, Rory,
I suppose that you use the ..._i2s_interrupt_transfer example to have a test, for the example, I think this is the the architecture of the example.
First of all, a handler is declared as static i2s_handle_t s_TxHandle; for i2s transmitter, the s_TxHandle->i2sQueue[handle->queueDriver] is a component with structure i2s_transfer_t, it contains the sample pointer and data size.
The example use interrupt mechanism to transfer sample to I2S transmitter FIFO, so in the ISR void I2S_TxHandleIRQ(I2S_Type *base, i2s_handle_t *handle) is called. NOTE the I2S_TxHandleIRQ() not exact ISR, it is called by real ISR of FC7. when a bunch of data defined in the s_TxHandle->i2sQueue[handle->queueDriver] is completed, the callback function static void TxCallback(I2S_Type *base, i2s_handle_t *handle, status_t completionStatus, void *userData) is called. in the TxCallback() function, you need fill NEW data, the NEW data will update the s_TxHandle->i2sQueue[handle->queueDriver] structure.
In conclusion, you are required to just write the callback function TxCallback(), it is okay.
For your application, this is the pseudo code:
assume the data size is 100
uint8_t sample[100]
uint32_t data_size=100;
static void TxCallback(I2S_Type *base, i2s_handle_t *handle, status_t completionStatus, void *userData)
{
//read data from file
read(filePointer, &sample[0],data_size);
/* Enqueue the same original s_Buffer all over again */
i2s_transfer_t *transfer;
transfer->data=sample
transfer->dataSize=100;
I2S_TxTransferNonBlocking(base, handle, *transfer);
}
Hope it can help you
BR
XiangJun Rong
Hi xiangjun.rong -
Thank you for the help. Unfortunately I am still having issues, due to odd behaviour from the f_read function in the FatFS library. (btw, using your example, i can get this to work if I simply initialise transfer->data to the values inside data1, if I do not read more data into data1. So thank you for helping me getting this much at least to work).
Inside my TxCallback function i have:
error = f_read(&g_fileObject1,&data1,sizeof(data1),&bytesRead);
i2s_transfer_t *transfer = malloc(sizeof(*transfer));
transfer->data = &data1[0];
transfer->dataSize=sizeof(data1);
free(transfer);
(data1 is an array of n elements long, of type uint8_t).
If I make the size of data1, be 100 elements long, I can only go into TxCallback 5 times, before I end up with a failure inside "f_read".
However, if I perform this "f_read" inside a while(1) loop, further up inside the code (before calling the appropriate i2s initialise functions), I can do more reads than this. I have tracked it down to a variable called "rcnt" within "f_read" which gets initialised differently if I perform "f_read" in the main code, as opposed to when I perform it inside my callback. However, i cannot see how "rcnt" gets initialised (it just happens to be holding some value when I step into "f_read").
If preferred, I can post this as a new question, as I'm not sure its directly related to I2S operation.
Many thanks for the help so far,
Cheers,
Rory