Nick's audio test system (AK5572 ADC 129KHz 32bit stereo balanced input)

I spent the evening banging away at lots of ideas, found a couple of bugs (bits not cleared when set etc due to copy'n'paste). If you excuse the skunkworks code:

Screenshot 2022-10-31 at 21.38.13.png


Well that's awesome. I gave the ADC a long reset it's working - this is the hardware double buffering with a breakpoint on the hardware handler 😀 😀 So it seems I should have a small control board that I can control the ADC reset pin, keep it reset until we're ready then let the ADC start.

So I'm happy - looks like the next week is going to be mega stressful at work and long hours so I think it's great to get to this point.
 
Last edited:
The normal approach is to wait until host sends an IN token (i.e. starts recording) so you get an USB OTG DataIn interrupt. Only then you initialize DMA transfers from SAI I2S input. So it does not matter when ADC is reseted provided it happens before host starts recording.
 
The normal approach is to wait until host sends an IN token (i.e. starts recording) so you get an USB OTG DataIn interrupt. Only then you initialize DMA transfers from SAI I2S input. So it does not matter when ADC is reseted provided it happens before host starts recording.

I was going to reset on power on (or in case of repeated framing errors) using an optocoupler i2c line. The STM on power up simply issues an i2c to reset and also use the same mechanism to allow ADC configuration. For USB data IN I was simply going to flush the FIFO and buffers, resetting the DMA to force it to start at the front of the buffer. Then stream the data as required. That approach means the ADC is left to settle after power on and the SAI interface is no having to lock on at the start of the recording. It also means that if the system is not locked on that can be highlighted.

The power needs to be provided for the ADC board anyway to allow the front end opamps to stabilise. So I think this approach would work.
 
Last edited:

NickKUK, why are you focusing so much on I2S, which I don't think is the most complex and problematic part of this design??

Why not to use some "dummy" functions to simulate I2S transfer (for example - to use interrupt from any timer with the sample rate frequency), to concentrate to the most important task - UAC2 USB?

Or did I miss something and this task was already completed?
 

NickKUK, why are you focusing so much on I2S, which I don't think is the most complex and problematic part of this design??

Why not to use some "dummy" functions to simulate I2S transfer (for example - to use interrupt from any timer with the sample rate frequency), to concentrate to the most important task - UAC2 USB?


I wanted to two projects for building knowledge - one for USB UAC2 and the other for i2s. The idea is to learn for each of those, then take that knowledge and build a final project. With the hardware SAI DMA double buffering that's available on the later STMS capable of this - this changes the design approach slightly.

So next is to focus on the the build where I bring the UAC2 and the i2s components together, stubbing the i2s based on the behaviour I've noted and that can use dummy data with an interrupt timer.
 
I was going to reset on power on (or in case of repeated framing errors) using an optocoupler i2c line. The STM on power up simply issues an i2c to reset and also use the same mechanism to allow ADC configuration. For USB data IN I was simply going to flush the FIFO and buffers, resetting the DMA to force it to start at the front of the buffer. Then stream the data as required. That approach means the ADC is left to settle after power on and the SAI interface is no having to lock on at the start of the recording. It also means that if the system is not locked on that can be highlighted.
Yes, MCU sets up the USB endpoints, DMAs, SAIs, resets and configures the ADC via I2C when powered up. Similar with DACs. Host will send a bunch of UAC setup requests to e.g. set the input I2S sample rate prior to the first IN token. With these setup request you should also set the ADC's sample rate via I2C. So when you receive the first IN token everything is set up correctly and you just start the DMA transfers and send USB packets to host.
 
So the UAC2 is almost complete - the key is data transfer but the IN + multiple SOF handling is there. However i was battling the USB DMA data transfer so gave that a rest to learn more in the dma for the i2s (hence the focus on hardware dma).
 
So looking into the DMA issues.

The STM32 has 256KB but the IDE auto generator places the all the memory at 0x2000000 DTCM (64K) then the SRAM1&2 are stacked after. The PSRAM (4Mbit) is attached to the FCM which we shouldn’t need to use.

The USB DMA controllers can’t access DTCM according some ST comments. So the USB and i2s buffers need to sit in the SRAM. I just need to ensure the stack and allocated memory (malloc) isnt going to overwrite and anchor the buffers in the SRAM mapped location. I can then map to a aligned address, disable the D-cache for those memory pages that will contain the buffers. Allowing the dma in and dma out without cache issues.
 
An interesting comment here that indicates the use of SRAM is the way togo, with cache enabled (obviously disabling for the buffer pages) and that the dma has a minimum size of 4 “packets” due to needing aligned transfers. So I’ll need to check what that means for the stm firmware and IN endpoint transfers. In theory you could NAK SOF frames if the data buffer is less than an aligned transfer. What impact that would have needs investigating.
 
IIRC I did not manage to get USB OTG dma working for input I2S even with placing buffers in SRAM and everything aligned to 4 bytes. It was not a caching issue as it simply did not send data to host. But I did not spend much time on it so it may well be that I overlooked something.
 
  • Like
Reactions: NickKUK
I probably understand that wrong - I would assume to copy into the USB packet at IN request whatever is new in the SAI buffer, and whatever comes over USB to the SAI buffer for EP OUT (provided it fits the buffer). But most likely I am assuming wrong 🙂