Last post for tonight. These are the pins for the I2S1 configuration I'll be using as a first attempt:
The MCLK shouldn't be needed as the i2s is running slave and the master clock is external. The clocking should should then synchronise via the bit clock input (CK), the frame clock input is WS and the SD is the data pin input.
The IDE has not generated a circle buffer directly from a cursory look although it has created a FIFO and possibly there's a circle buffer inside but what it does is calls my i2s data handling routines (to be written) via the handler block function pointers. I will look into this more, as it seems odd not to have a direct memory ring buffer as the destination of the DMA. Unless they mean the FIFO is the ring buffer.
Anyway it's late. I may have some time this week but it's going to be hectic at work plus add I have a birthday (the signal generator is my birthday present). I hope I'll have an evening or two in order to get the metalwork done and some i2s testing going.
The MCLK shouldn't be needed as the i2s is running slave and the master clock is external. The clocking should should then synchronise via the bit clock input (CK), the frame clock input is WS and the SD is the data pin input.
The IDE has not generated a circle buffer directly from a cursory look although it has created a FIFO and possibly there's a circle buffer inside but what it does is calls my i2s data handling routines (to be written) via the handler block function pointers. I will look into this more, as it seems odd not to have a direct memory ring buffer as the destination of the DMA. Unless they mean the FIFO is the ring buffer.
Anyway it's late. I may have some time this week but it's going to be hectic at work plus add I have a birthday (the signal generator is my birthday present). I hope I'll have an evening or two in order to get the metalwork done and some i2s testing going.
Being like a dog with a bone, i was thinking about cached areas and non cached areas for the compiler memory layout.
Simply put the idea is to place the buffers, fifo in a section of memory marked as non cached. So any reads and writes will be be immediate.
The article for microchip arm mincrocontrollers could be done for the stm32: http://ww1.microchip.com/downloads/...70)_MCU_Using_MPLAB_Harmonyv3_DS90003260A.pdf
You tell the compiler to have a data area mapped to pages of memory. Mark the peripherals memory mapped area and the new data area as non cacheable to the arm memory controller. You can statically define the buffer locations or even make a simple non_cached_malloc() to provide space in the area (i’d probably make it align to 4 bytes for each memory area).
Simply put the idea is to place the buffers, fifo in a section of memory marked as non cached. So any reads and writes will be be immediate.
The article for microchip arm mincrocontrollers could be done for the stm32: http://ww1.microchip.com/downloads/...70)_MCU_Using_MPLAB_Harmonyv3_DS90003260A.pdf
You tell the compiler to have a data area mapped to pages of memory. Mark the peripherals memory mapped area and the new data area as non cacheable to the arm memory controller. You can statically define the buffer locations or even make a simple non_cached_malloc() to provide space in the area (i’d probably make it align to 4 bytes for each memory area).
An interesting article but I doubt it is relevant to STM32F7 as the system architecture and memory allocation is different.ST point on the DMA D-cache issue: https://community.st.com/s/article/how-to-enable-dma-in-usb-with-stm32h7-devices
The arm m7 has two internal memories, which are close to the fetch unit. If the peripherals/buffer is held in the internal ram then that may be true.An interesting article but I doubt it is relevant to STM32F7 as the system architecture and memory allocation is different.
ST M7: https://www.st.com/content/ccc/reso...ations/en.STM32H7-System-ARM_Cortex_M7_M7.pdf
The D-cache buffers according to it’s policy (which is what we’re discussing), the DMA and teo internal memory locations of tightly coupled memory seem to be on die and tied into the fretch/store unit.
The question is - what is assigned to where. I’ll need to look. The tightly coupled memory has to be memory mapped (i assume a linear non overlaid paged memory space for the stm7f32 for this purpose).
Both the harmony and stm32 use the m7 core. So it’s worth pursuing.
I just wrote a load of stuff and then lost it.
I had a look at the M7 in more detail:
a) the tightly coupled memory connects the ITCM (128KB) and the DTCM (256KB) directly to the CPU and the DMA. Without being subject to the D-Cache or store buffer on the main bus.
b) ITCM is hard mapped to 0x00000000 and the DTCM is hard mapped to 0x20000000.
So as long as your GPIO DMA, dma list, fifo, and the USB DMA, dma list, fifo and the intermediate buffer fits into the small memory along side the stack in 256KBytes then you could make a fully DMA'd system. That would require careful sizings and would limit the call stacks (as the gcc typically stores the registers on the R13 stack as a standard frame that would limit the the call depths of your functions).
The reference manual states:
So the DTCM would naturally be the place for these areas (ignore the SRAM it's configured to use at the moment).
The issue is that the current USB implementation is obviously using SRAM for part of this hence the loss of data coherence.
Ok. Happy with that explanation. Now the effort expended in trying that is probably not worth it given the CPU can keep up with the USB with both ADC and DAC. So the fastest development option is to disable the DMA for USB.
I used to code ARM assembler - programming games on the ARM2 through ARM710 and StrongARM many moons ago. So sticking with C is probably more preferable nowadays rather than assembler 🙂
I had a look at the M7 in more detail:
a) the tightly coupled memory connects the ITCM (128KB) and the DTCM (256KB) directly to the CPU and the DMA. Without being subject to the D-Cache or store buffer on the main bus.
b) ITCM is hard mapped to 0x00000000 and the DTCM is hard mapped to 0x20000000.
So as long as your GPIO DMA, dma list, fifo, and the USB DMA, dma list, fifo and the intermediate buffer fits into the small memory along side the stack in 256KBytes then you could make a fully DMA'd system. That would require careful sizings and would limit the call stacks (as the gcc typically stores the registers on the R13 stack as a standard frame that would limit the the call depths of your functions).
The reference manual states:
This bus connects the USB OTG HS DMA master interface to the BusMatrix. This bus is used by the USB OTG DMA to load/store data to a memory. The targets of this bus are data memories: internal SRAM1, SRAM2 and DTCM (through the AHBS bus of Cortex®-M7), internal Flash memory, and external memories through the FMC or Quad SPI.
So the DTCM would naturally be the place for these areas (ignore the SRAM it's configured to use at the moment).
The issue is that the current USB implementation is obviously using SRAM for part of this hence the loss of data coherence.
Ok. Happy with that explanation. Now the effort expended in trying that is probably not worth it given the CPU can keep up with the USB with both ADC and DAC. So the fastest development option is to disable the DMA for USB.
I used to code ARM assembler - programming games on the ARM2 through ARM710 and StrongARM many moons ago. So sticking with C is probably more preferable nowadays rather than assembler 🙂
Hmm next issue is I've got a basic DMA double buffer that, specifically when I use HAL_I2S_Receive_DMA(&hi2s1, (uint16_t*)adcBuffer, BUF_SIZE ); it decides to hard_fault() which basically means a memory issue etc.
The DMA should be fine with the buffer and it should be circular too..
The DMA should be fine with the buffer and it should be circular too..
While not directly related to your problem why did you choose I2S instead of SAI? The latter is more flexible and has more functionality. My understanding is that focus has shifted to SAI in all upcoming STM32 MCUs.
Worth looking at - if it supports with the available pin outs.While not directly related to your problem why did you choose I2S instead of SAI? The latter is more flexible and has more functionality. My understanding is that focus has shifted to SAI in all upcoming STM32 MCUs.
IIRC SAI1_B at PF6-PF9 is available on some connector pins so those can be used without desoldering any components.
I think this issue seems to be due to the clock enable being in the wrong place as written by STM32Cube IDE..
I've moved the clocking initialisation and that seems to prevent it from throwing a hard_fault(). I'm not sure I'll have much time to play with it tonight (I think I'll be pulling an all nighter at work).
I've moved the clocking initialisation and that seems to prevent it from throwing a hard_fault(). I'm not sure I'll have much time to play with it tonight (I think I'll be pulling an all nighter at work).
It looks like i’m going to have to go through the code control register by control register, bit by bit.
Although the IDE is a great starting point, the STM ‘wizard’ obviously has some flaws in how it generates code. Specifically the sequence of configuration.
I’ve been attempting a SAI DMA as a new wizard project and I have the same issue as i2s DMA. I will try running non-DMA first to ensure i have a working base/hw configuration and code.
It looks like I will go through the documentation, map the register operations required, then compare against the STM IDE auto generated code.. joy joy happy happy. Judging by youtube this is a common theme and the STM examples from their website have hand written code (obviously they don’t see the IDE wizard as a true tool and so it doesnt get the testing it should get).
Although the IDE is a great starting point, the STM ‘wizard’ obviously has some flaws in how it generates code. Specifically the sequence of configuration.
I’ve been attempting a SAI DMA as a new wizard project and I have the same issue as i2s DMA. I will try running non-DMA first to ensure i have a working base/hw configuration and code.
It looks like I will go through the documentation, map the register operations required, then compare against the STM IDE auto generated code.. joy joy happy happy. Judging by youtube this is a common theme and the STM examples from their website have hand written code (obviously they don’t see the IDE wizard as a true tool and so it doesnt get the testing it should get).
Ok. Removing everything and starting at the beginning. If I apply signal generator generated 24.576MHz SCK and a 12.288MHz FS, does to the SAI - It works. So the STM does work with the DMA and interrupt.
So one option for now is to use BNC connections, not for the HV (connectors take 500Vpp) but instead use those connections for the test clocking for the DMA STM development. That will get me moving.

So one option for now is to use BNC connections, not for the HV (connectors take 500Vpp) but instead use those connections for the test clocking for the DMA STM development. That will get me moving.

Last edited:
The test setup is a little neater now:
Currently I have the BNC's connected to the signal pins, that way I can clock the SAI interface from the signal generator, leaving the SD to be random.
Currently I have the BNC's connected to the signal pins, that way I can clock the SAI interface from the signal generator, leaving the SD to be random.
Code:
HAL_SAI_ErrorCallback error code = 0x1 = SAI initialized and ready for use
HAL_DMA_GetStat error code = 0x1 = DMA initialized and ready for use
So I'm getting the drivers say they're ready - both SAI and DMA, but the system isn't getting an interrupt. I've checked the PCM clocking from the ADC - that seems good (~3.3V).
The ADC is running MCLK of 24.576Mhz (this into the ADC), running PCM output 192K 32 bit,
SCK: 12.288MHz
FS: 192.000KHz
SD: ~ 1MHz (although that's obviously depending on the bit pattern of the digitised signal)
Those are at the ARD pins of the DISCO. So the ADC seems to be 24.576M / 128fs = 192KHz so that seems right with the config I have the ADC hard wired with jumpers as. However that doesn't match the 13bit long PCM signal.. so I'm a little confused..
So either something not configured right or I've managed to bust the ARD pins (although I doubt it).
I think I will try a simple polled tomorrow - check the pins/system is working then I know it's simply something todo with configuration or DMA.
I solved most of the DMA hard_faulting by ensuring that the malloc() is 4 byte aligned and with in the 0x20000000 memory address space (ie in the non cached address space).
Previously I've fed the signal using the signal generator but the PCM FS is not a simple 1/2 rate switch (LONG Is 13bits of 32bits).
I may also simply switch the ADC to i2s but for now I want to see it actually receiving data and triggering interrupts/DMAs reliably.
Last edited:
Did you try to make a digital loop from ADC to DAC? If to put some signal (Sine, Square, Triangle) to ADC and to check DACs output with scope, this can prove that the hardware (ADC/DAC, SAI/I2S-ports) works correctly also the firmware (receiving->DMA->buffer->DMA->transmitting).
BTW, what with UAC? Is it works?
BTW, what with UAC? Is it works?
AFAIK AK5572 outputs I2S-like PCM (either left-justified MSB or standard I2S). So SAI should be configured to receive I2S instead of PCM (short or long).So the ADC seems to be 24.576M / 128fs = 192KHz so that seems right with the config I have the ADC hard wired with jumpers as. However that doesn't match the 13bit long PCM signal.. so I'm a little confused..
I'm not sure what you mean by this. Anything other than 0 is an error.Code:HAL_SAI_ErrorCallback error code = 0x1 = SAI initialized and ready for use HAL_DMA_GetStat error code = 0x1 = DMA initialized and ready for use
I’ll check but those were the HAL enum codes 1 = ready..AFAIK AK5572 outputs I2S-like PCM (either left-justified MSB or standard I2S). So SAI should be configured to receive I2S instead of PCM (short or long).
I'm not sure what you mean by this. Anything other than 0 is an error.
This is what I have in HAL SAI (stm32f7xx_hal_sai.h). HAL DMA is similar.
Code:
/** @defgroup SAI_Error_Code SAI Error Code
* @{
*/
#define HAL_SAI_ERROR_NONE ((uint32_t)0x00000000U) /*!< No error */
#define HAL_SAI_ERROR_OVR ((uint32_t)0x00000001U) /*!< Overrun Error */
#define HAL_SAI_ERROR_UDR ((uint32_t)0x00000002U) /*!< Underrun error */
#define HAL_SAI_ERROR_AFSDET ((uint32_t)0x00000004U) /*!< Anticipated Frame synchronisation detection */
#define HAL_SAI_ERROR_LFSDET ((uint32_t)0x00000008U) /*!< Late Frame synchronisation detection */
#define HAL_SAI_ERROR_CNREADY ((uint32_t)0x00000010U) /*!< codec not ready */
#define HAL_SAI_ERROR_WCKCFG ((uint32_t)0x00000020U) /*!< Wrong clock configuration */
#define HAL_SAI_ERROR_TIMEOUT ((uint32_t)0x00000040U) /*!< Timeout error */
#define HAL_SAI_ERROR_DMA ((uint32_t)0x00000080U) /*!< DMA error */
Hmm ok i’ll check again.This is what I have in HAL SAI (stm32f7xx_hal_sai.h). HAL DMA is similar.
Code:/** @defgroup SAI_Error_Code SAI Error Code * @{ */ #define HAL_SAI_ERROR_NONE ((uint32_t)0x00000000U) /*!< No error */ #define HAL_SAI_ERROR_OVR ((uint32_t)0x00000001U) /*!< Overrun Error */ #define HAL_SAI_ERROR_UDR ((uint32_t)0x00000002U) /*!< Underrun error */ #define HAL_SAI_ERROR_AFSDET ((uint32_t)0x00000004U) /*!< Anticipated Frame synchronisation detection */ #define HAL_SAI_ERROR_LFSDET ((uint32_t)0x00000008U) /*!< Late Frame synchronisation detection */ #define HAL_SAI_ERROR_CNREADY ((uint32_t)0x00000010U) /*!< codec not ready */ #define HAL_SAI_ERROR_WCKCFG ((uint32_t)0x00000020U) /*!< Wrong clock configuration */ #define HAL_SAI_ERROR_TIMEOUT ((uint32_t)0x00000040U) /*!< Timeout error */ #define HAL_SAI_ERROR_DMA ((uint32_t)0x00000080U) /*!< DMA error */
- Home
- Design & Build
- Equipment & Tools
- Nick's audio test system (AK5572 ADC 129KHz 32bit stereo balanced input)