本篇是此系列的最后一篇,重点是SAI(Serial audio interface).
前奏介绍
众所周知,声频、视频是人机界面的核心部分,有了它们,计算机的人性化、亲和感才会大大提升。从某个角度看,视频数据的处理表达已经变得容易多了,而声频数据表达要求的时间精确均匀的数据流,总是让人甚感棘手。嵌入处理器支持使用DAM的SAI接口使得声频在嵌入系统的CPU占用大大降低。
简单地看,SAI就像是连两个更全面的I2S总线构成(顺便说一句,各种串行通讯方式已经成为学习掌握嵌入系统的基本功夫,先学习SPI可以建立一个很好的基础)。对于声频数据传输,满足声频信息中包含的各种取样频率的要求,就是声频数据传输和普通SPI的一个重要不同点。通常SAI用于在播放解码和录音编码芯片之间建立通讯接口。
如图是 STM32F7的SAI功能图:
下图是STM32F7的I2S功能块图:
可以看出STM32F7的SAI有两个独立可配置的通道,带有FIFO、帧同步异步、时钟发生、主从模式、声频格式、DMA和中断等全面支持。每个通道主要有四信号线:数据、时钟、帧同步、主模式时钟(用于和外部编码解码芯片的时序协调,STM32F769-DISCO使用的声频处理芯片是WM8994)。
代码例子:
这里我们通过例子BSP例程(STM32F7xx_DFP\2.8.0\Projects\STM32F769I-Discovery\Examples\BSP)的一部分Audio-Player来说明SAI的工作方式。例子代码见附件,解压到STM32F7xx_DFP\2.8.0\Projects\STM32F769I-Discovery\Example下使用。
主程序:
- int main(void)
- {
- uint8_t lcd_status = LCD_OK;
- MPU_Config();
- CPU_CACHE_Enable();
- HAL_Init();
- SystemClock_Config();
- BSP_LED_Init(LED_GREEN);
- BSP_LED_Init(LED_RED);
- BSP_PB_Init(BUTTON_WAKEUP, BUTTON_MODE_GPIO);
- lcd_status = BSP_LCD_Init();
- while(lcd_status != LCD_OK);
- BSP_LCD_LayerDefaultInit(0, LCD_FB_START_ADDRESS);
- BSP_LCD_Clear(LCD_COLOR_WHITE);
- //以上所有例程序几乎一样,无需解释。详细学习,直接研究STM32F7xx_DFP\2.8.0\Projects\STM32F769I-Discovery\Examples\BSP
-
- while (1)
- AudioPlay_demo(); // 我们这里只分析这个例子。
- }
AudioPlay_Demo()第一部分,初始化:主要是LCD界面!!
- void AudioPlay_demo (void)
- {
- uint32_t *AudioFreq_ptr;
- AudioFreq_ptr = AudioFreq+6; /*AF_48K*/
- uint8_t frequency_str[256] = {0};
- uint8_t volume_str[256] = {0};
- uint8_t ts_status = TS_OK;
- Point Points2[] = {{100, 140}, {160, 180}, {100, 220}};
- uwVolume = 40;
- Audio_SetHint();
- BSP_LCD_SetFont(&Font20);
- ts_status = BSP_TS_Init(BSP_LCD_GetXSize(), BSP_LCD_GetYSize());
- if (ts_status != TS_OK)
- {
- BSP_LCD_SetBackColor(LCD_COLOR_WHITE);
- BSP_LCD_SetTextColor(LCD_COLOR_RED);
- BSP_LCD_DisplayStringAt(0, BSP_LCD_GetYSize() - 95, (uint8_t *)"ERROR", CENTER_MODE);
- BSP_LCD_DisplayStringAt(0, BSP_LCD_GetYSize() - 80, (uint8_t *)"Touch Screen cannot be initialized", CENTER_MODE);
- }
- /*<b><font color="#0000ff"> SAI初始化</font></b>*/
- if(<b><font color="#0000ff">BSP_AUDIO_OUT_Init</font></b>(OUTPUT_DEVICE_BOTH, uwVolume, *AudioFreq_ptr) == 0)
- {
- BSP_LCD_SetBackColor(LCD_COLOR_WHITE);
- BSP_LCD_SetTextColor(LCD_COLOR_GREEN);
- BSP_LCD_DisplayStringAt(0, BSP_LCD_GetYSize() - 95, (uint8_t *)" AUDIO CODEC OK ", CENTER_MODE);
- }
- else
- {
- BSP_LCD_SetBackColor(LCD_COLOR_WHITE);
- BSP_LCD_SetTextColor(LCD_COLOR_RED);
- BSP_LCD_DisplayStringAt(0, BSP_LCD_GetYSize() - 95, (uint8_t *)" AUDIO CODEC FAIL ", CENTER_MODE);
- BSP_LCD_DisplayStringAt(0, BSP_LCD_GetYSize() - 80, (uint8_t *)" Try to reset board ", CENTER_MODE);
- }
/* Play audio on slots 0 and 2 */
-
- BSP_AUDIO_OUT_SetAudioFrameSlot(CODEC_AUDIOFRAME_SLOT_02);
-
- AUDIO_Start((uint32_t *)AUDIO_SRC_FILE_ADDRESS, (uint32_t)AUDIO_FILE_SIZE);
-
- //开始播放,播放的声频文件audio_sample_tdm.bin在\Binary目录,事先用ST-Link utility写入flash地址0x08080000
- /* Display the state on the screen */
- BSP_LCD_SetBackColor(LCD_COLOR_WHITE);
- BSP_LCD_SetTextColor(LCD_COLOR_BLUE);
- BSP_LCD_DisplayStringAt(0, LINE(8), (uint8_t *)" PLAYING... changed by okwh at eeworld ", CENTER_MODE);
- sprintf((char*)volume_str, " VOL: %3ld ", uwVolume);
- BSP_LCD_DisplayStringAt(0, LINE(9), (uint8_t *)volume_str, CENTER_MODE);
- sprintf((char*)frequency_str, " FREQ: %6ld ", *AudioFreq_ptr);
- BSP_LCD_DisplayStringAt(0, LINE(10), (uint8_t *)frequency_str, CENTER_MODE);
- BSP_LCD_SetFont(&Font16);
- BSP_LCD_DisplayStringAt(0, BSP_LCD_GetYSize() - 40, (uint8_t *)"Write audio_sample_tdm.bin' in Binary to @0x08080000 of flash using ST-Link utility", CENTER_MODE);
- if(ts_status == TS_OK)
- {
- /* Set touchscreen in Interrupt mode and program EXTI accordingly on falling edge of TS_INT pin */
- ts_status = BSP_TS_ITConfig();
- BSP_TEST_APPLI_ASSERT(ts_status != TS_OK);
- Touchscreen_DrawBackground_Circles(16);
- }
- BSP_LCD_SetFont(&Font20);
- /* Audio is playing */
- BSP_LCD_SetTextColor(LCD_COLOR_WHITE);
- BSP_LCD_FillPolygon(Points2, 3);
- BSP_LCD_SetTextColor(LCD_COLOR_BLACK);
- BSP_LCD_FillRect(100, 140, 25 , 80);
- BSP_LCD_FillRect(140, 140, 25 , 80);
- while (1)
- {
- ...........略,主要是处理user按键,实现播放速度、音量控制
此例使用BSP_AUDIO_OUT_Init初始化SAI, 在AUDIO_Start先读取复制缓冲区大小的数据到整个环形缓冲区,并用BSP_AUDIO_OUT_Play设置DMA从缓冲区传送数据到SAI开始播放,播放中将使用BSP_AUDIO_OUT_xxxTransfer_CallBack更新赋值缓冲区半满全空标志。
系统时钟中断SysTick_Handler用 AUDIO_Process判断缓冲区标志,用GetData读取在flash的声频数据到缓冲区,
使用环形缓冲区(AUDIO_BufferTypeDef buffer_ctl)逐步从flash取得后续声频数据填充缓冲区,如此保证播放,
视频: 触摸控制播放的音量和频率
本例代码
本系列:
点击此处,查看STM32F769I开发板官方资源。 本帖最后由 okwh 于 2017-1-5 13:48 编辑