【STM32 HAL库】I2S的使用

使用CubeIDE实现I2S发数据

1、配置I2S

我们的有效数据是32位的,使用飞利浦格式。

在这里插入图片描述

2、配置DMA

在这里插入图片描述

**这里需要注意:**i2s的DR寄存器是16位的,如果需要发送32位的数据,是需要写两次DR寄存器的,所以DMA的外设数据宽度设置16位,而不是32位。

3、完善I2S文件

i2s.c和i2s.h文件都是MX自动生成的,并且生成MX_I2S3_Init函数进行了初始化,MX_I2S3_Init函数里面其实依次调用了HAL_I2S_Init库函数(和MCU不相关的初始化)和HAL_I2S_MspInit库函数(是个weak函数,和MCU相关的初始化)。所以,我们自己要写的代码也加到这个文件中。

/* USER CODE BEGIN Header */
/********************************************************************************* @file    i2s.c* @brief   This file provides code for the configuration*          of the I2S instances.******************************************************************************* @attention** Copyright (c) 2024 STMicroelectronics.* All rights reserved.** This software is licensed under terms that can be found in the LICENSE file* in the root directory of this software component.* If no LICENSE file comes with this software, it is provided AS-IS.********************************************************************************/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "i2s.h"/* USER CODE BEGIN 0 */
#include "stdio.h"#define  TX_DATA_16                 (0x1234)
#define  TX_DATA_32                 (0x12345678)
#define  HALF_TX_BUFFER_SIZE        (256)
#define  TX_BUFFER_SIZE             (HALF_TX_BUFFER_SIZE*2)
uint32_t tx_buffer[TX_BUFFER_SIZE];/* USER CODE END 0 */I2S_HandleTypeDef hi2s3;
DMA_HandleTypeDef hdma_spi3_tx;/* I2S3 init function */
void MX_I2S3_Init(void)
{/* USER CODE BEGIN I2S3_Init 0 *///这里有一点需要注�???,i2s的DR�???16位的,�???以如果想发�??32位的数据,得写两次,//如果想发�???0x12345678,就得先发�???0x1234,再发�???0x5678(标准飞利浦格式是高位在前)//但是32位数组是小端�???,�???以就�???要重组一�???for(int i=0;i<TX_BUFFER_SIZE;i++){*(tx_buffer+i)= (TX_DATA_32<<16)|(TX_DATA_32>>16);}/* USER CODE END I2S3_Init 0 *//* USER CODE BEGIN I2S3_Init 1 *//* USER CODE END I2S3_Init 1 */hi2s3.Instance = SPI3;hi2s3.Init.Mode = I2S_MODE_MASTER_TX;hi2s3.Init.Standard = I2S_STANDARD_PHILIPS;hi2s3.Init.DataFormat = I2S_DATAFORMAT_32B;hi2s3.Init.MCLKOutput = I2S_MCLKOUTPUT_ENABLE;hi2s3.Init.AudioFreq = I2S_AUDIOFREQ_48K;hi2s3.Init.CPOL = I2S_CPOL_HIGH;hi2s3.Init.ClockSource = I2S_CLOCK_PLL;hi2s3.Init.FullDuplexMode = I2S_FULLDUPLEXMODE_DISABLE;if (HAL_I2S_Init(&hi2s3) != HAL_OK){Error_Handler();}/* USER CODE BEGIN I2S3_Init 2 *//* USER CODE END I2S3_Init 2 */}void HAL_I2S_MspInit(I2S_HandleTypeDef* i2sHandle)
{GPIO_InitTypeDef GPIO_InitStruct = {0};RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0};if(i2sHandle->Instance==SPI3){/* USER CODE BEGIN SPI3_MspInit 0 *//* USER CODE END SPI3_MspInit 0 *//** Initializes the peripherals clock*/PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_I2S;PeriphClkInitStruct.PLLI2S.PLLI2SN = 192;PeriphClkInitStruct.PLLI2S.PLLI2SR = 2;if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK){Error_Handler();}/* I2S3 clock enable */__HAL_RCC_SPI3_CLK_ENABLE();__HAL_RCC_GPIOA_CLK_ENABLE();__HAL_RCC_GPIOC_CLK_ENABLE();/**I2S3 GPIO ConfigurationPA4     ------> I2S3_WSPC7     ------> I2S3_MCKPC10     ------> I2S3_CKPC12     ------> I2S3_SD*/GPIO_InitStruct.Pin = WCK_Pin;GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;GPIO_InitStruct.Pull = GPIO_NOPULL;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;GPIO_InitStruct.Alternate = GPIO_AF6_SPI3;HAL_GPIO_Init(WCK_GPIO_Port, &GPIO_InitStruct);GPIO_InitStruct.Pin = GPIO_PIN_7|BCK_Pin|DI_Pin;GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;GPIO_InitStruct.Pull = GPIO_NOPULL;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;GPIO_InitStruct.Alternate = GPIO_AF6_SPI3;HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);/* I2S3 DMA Init *//* SPI3_TX Init */hdma_spi3_tx.Instance = DMA1_Stream5;hdma_spi3_tx.Init.Channel = DMA_CHANNEL_0;hdma_spi3_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;hdma_spi3_tx.Init.PeriphInc = DMA_PINC_DISABLE;hdma_spi3_tx.Init.MemInc = DMA_MINC_ENABLE;hdma_spi3_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;hdma_spi3_tx.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;hdma_spi3_tx.Init.Mode = DMA_CIRCULAR;hdma_spi3_tx.Init.Priority = DMA_PRIORITY_LOW;hdma_spi3_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;if (HAL_DMA_Init(&hdma_spi3_tx) != HAL_OK){Error_Handler();}__HAL_LINKDMA(i2sHandle,hdmatx,hdma_spi3_tx);/* USER CODE BEGIN SPI3_MspInit 1 *//* USER CODE END SPI3_MspInit 1 */}
}void HAL_I2S_MspDeInit(I2S_HandleTypeDef* i2sHandle)
{if(i2sHandle->Instance==SPI3){/* USER CODE BEGIN SPI3_MspDeInit 0 *//* USER CODE END SPI3_MspDeInit 0 *//* Peripheral clock disable */__HAL_RCC_SPI3_CLK_DISABLE();/**I2S3 GPIO ConfigurationPA4     ------> I2S3_WSPC7     ------> I2S3_MCKPC10     ------> I2S3_CKPC12     ------> I2S3_SD*/HAL_GPIO_DeInit(WCK_GPIO_Port, WCK_Pin);HAL_GPIO_DeInit(GPIOC, GPIO_PIN_7|BCK_Pin|DI_Pin);/* I2S3 DMA DeInit */HAL_DMA_DeInit(i2sHandle->hdmatx);/* USER CODE BEGIN SPI3_MspDeInit 1 *//* USER CODE END SPI3_MspDeInit 1 */}
}/* USER CODE BEGIN 1 */int I2S_DMA_Start_Transmit()
{return HAL_I2S_Transmit_DMA(&hi2s3, (uint16_t *)tx_buffer, TX_BUFFER_SIZE);
}int I2S_DMA_Stop()
{return HAL_I2S_DMAStop(&hi2s3);
}/*** @brief  Tx Transfer Half completed callbacks* @param  hi2s pointer to a I2S_HandleTypeDef structure that contains*         the configuration information for I2S module* @retval None*/
void HAL_I2S_TxHalfCpltCallback(I2S_HandleTypeDef *hi2s)
{printf("%s\r\n",__func__);/* Prevent unused argument(s) compilation warning */UNUSED(hi2s);for(int i=0;i<HALF_TX_BUFFER_SIZE;i++){*(tx_buffer+i)+=1;}/* NOTE : This function Should not be modified, when the callback is needed,the HAL_I2S_TxHalfCpltCallback could be implemented in the user file*/
}/*** @brief  Tx Transfer completed callbacks* @param  hi2s pointer to a I2S_HandleTypeDef structure that contains*         the configuration information for I2S module* @retval None*/
void HAL_I2S_TxCpltCallback(I2S_HandleTypeDef *hi2s)
{printf("%s\r\n",__func__);/* Prevent unused argument(s) compilation warning */UNUSED(hi2s);for(int i=0;i<HALF_TX_BUFFER_SIZE;i++){*(tx_buffer+HALF_TX_BUFFER_SIZE+i)-=1;}/* NOTE : This function Should not be modified, when the callback is needed,the HAL_I2S_TxCpltCallback could be implemented in the user file*/
}/*** @brief  I2S error callbacks* @param  hi2s pointer to a I2S_HandleTypeDef structure that contains*         the configuration information for I2S module* @retval None*/
void HAL_I2S_ErrorCallback(I2S_HandleTypeDef *hi2s)
{/* Prevent unused argument(s) compilation warning */printf("HAL_I2S_Error\r\n");/* NOTE : This function Should not be modified, when the callback is needed,the HAL_I2S_ErrorCallback could be implemented in the user file*/
}/* USER CODE END 1 */
  1. 其实这里使用了DMA双buffer的思路,但是我没有使用双buffer,而是一个buffer的前后部分。当TxHalfCplt的时候,我们去更新buffer前半部分数据,当TxCplt的时候,我们去更新buffer的后半部分数据。HAL库没有很好封装DMA双buffer的配置函数。
  2. 关于DMA的buffer填充问题,I2S的DR寄存器是15位的,所以配置DMA的数据宽度也是16位的,如果I2S是32位的数据格式,那么需要写两次DR寄存器才能组一帧I2S数据,例如I2S想发送0x12345678,那么就得先发送0x1234,再发送0x5678(I2S飞利浦格式就是这样,高位在前),所以填充buffer的时候,也得按该顺序填充。
  3. 关于全双工DMA的封装,HAL好像也没有很好的支持,等下次再介绍。。。

在这里插入图片描述

4、I2S实现DMA双buffer发送

我们如果看过HAL库接口的话,就应该知道。在dma_ex文件中封装了DMA双buffer的接口,但是在i2s文件或者i2s_ex中没有封装双buffer的接口。所以,我们打算仿照HAL_I2S_Transmit_DMA库函数实现一个函数。

/* USER CODE BEGIN 1 */
static void I2S_DMAM0TxHalfCplt(DMA_HandleTypeDef *hdma)
{I2S_HandleTypeDef *hi2s = (I2S_HandleTypeDef *)((DMA_HandleTypeDef *)hdma)->Parent; /* Derogation MISRAC2012-Rule-11.5 *//* Call user Tx half complete callback */printf("%s\r\n",__func__);
}static void I2S_DMAM0TxCplt(DMA_HandleTypeDef *hdma)
{I2S_HandleTypeDef *hi2s = (I2S_HandleTypeDef *)((DMA_HandleTypeDef *)hdma)->Parent; /* Derogation MISRAC2012-Rule-11.5 *//* Call user Tx complete callback */printf("%s\r\n",__func__);
}static void I2S_DMAM1TxHalfCplt(DMA_HandleTypeDef *hdma)
{I2S_HandleTypeDef *hi2s = (I2S_HandleTypeDef *)((DMA_HandleTypeDef *)hdma)->Parent; /* Derogation MISRAC2012-Rule-11.5 *//* Call user Tx half complete callback */printf("%s\r\n",__func__);
}static void I2S_DMAM1TxCplt(DMA_HandleTypeDef *hdma)
{I2S_HandleTypeDef *hi2s = (I2S_HandleTypeDef *)((DMA_HandleTypeDef *)hdma)->Parent; /* Derogation MISRAC2012-Rule-11.5 *//* Call user Tx complete callback */printf("%s\r\n",__func__);
}static void I2S_DMA_Error(DMA_HandleTypeDef *hdma)
{I2S_HandleTypeDef *hi2s = (I2S_HandleTypeDef *)((DMA_HandleTypeDef *)hdma)->Parent; /* Derogation MISRAC2012-Rule-11.5 */printf("%s\r\n",__func__);
}static HAL_StatusTypeDef HAL_I2S_Transmit_DMA_DBuffer(I2S_HandleTypeDef *hi2s, uint16_t *pData0,uint16_t *pData1, uint16_t Size)
{uint32_t tmpreg_cfgr;if ((pData0 == NULL) || (Size == 0U)){return  HAL_ERROR;}/* Process Locked */__HAL_LOCK(hi2s);if (hi2s->State != HAL_I2S_STATE_READY){__HAL_UNLOCK(hi2s);return HAL_BUSY;}/* Set state and reset error code */hi2s->State = HAL_I2S_STATE_BUSY_TX;hi2s->ErrorCode = HAL_I2S_ERROR_NONE;hi2s->pTxBuffPtr = pData0;tmpreg_cfgr = hi2s->Instance->I2SCFGR & (SPI_I2SCFGR_DATLEN | SPI_I2SCFGR_CHLEN);if ((tmpreg_cfgr == I2S_DATAFORMAT_24B) || (tmpreg_cfgr == I2S_DATAFORMAT_32B)){hi2s->TxXferSize = (Size << 1U);hi2s->TxXferCount = (Size << 1U);}else{hi2s->TxXferSize = Size;hi2s->TxXferCount = Size;}/* Set the I2S Tx DMA Half transfer complete callback */hi2s->hdmatx->XferHalfCpltCallback = I2S_DMAM0TxHalfCplt;/* Set the I2S Tx DMA transfer complete callback */hi2s->hdmatx->XferCpltCallback = I2S_DMAM0TxCplt;hi2s->hdmatx->XferM1HalfCpltCallback=I2S_DMAM1TxHalfCplt;//callbackhi2s->hdmatx->XferM1CpltCallback=I2S_DMAM1TxCplt;//callback/* Set the DMA error callback */hi2s->hdmatx->XferErrorCallback = I2S_DMA_Error;/* Enable the Tx DMA Stream/Channel */if (HAL_OK != HAL_DMAEx_MultiBufferStart_IT(hi2s->hdmatx,(uint32_t)hi2s->pTxBuffPtr,(uint32_t)&hi2s->Instance->DR,(uint32_t)pData1,hi2s->TxXferSize)){/* Update SPI error code */SET_BIT(hi2s->ErrorCode, HAL_I2S_ERROR_DMA);hi2s->State = HAL_I2S_STATE_READY;__HAL_UNLOCK(hi2s);return HAL_ERROR;}/* Check if the I2S is already enabled */if (HAL_IS_BIT_CLR(hi2s->Instance->I2SCFGR, SPI_I2SCFGR_I2SE)){/* Enable I2S peripheral */__HAL_I2S_ENABLE(hi2s);}/* Check if the I2S Tx request is already enabled */if (HAL_IS_BIT_CLR(hi2s->Instance->CR2, SPI_CR2_TXDMAEN)){/* Enable Tx DMA Request */SET_BIT(hi2s->Instance->CR2, SPI_CR2_TXDMAEN);}__HAL_UNLOCK(hi2s);return HAL_OK;
}

注意几点:

  1. 这些函数还是写在i2s.c文件中。
  2. 相比原函数,在函数参数上多了一个buffer地址。
  3. 原函数中的回调函数都是本地函数,不供其他文件调用,所以全部重新定义在我们的本文件中。并且多了m1 buffer的回调函数。
  4. DMA_Start函数更换为双buffer函数接口。其他的地方都没有改变。
    在这里插入图片描述
    在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/47562.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

探索Python自然语言处理的新篇章:jionlp库介绍

探索Python自然语言处理的新篇章&#xff1a;jionlp库介绍 1. 背景&#xff1a;为什么选择jionlp&#xff1f; 在Python的生态中&#xff0c;自然语言处理&#xff08;NLP&#xff09;是一个活跃且不断发展的领域。jionlp是一个专注于中文自然语言处理的库&#xff0c;它提供了…

Ubuntu 安装 XRDP,替代系统自带RDP远程桌面

起因&#xff0c;Ubuntu的自带RDP远程桌面很好用&#xff0c;但很傻卵&#xff0c;必须登录。 而设置了自动登录也不能解开KEYRING&#xff0c;必须必须必须用GUI手动登录。 &#xff08;我远程我用头给你坐机子面前开显示器先登录&#xff1f;&#xff1f;&#xff09; 比起VN…

【HarmonyOS】HarmonyOS NEXT学习日记:三、初识ArkUI

【HarmonyOS】HarmonyOS NEXT学习日记&#xff1a;三、初识ArkUI 忘掉HTML和CSS&#xff0c;ArkUI里构建页面的最小单位就是 “组件”&#xff0c;所以今天的目标就是认识一些常用的基础组件&#xff0c;以及他们的用法&#xff0c;对ArkUI形成一个基本认识。 基本组成 了解…

重塑七星拼团模式:共创互赢新生态

在当今商业模式的洪流中&#xff0c;七星拼团模式凭借其创新的激励机制与深植的互助文化&#xff0c;独树一帜&#xff0c;成为了推动市场活跃与消费者参与的新引擎。本文将重新构思并阐述该模式的三大支柱——直推奖赏、滑落回馈与循环成就奖&#xff0c;同时深入探讨其互助逻…

(error) MOVED 12706 192.168.187.139:6379

Redis操作set、get等操作出现如下错误 (error) MOVED 12706 192.168.187.139:6379 这种情况一般是因为启动 redis-cli 时没有设置集群模式所导致&#xff1b; 在开启集群后&#xff0c;redis-cli用普通用户登录无法操作集群中的数据&#xff0c;需要加上-c 用集群模式登录才可…

网络故障处理及分析工具:Wireshark和Tcpdump集成

Wireshark 是一款免费的开源数据包嗅探器和网络协议分析器&#xff0c;已成为网络故障排除、分析和安全&#xff08;双向&#xff09;中不可或缺的工具。 本文深入探讨了充分利用 Wireshark 的功能、用途和实用技巧。 无论您是开发人员、安全专家&#xff0c;还是只是对网络操…

k8s集群 安装配置 Prometheus+grafana

k8s集群 安装配置 Prometheusgrafana k8s环境如下&#xff1a;机器规划&#xff1a; node-exporter组件安装和配置安装node-exporter通过node-exporter采集数据显示192.168.40.180主机cpu的使用情况显示192.168.40.180主机负载使用情况 Prometheus server安装和配置创建sa账号&…

飞凌全志T527开发板modbus移植使用教程

交叉编译 进入到源码目录&#xff0c;执行 ./configure ac_cv_func_malloc_0_nonnullyes --hostaarch64-none-linux-gnu --enable-static --prefix/home/feng/文档/development/Linux/application/OK527N/libmodbus-3.1.10/install/其中–host为交叉编译器的前缀&#xff1b;…

巧用通义灵码助力护网面试

前言 前几年护网还算是一个比较敏感的话题&#xff0c;但是随着近段时间的常态化开始&#xff0c;护网行动也是逐渐走进了大众的视野&#xff0c;成为了社会各界共同关注的安全盛事。本篇也是受通义灵码备战求职季活动的启发&#xff0c;结合近期要开始的护网行动&#xff0c…

前端面试题(JS篇五)

一、同步与异步的区别 同步指的是当一个进程在执行某一个请求的时候&#xff0c;如果这个请求需要等待一段时间才能返回&#xff0c;那么这个进程会一直等待下去&#xff0c;直到这个消息返回之后才会继续执行。 指的是当一个进程在执行某一个请求的时候&#xff0c;如果这个请…

SSCOM串口调试工具安装和使用方法--V5.13.1版本

安装 链接&#xff1a;下载 解压后直接双击打开使用 使用 1、选择端口 2、点击【打开串口】 3、输入内容点击发送 4、上方就会展示发送或接收数据

Chapter12 屏幕后处理效果——Shader入门精要学习笔记

Chapter12 屏幕后处理效果 一、屏幕后处理概述以及基本脚本系统1.OnRenderImage 函数 —— 获取屏幕图像2.Graphics.Blit 函数 —— 使用特定的Shader处理3.在Unity中实现屏幕后处理的基本流程4.屏幕后处理基类 二、调整亮度、饱和度和对比度1.BrightnessSaturationAndContrast…

GESP CCF C++ 三级认证真题 2024年6月

第 1 题 小杨父母带他到某培训机构给他报名参加CCF组织的GESP认证考试的第1级&#xff0c;那他可以选择的认证语言有&#xff08;&#xff09;种。 A. 1 B. 2 C. 3 D. 4 第 2 题 下面流程图在yr输入2024时&#xff0c;可以判定yr代表闰年&#xff0c;并输出 2月是29天 &#x…

20240718 每日AI必读资讯

大模型集体失智&#xff01;9.11和9.9哪个大&#xff0c;几乎全翻车了 - AI处理常识性问题能力受限&#xff0c;9.11&#xff1e;9.8数学难题暴露了AI短板。 - 训练数据偏差、浮点精度问题和上下文理解不足是AI在数值比较任务上可能遇到的困难。 - 改进AI需优化训练数据、Pr…

阿里云国际站:海外视频安全的DRM加密

随着科技的进步&#xff0c;视频以直播或录播的形式陆续开展海外市场&#xff0c;从而也衍生出内容安全的问题&#xff0c;阿里云在这方面提供了完善的内容安全保护机制&#xff0c;适用于不同的场景&#xff0c;如在视频安全提供DRM加密。 由图可以了解到阿里云保护直播安全的…

【ROS】的软件包应用商店使用-以小乌龟为例

文章目录 环境效果图介绍安装使用总结 环境 在Ubuntu20.04系统下运行 效果图 介绍 ros应用商店&#xff0c;里面有大量ros可使用的软件。 下面以ros经典的控制小乌龟为例。 安装 安装控制器 sudo apt install ros-noetic-rqt-robot-steering安装小乌龟 sudo apt insta…

微软GraphRAG +本地模型+Gradio 简单测试笔记

安装 pip install graphragmkdir -p ./ragtest/input#将文档拷贝至 ./ragtest/input/ 下python -m graphrag.index --init --root ./ragtest修改settings.yaml encoding_model: cl100k_base skip_workflows: [] llm:api_key: ${GRAPHRAG_API_KEY}type: openai_chat # or azu…

uniapp踩坑之项目:uni-table垂直居中和水平居中

uni-table 中的水平居中uni-td align"center"&#xff0c;css里的属性vertical-align: middle //html 水平居中<uni-table ref"table" :loading"loading" border stripe emptyText"暂无更多数据"><uni-tr><uni-th :wid…

[HDCTF2019]MFC

[HDCTF2019]MFC-CSDN博客 不会写 完全画瓢 我还以为win32什么系统逆向 原来是小瘪三! VM保护 下载xspy(看雪上有) 打开32位的 再打开 这个窗口 把这个放大镜托到这个大窗口(里面有个小窗口,不要托错了) 下面这个 onmeg 就她不正常,是什么0464 #include <stdio.h&g…

mac环境下安装python3的图文教程

Python 是一种功能多样且强大的编程语言&#xff0c;在各个领域得到广泛应用。许多 Mac 用户都在其设备上安装和运行 Python&#xff0c;以运行特定的应用程序或创建、运行自己的 Python 脚本。 文章源自设计学徒自学网-http://www.sx1c.com/49441.html 虽然某些版本的 macOS…