【MM32F5270开发板试用】播放TF卡WAV格式音乐,I2S驱动CS4344

上四篇文章:
【MM32F5270开发板试用】一、依靠SPI_SD,移植FatFs文件系统
【MM32F5270开发板试用】SysTick+Scheduler轮询
【MM32F5270开发板试用】如何将数据存放在DTCM
【MM32F5270开发板试用】依靠SPI_SD,移植FatFs文件系统(优化版本)
本次所有代码按照以前习惯全部开源:我的Github地址是:https://github.com/kings669/MM32F5

代码比较多,一篇文章也放不下,大家可以直接Clone下代码看就行。

一、I2S总线

I2S(Inter—IC Sound)总线, 又称
集成电路内置音频总线,是飞利浦公司为数字音频设备之间的音频数据传输而制定的一种总线标准,该总线专门用于音频设备之间的数据传输,广泛应用于各种多媒体系统。它采用了沿独立的导线传输时钟与数据信号的设计,通过将数据和时钟信号分离,避免了因时差诱发的失真,为用户节省了购买抵抗音频抖动的专业设备的费用。

在MM32F5270中,SPI与I2S共用引脚。在I2S的描述中,支持半双工通信,也支持全双工模式(通过配置 SPI_I2S_I2SCFGR.HDSEL 位来决定)。

在看一下引脚定义:

我们发送给CS4344的格式是飞利浦标准

我们需要配置为主模式,具体流程可以参考手册。

驱动代码部分

void I2S_Configure(I2S_Protocol_Type   Standard,I2S_DataWidth_Type DataFormat,uint32_t AudioFreq,I2S_XferMode_Type Mode)
{/* Setup the I2S. */I2S_Master_Init_Type i2s_master_init;i2s_master_init.ClockFreqHz  = CLOCK_APB1_FREQ;i2s_master_init.SampleRate   = AudioFreq;i2s_master_init.DataWidth    = DataFormat;i2s_master_init.Protocol     = Standard;i2s_master_init.EnableMCLK   = true;i2s_master_init.Polarity     = I2S_Polarity_1;i2s_master_init.XferMode     = Mode;I2S_InitMaster(SPI2, &i2s_master_init);I2S_EnableDMA(SPI2, true);I2S_Enable(SPI2, true);
}void I2S_DMA_Transfer(uint16_t *Buffer, uint32_t BufferSize)
{/* Setup the DMA for I2S RX. */DMA_Channel_Init_Type dma_channel_init;dma_channel_init.MemAddr           = (uint32_t)(Buffer);dma_channel_init.MemAddrIncMode    = DMA_AddrIncMode_IncAfterXfer;dma_channel_init.PeriphAddr        = I2S_GetTxDataRegAddr(SPI2);  /* use tx data register here. */dma_channel_init.PeriphAddrIncMode = DMA_AddrIncMode_StayAfterXfer;dma_channel_init.Priority          = DMA_Priority_Highest;dma_channel_init.XferCount         = BufferSize;dma_channel_init.XferMode          = DMA_XferMode_MemoryToPeriph;dma_channel_init.ReloadMode        = DMA_ReloadMode_AutoReload;             /* DMA_AutoReloadMode_Circular */dma_channel_init.XferWidth         = DMA_XferWidth_16b;DMA_InitChannel(DMA1, DMA_REQ_DMA1_SPI2_TX, &dma_channel_init);/* Enable DMA transfer done interrupt. */DMA_EnableChannelInterrupts(DMA1, DMA_REQ_DMA1_SPI2_TX, DMA_CHN_INT_XFER_DONE, true);DMA_EnableChannelInterrupts(DMA1, DMA_REQ_DMA1_SPI2_TX, DMA_CHN_INT_XFER_HALF_DONE, true);NVIC_EnableIRQ(DMA1_CH5_IRQn);DMA_EnableChannel(DMA1, DMA_REQ_DMA1_SPI2_TX, true);
}

二、WAV文件

WAV是最常见的声音文件格式之一,是微软公司专门为Windows开发的一种标准数字音频文件,该文件能记录各种单声道或立体声的声音信息,并能保证声音不失真。但WAV文件有一个致命的缺点,就是它所占用的磁盘空间太大(每分钟的音乐大约需要12兆磁盘空间)。它符合资源互换文件格式(RIFF)规范,用于保存Windows平台的音频信息资源,被Windows平台及其应用程序所广泛支持。Wave格式支持MSADPCM、CCITTA律、CCITT μ律和其他压缩算法,支持多种音频位数、采样频率和声道,是PC机上最为流行的声音文件格式;但其文件尺寸较大,多用于存储简短的声音片段。

网上也有许多关于WAV的讲解,这里就不展开讲解。刚好我在查找资料的时候发现了有类似工程的,我这里直接使用了他的播放部分,由于我没有购置屏幕,所以选择使用串口来打印信息。

#include "wav.h"
#include "i2s_port.h"FIL     WAV_File;
UINT    WAV_BR[2];
FRESULT WAV_RES;DTCM_RAM uint8_t WAV_DataBuffer[2][WAV_BUFFER_SIZE];
uint8_t WAV_NextIndex = 0;
uint8_t WAV_PlayEnded = 0;uint32_t WAV_PlaybackTotal     = 0;
uint32_t WAV_PlaybackProgress  = 0;static uint8_t WAV_DecodeFile(WAV_TypeDef *pWav, char *Path, char *Name)
{static ChunkRIFF_TypeDef *WAV_RIFF;static ChunkFMT_TypeDef  *WAV_FMT ;static ChunkFACT_TypeDef *WAV_FACT;static ChunkDATA_TypeDef *WAV_DATA;static uint8_t WAV_HeadBuffer[512];static uint8_t Result = 0;static char FilePath[ 100];memset( FilePath, 0x00, sizeof(FilePath));sprintf(FilePath, "%s%s",   Path,   Name);printf("%s\r\n",FilePath);WAV_RES = f_open(&WAV_File, FilePath, FA_READ);if(WAV_RES == FR_OK){/* ¶ÁÈ¡512×Ö½ÚÔÚÊý¾Ý */WAV_RES = f_read(&WAV_File, WAV_HeadBuffer, 512, &WAV_BR[0]);if((WAV_RES == FR_OK) && (WAV_BR[0] != 0)){/* »ñÈ¡RIFF¿é */WAV_RIFF = (ChunkRIFF_TypeDef *)WAV_HeadBuffer;/* ÊÇWAV¸ñʽÎļþ */if(WAV_RIFF->Format == 0x45564157){/* »ñÈ¡FMT¿é */WAV_FMT  = (ChunkFMT_TypeDef *)(WAV_HeadBuffer+12);/* ¶ÁÈ¡FACT¿é */WAV_FACT = (ChunkFACT_TypeDef *)(WAV_HeadBuffer+12+8+WAV_FMT->ChunkSize);if((WAV_FACT->ChunkID == 0x74636166) || (WAV_FACT->ChunkID == 0x5453494C)){/* ¾ßÓÐFACT/LIST¿éµÄʱºò(δ²âÊÔ) */pWav->DataStart=12+8+WAV_FMT->ChunkSize+8+WAV_FACT->ChunkSize;}else{pWav->DataStart=12+8+WAV_FMT->ChunkSize;}/* ¶ÁÈ¡DATA¿é */WAV_DATA = (ChunkDATA_TypeDef *)(WAV_HeadBuffer+pWav->DataStart);/* ½âÎö³É¹¦ */if(WAV_DATA->ChunkID == 0x61746164){pWav->AudioFormat   = WAV_FMT->AudioFormat;     /* ÒôƵ¸ñʽ */pWav->nChannels     = WAV_FMT->NumOfChannels;   /* ͨµÀÊý */pWav->SampleRate    = WAV_FMT->SampleRate;      /* ²ÉÑùÂÊ */pWav->BitRate       = WAV_FMT->ByteRate*8;      /* µÃµ½Î»ËÙ */pWav->BlockAlign    = WAV_FMT->BlockAlign;      /* ¿é¶ÔÆë */pWav->BitsPerSample = WAV_FMT->BitsPerSample;   /* λÊý,16/24/32λ */pWav->DataSize      = WAV_DATA->ChunkSize;      /* Êý¾Ý¿é´óС */pWav->DataStart     = pWav->DataStart+8;        /* Êý¾ÝÁ÷¿ªÊ¼µÄµØ·½ */printf("\r\npWav->AudioFormat   : %d", pWav->AudioFormat);printf("\r\npWav->nChannels     : %d", pWav->nChannels);printf("\r\npWav->SampleRate    : %d", pWav->SampleRate);printf("\r\npWav->BitRate       : %d", pWav->BitRate);printf("\r\npWav->BlockAlign    : %d", pWav->BlockAlign);printf("\r\npWav->BitsPerSample : %d", pWav->BitsPerSample);printf("\r\npWav->DataSize      : %d", pWav->DataSize);printf("\r\npWav->DataStart     : %d", pWav->DataStart);WAV_PlaybackTotal = pWav->DataSize;}else{Result = 3; /* DATAÇøÓòδÕÒµ½ */}}else{Result = 2;     /* ·ÇWAV¸ñʽÎļþ */}}f_close(&WAV_File);}else{Result = 1;             /* ´ò¿ªÎļþ´íÎó */}printf("\r\n\r\nWAV Decode File Result : %d\r\n\r\n", Result);return Result;
}void WAV_PrepareData(void)
{if(WAV_NextIndex == 0){WAV_RES = f_read(&WAV_File, WAV_DataBuffer[WAV_NextIndex], WAV_BUFFER_SIZE, &WAV_BR[WAV_NextIndex]);if(WAV_BR[0] == 0) WAV_PlayEnded = 1;}else{WAV_RES = f_read(&WAV_File, WAV_DataBuffer[WAV_NextIndex], WAV_BUFFER_SIZE, &WAV_BR[WAV_NextIndex]);if(WAV_BR[1] == 0) WAV_PlayEnded = 1;}
}void WAV_PlayHandler(void)
{if(WAV_PlayEnded == 0){WAV_PlaybackProgress += WAV_BR[WAV_NextIndex];I2S_DMA_Transfer((uint16_t *)&WAV_DataBuffer[WAV_NextIndex][0], (WAV_BR[WAV_NextIndex] /2));}else{DMA_EnableChannel(DMA1,DMA_REQ_DMA1_SPI2_TX,false);f_close(&WAV_File); I2S_PowerON(0);printf("\r\nWAV Play Finish!\r\n");}
//WAV_NextIndex = 1;if(WAV_NextIndex == 0) WAV_NextIndex = 1;else                   WAV_NextIndex = 0;
}void WAV_PlaySong(char *Path, char *Name)
{WAV_TypeDef WaveFile;char FilePath[100];/* »ñÈ¡WAVÎļþµÄÐÅÏ¢ */if(WAV_DecodeFile(&WaveFile, Path, Name) == 0){if((WaveFile.BitsPerSample == 16) && (WaveFile.nChannels == 2) &&(WaveFile.SampleRate  > 44000) && (WaveFile.SampleRate < 48100)){I2S_PowerON(1);I2S_Configure(I2S_Protocol_PHILIPS, I2S_DataWidth_16b,I2S_AudioFreq_44k, I2S_XferMode_TxOnly);}else{printf("\r\nWAV File Error!\r\n");  return;}}else{printf("\r\nNot WAV File!\r\n");    return;}memset( FilePath, 0x00, sizeof(FilePath));sprintf(FilePath, "%s%s",   Path,   Name);printf(">f_open WAV Start...\r\n");WAV_RES = f_open(&WAV_File, FilePath, FA_READ);if(WAV_RES == FR_OK){printf(">f_open WAV Done!\r\n");WAV_NextIndex = 0;WAV_PlayEnded = 0;WAV_PlaybackProgress = 0;WAV_PrepareData();WAV_PlayHandler();}else{printf("\r\nWAV File Open Error : %d", WAV_RES);}
}

国产芯片MM32F5270播放音频

总结

能够加上DMA的地方都已经使用,参考了最大吞吐率的那篇文章,数据放在了DTCM区,通过DMA传输给I2S。感觉播放效果还行。现在代码播放mp3文件还有些问题,正在排查。在测试的时候,播放wav一直没有声音,之后将SPI改为硬件后效果直接上来了。从接触新板子开始,已经感受到国产MCU进步之快,希望有一天能够干翻ST。

【MM32F5270开发板试用】播放TF卡WAV格式音乐,I2S驱动CS4344相关推荐

  1. 【MM32F5270开发板试用】快速移植STM32应用到MM32F5270(以OLED为例)

    本篇文章来自极术社区与灵动组织的MM32F5270开发板评测活动,更多开发板试用活动请关注极术社区网站.作者:@#@ 本篇文章来自极术社区与灵动组织的MM32F5270开发板评测活动,更多开发板试用活 ...

  2. 【MM32F5270开发板试用】 MindSDK使用测评

    本篇文章来自极术社区与灵动组织的MM32F5270开发板评测活动,更多开发板试用活动请关注极术社区网站.作者:胖墩墩 一.前言: 非常感谢极术社区和灵动微电子开展的MM32F5270开发板试用申请活动 ...

  3. 【MM32F5270开发板试用】手势传感PAJ7620U2的智能家居应用

    本篇文章来自极术社区与灵动组织的MM32F5270开发板评测活动,更多开发板试用活动请关注极术社区网站.作者:风云再起 一.序 很高兴能参加极术社区联合灵动微电子组织的[灵动MM32F5270开发板试 ...

  4. 【MM32F5270开发板试用】RT-Thread SPI 驱动适配指南

    本篇文章来自极术社区与灵动组织的MM32F5270开发板评测活动,更多开发板试用活动请关注极术社区网站.作者:xusiwei1236 本文记录了我在社区"Rice我叫加饭?"大佬移 ...

  5. 【MM32F5270开发板试用】六、如何用 星辰内核 + 国产RTOS 通过I2S播放 “星辰大海”

    本篇文章来自极术社区与灵动组织的MM32F5270开发板评测活动,更多开发板试用活动请关注极术社区网站.作者:Magicoe是攻城狮 这个demo和想法是参考了大神的文章 https://aijish ...

  6. 【MM32F5270开发板试用】定制MicroPython及读取MPU6050数据到OLED1306

    本篇文章来自极术社区与灵动组织的MM32F5270开发板评测活动,更多开发板试用活动请关注极术社区网站.作者:HonestQiao 前言 这次有幸获得MM32F5270开发板的试用,非常幸运. 收到板 ...

  7. 【MM32F5270开发板试用】移植Google Chrome小恐龙游戏到MM32F5270

    本篇文章来自极术社区与灵动组织的MM32F5270开发板评测活动,更多开发板试用活动请关注极术社区网站.作者:曾是一颗薏米 一.项目背景 在几年前,Google 给 Chrome 浏览器加了一个有趣的 ...

  8. 【MM32F5270开发板试用】GPIO输入+EXTI外部中断例程demo试用

    本篇文章来自极术社区与灵动组织的MM32F5270开发板评测活动,更多开发板试用活动请关注极术社区网站.作者:Zeee 前言: 首先,感谢灵动微电子与极术社区给予宝贵的试用机会.借助本次对Plus-F ...

  9. 【MM32F5270开发板试用】二、探测环境温度和光照度参数

    本篇文章来自极术社区与灵动组织的MM32F5270开发板评测活动,更多开发板试用活动请关注极术社区网站.作者:Red Sensor 环境参数感知 ADC 相关的硬件信息 ADC1 有 19 个通道, ...

最新文章

  1. 缓存DNS域名解析服务器的制作方法
  2. 扔掉工具类,Mybatis一个简单配置搞定数据加密解密!
  3. WPF之依赖属性和附加属性
  4. first OData Batch operation when Sales Pipeline is launched
  5. 图解python pdf_Python合并同一个文件夹下所有PDF文件的方法
  6. 如何将视频设置为网页背景
  7. linux内核时钟工作原理,linux内核的时钟机制
  8. oracle flex cluster,【Ora12c-GI】将Standard集群修改为Flex集群
  9. 极速体验:Oracle 18c 下载和Scalable Sequence新特性
  10. 物理实验模拟软件_网络系统实验平台:发展现状及展望
  11. [Delphi]ListView基本用法大全
  12. 机器学习实战 - 读书笔记(05) - Logistic回归
  13. c++ 覆盖、重载与隐藏
  14. Linux下通过ssh上传、下载文件或者文件夹
  15. 芯烨 Xprinter XP-DT108A 打印机驱动
  16. 《第二次曲线创新》李善友教授
  17. java 订单减库存_订单和库存处理方案
  18. gitter 卸载_最佳的Gitter渠道:数据科学和机器学习
  19. html鼠标悬停图片释义文字消失,鼠标悬停,在图片上显示文字~
  20. 京东健康和药明康德入股卫宁软件,分别持有7.7%股权

热门文章

  1. strtol,strtoll,strtoul, strtoull字符串转化成数字
  2. 对话白先勇:中国文化是世界上最美的
  3. 买外链,seo发外链,外链发布平台有哪些?
  4. 最全Pycharm教程(2)——代码风格
  5. anaconda初体验
  6. 计算机网络 - chunk协议
  7. 人工智能处理的几大基础任务、元宇宙和人工智能
  8. Prometheus 之 Alertmanager告警抑制与静默
  9. GOF23设计模式之桥接模式
  10. 互联网新机遇:移动社交电商将成为下一个风口?