Hi
I've some comprehension questions for using the uDMA with the I2S. I have set the uDMA to serve the I2SRx channel in ping-pong mode. I set the fifo level of the I2SRx and the arbitration level of the uDMA to 4, so with a datasize of 24 bits per sample (the data were in two's complement) in mono mode of the I2S, I will get two samples every time the uDMA reads the fifo.Might this be efficient enough or should I raise the trigger level?In the case, my code will work right, the uDMA releases an I2S interrupt and the I2S int handler occurs. In this handler I'll check if the uDMA has done all the transfers and switch the ping-pong buffers. The buffers are two static signed long arrays. The size is 16 so far. I set the uDMA size and the buffer destination increment to 32 bit so I expect every 24 bit I2S sample will assign one array entry.What will the uDMA do when buffer1 will be filled again. Will it start filling the array by the first adress again and overwrite the previous samples? In this case it wouldn't be necessary to make the buffers bigger than the number of transfered sample, wouldn't it? Then it would make more sense to have more little arrays and build a ring buffer?
I attach my code I wrote. So far it's just hardware configuration but if someone has a little time it would be very nice to take a look at if and tell me if there could be something wrong.
Thanks for your reply
EDIT: I use the LM3S9B92 Kit with the code composer studio
Hello Andre,
In your code you have the alternate buffer set the same as the primary buffer. Typically you would allocate two separate buffers (it looks as though you have them already defined, but it may be a typo). When the first one fills up the DMA transfers to the alternate control block. At this point the second buffer begins to fill. While this second buffer fills you can be moving the data from buffer 1 to whatever handling process you have. Once the secondary transfer is complete then it will go back to buffer1.
As far as the DMA sizing goes you can retrieve up to 8 mono samples from the FIFO so if you set the level to 4 as you mention you would get 4 mono samples. Four samples is a good mid-point. As far as the system timing goes, the interrupt is generated upon completion of the DMA transfer not the FIFO level setting. In your case the transfer size is 16 bytes which means you get an interrupt after 16 samples. You can increase the DMA transfer size (increase the buffer sze) to increase the time between services to the DMA buffers. Overall timing is going to be dependent on what processing and throughput you require.
Hope this helps.
Regards,
Craig
Hi Craig,
thank you for your reply. If I understand you correctly, then the first buffer will be filled until it is full and only then the control structur switch to the alternate and then the second buffer will be filled? And I get an interrupt, after any of the buffers were full, in my case after 16 samples because of the buffer size of 16?
I changed the part of my code where I switch the buffers. Is this code better now?
static signed long ulBuffer1[4][BUFFER_SIZE]; static signed long ulBuffer2[4][BUFFER_SIZE]; static signed long ul_Buf1Index = 0; static signed long ul_Buf2Index = 0; //################################################################################################# void I2SIntHandler(void) { unsigned long ulStatus; unsigned long ulMode; // Interruptstatus abfragen ulStatus = ROM_I2SIntStatus(I2S0_BASE,1); //Interruptquelle löschen, damit der Handler am Ende nicht erneut aufgerufen wird ROM_I2SIntClear(I2S0_BASE, ulStatus); // Status des uDMA I2S Kanals abfragen, primäre Kontrollstruktur ulMode = ROM_uDMAChannelModeGet(UDMA_CHANNEL_I2S0RX | UDMA_PRI_SELECT); // Wenn der uDMA den Transfer abgeschlossen hat, stoppt er automatisch if(ulMode == UDMA_MODE_STOP) { /* * Konfiguriert die Übertragungsparamter für den nächsten Transfer des I2SRx Kanals für den uDMA * Primäre Kontrollstruktur (Ping Pong Modus, Buffer1), Datenquelle ist der I2SRx FIFO */ ROM_uDMAChannelTransferSet(UDMA_CHANNEL_I2S0RX | UDMA_PRI_SELECT, UDMA_MODE_PINGPONG, (void*) I2S_SOURCE, ulBuffer1[ul_Buf1Index], sizeof(ulBuffer1[ul_Buf1Index])); if(ul_Buf1Index >=3) { ul_Buf1Index = 0; } else { ul_Buf1Index++; } } // Status des uDMA I2S Kanals abfragen, primäre Kontrollstruktur ulMode = ROM_uDMAChannelModeGet(UDMA_CHANNEL_I2S0RX | UDMA_ALT_SELECT); // Wenn der uDMA den Transfer abgeschlossen hat, stoppt er automatisch if(ulMode == UDMA_MODE_STOP) { /* * Konfiguriert die Übertragungsparamter für den nächsten Transfer des I2SRx Kanals für den uDMA * Primäre Kontrollstruktur (Ping Pong Modus, Buffer1), Datenquelle ist der I2SRx FIFO */ ROM_uDMAChannelTransferSet(UDMA_CHANNEL_I2S0RX | UDMA_ALT_SELECT, UDMA_MODE_PINGPONG, (void*) I2S_SOURCE, ulBuffer2[ul_Buf2Index], sizeof(ulBuffer2[ul_Buf2Index])); if(ul_Buf2Index >=3) { ul_Buf2Index = 0; } else { ul_Buf2Index++; } } }
One additional question:
The I2S reads the incoming datastream beginning with the MSB one SCK cycle after the word select edge. How is the positioning in the FIFO and in the buffer? Were they filled from left to right respectively from the MSB 24 bits down to the LSB? In that case I have to right shift every buffer entry 8 positions, didn't I?
Going back to your first post I believe you have a good understanding of the DMA operation now. Back to your code, in the original initialization for the DMA you have buffer 1 also used as the alternate and it should be changed ot the buffer 2.
As far as your second post goes all data in the FIFO is stored MSB aligned. Check out "Table 16-8. I2S Receive FIFO Interface" for more information on the data alignement.
Regarrs,
Craog
Hello Craigthank you for your help. Maybe you could help me once again. The attached file contains the latest version of my program. Unfortunately, it ends up in the FaultISR() Handler. At this point I don't exactly know the reason, but I think it's something with the uDMA or my I2S Handler. I would be very nice if you could take a look at my code.
Regard
André
I made some tests that show the I2SIntHandler will be reached. But after that line
ulStatus = ROM_I2SIntStatus(I2S0_BASE , 1)
the error occurs.
If I use I2SIntStatus(I2S0_BASE , 1) instead of the the ROM_ function, I don't get an error. But it seems that the I2SIntHandler would be reached only one time and not anymore.
UPDATE:
I forgot to reenable the uDMA channel in the interrupt handler.... but now the I2SIntHandler seems to work. Unfortunately there will be no real data coming from the I2S device. I only get zeros although the oscilloscope shows some bits on the SD line.
I heard about some problems with the uDMA and core speed above 50 MHz, so I set the speed down to 40 MHz but it doesn't fix the problem. Then I tried to do without the uDMA, to avoid that there are any problems with it. But I still get only zeros from the fifo.
After over one week I realy need a solution, so I would be happy about any help.
I've written a "quick & dirty" program without uDMA. If I use I2S_CONFIG_MODE_DUAL instead of I2S_CONFIG_MODE_MONO I get data that is different from zero. But I don't know why?
In the Stellarisware boards directory for the lm3s9B96 there is a drivers directory. Located in that directory is a file called sound.c which contains some initialization routines for the I2S module. This may help with you configuration.
C:\StellarisWare\boards\dk-lm3s9b96\drivers
If it doesn't let me know.
Well, I already know the code for the b96, but it doesn't bring me further. Till now, it works with
I2SRxConfigSet(I2S0_BASE, I2S_CONFIG_FORMAT_I2S | I2S_CONFIG_MODE_DUAL | I2S_CONFIG_CLK_MASTER | I2S_CONFIG_SAMPLE_SIZE_24 | I2S_CONFIG_WIRE_SIZE_32);
and it doesn't with
First I got only zeros in the mono mode but now I don't get any output anymore. In dual mode I always get an output. Is there a coupling between the WS signal and the readout? In fact, I just have one microfone. Maybe it wouldn't make any difference between mono and dual mode, didn't it?