嘗試結合STM32F401的ADC, PWM, SPI(NRF24L01)和TIM, 試驗了一下音頻的無線傳輸(對講機原型)
工作機制
音頻采樣
因為硬件的限制, 包括STM32F401片內存儲, 內存大小, PWM頻率, 以及之前實際測試NRF24L01得到的經驗數據, 采樣使用了最基礎的8bit分辨率, 采樣頻率為16KHz附近
- SYSCLK使用25MHz, APB2CLK使用一半頻率, 即12.5MHz
- ADC在APB2CLK基礎上8分頻, 所以ADC時鍾為12.5MHz/8
- ADC使用8bit分辨率, 對應11個ADC時鍾, 采樣周期設置為84, 所以每次采樣為95個ADC周期, 這樣實際采樣頻率為 12500000 / 8 / 95 = 16,447 Hz, 接近16KHz
- 使用ADC2DMA, DMA使用一個32byte大小的uint8_t數組
無線傳輸
- 使用fastwrite機制, 即一直保持在發狀態, 只要FIFO TX隊列未滿就一直往里寫, 如果滿了就檢查MAX_RT標志位, 如果置位則拉低再拉高CE重置發送狀態
- 采樣端使用DMA的傳輸完成中斷, 對應32個byte的DMA內存, 每次采集滿32個byte都會觸發中斷, 此時調用NRF24L01進行發送
- 接收端使用IRQ中斷接收, 創建一個128Byte的接收數組, 循環寫入. 每次接收中斷就往里面寫32個byte, 往后增長, 到右邊界后再從0開始
音頻輸出
- 接收端也使用25MHz的SYSCLK
- 接收端啟用PWM輸出, 輸出分辨率為8bit
- 接收端啟用Prescaler=0, Period=1561的定時器TIM3, 這個配置對應的頻率為 25000000 / (0 + 1)(1561 + 1) = 16,005 Hz, 接近16KHz. (注: 這里頻率選擇有些問題, 應該要比發送端頻率略高, 這樣才能保證在持續發送中, 播放不被接收打斷)
- 每次定時器觸發中斷, 都會在128byte的接收數組中檢查是否有新數據, 有則前進一格並以此值修改PWM占空比, 無則跳過. 如果已經到達數組右邊界則返回到數組0下標.
電路
輸入端電路
輸入端使用一個駐極體二極管加S9014組成簡單的放大電路.
輸出端電路
輸出端先經過以及RC低通濾波(R=20, C=10uF), 再使用PAM8403進行放大
項目代碼
項目代碼在Github: https://github.com/IOsetting/stm32f4-hal-projects/tree/main/Projects/WalkieTalkieDemo
可以使用Keil5 MDK打開和編譯
測試記錄
- 采樣: 采樣工作正常, 觀察輸出可以看到有動靜時采樣值的變化
- 傳輸: 僅在10米以內距離測試, 出現MAX_RT標志的比例很小, 至少從16KHz采樣, 32byte一個package的發送速率看, 發送和接收都不是瓶頸. 當有牆體阻擋時錯誤率上升明顯
- 播放: 背景噪音大, 在近距離時容易互相干擾產生嘯叫. 播放效果較差, 沙沙聲明顯. 在加入低通濾波后能聽清人聲, 但是依然未能達到"能聽"的水平.
電路部分原型
電路部分原型
發送端
下一步
因為傳輸不是瓶頸, 所以改進的方向主要是音質. 可能需要從幾個方面進行排查:
- 播放方面. 這塊是比較容易排查的, 比如使用單頻音源輸出, 使用預錄的音源輸出, 需要評估使用多高的PWM頻率以及RC濾波參數能達到可接受的播放效果
- 采樣方面. 如果有示波器會很方便, 沒有示波器的話, 只能通過ADC采樣的輸出來判斷, 需要寫代碼將數組輸出到存儲, 需要加一些片外存儲