Attached is the source code. It runs on FreeRTOS although this version does not really utilize it.
I used STM32F723E-DISCO board's Arduino connectors CN11 and CN13 for all I/O.
I2S signals are at CN11.1 (FS), CN13.4 (BCK) and CN13.7 (SD).
I2C2 is available at CN11.10 (SCL) and CN11.9 (SDA).
4 GPIO outputs at CN13.3, CN13.5, CN13.6 and CN13.8.
GND at CN11.7.
The source code also includes a "driver" for my AK5394 board which uses all 4 GPIO outputs. This can be used as an example of how to connect to ADC board.
STM32F723E-DISCO board is of course not optimal for running I2S as it is meant to be a showcase of various MCU capabilities. For best results a custom board dedicated to I2S should be used.
The FW uses STM32CubeProgrammer's SWV (Serial Wire Viewer) for debug output. So printf goes to SWV. System clock in SWV should be set to 216 MHz. Existing FW debug output can be switched on in main.c:
bool _debug_output = true;
@bohrok2610 thanks for sharing!
Have looked through the code. Are you sure the code of "USBD_AUDIO_IsoINIncomplete()" and "USBD_AUDIO_IsoOutIncomplete" in "usbd_audio.c" is included in the firmware and reachable?
uint8_t USBD_AUDIO_IsoINIncomplete (USBD_HandleTypeDef *pdev, uint8_t epnum)
{
// Check all IN-endpoints
for (int i = 1; i <= USBD_AUDIO_MAX_IN_EP; i++) {
if (USB_DIEPCTL(i) & USB_OTG_DIEPCTL_EPENA) {
if (epnum == (AUDIO_IN_EP & EP_ADDR_MSK)) {
// Flip parity if not flipped already
USBD_AUDIO_HandleTypeDef *haudio;
haudio = &((USBD_AUDIO_DeviceTypeDef*)pdev->pClassData)->in;
if (haudio->parity != PARITY_FLIP) {
if (_debug_output) {
printf("diepctl2: %d %08lx %ld\r\n", i, USB_DIEPCTL(epnum), HAL_GetTick());
}
FLIP_PARITY(epnum);
USB_CLEAR_INCOMPLETE_IN_EP(epnum);
USBD_LL_FlushEP(pdev, AUDIO_IN_EP);
USBD_LL_Transmit(pdev, AUDIO_IN_EP, inEmptyBuffer, AUDIO_IN_PACKET_SIZE(haudio->fs, haudio->bytes_per_sample));
haudio->parity = PARITY_FLIP;
}
}
}
}
return (uint8_t)USBD_OK;
}
//---------------------------------------------------------------------------
uint8_t USBD_AUDIO_IsoOutIncomplete(USBD_HandleTypeDef *pdev, uint8_t epnum)
{
if (epnum != 0) {
if (_debug_output) {
printf("IsoOut: %d %ld\r\n", epnum, HAL_GetTick());
}
}
UNUSED(pdev);
UNUSED(epnum);
return (uint8_t)USBD_OK;
}
I believe it's not. Explanation:
1) When InComplete interrupts rise, corresponding functions in "usbd_conf.c" are called from USB ISR "HAL_PCD_IRQHandler()".
2) Then from incomplete functions (mentioned in spoiler above) in "usbd_conf.c" functions "USBD_LL_IsoOUTIncomplete" and "USBD_LL_IsoINIncomplete" are called which are located in "usbd_core.c" file of ST USB device library.
3) And from these functions in "usbd_core.c" corresponding InComplete functions of implemented USB class should be called. But these calls are not implemented in "usbd_core.c" file of ST USB device library.
if (pdev->dev_state == USBD_STATE_CONFIGURED)
{
if (pdev->pClass->IsoOUTIncomplete != NULL)
{
pdev->pClass->IsoOUTIncomplete(pdev, epnum);
}
}
return USBD_OK;
}
After these corrections made functions "USBD_AUDIO_IsoINIncomplete" and "USBD_AUDIO_IsoOutIncomplete" in "usbd_audio.c" are called.
I believe that's why your UAC2 log reports messages like "feedback packet 1 has invalid packet length 0, ignoring packet" you mentioned in that thread https://www.diyaudio.com/community/threads/uac2-0-on-stm32.393081/post-7208377, because InComplete inerrupts are not serviced. I faced with the very same situation with "usbd_core.c". With corrected file InComplete interrupts are called and UAC2 log reports no messages mentioned above.
That’s a IDE issue, but i had that issue and the got it compiling and working.
There was an issue with the version if you attempt to migrate the cube file file too.
I believe that's why your UAC2 log reports messages like "feedback packet 1 has invalid packet length 0, ignoring packet" you mentioned in that thread https://www.diyaudio.com/community/threads/uac2-0-on-stm32.393081/post-7208377, because InComplete inerrupts are not serviced. I faced with the very same situation with "usbd_core.c". With corrected file InComplete interrupts are called and UAC2 log reports no messages mentioned above.
The reason for "feedback packet 1 has invalid packet length 0, ignoring packet" is simply the processing of incomplete interrupts as I mentioned before. I'm running the FW with feedback at 1 microframe intervals.
I dont think this is related to @bohrok2610’s code but has anyone got it working via virtualbox? It seems it works on mac, but if I try to move the usb device to the virtualbox VM it fails to connect it (it doesn’t get to ubuntu).
@bohrok2610 , while working with stm32 MCUs, in ISO Incomplete ISR like
C:
uint8_t USBD_AUDIO_IsoINIncomplete (USBD_HandleTypeDef *pdev, uint8_t epnum)
{
// Check all IN-endpoints
for (int i = 1; i <= USBD_AUDIO_MAX_IN_EP; i++) {
if (USB_DIEPCTL(i) & USB_OTG_DIEPCTL_EPENA) {
if (epnum == (AUDIO_IN_EP & EP_ADDR_MSK)) {
// Flip parity if not flipped already
USBD_AUDIO_HandleTypeDef *haudio;
haudio = &((USBD_AUDIO_DeviceTypeDef*)pdev->pClassData)->in;
if (haudio->parity != PARITY_FLIP) {
if (_debug_output) {
printf("diepctl2: %d %08lx %ld\r\n", i, USB_DIEPCTL(epnum), HAL_GetTick());
}
FLIP_PARITY(epnum);
USB_CLEAR_INCOMPLETE_IN_EP(epnum);
USBD_LL_FlushEP(pdev, AUDIO_IN_EP);
USBD_LL_Transmit(pdev, AUDIO_IN_EP, inEmptyBuffer, AUDIO_IN_PACKET_SIZE(haudio->fs, haudio->bytes_per_sample));
haudio->parity = PARITY_FLIP;
}
}
}
}
return (uint8_t)USBD_OK;
}
checking endpoint number that caused interrupt like "if (epnum == (AUDIO_IN_EP & EP_ADDR_MSK))" is useless and even harmfull, because stm32 hardware and stm32 USB library itself do not allow to determine endpoint number which is the interrupt source. stm32 USB library always transfers epnum = 0. The code under epnum check is unreachable.
Hello. I've lurked here for a while. Have you considered posting your work with i2s input and output on GitHub? It'll be great if everyone can use that instead of relying on "Tinyusb" for audio, a git some have had trouble with in the past.
This type of SW is not generic as it works with a particular board so the code in this thread works with STM32F723E-DISCO board. I have more comprehensive SW for UAC2 on STM32 MCUs but those versions are only for my own STM32F7/H7 boards.
There is an alternative on this site for I2S output on STM32F446 with board gerbers included (see here). It has a slightly different approach to mine so I'm not sure how well it works.
I'm sorry but I can't find information about the github repo you referenced. I am not very familiar with your forums, please excuse me. I am developing a uac2 implementation for the STM32 and would like to collaborate with others that are working in that area. Can you refer me to someone who is working on that repo? Thanks!