Hmm ok i’ll check again.
Code:
typedef enum
{
HAL_SAI_STATE_RESET = 0x00U, /*!< SAI not yet initialized or disabled */
HAL_SAI_STATE_READY = 0x01U, /*!< SAI initialized and ready for use */
HAL_SAI_STATE_BUSY = 0x02U, /*!< SAI internal process is ongoing */
HAL_SAI_STATE_BUSY_TX = 0x12U, /*!< Data transmission process is ongoing */
HAL_SAI_STATE_BUSY_RX = 0x22U, /*!< Data reception process is ongoing */
} HAL_SAI_StateTypeDef;
Not the error code but the state is what I'm returning (sorry if that was confusing).
So the error code is a late sync frame - which ties up with the mismatch in protocol type. I'm switching to i2s to see if it will work.
Ok so I have a hard fault - however I think this is my ring buffer corrupting something, if I look at the HAL LOCK which I use it appears to indicate it's locked and the only thing that manipulates that is the ring buffer code. So I think the memcpy is at fault.
Try without I and D-Cache enabled, to avoid Hard Fault.
CPU performance for SAI/I2S operation will be more than enough.
When SAI/I2S will work fine, you can continue the fight with the cache.
F7/H7 memory system is very confusing, (especially using Cube and HAL).
In general, own scatter file should be developed, and MPU to define different behavior of the memory regions.
But a lot of things are not 100% clear from the documentation, so sometimes using the cache in STM is a black magic...
CPU performance for SAI/I2S operation will be more than enough.
When SAI/I2S will work fine, you can continue the fight with the cache.
F7/H7 memory system is very confusing, (especially using Cube and HAL).
In general, own scatter file should be developed, and MPU to define different behavior of the memory regions.
But a lot of things are not 100% clear from the documentation, so sometimes using the cache in STM is a black magic...
Last edited:
That autogenerated code is doing my head in - I no longer have debugging SWV output.. it's almost like everything is dependant on everything else and it's a mess.. the auto wizard touches one thing and it results in an unusable project.
Sorry but it's 19:44 now and I started work at 04:40 so perhaps I'm not in the right patient mind set for this tonight.
It's definitely the DMA - if I remove that RX DMA start there's no faulting. So obviously something is not initialised or is blowing up.
Sorry but it's 19:44 now and I started work at 04:40 so perhaps I'm not in the right patient mind set for this tonight.
It's definitely the DMA - if I remove that RX DMA start there's no faulting. So obviously something is not initialised or is blowing up.
Last edited:
Actually if I step through the code - it will operate without crashing immediately. The DMA call back works, and the flip flop works. So to be that's either the clock is operating too fast for the peripherals so flags are set and unset too fast, or there's a race condition in the code base it's generating.
I'm starting to think about writing the code from register operations and not use the existing auto generated software..
I'm starting to think about writing the code from register operations and not use the existing auto generated software..
Last edited:
I used autogenerator only once when I started my project. But I've never been a fan of code generators.
I used autogenerator only once when I started my project. But I've never been a fan of code generators.
In the past i’ve done the same but as theres an exploritory aspect to the work it would have proved more useful!
There’s s final option - the stack is configure too small.
I’ll start again, generate a new shell project, move stuff over. I’ll then re-write the initiation and ho from there.
I’ve now got my head stuck in the reference manual - I see what you mean about burst mode, especially things like crossing the 1K boundaries.
Things now make sense - even better I’be found the recommended sequence for initialisation, config and the procedures for recovering for things like underflow or frame issues.
Looking back at the auto configurator it seems to overcomplicate and miss the basics.
Things now make sense - even better I’be found the recommended sequence for initialisation, config and the procedures for recovering for things like underflow or frame issues.
Looking back at the auto configurator it seems to overcomplicate and miss the basics.
So after about 6 hours.. trawling through the register bitfields and coding up (explicitly clearing/setting bits):
So if you excuse the noise on this you can see SCK(cyan), FS(yellow) and SD (purple) so:
I've now got a complete SAI (all registers), DMA (all registers) routine that configures it but still leaves the interrupt handling to the old STM routines. It's setup for DMA double buffering with interrupts.
Reliably no errors being raised via callback. I did have anticipated FS detected and overflow until I managed to work out stereo = 2 slots, changed to the right leading edge FS and configured data to 24bits.
Times like these a 4 channel oscilloscope is the only way to collate the two data sheets and what is actually being sent between the two chips.
So if you excuse the noise on this you can see SCK(cyan), FS(yellow) and SD (purple) so:
- Two slots (stereo) both 32bits, audio data (DS) being 24bits MSB
- FS being 32bits long, frame length = 64bits
I've now got a complete SAI (all registers), DMA (all registers) routine that configures it but still leaves the interrupt handling to the old STM routines. It's setup for DMA double buffering with interrupts.
Reliably no errors being raised via callback. I did have anticipated FS detected and overflow until I managed to work out stereo = 2 slots, changed to the right leading edge FS and configured data to 24bits.
Times like these a 4 channel oscilloscope is the only way to collate the two data sheets and what is actually being sent between the two chips.
Doh, and it appears the stm autogenerated code interrupt controller is hiding the anticipated frame detect but resetting it and not calling any error handler.
I think i will recode the interrupt handling to and just give up on the auto generated code after clock configuration.
Also my double buffer implementation is using the single buffer swapped, instead I will recode for hardware double buffer support, a notice feature is the non-dma buffer can be reprogrammed live, so you can make it walk through a ring buffer directly used by usb transmit thus reducing overhead and latency. So as long as that ring buffer sits in the 0x20000000 ram area, there will be no data cache issues.
The mechanism is will been to be large enough go cope with packing 24 sound fames into the USB microframes with and USB SOF request “jitter” caused by USB bandwidth.
I need to look at the USB complexity - if i replace the interrupt control then how does that impact USB. Or if the USB code even uses that HAL code itself.
I can test the anticipated frame, where the frame switch is occuring too early but generating the two timing signals using the signal generator directly on the pins. I suspect it may be a noise issue causing the schmitt trigger on the STM to fire early. The current ribbon cable has alternate grounding so each clock signal neightbour is a ground. I’ll also sort the remaining case modifications to allow it to be closed and fully grounded.
I think i will recode the interrupt handling to and just give up on the auto generated code after clock configuration.
Also my double buffer implementation is using the single buffer swapped, instead I will recode for hardware double buffer support, a notice feature is the non-dma buffer can be reprogrammed live, so you can make it walk through a ring buffer directly used by usb transmit thus reducing overhead and latency. So as long as that ring buffer sits in the 0x20000000 ram area, there will be no data cache issues.
The mechanism is will been to be large enough go cope with packing 24 sound fames into the USB microframes with and USB SOF request “jitter” caused by USB bandwidth.
I need to look at the USB complexity - if i replace the interrupt control then how does that impact USB. Or if the USB code even uses that HAL code itself.
I can test the anticipated frame, where the frame switch is occuring too early but generating the two timing signals using the signal generator directly on the pins. I suspect it may be a noise issue causing the schmitt trigger on the STM to fire early. The current ribbon cable has alternate grounding so each clock signal neightbour is a ground. I’ll also sort the remaining case modifications to allow it to be closed and fully grounded.
And.. on checking the pins for the signal handler - I found the SCK pin in D0.. I'd managed to reverse the small block of pins used for the SCK connection which should be in D3. facepalm
So ai have a non HAL implementation almost working.
Currently the registers of the SAI are appearing as containing zeros, unlike the DMA which looks good. This is causing SAI DMAEN and the SAIEN to hang on the while loop after that checks for enablement before continuing. I suspect this a hardware initialisation failure.
Thinking forward the USB microframes are 192 bytes with 24 i2s frames in each USB microframe. With the hardware supporting double buffering, it should e possible to have frames copes from the FIFO via DMA into memory which is the. Set as the source usb buffer, the key is the double bugger hardware implementation updates the next block pointer (which the DMA is using the other buffer uses).
I’ll then use the buffer souce, if the usb output catches the the i2s buffer then i will just zeros.
Currently the registers of the SAI are appearing as containing zeros, unlike the DMA which looks good. This is causing SAI DMAEN and the SAIEN to hang on the while loop after that checks for enablement before continuing. I suspect this a hardware initialisation failure.
Thinking forward the USB microframes are 192 bytes with 24 i2s frames in each USB microframe. With the hardware supporting double buffering, it should e possible to have frames copes from the FIFO via DMA into memory which is the. Set as the source usb buffer, the key is the double bugger hardware implementation updates the next block pointer (which the DMA is using the other buffer uses).
I’ll then use the buffer souce, if the usb output catches the the i2s buffer then i will just zeros.
On average, the actual number of audio frames will depend on the USB host clock vs. I2S clock - USB async input.Thinking forward the USB microframes are 192 bytes with 24 i2s frames in each USB microframe.
So now I have a SAI interface configured from scratch. Well, I say configured - it seems operational, it enables, the pins are configured etc however I'm not getting any events. The SAI when you're using hardware double buffering should give you interrupts from either FIFO or DMA. I can see the DMA stream global interrupts coming through the main interrupt handler (things like the printf etc) but I'm not seeing anything else.
The new initialisation routine also sits and waits for each bit to be enabled or disabled. I've got a period check routine in the main loop to check that everything is enabled, and I'll add more to that to check the status and interrupt states. So far now there's been zero hard faults..
The auto generator seems to configure parts all over the code base of the firmware which is probably why it gets into trouble. A very coupled approach and very bad for code maintenance. It should keep the auto generated and the firmware code distinct (even in separate files). Which is explains it's problems.
Also due to bus contention I suspect. Either way essentially the buffer will act like a pool that the USB incoming SOF will be able to take as much (or as little) data from as it needs so the system isn't hard coded to sync exactly frame sizes to data rates. As long as there's enough USB transfer of data to keep up with the audio data (which it should).
The new initialisation routine also sits and waits for each bit to be enabled or disabled. I've got a period check routine in the main loop to check that everything is enabled, and I'll add more to that to check the status and interrupt states. So far now there's been zero hard faults..
The auto generator seems to configure parts all over the code base of the firmware which is probably why it gets into trouble. A very coupled approach and very bad for code maintenance. It should keep the auto generated and the firmware code distinct (even in separate files). Which is explains it's problems.
On average, the actual number of audio frames will depend on the USB host clock vs. I2S clock - USB async input.
Also due to bus contention I suspect. Either way essentially the buffer will act like a pool that the USB incoming SOF will be able to take as much (or as little) data from as it needs so the system isn't hard coded to sync exactly frame sizes to data rates. As long as there's enough USB transfer of data to keep up with the audio data (which it should).
At least Windows and Linux have strict fs-specific lower and upper bounds for the amount of audio slots in each USB packet. For 192k these limits are 23 & 25 with 24 as nominal. Some control for this variation is required also for incoming I2S even though async feedback is not used.Also due to bus contention I suspect. Either way essentially the buffer will act like a pool that the USB incoming SOF will be able to take as much (or as little) data from as it needs so the system isn't hard coded to sync exactly frame sizes to data rates. As long as there's enough USB transfer of data to keep up with the audio data (which it should).
I have a mixed implementation (HAL & non HAL) and used direct register access sparingly. USB and SAI HAL layer is fairly thin so performance benefits are slim. Without HAL the implementation becomes more MCU specific. So if you switch to e.g. STM32H7 MCUs the implementation will probably need more changes.So ai have a non HAL implementation almost working.
I have a mixed implementation (HAL & non HAL) and used direct register access sparingly. USB and SAI HAL layer is fairly thin so performance benefits are slim. Without HAL the implementation becomes more MCU specific. So if you switch to e.g. STM32H7 MCUs the implementation will probably need more changes.
Yes, however i suspect understanding the HAL is better once you have a hard register coding. I will then have a reference point.
Currently the FIFO appears as empty and the system isn’t processing data so that is the big issue atm. No interrupts so i’m wondering if it’s seeing data or not.
Yes, I agree.Yes, however i suspect understanding the HAL is better once you have a hard register coding.
I found a loose connection - now I'm getting something at least - anticipated frame again. So I'll go through that config (I've been playing a little so it may be cable or config). I'll get the scope out on it tonight and recheck but I'm close to getting it operational I think.
- Home
- Design & Build
- Equipment & Tools
- Nick's audio test system (AK5572 ADC 129KHz 32bit stereo balanced input)