{"id":16672260,"url":"https://github.com/dragonman225/stm32f469-usbaudio","last_synced_at":"2025-03-17T00:32:17.755Z","repository":{"id":47792414,"uuid":"209611630","full_name":"dragonman225/stm32f469-usbaudio","owner":"dragonman225","description":"Enable 24-bit / 96kHz Hi-Fi PCM stereo audio output via USB Audio Class 1.0 asynchronous mode on STM32469I-Discovery · Volume and mute control implemented","archived":false,"fork":false,"pushed_at":"2021-06-26T02:16:36.000Z","size":17664,"stargazers_count":133,"open_issues_count":6,"forks_count":33,"subscribers_count":9,"default_branch":"master","last_synced_at":"2024-10-13T12:05:15.938Z","etag":null,"topics":["embedded-c","stm32","stm32f4","usb-audio"],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dragonman225.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-09-19T17:28:22.000Z","updated_at":"2024-09-24T16:01:39.000Z","dependencies_parsed_at":"2022-09-10T06:51:19.822Z","dependency_job_id":null,"html_url":"https://github.com/dragonman225/stm32f469-usbaudio","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dragonman225%2Fstm32f469-usbaudio","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dragonman225%2Fstm32f469-usbaudio/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dragonman225%2Fstm32f469-usbaudio/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dragonman225%2Fstm32f469-usbaudio/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dragonman225","download_url":"https://codeload.github.com/dragonman225/stm32f469-usbaudio/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":221669288,"owners_count":16860849,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["embedded-c","stm32","stm32f4","usb-audio"],"created_at":"2024-10-12T12:05:43.969Z","updated_at":"2024-10-27T11:35:18.151Z","avatar_url":"https://github.com/dragonman225.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"# STM32F4 Asynchronous USB Audio Firmware\n\n![Actions Status](https://github.com/dragonman225/stm32f469-usbaudio/workflows/ARM%20Cross-compilation%20CI/badge.svg)\n\nThis project is based on [STM32469I-Discovery \"AUDIO_Standalone\" Example](https://github.com/STMicroelectronics/STM32CubeF4/tree/master/Projects/STM32469I-Discovery/Applications/USB_Device/AUDIO_Standalone), and I largely rewrite the [USB audio class library](https://github.com/dragonman225/stm32f469-usbaudio/tree/master/Middlewares/ST/STM32_USB_Device_Library/Class/AUDIO) provided by ST.\n\n* Folder structure, startup script, linker file are generated by setting up a dummy project (USB, SAI, DMA, I2C, GPIO enabled) with [STM32CubeMX](https://www.st.com/en/development-tools/stm32cubemx.html).\n* `Drivers/BSP/` and `Middlewares/ST/STM32_Audio/` are copied from [STM32CubeF4 Repositiry](https://github.com/STMicroelectronics/STM32CubeF4).\n* Files generated by [STM32CubeMX](https://www.st.com/en/development-tools/stm32cubemx.html) in `Inc/` and `Src/` are replaced with those from [STM32469I-Discovery \"AUDIO_Standalone\" Example](https://github.com/STMicroelectronics/STM32CubeF4/tree/master/Projects/STM32469I-Discovery/Applications/USB_Device/AUDIO_Standalone).\n\n## Table of Contents\n\n* [Feature](#Feature)\n* [For User](#For-User)\n* [For Developer](#For-Developer)\n* [Firmware Architecture](#Firmware-Architecture)\n* [Technical Highlight](#Technical-Highlight)\n* [Background Knowledge](#Background-Knowledge)\n\n## Feature\n\n* Using asynchronous mode for isochronous transfer.\n  \n  * 1 ISO OUT endpoint for PCM data, 1 ISO IN endpoint for feedback.\n  \n* Support 16-bit / 24-bit, 44.1 kHz / 48 kHz / 96 kHz, stereo PCM audio.\n\n* Support mute, volume, frequency control from USB host.\n  * Mute and volume control commands are passed to CS43L22 codec.\n  * Frequency control commands change the PLL settings on MCU to generate different MCLK for SAI block.\n  \n* Implement USB Audio Class 1.0 on USB OTG Full-speed core.\n\n* LED status indicator\n\n  **Green LED** : ON when playing.\n\n  **Orange LED** : ON when buffer overrun (with audible distortion).\n\n  **Red and Blue LED** : Depend on audio data frequency.\n\n  | Frequency | Red LED | Blue LED |\n  | :-------: | :-----: | :------: |\n  | 44.1 kHz  |   ON    |    -     |\n  |  48 kHz   |    -    |    ON    |\n  |  96 kHz   |   ON    |    ON    |\n\n## For User\n\n### Install basic tools\n\n```bash\n# Arch Linux\npacman -S make arm-none-eabi-gcc\n\n# Ubuntu\napt-get install make gcc-arm-none-eabi\n```\n\n### Compile the code\n\n```bash\nmake\n```\n\n### Flash the binary\n\n#### Method 1 : Use open-source version of [stlink](https://github.com/texane/stlink)\n\n```bash\n# Install stlink you don't have it\n# Arch Linux\npacman -S stlink\n# Ubuntu\napt-get install stlink-tools\n\n# Connect your board from the ST-LINK connector to PC. Then, run\nmake flash\n```\n\n#### Method 2 : Use [STM32CubeProg](https://www.st.com/en/development-tools/stm32cubeprog.html)\n\n1. Connect your board to PC from the ST-LINK connector, open STM32CubeProg, click \"Connect\".\n2. Go to \"Erasing \u0026 Programming\" tab, click \"Browse\", choose the binary `build/f469-usbaudio-ex2.bin`.\n3. Click \"Start Programming\".\n\n### Use the USB audio device\n\n1. Connect your board to PC from the **MicroUSB** connector (CN13). (Not the ST-LINK **MiniUSB** connector). \n\n   The ST-LINK **MiniUSB** connector should still be connected to PC because the board is powered from this port.\n\n2. There will be something like \"USB Audio Speaker\" appears on PC. Set it to default audio device and play music  with that device.\n\n   \u003e #### :warning: Warning\n   \u003e\n   \u003e Set volume to the lowest level before plug-in a headphone. The firmware is not well-tested to guarantee safe initial volume on all platforms.\n\n* On Linux, `pactl list short sinks` recognizes the USB audio device as the following :\n\n   ```\n   alsa_output.usb-STMicroelectronics_STM32_AUDIO_Streaming_in_FS_Mode_\u003cserial_number\u003e-00.analog-stereo\n   ```\n\n## For Developer\n\n### Development tools\n\n* `make` The build system.\n* `arm-none-eabi-gcc`, `arm-none-eabi-gdb`, `arm-none-eabi-newlib` ARM cross-compiling and debugging toolchain.\n* `stlink` For firmware flashing and debugging.\n* `openocd` Debugging tool.\n\n```bash\n# Arch Linux\npacman -S make arm-none-eabi-gcc arm-none-eabi-gdb arm-none-eabi-newlib stlink openocd\n```\n\nIf you use VSCode, the following extensions may help (not necessarily needed) :\n\n* [`C/C++` by Microsoft](https://marketplace.visualstudio.com/items?itemName=ms-vscode.cpptools)\n* [`Cortex-Debug` by marus25](https://marketplace.visualstudio.com/items?itemName=marus25.cortex-debug)\n\n### Compile the code\n\n```bash\nmake\n```\n\nTo clean up `build/` directory,\n\n```bash\nmake clean\n```\n\n### Flash the binary\n\n```bash\nmake flash\n```\n\nThis is the shorthand for :\n\n```bash\nst-flash --reset write $(BUILD_DIR)/$(TARGET).bin 0x08000000\n```\n\n### Debug the code\n\n\u003e I debug on VSCode with [`Cortex-Debug`](https://github.com/Marus/cortex-debug) extension.\n\nFirst, connect your board to PC from the ST-LINK connector.\n\nOn **Debug** tab in VSCode, choose **Debug (OpenOCD)** config and start. Then, you'll see the familiar [debugger](https://code.visualstudio.com/docs/editor/debugging) running.\n\n- SVD file used to display peripheral registers is taken from https://github.com/posborne/cmsis-svd/blob/master/data/STMicro/STM32F469.svd\n\n### Debug USB\n\n\u003e I use `wireshark` to inspect USB packets.\n\n```bash\n# Arch Linux\npacman -S wireshark-qt\n```\n\nTo enable USB sniffing, one needs to load `usbmon` kernel module. It's built in Linux kernel.\n\n```bash\nsudo modprobe usbmon\n```\n\nThen, run `wireshark` with `root` so that it can intercept USB packets.\n\n```bash\nsudo wireshark\n```\n\n##### Some useful filters :\n\n```c\n# Device address\nusb.device_address == 123\n  \n# Endpoint 1, IN direction\nusb.endpoint_address == 0x81\n  \n# Frame length. Valid feedback packet is 83 bytes (80 bytes header and 3 bytes data).\nframe.len == 83\n  \n# bRequest can be used to filter control packets\nusb.setup.bRequest == 11\n```\n\n### Useful commands\n\n* List USB devices\n\n```bash\n$ lsusb\nBus 002 Device 067: ID 0483:5730 STMicroelectronics Audio Speaker\n```\n\n* USB device details\n\n```bash\n$ lsusb -D /dev/bus/usb/002/067\nDevice: ID 0483:5730 STMicroelectronics Audio Speaker\nDevice Descriptor:\n  bLength                18\n  bDescriptorType         1\n  bcdUSB               2.00\n  bDeviceClass            0 \n  bDeviceSubClass         0 \n  bDeviceProtocol         0 \n  bMaxPacketSize0        64\n  idVendor           0x0483 STMicroelectronics\n  idProduct          0x5730 Audio Speaker\n  bcdDevice            2.00\n  iManufacturer           1 \n  iProduct                2 \n  iSerial                 3 \n  bNumConfigurations      1\n  Configuration Descriptor:\n    bLength                 9\n    bDescriptorType         2\n    wTotalLength       0x007c\n    bNumInterfaces          2\n    bConfigurationValue     1\n    iConfiguration          0 \n    bmAttributes         0xc0\n      Self Powered\n    MaxPower              100mA\n...\n```\n\n* Monitor audio playback status (change the `X` in `cardX` to the number of actual device)\n\n```bash\n$ watch -n 1 cat /proc/asound/cardX/stream0                                                    \nDragonode Audio Venus DAC at usb-0000:00:02.0-3, full speed : USB Audio\n\nPlayback:\n  Status: Running\n    Interface = 1\n    Altset = 2\n    Packet Size = 432\n    Momentary freq = 47569 Hz (0x2f.918c)\n    Feedback Format = 10.14\n  Interface 1\n    Altset 1\n    Format: S16_LE\n    Channels: 2\n    Endpoint: 1 OUT (ASYNC)\n    Rates: 44100, 48000, 96000\n  Interface 1\n    Altset 2\n    Format: S24_3LE\n    Channels: 2\n    Endpoint: 1 OUT (ASYNC)\n    Rates: 44100, 48000, 96000\n```\n\n* Kernel messages\n\n```bash\n$ dmesg\n[72898.617745] usb 2-1: new full-speed USB device number 67 using xhci_hcd\n[72898.759182] usb 2-1: New USB device found, idVendor=0483, idProduct=5730, bcdDevice= 2.00\n[72898.759188] usb 2-1: New USB device strings: Mfr=1, Product=2, SerialNumber=3\n[72898.759190] usb 2-1: Product: Venus DAC\n[72898.759193] usb 2-1: Manufacturer: Dragonode Audio\n```\n\n## Firmware Architecture\n\n* Incoming (USB) to outgoing (I2S) buffer chain (bit width, byte alignment, config) *TBD*\n  * USB buffer : 16-bit or 24-bit frame, little-endian -\u003e Audio buffer : 32-bit frame, right-aligned, little-endian -\u003e 32-bit DMA -\u003e SAI FIFO (32-bit width)\n* Feedback (method \u0026 algorithm) *TBD*\n  * Calculate by timer.\n  * Calculate by remaining buffer size.\n* USB Interrupts \u0026 data flow *TBD*\n* Relationship between USB class driver, main program, audio codec and SAI. *TBD*\n\n## Technical Highlight\n\n* `PCD_HandleTypeDef-\u003eInit-\u003eSof_enable` ([`Src/usbd_conf.c:274`](https://github.com/dragonman225/stm32f469-usbaudio/blob/9d58b8c0d2e16ad177b0d531f47a877ad5596508/Src/usbd_conf.c#L274)) must be 1 to enable SOF (Start-of-frame) interrupt.\n\n* The second parameter of `HAL_PCDEx_SetTxFiFo(\u0026hpcd, 1, 0x60)` ([`Src/usbd_conf.c:287`](https://github.com/dragonman225/stm32f469-usbaudio/blob/9d58b8c0d2e16ad177b0d531f47a877ad5596508/Src/usbd_conf.c#L287)) must be \u003e 0 so that there is FIFO to store Tx data (in this case, the feedback data). If it's 0, there will be bugs described [here](https://github.com/dragonman225/stm32f469-usbaudio/issues/1).\n\n* Feedback data byte order. *TBD*\n\n* When to recv / send data ? USB IN / OUT / SOF token. *TBD*\n\n* USB volume to Codec volume mapping. *TBD*\n\n* Extending 16-bit to 24-bit\n  \n  * DMA\n    \n    Set `DMA_HandleTypeDef.Init.PeriphDataAlignment` to `DMA_PDATAALIGN_WORD` and `DMA_HandleTypeDef.Init.MemDataAlignment` to `DMA_MDATAALIGN_WORD`.\n    \n    This means we need to wrap 24-bit audio sample in 32-bit structure.\n    \n    \u003e A DMA transaction consists of a sequence of a given number of data transfers. The number of data items to be transferred and their width (8-bit, 16-bit or 32-bit) are software-programmable. \n    \u003e \n    \u003e *RM0386 Reference Manual - 9.3.3 DMA transactions*\n    \n  * SAI\n  \n    Set `SAI_HandleTypeDef.Init.DataSize` to `SAI_DATASIZE_24`.\n  \n    Set `SAI_HandleTypeDef.FrameInit.FrameLength` to `128`.\n  \n    Set `SAI_HandleTypeDef.FrameInit.ActiveFrameLength` to `64`.\n  \n  * USB\n  \n    * Set `USBD_MAX_NUM_INTERFACES`(`Inc/usbd_conf.h:58`) to `2`.\n  \n    * Add an **Audio Streaming Interface Descriptor** with `bAlternateSetting` set to `2`.\n  \n      Set `bSubFrameSize` to `0x03` and `bBitResolution` to `0x18`.\n      \n    * Open OUT EP with max packet size of 24-bit / 96 kHz\n      ```c\n      USBD_LL_OpenEP(pdev, AUDIO_OUT_EP, USBD_EP_TYPE_ISOC, AUDIO_OUT_PACKET_24B);\n      ```\n      \n    * Handle `SET_INTERFACE` request in **Setup** stage. e.g. Set a flag to let other processes know it's 24-bit data.\n  \n    * Extend 16-bit or 24-bit data to 32-bit\n  \n      Note that ARM is little-endian. Consider the following :\n  \n      ```c\n      uint8_t tmpbuf[2] = { 0x34, 0x12 };\n      // *(uint16_t*)\u0026tmpbuf[0] is 0x1234\n      ```\n  \n    * USB Device Rx FIFO size must be sufficiently large ( \u003e Max audio payload size + USB Header ). At the same time Tx FIFO size may need to be shrunk so that total FIFO size doesn't exceed the limit (In Full-speed : 1.25 Kbytes, 0x140 words). [Ref : *STM32 Cube USB Host wmaxpacketsize problem*](https://community.st.com/s/question/0D50X00009XkglOSAR/stm32-cube-usb-host-wmaxpacketsize-problem)\n  \n      ```c\n      HAL_PCDEx_SetRxFiFo(\u0026hpcd, 0x110);\n      HAL_PCDEx_SetTxFiFo(\u0026hpcd, 1, 0x10);\n      ```\n\n## Background Knowledge\n\n### USB \u0026 USB Audio Class\n\n* [Асинхронное USB аудио на STM32](http://we.easyelectronics.ru/electro-and-pc/asinhronnoe-usb-audio-na-stm32.html) I follow most of the steps in this forum post except for using timer to calculate feedback values.\n* [borgestrand/sdr-widget](https://github.com/borgestrand/sdr-widget/blob/audio-widget/src/uac1_device_audio_task.c) An USB audio class implementation for Atmel AT32UC3A3. They use remaining buffer size to calculate feedback data, which is easier and more portable since it doesn't require specific hardware feature like the timer solution.\n* [USB Specification v1.1](http://esd.cs.ucr.edu/webres/usb11.pdf)\n  * **5.10.4.2 Feedback** - Describe the 10.14 format and explain the theory to calculate feedback data using a timer. (So, the timer solution is actually the *standard* answer.)\n  * **Chapter 8 Protocol Layer** - Get concepts about USB packet and transaction.\n  * [USB Made Simple](http://www.usbmadesimple.co.uk/index.html) has a simplified version that is easier to read.\n* [USB Device Class Definition for Audio Devices v1.0](https://www.usb.org/sites/default/files/audio10.pdf) For writing audio class descriptors and class-specific control logic.\n* [成大資工 Wiki - USB](http://wiki.csie.ncku.edu.tw/embedded/USB) USB 基礎介紹（中文）\n* [USB Audio 簡介 (UAC 1.0)](https://blog.csdn.net/xjq163/article/category/7041844) （中文）\n* [USB 之一 USB2.0 规范详解 第一部分](https://blog.csdn.net/ZCShouCSDN/article/details/79957404) 簡化版的 [USB Specification v2.0](https://www.usb.org/document-library/usb-20-specification)（中文）\n* [UAC2 Feedback Mechanism](https://github.com/borgestrand/sdr-widget/blob/d6671c839e7b513bdfd833afe3bb57a58a04dafe/AW_readme.txt#L945)\n\n### STM32\n\n* [UM1021 STM32 USB OTG Library User Manual](https://www.st.com/content/ccc/resource/technical/document/user_manual/1c/6b/06/e6/19/6c/46/bf/CD00289278.pdf/files/CD00289278.pdf/jcr:content/translations/en.CD00289278.pdf) The architecture of ST's USB library and how to use it.\n\n* [STM32 之三 标准外设版USB驱动库详解](https://blog.csdn.net/ZCShouCSDN/article/details/78936456) 大致與 UM1021 的內容相同（中文）\n\n* [UM1725 Description of STM32F4 HAL and LL drivers](https://www.st.com/content/ccc/resource/technical/document/user_manual/2f/71/ba/b8/75/54/47/cf/DM00105879.pdf/files/DM00105879.pdf/jcr:content/translations/en.DM00105879.pdf) Chapter 47 and 48 are USB-related. The UM1201 USB library relies on these drivers to do low level work.\n\n* [RM0386 STM32F469xx and STM32F479xx Reference Manual](https://www.st.com/content/ccc/resource/technical/document/reference_manual/29/77/09/5a/b1/60/4e/bd/DM00127514.pdf/files/DM00127514.pdf/jcr:content/translations/en.DM00127514.pdf) The documentation for the MCU itself, it's mostly about peripheral registers. HAL and LL drivers translate software commands to electrical actions by manipulating these registers. \n\n  **Important chapters :**\n\n  * **9 Direct memory access controller (DMA)**\n  * **32 Serial audio interface (SAI)**\n  * **35 USB on-the-go full-speed/high-speed (OTG_FS/OTG_HS)**\n\n* [ChibiOS forum - Usage of USB driver in isochronous mode (STM32)](http://www.chibios.com/forum/viewtopic.php?f=16\u0026t=926) Register level details about gotchas in implementing audio class with STM32 USB hardware stack. After some investigations, I think the problems described there seem to be solved in the latest STM32F4xx LL / HAL driver.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdragonman225%2Fstm32f469-usbaudio","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdragonman225%2Fstm32f469-usbaudio","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdragonman225%2Fstm32f469-usbaudio/lists"}