嵌入式大厂面经 STM32 DMA常见面试题(持续更新中!)

这是一个嵌入式大厂面试题专栏,每天更新高频面试题。专栏将包含题目描述、详细解析、相关知识点扩展以及实际代码示例。内容涵盖操作系统、驱动开发、通信协议等核心领域,并结合实际项目经验进行分析。每道题目都会附带面试官可能的追问方向,帮助大家更好地准备面试!

STM32 DMA常见面试题

DMA(直接内存访问)是STM32微控制器中非常重要的外设,能够显著提高系统性能。以下是STM32 DMA相关的常见面试题及解答:

1. DMA的基本概念

什么是DMA?

DMA(Direct Memory Access)是一种无需CPU干预即可在外设和内存之间、或内存与内存之间传输数据的技术。DMA控制器可以独立于CPU工作,从而释放CPU资源用于其他任务。

DMA的主要优势

  • 减轻CPU负担,提高系统效率
  • 数据传输速度快,实时性好
  • 适合大量数据传输场景
  • 降低功耗(相比CPU轮询方式)

2. STM32 DMA架构

STM32 DMA控制器特点

不同系列STM32的DMA控制器有所不同:

  • STM32F1系列:2个DMA控制器(DMA1/DMA2)每个控制器有7个通道通道优先级可配置
  • STM32F4系列:2个DMA控制器每个控制器有8个数据流(Stream)每个数据流可以配置为8个通道请求之一支持双缓冲区模式和FIFO
// STM32F4 DMA控制器结构
typedef struct {
    DMA_Stream_TypeDef *Stream;    // DMA数据流
    uint32_t Channel;              // DMA通道
    uint32_t PeripheralBaseAddr;   // 外设地址
    uint32_t MemoryBaseAddr;       // 内存地址
    uint32_t Direction;            // 传输方向
    uint32_t BufferSize;           // 缓冲区大小
    uint32_t PeripheralInc;        // 外设地址增量模式
    uint32_t MemoryInc;            // 内存地址增量模式
    uint32_t PeripheralDataSize;   // 外设数据宽度
    uint32_t MemoryDataSize;       // 内存数据宽度
    uint32_t Mode;                 // 工作模式
    uint32_t Priority;             // 优先级
} DMA_InitTypeDef;

3. DMA传输模式

基本传输模式

  • 存储器到外设:从内存读取数据发送到外设
  • 外设到存储器:从外设接收数据存储到内存
  • 存储器到存储器:在两个内存区域之间传输数据(部分STM32系列支持)

工作模式

  • 正常模式:传输完成后停止
  • 循环模式:传输完成后自动重新开始传输
  • 双缓冲模式:使用两个内存缓冲区交替工作(F4及以上系列支持)
// 配置DMA工作模式示例
void DMA_ModeConfig(void) {
    // 正常模式
    DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
    
    // 循环模式
    DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
    
    // STM32F4双缓冲模式
    DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
    DMA_DoubleBufferModeConfig(DMA2_Stream0, (uint32_t)Buffer1, (uint32_t)Buffer2);
    DMA_DoubleBufferModeCmd(DMA2_Stream0, ENABLE);
}

4. DMA配置参数详解

关键配置参数

  • 外设/内存地址:数据源和目标地址
  • 数据方向:外设到内存、内存到外设、内存到内存
  • 传输数据大小:要传输的数据项数量
  • 地址增量模式:地址是否在每次传输后自动增加
  • 数据宽度:8位、16位或32位
  • 优先级:低、中、高、超高
  • 传输模式:正常、循环等
  • 中断使能:传输完成、半传输完成、错误中断等
// STM32F1 DMA基本配置示例
void DMA_BasicConfig(void) {
    // 使能DMA时钟
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
    
    // 配置DMA通道
    DMA_InitTypeDef DMA_InitStructure;
    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&SPI1->DR;       // 外设地址
    DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)TxBuffer;            // 内存地址
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;                    // 数据方向
    DMA_InitStructure.DMA_BufferSize = BUFFER_SIZE;                       // 缓冲区大小
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;      // 外设地址固定
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;               // 内存地址递增
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; // 外设数据宽度
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;       // 内存数据宽度
    DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;                         // 工作模式
    DMA_InitStructure.DMA_Priority = DMA_Priority_High;                   // 优先级
    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;                          // 非内存到内存模式
    
    DMA_Init(DMA1_Channel3, &DMA_InitStructure);
    
    // 使能DMA通道
    DMA_Cmd(DMA1_Channel3, ENABLE);
}

5. DMA与外设结合应用

UART与DMA结合

// UART DMA发送配置
void UART_DMA_TxConfig(void) {
    // 配置DMA
    DMA_InitTypeDef DMA_InitStructure;
    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&USART1->DR;
    DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)TxBuffer;
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
    DMA_InitStructure.DMA_BufferSize = BUFFER_SIZE;
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
    DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
    DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;
    DMA_Init(DMA1_Channel4, &DMA_InitStructure);  // USART1_TX对应DMA1_Channel4
    
    // 使能UART DMA发送请求
    USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE);
    
    // 使能DMA通道
    DMA_Cmd(DMA1_Channel4, ENABLE);
}

// UART DMA接收配置
void UART_DMA_RxConfig(void) {
    // 配置DMA
    DMA_InitTypeDef DMA_InitStructure;
    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&USART1->DR;
    DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)RxBuffer;
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
    DMA_InitStructure.DMA_BufferSize = BUFFER_SIZE;
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
    DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;  // 循环模式接收
    DMA_InitStructure.DMA_Priority = DMA_Priority_High;
    DMA_Init(DMA1_Channel5, &DMA_InitStructure);  // USART1_RX对应DMA1_Channel5
    
    // 使能UART DMA接收请求
    USART_DMACmd(USART1, USART_DMAReq_Rx, ENABLE);
    
    // 使能DMA通道
    DMA_Cmd(DMA1_Channel5, ENABLE);
}

ADC与DMA结合

// ADC DMA配置
void ADC_DMA_Config(void) {
    // 配置DMA
    DMA_InitTypeDef DMA_InitStructure;
    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR;
    DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)ADC_ConvertedValue;
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
    DMA_InitStructure.DMA_BufferSize = ADC_CHANNEL_NUM;  // 多通道采样
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
    DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
    DMA_InitStructure.DMA_Priority = DMA_Priority_High;
    DMA_Init(DMA1_Channel1, &DMA_InitStructure);  // ADC1对应DMA1_Channel1
    
    // 使能DMA通道
    DMA_Cmd(DMA1_Channel1, ENABLE);
    
    // 配置ADC DMA模式
    ADC_DMACmd(ADC1, ENABLE);
}

SPI与DMA结合

// SPI DMA发送配置
void SPI_DMA_TxConfig(void) {
    // 配置DMA
    DMA_InitTypeDef DMA_InitStructure;
    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&SPI1->DR;
    DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)SPI_TxBuffer;
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
    DMA_InitSt

剩余60%内容,订阅专栏后可继续查看/也可单篇购买

嵌入式面试八股文全集 文章被收录于专栏

这是一个全面的嵌入式面试专栏。主要内容将包括:操作系统(进程管理、内存管理、文件系统等)、嵌入式系统(启动流程、驱动开发、中断管理等)、网络通信(TCP/IP协议栈、Socket编程等)、开发工具(交叉编译、调试工具等)以及实际项目经验分享。专栏将采用理论结合实践的方式,每个知识点都会附带相关的面试真题和答案解析。

全部评论

相关推荐

韶音科技-嵌入式面经韶音给我的感受还是很不错的,分享一手面经一面-hr面-30分钟主要聊聊家常,问题都比较常规吧,真诚回答就行二面-专业面-30分钟自我介绍想聊一聊哪个项目?项目是如何进行通信的?有哪些措施来保证数据的可靠性?讲一讲CRC校验讲一讲你了解的linux操作系统项目能实现哪些功能?多线程开发需要注意些什么?遇到哪些困难?为什么选择嵌入式开发方向?反问三面-专业面-30分钟自我介绍项目介绍介绍一下Linux操作系统线程和进程的区别,分别是怎么通信的用户空间和内核空间的访问方式内存映射的适应场景?内存映射可能出现什么问题?自旋锁和互斥锁的概念是什么对epoll的理解EMMC读写是怎么用的?手撕:一道简单链表题(口述思路)反问战略和营销很多HC!韶音科技25届补招内推启动拉!!!深圳市韶音科技有限公司(简称“韶音科技”)创立于2004年,是一家专注于电、声产品研发、设计、生产和营销的专精特新重点“小巨人”企业。还有大量需求!使用内推码简历优先筛选,有任何问题包括进度查询可以私信我,内推后在评论区留言【姓名缩写+岗位】,方便捞人和确认投递状态研发,营销,供应链,财务,法务,专利,人资,IT,设计超多米哈游岗位近7年营收增长超百倍的科技公司等你加入!【内推链接】https://app.mokahr.com/m/campus-recruitment/aftershokzhr/36940?recommendCode=DSe1vF9A&hash=%23%2Fjobs#/jobs【内推码】DSe1vF9A(内推简历有免笔试的机会!)使用内推码简历优先筛选,有任何问题包括进度查询可以私信我,内推后在评论区留言【姓名缩写+岗位】,方便捞人和确认投递状态 #春招#                                       #内推#                                       #内推码#                                       #秋招#                                       #韶音科技#                                       #牛客创作赏金赛#                     
点赞 评论 收藏
分享
评论
点赞
6
分享

创作者周榜

更多
牛客网
牛客企业服务