2026年8月15日 星期六

STM32F4 and Audio Card Interface (Mic/Spk) to USB (Windows/Linux) - PCM5102A

本章內容說明 STM32 上的 USB Library 建立單個連線開出多個 USB 介面的方式以及 Linux 下的UART Serial Port 模式支援的驅動編譯和執行。


目標

  1. 說明 USB CDC / Interface 原理
  2. 建立多組 USB Interface 
  3. 如何同時支援 Windows / Linux 免驅動模式
  4. Linux 下的不支援的 UART 模式,透過寫驅動編譯後執行達到支援效果
  5. STM32F4 燒錄方式
  6. 音效卡焊接方式
  7. 接線方式
  8. 效果展示


USB CDC

USB CDC 是  USB 裝置類別的其中一種 (USB Device Class),是主機模式和周邊裝置互動的協議規範,其他還有 USB HID, USB MSC...etc 

CDC: Communication Device Class 就是指通訊裝置類的規範,本篇主要目的是音訊通訊和文字訊號通訊,所以特別說明 CDC 意義。


USB Interface

USB Interface 就是接上電腦後會出現的裝置,一個 USB 可以開出多個複合裝置,比方說同時是麥克風又是喇叭,又是其他的東西。  主機的話由於一個 USB 硬體控制器內部可分配地址是 7 位元 (2^7) 大約可以分配 128 地址給 USB,而 USB 硬體的話通常是受限於晶片內部用於傳輸資料的 Packet Buffer,一次開 10 幾個會衝爆那個 Buffer,所以是一個物理導致的上限。


在這裡開出 Interface 則是:

  • CDC Communication / 通訊 / 控制 (1 組)
  • CDC Data 用的 bulk in / OUT Interface (2 組)
  • Audio Control (控制音訊設備) (1 組)
  • Audio Streaming In (1 組)
  • Audio Streaming Out (1 組)

其中在系統內體現的裝置有:

  1. speaker
  2. mic
  3. UART COM

三個,體現的裝置跟 Interface 沒有直接關連,Interface 只是定義訊號傳輸的 channel,實際上在 CDC Communication 那組線通訊時就會有 USB Description 行為,告訴電腦有幾個裝置要註冊了。

硬體方面,開機時是按照這個方式啟動硬體的:

HAL_Init
SystemClock_Config                 -> USB clock 48 MHz
UART_Bridge_Init                   -> USART1 PA9/PA10
AudioIn_Init                       -> ADC/TIM3/DMA,尚未開始取樣
AudioOut_Init                      -> I2S2/DMA/PLLI2S,尚未開始播放
MX_USB_DEVICE_Init


int main(void)
{
  HAL_Init();
  SystemClock_Config();
  LED_GPIO_Init();

  LOG("=== usb-exp boot ===");
  LOG("SYSCLK=%lu Hz, HCLK=%lu Hz", (unsigned long)HAL_RCC_GetSysClockFreq(),
      (unsigned long)HAL_RCC_GetHCLKFreq());

  UART_Bridge_Init(); // COM Port 或是其他裝置
  AudioIn_Init();
  AudioOut_Init();   /* I2S2 播放路徑(喇叭),要在 USB 之前初始化好 */
  MX_USB_DEVICE_Init();
  LOG("USB device started, waiting for host enumeration");



又,MX_USB_DEVICE_Init 針對這個流程啟動,最後才會出現 USB 裝置 (因為 enumeration 是根據主機來列舉的):

1. USBD_Init(&hUsbDeviceFS, &FS_Desc, DEVICE_FS) 建立 device handle、接上 descriptor 與 low-level OTG FS。
2. USBD_RegisterClass(&hUsbDeviceFS, &USBD_CDC_AUDIO) 把自訂 class callback table 綁到 device core。這個 class table 的 descriptor 由 USBD_CDC_AUDIO_GetCfgDesc() 回傳。
3. USBD_CDC_RegisterInterface(&hUsbDeviceFS, &USBD_Interface_fops_FS) 把 CDC application callbacks 放到 pdev->pUserData[pdev->classId]。
4. USBD_Start(&hUsbDeviceFS) 開始 USB peripheral,等待 host reset、descriptor request 與   enumeration。

其他 USB 標準的流程就不在此篇贅述,後面也許會在寫另一篇文章紀錄 USB 開發。


外接裝置

  • PCM5120A

這是一個 PCM 轉類比 Audio 的模組,主要是因為主機傳來的信號是 PCM,需要解碼為類比訊號,則會透過這個模組處理 DAC 的部分。


焊接方式

PCM5120A 如果是開發版時,需要特別注意在音訊控制上原廠有留空接的線路,分別是 H1L, H2L, H3L, H4L,H 是高電位、L 是低電位,在這裡需要特別焊接來控制初始設定。


SCK 的部分是要直接接地,建議也可以加一個 1k 電阻後接地。



背面的部分,控制分別是:

1 -> L
2 -> L
3 -> H
4 -> L

其實這裡就是側排控制的方便接點。

然後在接線方面:

  • SCK -> GND
  • BCK -> I2S2_CK 位元時脈
  • LRCK -> I2S2_WS 左右聲道時脈(frame clock)
  • DIN -> 主機發出的 PCM 訊號 OUT 接到這裏的 IN
  • VIN -> 3.3V
  • GND -> GND

COM / UART tty 支援

接上 USB 後,對於 COM Port (UARD) 控制部分,Windows 可以列出,Linux 不一定可以,但需要先打開 kernel 驅動:


./build.sh kernelconfig

CONFIG_USB_ACM=y


打開之後只需要重新編譯 kernel 即可

./build.sh kernel

然後燒錄到 linux 機器上。


如果 linux 機器不支援,就要自己寫 linux 驅動來註冊 tty:

static int __init usbexp_init(void)

{

int ret;


ret = my_usb_tty_init();    // <--- 註冊

if (ret)


這裡也暫時不贅述,寫驅動後要編譯成 .ko 或是打包到 kernel 上 porting 也可以,如果是 .ko 檔案的話就是在系統上執行 insmod xxx.ko 。


STM 燒錄方式

使用 STM32Cube IDE 開發完後,會編譯出 elf / obj 檔案,然後有兩種燒錄方式: 

1. STLink USB: 直接接上後,在 IDE 上就可以 Debug download (需要另外買 STLink)

2. USB DFU: 需要下載 STM32Cube Programmer 連上機器後,按著 boot + reset 放開 reset 進入下載模式,然後選擇 USB 連線後,就可以下載。




沒有留言:

張貼留言

© Mac Taylor, 歡迎自由轉貼。
Background Email Pattern by Toby Elliott
Since 2014