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:
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.
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.
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.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.
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).
With the hardware SAI DMA double buffering that's available on the later STMS capable
Not only the later, even the old STMF1, F4, L4, have double buffering with 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.
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.
When processing every 125us microframe in the microcontroller CPU anyway, would DMA from the SAI buffer bring any advantage?
IME the lack of USB OTG dma is not a problem. Especially with lower sampling rates USB HS packets are quite small so dma does not offer any real benefits.
And DMA to/from the SAI? IIUC the CPU in this usecase does not do much apart of serving the microframes and passing the data between USB OTG and SAI.
Do I understand correctly that for the SAI DMA to have no benefit the SAI buffer must fit one microframe load of samples, to avoid having to buffer in memory?
This works without issues.And DMA to/from the SAI?
I don't see how this could work without a memory buffer with all sampling rates and bit depths.Do I understand correctly that for the SAI DMA to have no benefit the SAI buffer must fit one microframe load of samples, to avoid having to buffer in memory?
I see, good.This works without issues.
That's what I meant, IIUC - the microframe/packet load would have to fit into the SAI buffer (which I do not know what size it is).I don't see how this could work without a memory buffer with all sampling rates and bit depths.
SAI buffer size can be freely set. But e.g. for input I2S with 44k1 family sample rates the USB packet size is not constant. So it is not possible to manage this without some buffering.
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 🙂
E.g. for incoming I2S at 88k2 Windows UAC2 driver accepts 11 or 12 samples in microframe. So for every 40 packets host needs 39x 11 sample packets and 1x 12 sample packet. I believe Linux driver works in same fashion.
- Home
- Design & Build
- Equipment & Tools
- Nick's audio test system (AK5572 ADC 129KHz 32bit stereo balanced input)