这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 嵌入式开发 » STM32 » 【STM32F469I-DISCO】驱动音频CS43L22

共5条 1/1 1 跳转至

【STM32F469I-DISCO】驱动音频CS43L22

工程师
2025-04-20 11:53:44     打赏

【前言】

在前面,我驱动了SD卡并实现在fatfs功能,这一篇分享如何驱动音频。

【硬件】

在开发板的原理图上,可以看到我们这块开发板使用的音频为CS43L22如下图所示:

image.png

【驱动移植】

驱动有很多例子都是在用的,比如\STM32Cube_FW_F4_V1.26.2\Projects\STM32469I-Discovery\Applications\Audio\Audio_playback_and_record以及STM32Cube_FW_F4_V1.26.2\Projects\STM32469I-Discovery\Examples\BSP都有他的驱动的。

经分析这两个例子,都是使用了官方的驱动,他的驱动在:\STM32Cube_FW_F4_V1.26.2\Drivers\BSP\STM32469I-Discovery,当然还需要调用STM32Cube_FW_F4_V1.26.2\Drivers\BSP\Components\cs43l22下的驱动。

1、引入cs43l22.c到工程Drivers/BSP/Components下面,同时把板载audio驱动stm32f469_discovery_audio.c引入到工程的/Drivers/BSP/STM32f469-Discovery目录下面:

image.png

2、复制示例STM32Cube_FW_F4_V1.26.2\Projects\STM32469I-Discovery\Examples\BSP\Src下面的audio_play.c到工程User目录下面:

image.png

3、在stm32f4xx_it.c中添加audio的dma中断函数:

void AUDIO_I2Sx_DMAx_IRQHandler(void)
{
  HAL_DMA_IRQHandler(haudio_in_i2s.hdmarx);
}

void AUDIO_SAIx_DMAx_IRQHandler(void)
{
  HAL_DMA_IRQHandler(haudio_out_sai.hdmatx);
}


4、原先读取的是rom里面的数据,在这个工程中,需要修改为读取sd卡中的wav数据。

因此修改代码如下:

/**
  ******************************************************************************
  * @file    BSP/Src/audio.c_play
  * @author  MCD Application Team
  * @brief   This example code shows how to use the audio feature in the
  *          stm32469i_discovery driver
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; COPYRIGHT(c) 2017 STMicroelectronics</center></h2>
  *
  * Redistribution and use in source and binary forms, with or without modification,
  * are permitted provided that the following conditions are met:
  *   1. Redistributions of source code must retain the above copyright notice,
  *      this list of conditions and the following disclaimer.
  *   2. Redistributions in binary form must reproduce the above copyright notice,
  *      this list of conditions and the following disclaimer in the documentation
  *      and/or other materials provided with the distribution.
  *   3. Neither the name of STMicroelectronics nor the names of its contributors
  *      may be used to endorse or promote products derived from this software
  *      without specific prior written permission.
  *
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  ******************************************************************************
  */

/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include <stdio.h>

/** @addtogroup STM32F4xx_HAL_Examples
  * @{
  */

/** @addtogroup BSP
  * @{
  */

/* Private typedef -----------------------------------------------------------*/

/* Private define ------------------------------------------------------------*/

/*Since SysTick is set to 1ms (unless to set it quicker) */
/* to run up to 48khz, a buffer around 1000 (or more) is requested*/
/* to run up to 96khz, a buffer around 2000 (or more) is requested*/
#define AUDIO_DEFAULT_VOLUME    70

/* Audio file size and start address are defined here since the audio file is
   stored in Flash memory as a constant table of 16-bit data */
#define AUDIO_START_OFFSET_ADDRESS    0            /* Offset relative to audio file header size */
#define AUDIO_BUFFER_SIZE            
extern float AudioCurrentTime;

/* Private typedef -----------------------------------------------------------*/
typedef enum {
AUDIO_STATE_IDLE = 0,
AUDIO_STATE_INIT,
AUDIO_STATE_PLAYING,
}AUDIO_PLAYBACK_StateTypeDef;

typedef enum {
BUFFER_OFFSET_NONE = 0,
BUFFER_OFFSET_HALF,
BUFFER_OFFSET_FULL,
}BUFFER_StateTypeDef;

typedef struct {
uint8_t buff[AUDIO_BUFFER_SIZE];
uint32_t fptr;
BUFFER_StateTypeDef state;
uint32_t AudioFileSize;
uint32_t *SrcAddress;
}AUDIO_BufferTypeDef;

typedef enum {
TS_ACT_NONE = 0,
TS_ACT_FREQ_DOWN,
TS_ACT_FREQ_UP,
TS_ACT_VOLUME_DOWN,
TS_ACT_VOLUME_UP,
TS_ACT_PAUSE = 0xFE
}TS_ActionTypeDef;

/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
static AUDIO_BufferTypeDef  buffer_ctl;
static AUDIO_PLAYBACK_StateTypeDef  audio_state;
__IO uint32_t uwVolume = 50;
__IO uint32_t uwPauseEnabledStatus = 0;

/* Private function prototypes -----------------------------------------------*/

uint32_t GetData(void *pdata, uint32_t offset, uint8_t *pbuf, uint32_t NbrOfData);

extern uint32_t AudioFre;
extern char* pDirectoryFiles[MAX_BMP_FILES];
extern uint8_t corruntPlayingFileNo;
	
/* Private functions ---------------------------------------------------------*/

/**
  * @brief  Starts Audio streaming.
  * @param  None
  * @retval Audio error
  */
AUDIO_ErrorTypeDef AUDIO_Play_Start(uint32_t *psrc_address, uint32_t file_size)
{
uint32_t bytesread;

buffer_ctl.state = BUFFER_OFFSET_NONE;
buffer_ctl.AudioFileSize = file_size;
buffer_ctl.SrcAddress = psrc_address;

bytesread = GetData( (void *)psrc_address,
0,
&buffer_ctl.buff[0],
AUDIO_BUFFER_SIZE);
if(bytesread > 0)
{
BSP_AUDIO_OUT_Play((uint16_t *)&buffer_ctl.buff[0], AUDIO_BUFFER_SIZE);
audio_state = AUDIO_STATE_PLAYING;
buffer_ctl.fptr = bytesread;
return AUDIO_ERROR_NONE;
}
return AUDIO_ERROR_IO;
}

/**
  * @brief  Manages Audio process.
  * @param  None
  * @retval Audio error
  */
uint8_t AUDIO_Play_Process(void)
{
uint32_t bytesread;
AUDIO_ErrorTypeDef error_state = AUDIO_ERROR_NONE;
switch(audio_state)
{
case AUDIO_STATE_PLAYING:
if(buffer_ctl.fptr >= buffer_ctl.AudioFileSize)
{
/* Play audio sample again ... */
buffer_ctl.fptr = 0;
error_state = AUDIO_ERROR_EOF;
}
/* 1st half buffer played; so fill it and continue playing from bottom*/
if(buffer_ctl.state == BUFFER_OFFSET_HALF)
{
			AudioCurrentTime+=(float)AUDIO_BUFFER_SIZE/(8*(float)AudioFre);
bytesread =8*1024;
Storage_OpenRead_8KB_File(&buffer_ctl.buff[0], pDirectoryFiles[corruntPlayingFileNo]);
if( bytesread >0)
{
buffer_ctl.state = BUFFER_OFFSET_NONE;
buffer_ctl.fptr += bytesread;
}
}
/* 2nd half buffer played; so fill it and continue playing from top */
if(buffer_ctl.state == BUFFER_OFFSET_FULL)
{
			AudioCurrentTime+=(float)AUDIO_BUFFER_SIZE/(8*(float)AudioFre);
		bytesread =8*1024;
Storage_OpenRead_8KB_File(&buffer_ctl.buff[AUDIO_BUFFER_SIZE /2], pDirectoryFiles[corruntPlayingFileNo]);
if( bytesread > 0)
{
buffer_ctl.state = BUFFER_OFFSET_NONE;
buffer_ctl.fptr += bytesread;
}
}
break;
default:
error_state = AUDIO_ERROR_NOTREADY;
break;
}
return (uint8_t) error_state;
}
/*------------------------------------------------------------------------------
       Callbacks implementation:
           the callbacks API are defined __weak in the stm32469i_discovery_audio.c file
           and their implementation should be done the user code if they are needed.
           Below some examples of callback implementations.
  ----------------------------------------------------------------------------*/
/**
  * @brief  Manages the full Transfer complete event.
  * @param  None
  * @retval None
  */
void BSP_AUDIO_OUT_TransferComplete_CallBack(void)
{
if(audio_state == AUDIO_STATE_PLAYING)
{
/* allows AUDIO_Play_Process() to refill 2nd part of the buffer  */
buffer_ctl.state = BUFFER_OFFSET_FULL;
}
}

/**
  * @brief  Manages the DMA Half Transfer complete event.
  * @param  None
  * @retval None
  */
void BSP_AUDIO_OUT_HalfTransfer_CallBack(void)
{
if(audio_state == AUDIO_STATE_PLAYING)
{
/* allows AUDIO_Play_Process() to refill 1st part of the buffer  */
buffer_ctl.state = BUFFER_OFFSET_HALF;
}
}

/**
  * @brief  Manages the DMA FIFO error event.
  * @param  None
  * @retval None
  */


/**
  * @brief  Gets Data from storage unit.
  * @param  None
  * @retval None
  */
uint32_t GetData(void *pdata, uint32_t offset, uint8_t *pbuf, uint32_t NbrOfData)
{
uint8_t *lptr = pdata;
uint32_t ReadDataNbr;

ReadDataNbr = 0;
while(((offset + ReadDataNbr) < buffer_ctl.AudioFileSize) && (ReadDataNbr < NbrOfData))
{
pbuf[ReadDataNbr]= lptr [offset + ReadDataNbr];
ReadDataNbr++;
}
return ReadDataNbr;
}


/**
  * @}
  */

/**
  * @}
  */

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

6、在这个函数中,我们采用i2s dma传输,采用半传输中断与传输完中断,在不同的中断产生后,我们向缓冲区读入数据来实现不间隔断的播放功能。





关键词: STM32F469I-DISCO     Audio    

专家
2025-04-20 14:53:02     打赏
2楼

感谢分享


专家
2025-04-20 15:36:12     打赏
3楼

感谢分享


专家
2025-04-20 19:35:40     打赏
4楼

感谢分享


专家
2025-04-21 07:49:12     打赏
5楼

谢谢分享


共5条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]