stm32之hal库i2s驱动的封装记录

前言

  1. 本次使用的框架为threadx+filex+shell组件

程序

共用驱动文件(dma和nvic)

nvic文件

头文件
/** Copyright (c) 2024-2024,shchl** SPDX-License-Identifier: Apache-2.0** Change Logs:* Date           Author       Notes* 2024-5-3     shchl   first version*/#ifndef TX_STM32_F4_DRV_NVIC_OS_H
#define TX_STM32_F4_DRV_NVIC_OS_H
#include "drv_common.h"void stm32_nvic_common_enable(uint32_t instance,uint32_t preempt,uint32_t sub);
void stm32_nvic_common_disable(uint32_t instance);
uint8_t stm32_nvic_common_enabled_check(uint32_t instance);
#endif //TX_STM32_F4_DRV_NVIC_OS_H
源文件
/** Copyright (c) 2024-2024,shchl** SPDX-License-Identifier: Apache-2.0** Change Logs:* Date           Author       Notes* 2024-5-3     shchl   first version*/#include "drv_nvic_os.h"enum stm32_irq_op_enum {OPEN_IRQn,CLOSE_IRQn,READ_IRQn
};/*** @brief* @param instance* @param preempt* @param sub* @param open_flag*/
static uint32_t stm32_nvic_common(uint32_t instance, uint32_t preempt, uint32_t sub, enum stm32_irq_op_enum mode) {uint32_t irq;switch (instance) {
#define irq_set(IRQn) {irq=IRQn;}breakcase (uint32_t) SPI1: irq_set(SPI1_IRQn);case (uint32_t) SPI2: irq_set(SPI2_IRQn);case (uint32_t) SPI3: irq_set(SPI3_IRQn);case (uint32_t) USART1: irq_set(USART1_IRQn);case (uint32_t) USART2: irq_set(USART2_IRQn);case (uint32_t) USART3: irq_set(USART3_IRQn);case (uint32_t) UART4: irq_set(UART4_IRQn);case (uint32_t) UART5: irq_set(UART5_IRQn);case (uint32_t) SDIO: irq_set(SDIO_IRQn);case (uint32_t) DMA2_Stream0: irq_set(DMA2_Stream0_IRQn);case (uint32_t) DMA2_Stream1: irq_set(DMA2_Stream1_IRQn);case (uint32_t) DMA2_Stream2: irq_set(DMA2_Stream2_IRQn);case (uint32_t) DMA2_Stream3: irq_set(DMA2_Stream3_IRQn);case (uint32_t) DMA2_Stream4: irq_set(DMA2_Stream4_IRQn);case (uint32_t) DMA2_Stream5: irq_set(DMA2_Stream5_IRQn);case (uint32_t) DMA2_Stream6: irq_set(DMA2_Stream6_IRQn);case (uint32_t) DMA2_Stream7: irq_set(DMA2_Stream7_IRQn);case (uint32_t) DMA1_Stream0: irq_set(DMA1_Stream0_IRQn);case (uint32_t) DMA1_Stream1: irq_set(DMA1_Stream1_IRQn);case (uint32_t) DMA1_Stream2: irq_set(DMA1_Stream2_IRQn);case (uint32_t) DMA1_Stream3: irq_set(DMA1_Stream3_IRQn);case (uint32_t) DMA1_Stream4: irq_set(DMA1_Stream4_IRQn);case (uint32_t) DMA1_Stream5: irq_set(DMA1_Stream5_IRQn);case (uint32_t) DMA1_Stream6: irq_set(DMA1_Stream6_IRQn);case (uint32_t) DMA1_Stream7: irq_set(DMA1_Stream7_IRQn);default: {return UINT32_MAX;}}
#undef  irq_setswitch (mode) {case OPEN_IRQn: {HAL_NVIC_SetPriority(irq, preempt, sub);HAL_NVIC_EnableIRQ(irq);}break;case CLOSE_IRQn: {HAL_NVIC_DisableIRQ(irq);}break;default: {break;}}return irq;
}/*** @brief 中断使能* @param instance* @param preempt* @param sub*/
void stm32_nvic_common_enable(uint32_t instance, uint32_t preempt, uint32_t sub) {stm32_nvic_common(instance, preempt, sub, OPEN_IRQn);
}void stm32_nvic_common_disable(uint32_t instance) {stm32_nvic_common(instance, 0, 0, CLOSE_IRQn);
}
/*** @brief nvic 启用状态检测* @param instance* @return 0 未启用,1 启用*/
uint8_t stm32_nvic_common_enabled_check(uint32_t instance) {uint32_t irq = stm32_nvic_common(instance, 0, 0, READ_IRQn);return NVIC_GetEnableIRQ(irq);
}

DMA文件

头文件
/** Copyright (c) 2024-2024,shchl** SPDX-License-Identifier: Apache-2.0** Change Logs:* Date           Author       Notes* 2024-5-3     shchl   first version*/#ifndef TX_STM32_F4_DRV_DMA_OS_H
#define TX_STM32_F4_DRV_DMA_OS_H#include "drv_common.h"struct stm32_dma_info {uint32_t instance;DMA_HandleTypeDef *dma_tx;DMA_HandleTypeDef *dma_rx;
};struct stm32_dma_info *stm32_dma_info_get(uint32_t instance);void stm32_dma_clk_enable(const DMA_HandleTypeDef *handle);
void stm32_dma_clk_disable(const DMA_HandleTypeDef *handle);
#endif //TX_STM32_F4_DRV_DMA_OS_H
源文件
/** Copyright (c) 2024-2024,shchl** SPDX-License-Identifier: Apache-2.0** Change Logs:* Date           Author       Notes* 2024-5-3     shchl   first version*/#include "drv_dma_os.h"#if SPI1_DMA
static DMA_HandleTypeDef spi1_dma_tx = {.Instance=DMA2_Stream3, .Init.Channel=DMA_CHANNEL_3};
static DMA_HandleTypeDef spi1_dma_rx = {.Instance=DMA2_Stream0, .Init.Channel=DMA_CHANNEL_3};
#endifstatic DMA_HandleTypeDef sdio_dma_tx = {.Instance = DMA2_Stream6, .Init.Channel = DMA_CHANNEL_4};
static DMA_HandleTypeDef sdio_dma_rx = {.Instance = DMA2_Stream3, .Init.Channel = DMA_CHANNEL_4};
static DMA_HandleTypeDef i2s_spi2_dma_tx = {.Instance = DMA1_Stream4, .Init.Channel = DMA_CHANNEL_0};
static DMA_HandleTypeDef i2s_spi2_dma_rx = {.Instance = DMA1_Stream3, .Init.Channel = DMA_CHANNEL_3};static struct stm32_dma_info dma_info_map[] = {
#if SPI1_DMA{(uint32_t) SPI1, &spi1_dma_tx, &spi1_dma_rx},
#endif{(uint32_t) SDIO, &sdio_dma_tx, &sdio_dma_rx},{(uint32_t) SPI2, &i2s_spi2_dma_tx,&i2s_spi2_dma_rx}};
#define DMA_MAP_CNT ( sizeof(dma_info_map)/ sizeof(dma_info_map[0]))struct stm32_dma_info *stm32_dma_info_get(uint32_t instance) {for (int i = 0; i < DMA_MAP_CNT; ++i) {if (dma_info_map[i].instance == instance) {return dma_info_map + i;}}return NULL;
}void stm32_dma_clk_enable(const DMA_HandleTypeDef *handle) {switch ((uint32_t) handle->Instance) {case (uint32_t) DMA2_Stream0:case (uint32_t) DMA2_Stream1:case (uint32_t) DMA2_Stream2:case (uint32_t) DMA2_Stream3:case (uint32_t) DMA2_Stream4:case (uint32_t) DMA2_Stream5:case (uint32_t) DMA2_Stream6:case (uint32_t) DMA2_Stream7:__HAL_RCC_DMA2_CLK_ENABLE();break;case (uint32_t) DMA1_Stream0:case (uint32_t) DMA1_Stream1:case (uint32_t) DMA1_Stream2:case (uint32_t) DMA1_Stream3:case (uint32_t) DMA1_Stream4:case (uint32_t) DMA1_Stream5:case (uint32_t) DMA1_Stream6:case (uint32_t) DMA1_Stream7:__HAL_RCC_DMA1_CLK_ENABLE();break;default:return;}
}void stm32_dma_clk_disable(const DMA_HandleTypeDef *handle) {switch ((uint32_t) handle->Instance) {case (uint32_t) DMA2_Stream0:case (uint32_t) DMA2_Stream1:case (uint32_t) DMA2_Stream2:case (uint32_t) DMA2_Stream3:case (uint32_t) DMA2_Stream4:case (uint32_t) DMA2_Stream5:case (uint32_t) DMA2_Stream6:case (uint32_t) DMA2_Stream7:__HAL_RCC_DMA2_CLK_DISABLE();break;case (uint32_t) DMA1_Stream0:case (uint32_t) DMA1_Stream1:case (uint32_t) DMA1_Stream2:case (uint32_t) DMA1_Stream3:case (uint32_t) DMA1_Stream4:case (uint32_t) DMA1_Stream5:case (uint32_t) DMA1_Stream6:case (uint32_t) DMA1_Stream7:__HAL_RCC_DMA1_CLK_DISABLE();break;default:return;}
}#if SPI1_DMA
void DMA2_Stream0_IRQHandler(void) {TX_INTERRUPT_SAVE_AREATX_DISABLEHAL_DMA_IRQHandler(&spi1_dma_rx);TX_RESTORE
}void DMA2_Stream3_IRQHandler(void) {TX_INTERRUPT_SAVE_AREATX_DISABLEHAL_DMA_IRQHandler(&spi1_dma_tx);TX_RESTORE
}
#endifvoid DMA2_Stream3_IRQHandler(void) {TX_INTERRUPT_SAVE_AREATX_DISABLEHAL_DMA_IRQHandler(&sdio_dma_rx);TX_RESTORE
}void DMA2_Stream6_IRQHandler(void) {TX_INTERRUPT_SAVE_AREATX_DISABLEHAL_DMA_IRQHandler(&sdio_dma_tx);TX_RESTORE
}void DMA1_Stream4_IRQHandler(void) {HAL_DMA_IRQHandler(&i2s_spi2_dma_tx);
}
void DMA1_Stream3_IRQHandler(void) {HAL_DMA_IRQHandler(&i2s_spi2_dma_rx);
}

i2s底层驱动(使用的是双缓冲方式)

头文件

/** Copyright (c) 2024-2024,shchl** SPDX-License-Identifier: Apache-2.0** Change Logs:* Date           Author       Notes* 2024-5-6     shchl   first version*/#ifndef DRV_I2S_OS_H
#define DRV_I2S_OS_H
#include <drv_common.h>
#define I2S_AUDIO_INSTANCE SPI2
void bsp_I2sParSet(uint32_t sample_freq, uint16_t bps);
void bsp_I2sDmaEnable(uint8_t dma_tx_enable, uint8_t dma_rx_enable);
void bsp_I2sDmaParSet(DMA_InitTypeDef *tx_cfg, DMA_InitTypeDef *rx_cfg);void bsp_I2sInit(void);
void i2s_dma_tx_trans_set(const uint8_t *m0, const uint8_t *m1, uint16_t size);void i2s_play_start();
void i2s_play_stop();
void i2s_play_pause();
void i2s_play_resume();void i2s_dma_rx_trans_set(const uint8_t *m0, const uint8_t *m1, uint16_t size);
void i2s_record_start();
void i2s_record_stop();
void i2s_record_pause();
void i2s_record_resume();
#endif //DRV_I2S_OS_H

源文件

/** Copyright (c) 2024-2024,shchl** SPDX-License-Identifier: Apache-2.0** Change Logs:* Date           Author       Notes* 2024-5-6     shchl   first version*/#include "drv_i2s_os.h"
#include <drv_dma_os.h>
#include <drv_nvic_os.h>extern void i2s_dma_m0_cpltcallback(struct __DMA_HandleTypeDef *hdma) __attribute__((weak));extern void i2s_dma_m1_cpltcallback(struct __DMA_HandleTypeDef *hdma) __attribute__((weak));extern void i2s_dma_errcallback(struct __DMA_HandleTypeDef *hdma)__attribute__((weak));static I2S_HandleTypeDef handle = {.Instance = I2S_AUDIO_INSTANCE};
#define _i2s_handle (handle)/**** @param sample_freq 采样频率(hz)* @param bps 数据长度*/
void bsp_I2sParSet(const uint32_t sample_freq, uint16_t bps) {// 采样频率时钟设置RCC_PeriphCLKInitTypeDef RCCI2S2_ClkInitSture;uint32_t AudioFreq = I2S_AUDIOFREQ_44K;;if (_i2s_handle.Init.AudioFreq != sample_freq) {uint32_t PLLI2SN;uint32_t PLLI2SR;
#define SWITCH_SAMPLE_FREQ(sn,sr,freq)    {PLLI2SN = sn;PLLI2SR = sr;AudioFreq =freq;}break;// 参数配置switch (sample_freq) {case I2S_AUDIOFREQ_8K: SWITCH_SAMPLE_FREQ(256, 5, sample_freq)case I2S_AUDIOFREQ_11K: SWITCH_SAMPLE_FREQ(429, 4, sample_freq)case I2S_AUDIOFREQ_16K: SWITCH_SAMPLE_FREQ(213, 2, sample_freq)case I2S_AUDIOFREQ_22K: SWITCH_SAMPLE_FREQ(429, 4, sample_freq)case I2S_AUDIOFREQ_32K: SWITCH_SAMPLE_FREQ(213, 2, sample_freq)case I2S_AUDIOFREQ_44K: SWITCH_SAMPLE_FREQ(271, 2, sample_freq)case I2S_AUDIOFREQ_48K: SWITCH_SAMPLE_FREQ(258, 3, sample_freq)case I2S_AUDIOFREQ_96K: SWITCH_SAMPLE_FREQ(344, 2, sample_freq)case I2S_AUDIOFREQ_192K: SWITCH_SAMPLE_FREQ(393, 2, sample_freq)default: SWITCH_SAMPLE_FREQ(271, 2, 44100) // 使用44100}
#undef SWITCH_SAMPLE_FREQRCCI2S2_ClkInitSture.PeriphClockSelection = RCC_PERIPHCLK_I2S; //外设时钟源选择RCCI2S2_ClkInitSture.PLLI2S.PLLI2SN = PLLI2SN; //设置PLLI2SNRCCI2S2_ClkInitSture.PLLI2S.PLLI2SR = PLLI2SR; //设置PLLI2SRHAL_RCCEx_PeriphCLKConfig(&RCCI2S2_ClkInitSture); //设置时钟,并启用}// i2s 配置{_i2s_handle.Instance = I2S_AUDIO_INSTANCE;_i2s_handle.Init.AudioFreq = AudioFreq; //IIS频率设置_i2s_handle.Init.MCLKOutput = I2S_MCLKOUTPUT_ENABLE; //主时钟输出使能_i2s_handle.Init.ClockSource = I2S_CLOCK_PLL; //IIS时钟源为PLLswitch (bps) {//("飞利浦标准,24位数据长度");case 24:_i2s_handle.Init.Mode = I2S_MODE_MASTER_TX; //IIS模式_i2s_handle.Init.Standard = I2S_STANDARD_PHILIPS; //IIS标准_i2s_handle.Init.CPOL = I2S_CPOL_LOW; //空闲状态时钟电平_i2s_handle.Init.DataFormat = I2S_DATAFORMAT_24B; //IIS数据长度break;case 32://飞利浦标准,主机发送,时钟低电平有效,24位扩展帧长度_i2s_handle.Init.Mode = I2S_MODE_MASTER_TX;_i2s_handle.Init.Standard = I2S_STANDARD_PHILIPS;_i2s_handle.Init.CPOL = I2S_CPOL_LOW;_i2s_handle.Init.DataFormat = I2S_DATAFORMAT_32B;break;default:// 飞利浦标准,主机发送,时钟低电平有效,16位帧长度_i2s_handle.Init.Mode = I2S_MODE_MASTER_TX;_i2s_handle.Init.Standard = I2S_STANDARD_PHILIPS;_i2s_handle.Init.CPOL = I2S_CPOL_LOW;_i2s_handle.Init.DataFormat = I2S_DATAFORMAT_16B_EXTENDED;break;}}}void bsp_I2sDmaEnable(uint8_t dma_tx_enable, uint8_t dma_rx_enable) {struct stm32_dma_info *dma_info = stm32_dma_info_get((uint32_t) _i2s_handle.Instance);if (dma_tx_enable && dma_info->dma_tx) {__HAL_LINKDMA(&_i2s_handle, hdmatx, *(dma_info->dma_tx)); //将DMA与I2S联系起来}if (dma_rx_enable && dma_info->dma_rx) {__HAL_LINKDMA(&_i2s_handle, hdmarx, *(dma_info->dma_rx)); //将DMA与I2S联系起来}
}/*** @brief dma 配置设置   使用此函数之前,必须调用 @ref bsp_I2sDmaEnable ;* @param tx_cfg   tx dma 配置* @param rx_cfg   rx dma 配置*/
void bsp_I2sDmaParSet(DMA_InitTypeDef *tx_cfg, DMA_InitTypeDef *rx_cfg) {if (_i2s_handle.hdmatx) {if (tx_cfg) {// 统一在dma配置源文件中配置,不在此处进行配置_i2s_handle.hdmatx->Init.Direction = tx_cfg->Direction;_i2s_handle.hdmatx->Init.PeriphInc = tx_cfg->PeriphInc;_i2s_handle.hdmatx->Init.MemInc = tx_cfg->MemInc;_i2s_handle.hdmatx->Init.PeriphDataAlignment = tx_cfg->PeriphDataAlignment;_i2s_handle.hdmatx->Init.MemDataAlignment = tx_cfg->MemDataAlignment;_i2s_handle.hdmatx->Init.Mode = tx_cfg->Mode;_i2s_handle.hdmatx->Init.Priority = tx_cfg->Priority;_i2s_handle.hdmatx->Init.FIFOMode = tx_cfg->FIFOMode;_i2s_handle.hdmatx->Init.FIFOThreshold = tx_cfg->FIFOThreshold;_i2s_handle.hdmatx->Init.MemBurst = tx_cfg->MemBurst;_i2s_handle.hdmatx->Init.PeriphBurst = tx_cfg->PeriphBurst;} else {// 统一在dma配置源文件中配置,不在此处进行配置// hi2s_ptr->hdmatx->Instance = DMA1_Stream4; //DMA1数据流4// hi2s_ptr->hdmatx->Init.Channel = DMA_CHANNEL_0; //通道0_i2s_handle.hdmatx->Init.Direction = DMA_MEMORY_TO_PERIPH; //存储器到外设模式_i2s_handle.hdmatx->Init.PeriphInc = DMA_PINC_DISABLE; //外设非增量模式_i2s_handle.hdmatx->Init.MemInc = DMA_MINC_ENABLE; //存储器增量模式_i2s_handle.hdmatx->Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD; //外设数据长度:16位_i2s_handle.hdmatx->Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD; //存储器数据长度:16位_i2s_handle.hdmatx->Init.Mode = DMA_CIRCULAR; //使用循环模式_i2s_handle.hdmatx->Init.Priority = DMA_PRIORITY_MEDIUM; //高优先级_i2s_handle.hdmatx->Init.FIFOMode = DMA_FIFOMODE_ENABLE; //使用FIFO_i2s_handle.hdmatx->Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL; // 使用FIFO阈值完全配置_i2s_handle.hdmatx->Init.MemBurst = DMA_MBURST_INC8; //存储器单次突发传输_i2s_handle.hdmatx->Init.PeriphBurst = DMA_MBURST_INC8; //外设突发单次传输}}if (_i2s_handle.hdmarx) {if (rx_cfg) {_i2s_handle.hdmarx->Init.Direction = rx_cfg->Direction;_i2s_handle.hdmarx->Init.PeriphInc = rx_cfg->PeriphInc;_i2s_handle.hdmarx->Init.MemInc = rx_cfg->MemInc;_i2s_handle.hdmarx->Init.PeriphDataAlignment = rx_cfg->PeriphDataAlignment;_i2s_handle.hdmarx->Init.MemDataAlignment = rx_cfg->MemDataAlignment;_i2s_handle.hdmarx->Init.Mode = rx_cfg->Mode;_i2s_handle.hdmarx->Init.Priority = rx_cfg->Priority;_i2s_handle.hdmarx->Init.FIFOMode = rx_cfg->FIFOMode;_i2s_handle.hdmarx->Init.FIFOThreshold = rx_cfg->FIFOThreshold;_i2s_handle.hdmarx->Init.MemBurst = rx_cfg->MemBurst;_i2s_handle.hdmarx->Init.PeriphBurst = rx_cfg->PeriphBurst;} else {// todo 录音部分// _i2s_handle.hdmarx->Instance=DMA1_Stream3;                       		//DMA1数据流3// _i2s_handle.hdmarx->Init.Channel=DMA_CHANNEL_3;                  		//通道3_i2s_handle.hdmarx->Init.Direction = DMA_PERIPH_TO_MEMORY; //外设到存储器模式_i2s_handle.hdmarx->Init.PeriphInc = DMA_PINC_DISABLE; //外设非增量模式_i2s_handle.hdmarx->Init.MemInc = DMA_MINC_ENABLE; //存储器增量模式_i2s_handle.hdmarx->Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD; //外设数据长度:16位_i2s_handle.hdmarx->Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD; //存储器数据长度:16位_i2s_handle.hdmatx->Init.Mode = DMA_CIRCULAR; //使用循环模式_i2s_handle.hdmatx->Init.Priority = DMA_PRIORITY_MEDIUM; //高优先级_i2s_handle.hdmatx->Init.FIFOMode = DMA_FIFOMODE_ENABLE; //使用FIFO_i2s_handle.hdmatx->Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL; // 使用FIFO阈值完全配置_i2s_handle.hdmatx->Init.MemBurst = DMA_MBURST_INC8; //存储器单次突发传输_i2s_handle.hdmatx->Init.PeriphBurst = DMA_MBURST_INC8; //外设突发单次传输}}
}void bsp_I2sInit(void) {// 初始化{HAL_I2S_Init(&_i2s_handle);}}
void i2s_play_start() {// 判断是否初始化i2sDISABLE_INT();if (_i2s_handle.Instance) {__HAL_DMA_ENABLE(_i2s_handle.hdmatx); //打开dma/*使能相应标志位*/__HAL_I2S_ENABLE(&_i2s_handle); //使能I2S2/* Enable Tx DMA Request */__HAL_I2S_ENABLE_IT(&_i2s_handle, SPI_CR2_TXDMAEN); //SPI2 TX DMA请求使能.}ENABLE_INT();
}void i2s_play_stop() {// 判断是否初始化,并只初始化一次if (_i2s_handle.Instance) {// 复位i2s,内部已经对相应的DMA进行复位,所以这里就不需要__HAL_I2S_DISABLE_IT(&_i2s_handle, SPI_CR2_TXDMAEN); //SPI2 TX DMA请求使能.HAL_I2S_DeInit(&_i2s_handle);_i2s_handle.Instance = NULL;}
}void i2s_play_pause() {if ((_i2s_handle.hdmatx->Instance->CR & DMA_SxCR_EN)) {/* Disable the stream */__HAL_DMA_DISABLE(_i2s_handle.hdmatx);/* Check if the DMA Stream is effectively disabled */while ((_i2s_handle.hdmatx->Instance->CR & DMA_SxCR_EN) != RESET) {}}
}void i2s_play_resume() {if ((_i2s_handle.hdmatx->Instance->CR & DMA_SxCR_EN) == RESET) {__HAL_DMA_ENABLE(_i2s_handle.hdmatx);}
}/*** 用于播放* @param m0* @param m1* @param size*/
void i2s_dma_tx_trans_set(const uint8_t *m0, const uint8_t *m1, uint16_t size) {if (_i2s_handle.hdmatx == NULL) {Error_Handler();}/*配置回调函数*/_i2s_handle.hdmatx->XferCpltCallback = i2s_dma_m0_cpltcallback;_i2s_handle.hdmatx->XferM1CpltCallback = i2s_dma_m1_cpltcallback;_i2s_handle.hdmatx->XferErrorCallback = i2s_dma_errcallback;/*开启dma双缓冲模式*//* 开启双缓冲模式 */_i2s_handle.hdmatx->Instance->CR |= (uint32_t) DMA_SxCR_DBM;/* m1地址 */_i2s_handle.hdmatx->Instance->M1AR = (uint32_t) m1;/* m0地址 */_i2s_handle.hdmatx->Instance->M0AR = (uint32_t) m0;/* 传输数据长度 */_i2s_handle.hdmatx->Instance->NDTR = size;/* 目标地址 */_i2s_handle.hdmatx->Instance->PAR = (uint32_t) &(_i2s_handle.Instance->DR);/* 清除所有标志位 */__HAL_DMA_CLEAR_FLAG(_i2s_handle.hdmatx, __HAL_DMA_GET_TC_FLAG_INDEX( _i2s_handle.hdmatx));__HAL_DMA_CLEAR_FLAG(_i2s_handle.hdmatx, __HAL_DMA_GET_HT_FLAG_INDEX( _i2s_handle.hdmatx));__HAL_DMA_CLEAR_FLAG(_i2s_handle.hdmatx, __HAL_DMA_GET_TE_FLAG_INDEX( _i2s_handle.hdmatx));__HAL_DMA_CLEAR_FLAG(_i2s_handle.hdmatx, __HAL_DMA_GET_DME_FLAG_INDEX( _i2s_handle.hdmatx));__HAL_DMA_CLEAR_FLAG(_i2s_handle.hdmatx, __HAL_DMA_GET_FE_FLAG_INDEX( _i2s_handle.hdmatx));/* 使能中断标志位*/_i2s_handle.hdmatx->Instance->CR |= DMA_IT_TC | DMA_IT_TE | DMA_IT_DME;_i2s_handle.hdmatx->Instance->FCR |= DMA_IT_FE;
}void i2s_dma_rx_trans_set(const uint8_t *m0, const uint8_t *m1, uint16_t size) {if (_i2s_handle.hdmarx == NULL) {Error_Handler();}/*配置回调函数*/_i2s_handle.hdmarx->XferCpltCallback = i2s_dma_m0_cpltcallback;_i2s_handle.hdmarx->XferM1CpltCallback = i2s_dma_m1_cpltcallback;_i2s_handle.hdmarx->XferErrorCallback = i2s_dma_errcallback;/*开启dma双缓冲模式*//* 开启双缓冲模式 */_i2s_handle.hdmarx->Instance->CR |= (uint32_t) DMA_SxCR_DBM;/* m1地址 */_i2s_handle.hdmarx->Instance->M1AR = (uint32_t) m1;/* m0地址 */_i2s_handle.hdmarx->Instance->M0AR = (uint32_t) m0;/* 传输数据长度 */_i2s_handle.hdmarx->Instance->NDTR = size;/* 源地址 */_i2s_handle.hdmarx->Instance->PAR = (uint32_t) &(_i2s_handle.Instance->DR);/* 清除所有标志位 */__HAL_DMA_CLEAR_FLAG(_i2s_handle.hdmarx, __HAL_DMA_GET_TC_FLAG_INDEX( _i2s_handle.hdmarx));__HAL_DMA_CLEAR_FLAG(_i2s_handle.hdmarx, __HAL_DMA_GET_HT_FLAG_INDEX( _i2s_handle.hdmarx));__HAL_DMA_CLEAR_FLAG(_i2s_handle.hdmarx, __HAL_DMA_GET_TE_FLAG_INDEX( _i2s_handle.hdmarx));__HAL_DMA_CLEAR_FLAG(_i2s_handle.hdmarx, __HAL_DMA_GET_DME_FLAG_INDEX( _i2s_handle.hdmarx));__HAL_DMA_CLEAR_FLAG(_i2s_handle.hdmarx, __HAL_DMA_GET_FE_FLAG_INDEX( _i2s_handle.hdmarx));/* 使能中断标志位*/_i2s_handle.hdmarx->Instance->CR |= DMA_IT_TC | DMA_IT_TE | DMA_IT_DME;_i2s_handle.hdmarx->Instance->FCR |= DMA_IT_FE;
}void i2s_record_start() {// 判断是否初始化i2sDISABLE_INT();if (_i2s_handle.Instance) {__HAL_DMA_ENABLE(_i2s_handle.hdmarx); //打开dma/*使能相应标志位*/__HAL_I2S_ENABLE(&_i2s_handle); //使能I2S2/* Enable Tx DMA Request */__HAL_I2S_ENABLE_IT(&_i2s_handle, SPI_CR2_RXDMAEN); //SPI2 TX DMA请求使能.}ENABLE_INT();
}void i2s_record_stop() {// 判断是否初始化,并只初始化一次if (_i2s_handle.Instance) {// 复位i2s,内部已经对相应的DMA进行复位,所以这里就不需要__HAL_I2S_DISABLE_IT(&_i2s_handle, SPI_CR2_RXDMAEN); //SPI2 TX DMA请求使能.HAL_I2S_DeInit(&_i2s_handle);_i2s_handle.Instance = NULL;}
}void i2s_record_pause() {if ((_i2s_handle.hdmarx->Instance->CR & DMA_SxCR_EN)) {/* Disable the stream */__HAL_DMA_DISABLE(_i2s_handle.hdmarx);/* Check if the DMA Stream is effectively disabled */while ((_i2s_handle.hdmarx->Instance->CR & DMA_SxCR_EN) != RESET) {}}
}void i2s_record_resume() {if ((_i2s_handle.hdmarx->Instance->CR & DMA_SxCR_EN) == RESET) {__HAL_DMA_ENABLE(_i2s_handle.hdmarx);}
}

硬件io文件

/** Copyright (c) 2024-2024,shchl** SPDX-License-Identifier: Apache-2.0** Change Logs:* Date           Author       Notes* 2024-5-2     shchl   first version*/
#include "bsp.h"/*** @brief I2S MSP Init* @param  hi2s_ptr pointer to a I2S_HandleTypeDef structure that contains*         the configuration information for I2S module* @retval None*/
void HAL_I2S_MspInit(I2S_HandleTypeDef *hi2s_ptr) {if (hi2s_ptr->Instance == SPI2) {/*I2S GPIO 初始化*/{GPIO_InitTypeDef GPIO_InitStruct;/* Peripheral clock enable */__HAL_RCC_SPI2_CLK_ENABLE();__HAL_RCC_GPIOC_CLK_ENABLE();__HAL_RCC_GPIOB_CLK_ENABLE();/**I2S2 GPIO ConfigurationPC2     ------> I2S2_ext_SDPC3     ------> I2S2_SDPB12     ------> I2S2_WSPB13     ------> I2S2_CKPC6     ------> I2S2_MCK*/GPIO_InitStruct.Pin = GPIO_PIN_2;GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;GPIO_InitStruct.Pull = GPIO_NOPULL;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;GPIO_InitStruct.Alternate = GPIO_AF6_I2S2ext;HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);GPIO_InitStruct.Pin = GPIO_PIN_3 | GPIO_PIN_6;GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;GPIO_InitStruct.Pull = GPIO_NOPULL;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;GPIO_InitStruct.Alternate = GPIO_AF5_SPI2;HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);GPIO_InitStruct.Pin = GPIO_PIN_12 | GPIO_PIN_13;GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;GPIO_InitStruct.Pull = GPIO_NOPULL;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;GPIO_InitStruct.Alternate = GPIO_AF5_SPI2;HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);}/* I2S DMA发送配置 */if (hi2s_ptr->hdmatx) {stm32_dma_clk_enable(hi2s_ptr->hdmatx); //使能DMA时钟HAL_DMA_Init(hi2s_ptr->hdmatx); //初始化DMAstm32_nvic_common_enable((uint32_t) hi2s_ptr->hdmatx->Instance, 0, 0);};}
}void HAL_I2S_MspDeInit(I2S_HandleTypeDef *handle_ptr) {if (handle_ptr->Instance == SPI2) {/**//* Peripheral clock disable */__HAL_RCC_SPI2_CLK_DISABLE();/**I2S2 GPIO ConfigurationPC2     ------> I2S2_ext_SDPC3     ------> I2S2_SDPB12     ------> I2S2_WSPB13     ------> I2S2_CKPC6     ------> I2S2_MCK*/HAL_GPIO_DeInit(GPIOC, GPIO_PIN_2 | GPIO_PIN_3 | GPIO_PIN_6);HAL_GPIO_DeInit(GPIOB, GPIO_PIN_10 | GPIO_PIN_12);if (handle_ptr->hdmatx) {/* I2S2 DMA DeInit */HAL_DMA_DeInit(handle_ptr->hdmatx);stm32_nvic_common_disable((uint32_t) handle_ptr->hdmatx->Instance);}}
}

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

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

相关文章

Mac电脑设置hosts的方法

hosts文件是什么 hosts文件是一个系统文件&#xff0c;通过绑定域名与ip的关系&#xff0c;当本机访问该域名时 从这个文件中如果找到了对应域名&#xff0c;则转发到对应ip&#xff1b;如果没有找到对应域名&#xff0c;则走默认的DNS公网解析。 好处&#xff1a; 加速访问…

如何delphi7中添加自定义的控件或组件

1.问题 为了编写方便&#xff0c;会自己生成一些自定义的控件。 XXX.PAS:源码文件&#xff0c;后续可以再调整 XXX.DCU:编译后的文件 2.解决办法 1.自定义控件的文件如下 2.将这些文件保留在程式代码中&#xff0c;万一丢失会导致程式开启后报是否忽略 3.选择菜单栏中的com…

我独自升级崛起游戏账号登录注册教程 (5.8最新版)

新韩漫公司所发布的这项动作游戏已向玩家们敞开大门&#xff0c;为大家带来了前所未有的游戏体验和乐趣。这个游戏内包含了大量令人着迷的故事、令人印象深刻的战斗场景以及丰富多样的娱乐元素。在这其中最为引人注目的一点就是游戏内容中融入了“虚拟角色”的元素&#xff0c;…

QT:基于QT实现Boost搜索引擎客户端

文章目录 写在前面关于服务器开源仓库和项目上线其他文档说明 登录界面主体设计思路验证登录注册功能 注册界面主体界面main函数中绑定槽函数 写在前面 关于服务器 本项目使用的是一个仿mudou库one-thread-one-loop式并发服务器的组件&#xff0c;关于该组件的细节内容在下面…

计算机网络4——网络层8 软件定义网络 SDN

文章目录 一、介绍1、简介2、原理3、案例1&#xff09;普通2&#xff09;负载均衡的例子3&#xff09;防火墙的例子 二、控制层面1、特征2、层次 一、介绍 1、简介 SDN的概念最初由斯坦福大学N.McKeown于2009年首先提出。当时还只是在学术界进行探讨的一种新的网络体系结构。…

Nvidia发布Llama3-ChatQA-1.5: 提升对话问答和表格推理能力,平均性能超越GPT-4

前言 近日&#xff0c;Nvidia推出了一款名为Llama3-ChatQA-1.5的对话问答模型。该模型在对话式问答和检索增强型生成等能力方面表现出色&#xff0c;在综合评测指标上甚至超越了当前业界顶尖的GPT-4模型。 技术特点 Llama3-ChatQA-1.5是基于Llama-3基础模型训练而成的。相比之…

JS本地储存基础(一)

本地存储分类-localStorage 语法&#xff1a;存储数据&#xff1a;(本来没有就是储存&#xff0c;本来有就是修改) localStorage.setltem(key,value) 获取数据&#xff1a; localStorage.getltem(key) 删除数据&#xff1a; localStorage.removeltem(key) 注意&#xf…

HTML 基本骨架(二)

基本骨架 <!DOCTYPE html> <!-- 声明文档类型为 HTML --> <html lang"en"> <!-- 指定文档语言为英语 --> <head><meta charset"UTF-8"> <!-- 设置字符编码为 UTF-8 --><meta name"viewport" cont…

东湖高新区2023年现代服务业政策奖励申报对象、申报方式

东湖高新区信息服务、科技服务、科创金融、新消费、商务服务、现代物流等行业的服务业企业开展2023年度现代服务业政策奖励申报工作,有关申报内容如下&#xff0c;东湖高新区的企业单位可以了解一下&#xff0c;有问题看名字找我。 一、申报对象 工商注册、税务关系及统计关系…

《QT实用小工具·五十八》模仿VSCode的可任意拖拽的Tab标签组

1、概述 源码放在文章末尾 该项目实现了模仿VSCode的可任意拖拽的Tab标签组&#xff0c;包含如下功能&#xff1a; 拖拽标签页至新窗口 拖拽标签页合并控件 无限嵌套的横纵分割布局&#xff08;类似Qt Creator的编辑框&#xff09; 获取当前使用的标签组、标签页 自动向上合并…

Elementui的el-footer标签使用报错

Elementui的el-footer标签使用报错 其余标签的使用没有报错信息 el-footer的报错信息 原因: ​ 警告信息表示 Vue 不识别 <el-footer> 解决方式: 在组件中进行引入和暴露

Hive数据模型

Hive数据模型 1. 表&#xff08;Table&#xff09;&#xff1a; 表是数据库中的基本组成单位&#xff0c;用于存储数据。它由一系列的行和列组成&#xff0c;每行代表一个记录&#xff0c;每列代表一种属性或字段。创建表时&#xff0c;你需要定义列的数据类型、约束和索引等信…

Linux:进程概念(二.查看进程、父进程与子进程、进程状态详解)

Linux&#xff1a;进程概念&#xff08;二.查看进程、父进程与子进程、进程状态详解&#xff09; 上次讲了一下:Linux&#xff1a;冯诺依曼体系结构、操作系统、初识进程 文章目录 1.查看进程1.1准备工作1.2 指令&#xff1a;ps—显示当前系统中运行的进程信息1.3查看进程属性…

偶然发现了Python的一个BUG。。。

一般情况下&#xff0c;dict(id1, **{id: 1})这句代码应该报TypeError。但如果在捕获了其他异常的情况下&#xff0c;再来执行这句代码&#xff0c;却是会报KeyError&#xff0c;如下图&#xff1a; Python3.10和Python3.9也能复现该情况&#xff0c;正当我摩拳踩掌&#xff0c…

C语言知识点补充——ASCLL码表

1、ASCLL码表 ASCII码表&#xff08;American Standard Code for Information Interchange&#xff09;是一种用于将字符编码为数字的标准。它定义了128个字符的编码方式&#xff0c;包括数字、字母、标点符号和控制字符等。每个字符都对应一个唯一的7位或8位二进制数 2、Ascl…

【Ping】Windows 网络延迟测试 ping 、telnet、tcping 工具

ping 命令 属于网络层的ICMP协议&#xff0c;只能检查 IP 的连通性或网络连接速度&#xff0c; 无法检测IP的端口状态。 telnet telnet命令&#xff0c;属于应用层的协议&#xff0c;用于远程登录&#xff0c;也可用于检测IP的端口状态。但是功能有限&#xff0c;只能检测一时…

如何使git提交的时候忽略一些特殊文件?

认识.gitignore文件 在生成远程仓库的时候我们会看到这样一个选项&#xff1a; 这个.gitignore文件有啥用呢&#xff1f; .gotignore文件是Git版本控制系统中的一个特殊文件。用来指定哪些文件或者目录不被Git追踪或者提交到版本库中。也就意味着&#xff0c;如果我们有一些文…

在spring中使用bytebuddy 对bean做Aop拦截

背景 拦截spring 中的某个bean拦截其方法的调用。在其前后做一些类似于aop的操作 拦截bean MyBeanDefinitionRegistryPostProcessor import lombok.extern.slf4j.Slf4j; import net.bytebuddy.ByteBuddy; import net.bytebuddy.asm.Advice; import org.springframework.bea…

Linux下网络编程-简易Epll服务器和客户端

Linux下网络编程-简易Epll服务器和客户端 简易Epll服务器: #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <arpa/inet.h> #include <sys/socket.h> #include <sys/epoll.h>#define B…

NIO BIO AIO详解

BIO: 同步阻塞I/O&#xff0c;是JDK1.4之前的传统IO模型。 线程发起IO请求后&#xff0c;一直阻塞&#xff0c;直到缓冲区数据就绪后&#xff0c;再进入下一步操作。 NIO:同步非阻塞IO&#xff0c;当线程发起IO请求后&#xff0c;不需要阻塞&#xff0c;会立即返回。用户线程不…