尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

STM32F030 SPI从机配置实战:硬件NSS与DMA双缓冲架构详解

STM32F030 SPI从机配置实战:硬件NSS与DMA双缓冲架构详解 简介本资源是一套面向嵌入式初学者与STM32开发者的SPI从机实战工程聚焦STM32F030系列在Cortex-M0平台上的SPI从机模式完整实现解决常见从机配置难、时序不稳定、中断响应不及时等实际问题。压缩包含136个文件主体为37个.h头文件与29个.c源码文件涵盖SPI底层驱动、GPIO初始化、中断服务及主循环逻辑辅以.o目标文件、.d依赖文件、.axf调试镜像及Keil工程相关配置.uvprojx/.uvoptx/.dbgconf等整体大小1.22MB结构完整可直接编译运行。已有2061人学习下载配套Keil MDK工程已预置TIM/RTC/USART等外设基础模块SPI1从机配置采用HAL库标准流程包含NSS硬输入模式、8位数据帧、CPOL/CPHA参数适配及阻塞式接收示例同时保留关键寄存器操作注释便于理解协议层与硬件交互细节是掌握STM32 SPI从机开发的高实用性参考工程。1. 项目概述从零构建一个可靠的STM32F030 SPI从机搞嵌入式开发尤其是用STM32做通信SPI绝对是个绕不开的坎。主机模式相对好理解配置好时钟、发数据就完事了。但一到从机模式尤其是用STM32F030这种资源相对紧凑的Cortex-M0内核芯片各种坑就来了时钟相位对不上、数据错位、DMA配置不当导致死锁……我最近刚用STM32F030F4P6这颗只有16KB Flash的芯片为一个CCD视觉对位贴合机的传感器模块完成了SPI从机程序期间踩遍了能想到的坑也总结出了一套稳定可靠的配置流程。这个项目的核心目标是让STM32F030作为从设备能够稳定、准确地响应来自主机可能是一台工控机、另一颗MCU或者像AD2S1210这样的专用芯片的SPI通信请求。它不仅要能收数据还要能根据命令回传正确的数据并且在资源有限的情况下处理好可能的数据流突发。整个过程涉及硬件SPI外设的精准配置、GPIO的复用、中断或DMA的高效利用以及如何规避M0内核的一些特殊陷阱比如结构体对齐引发的Hard Fault。如果你正在为STM32F030或者其他M0/M0内核的SPI从机配置头疼这篇从实战中总结的笔记应该能给你一条清晰的路径。2. 核心思路与硬件框架解析2.1 为什么是SPI以及从机的特殊挑战在视觉对位、电机控制、高速数据采集这些场景里SPISerial Peripheral Interface因其全双工、高速率轻松上MHz、协议简单的特点成为首选。相比I2C它没有复杂的起始停止信号和地址寻址就是纯粹的时钟线SCK、主机出从机入线MOSI、主机入从机出线MISO和片选线NSS。简单直接意味着在软件和硬件层面都可以做到很高的实时性和确定性。但“从机”角色给STM32编程带来了本质不同的视角。主机掌控时钟发起通信从机则必须被动响应。这带来了几个关键挑战时钟同步问题从机的SPI时钟完全由主机提供。从机的SPI配置时钟极性CPOL和时钟相位CPHA必须与主机严格匹配差一点都不行否则读到的数据全是错的。这是从机配置的第一要务。片选NSS管理片选信号是主机通知从机“会话开始”和“会话结束”的方式。STM32的SPI外设支持硬件NSS和软件NSS。对于从机硬件NSS模式可以自动检测电平但硬件连接和配置有讲究软件NSS则需要手动控制一个GPIO并在代码中精确管理其电平灵活性高但更考验编程。数据缓冲与响应时机主机随时可能发起通信。从机必须在极短的时间内几个时钟周期内准备好要发送的数据放在发送数据寄存器DR里否则主机会读到无意义的数据通常是上一次发送的残留或0xFF。如何提前准备好数据或者快速生成数据是程序架构的核心。资源限制与性能尤其在STM32F030上内存小主频不高通常48MHz。使用查询方式会大量占用CPU使用中断能提高效率但频繁中断在高波特率下也是负担最理想的是使用DMA但这需要仔细配置通道和传输计数器避免溢出和死锁。我的项目选择了“硬件SPI 硬件NSS DMA双缓冲”的架构。硬件SPI确保时序精准硬件NSS让芯片自己管理片选减少软件负担和误差DMA双缓冲则用来处理主机可能发起的长数据帧传输在后台搬运数据解放CPU。这个架构在应对CCD传感器上传的数百字节图像数据块时表现非常稳定。2.2 STM32F030的SPI外设特点与引脚分配STM32F030系列通常有1到2个SPI外设SPI1, SPI2。以常见的SPI1为例它位于APB2总线上理论上可以获得更高的时钟频率。在配置前必须查阅芯片的具体数据手册和参考手册确认SPI引脚所在的GPIO端口和复用功能。例如对于STM32F030F4P6SPI1:NSS: PA4 (也可以是PA15需重映射)SCK: PA5MISO: PA6MOSI: PA7注意STM32F030的调试接口SWD默认占用PA13(SWDIO)和PA14(SWCLK)。如果你的板子PA13/PA14也被用作其他功能比如普通IO或SPI在下载调试程序后可能会无法再次连接调试器。这是一个经典的坑。建议在项目早期就规划好引脚或者准备好通过BOOT0进入RAM编程模式来恢复。配置GPIO时模式设置至关重要SCK, MOSI, NSS: 对于从机这些是输入。应配置为复用功能模式Alternate Function并且通常不需要上拉/下拉因为主机会驱动它们。但为了抗干扰可以考虑使能内部弱上拉尤其在板子较长时。MISO: 这是从机的输出。配置为复用功能推挽输出Alternate Function Push-Pull。输出速度可以根据SPI时钟频率选择“Low”或“Medium”在10MHz以下“Low”即可有助于减少过冲。// GPIO初始化示例 (以HAL库为例) GPIO_InitTypeDef GPIO_InitStruct {0}; // SPI1 GPIO 时钟使能 __HAL_RCC_GPIOA_CLK_ENABLE(); // 配置 PA5(SCK), PA6(MISO), PA7(MOSI), PA4(NSS) GPIO_InitStruct.Pin GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7 | GPIO_PIN_4; GPIO_InitStruct.Mode GPIO_MODE_AF_PP; // 复用推挽输出 (对于MISO) GPIO_InitStruct.Pull GPIO_NOPULL; // 或 GPIO_PULLUP GPIO_InitStruct.Speed GPIO_SPEED_FREQ_LOW; GPIO_InitStruct.Alternate GPIO_AF0_SPI1; // 关键F030的SPI1复用功能是AF0 HAL_GPIO_Init(GPIOA, GPIO_InitStruct); // 特别注意对于SCK和MOSI它们实际是输入但HAL库的GPIO_MODE_AF_PP模式对于输入引脚也是兼容的。 // 更精确的做法是分开配置MISO用AF_PPSCK/MOSI/NSS用AF_INPUT。但HAL的GPIO_MODE_AF_PP在内部处理上对输入也是有效的。3. SPI从机模式深度配置详解3.1 时钟极性(CPOL)与相位(CPHA)的精确匹配这是SPI通信的基石配错了通信绝对失败。CPOL和CPHA共同定义了数据在时钟线的哪个边沿被采样捕获和更新改变。CPOL (Clock Polarity): 时钟空闲状态的电平。CPOL0: SCK在空闲时为低电平。CPOL1: SCK在空闲时为高电平。CPHA (Clock Phase): 数据采样的边沿。CPHA0: 数据在时钟的第一个边沿如果CPOL0就是上升沿如果CPOL1就是下降沿被采样在第二个边沿更新。CPHA1: 数据在时钟的第二个边沿被采样在第一个边沿更新。常见的模式有4种Mode 0-3。我的经验是永远不要死记“Mode 0”或“Mode 3”而是去理解主机的时序图然后根据时序图推导出CPOL和CPHA。大多数传感器如AD2S1210、AD7616的数据手册都会给出清晰的SPI时序图。如何看图配置找到时序图中SCK线。看两个数据字节之间SCK处于什么电平那就是空闲状态决定CPOL。找到数据线MOSI/MISO的采样点。看主机是在SCK的哪个边沿去读MISO对于主机是采样或者从机应在哪个边沿去读MOSI。这个边沿相对于SCK空闲到跳变的第一个边沿是第几个边沿第一个边沿则CPHA0第二个边沿则CPHA1。例如如果时序图显示SCK空闲为低数据在SCK的上升沿被采样。那么空闲为低 - CPOL 0上升沿采样由于空闲是低第一个边沿是上升沿 - CPHA 0这就是SPI_MODE0。在STM32 HAL库中通过SPI_InitTypeDef结构体的CPOL和CPHA字段设置。SPI_HandleTypeDef hspi1; hspi1.Instance SPI1; hspi1.Init.Mode SPI_MODE_SLAVE; // 从机模式 hspi1.Init.Direction SPI_DIRECTION_2LINES; // 全双工 hspi1.Init.DataSize SPI_DATASIZE_8BIT; // 8位数据 hspi1.Init.CLKPolarity SPI_POLARITY_LOW; // CPOL 0 hspi1.Init.CLKPhase SPI_PHASE_1EDGE; // CPHA 0 (第一个边沿) hspi1.Init.NSS SPI_NSS_HARD_INPUT; // 硬件NSS输入模式 hspi1.Init.BaudRatePrescaler SPI_BAUDRATEPRESCALER_2; // 从机忽略此参数但必须设置 hspi1.Init.FirstBit SPI_FIRSTBIT_MSB; // 高位先行需与主机一致 hspi1.Init.TIMode SPI_TIMODE_DISABLE; hspi1.Init.CRCCalculation SPI_CRCCALCULATION_DISABLE; hspi1.Init.CRCPolynomial 7; if (HAL_SPI_Init(hspi1) ! HAL_OK) { Error_Handler(); }实操心得调试时如果通信失败第一件事就是用逻辑分析仪或示波器抓取SCK、MOSI、MISO、NSS的波形。对照波形检查CPOL和CPHA是否匹配这是最高效的排查方法。没有仪器的话可以尝试循环遍历4种模式总有一种能通但这不是严谨的做法。3.2 片选NSS模式硬件与软件的抉择片选信号是SPI从机的“门铃”。STM32提供了几种NSS管理模式硬件NSS输入Hardware NSS InputSPI_NSS_HARD_INPUT这是最标准的从机模式。芯片的NSS引脚被配置为硬件NSS功能。当主机拉低这个引脚时STM32的SPI外设自动进入“选中”状态开始响应时钟和数据。主机拉高NSS后通信结束SPI状态机复位。优点全硬件自动管理时序精准CPU无需干预。缺点占用一个专用引脚。并且根据参考手册在NSS硬件模式下从机有时需要将NSS引脚配置为复用功能输入而不是简单的GPIO输入。具体配置要查手册。软件NSS管理Software NSS ManagementSPI_NSS_SOFT在此模式下SPI外设内部忽略硬件NSS引脚的电平。NSS引脚可以当作普通GPIO使用。片选功能完全由软件控制通过设置SPI_CR1寄存器的SSI位和SSM位来模拟内部NSS信号。通常做法是使能SSM软件从机管理然后通过设置SSI位为0来让SPI认为自己被选中开始等待主机时钟设置SSI位为1来结束会话。优点灵活可以用任意GPIO作为片选适合一主多从且片选逻辑复杂的场景。缺点软件控制有延迟需要精确的代码时序来匹配主机时钟的开始和结束容易出错。我的选择与建议 对于大多数单从机或片选信号干净的应用强烈推荐使用硬件NSS输入模式。它省心、可靠。在HAL库初始化时设置NSS SPI_NSS_HARD_INPUT即可。确保你的原理图中主机的NSS输出确实连接到了STM32的这个NSS引脚上。如果必须使用软件NSS代码需要这样处理// 假设用PA1作为软件片选引脚 hspi1.Init.NSS SPI_NSS_SOFT; // 软件NSS管理 hspi1.Init.SSM SPI_SSM_ENABLE; // 使能软件从机管理 // 初始化SPI... // 在主机拉低片选PA1的中断或查询函数中 HAL_GPIO_WritePin(SPI_NSS_GPIO_Port, SPI_NSS_Pin, GPIO_PIN_RESET); // 实际拉低GPIO __HAL_SPI_SET_SSI(hspi1, SPI_SSI_0); // 内部设置SSI0SPI准备就绪 // 通信结束后在主机拉高片选时 __HAL_SPI_SET_SSI(hspi1, SPI_SSI_1); // 内部设置SSI1SPI结束 HAL_GPIO_WritePin(SPI_NSS_GPIO_Port, SPI_NSS_Pin, GPIO_PIN_SET); // 实际拉高GPIO这种方式对代码的实时性要求极高不推荐在高波特率下使用。3.3 数据帧格式与大小端配置SPI是位级别的串行通信所以需要约定每个数据帧的位数和位的传输顺序。DataSize: 通常是8位或16位。SPI_DATASIZE_8BIT或SPI_DATASIZE_16BIT。这需要和主机完全一致。8位是最常见的。如果设置成16位那么每次HAL_SPI_TransmitReceive发送和接收的都是16位的uint16_t数据。FirstBit: 数据传输是高位MSB先行还是低位LSB先行。SPI_FIRSTBIT_MSB或SPI_FIRSTBIT_LSB。绝大多数SPI设备都是MSB先行但有些比如某些老式器件可能是LSB。必须与主机匹配。这里有个隐藏的坑当使用DMA传输时数据缓冲区的对齐方式需要小心。特别是16位模式如果定义一个uint8_t数组但以16位模式访问可能会因为非对齐访问在Cortex-M0上触发Hard Fault。M0内核不支持非对齐的存储器访问。// 错误示例可能导致Hard Fault uint8_t rx_buf[10]; hspi1.Init.DataSize SPI_DATASIZE_16BIT; HAL_SPI_Receive_DMA(hspi1, (uint8_t*)rx_buf, 5); // 试图接收5个16位数据即10字节 // 正确做法使用对齐的16位数组 __ALIGNED(2) uint16_t rx_buf[5]; // 使用__ALIGNED确保对齐如果编译器支持或者直接定义uint16_t数组其地址通常是2字节对齐的。 HAL_SPI_Receive_DMA(hspi1, (uint8_t*)rx_buf, 5); // 传输计数是516-bit item对于8位模式使用uint8_t数组即可自然对齐。4. 通信数据流管理与DMA实战配置配置好SPI参数只是第一步如何高效、可靠地收发数据才是程序的核心。对于从机数据到来的时机不可控我们需要设计好数据缓冲区和管理机制。4.1 查询、中断与DMA方式对比查询Polling在主循环里不断检查SPI状态标志位如RXNE接收非空。这种方式在从机模式下几乎不可用因为CPU会被完全阻塞无法处理其他任务且极易丢失数据。除非你的应用极其简单只有SPI这一件事。中断Interrupt使能SPI的RXNE接收缓冲区非空和TXE发送缓冲区空中断。每收到或发送一个字节/半字就进入中断服务程序进行搬运。这种方式响应及时CPU利用率比查询高但在高波特率比如1Mbps下频繁中断会成为系统负担影响其他实时任务。DMADirect Memory Access这是最理想的方式。DMA控制器在外设和内存之间直接搬运数据无需CPU介入。你只需要提前设置好源地址SPI数据寄存器、目标地址内存缓冲区、传输数据量然后启动DMA和SPI。数据会在后台自动完成搬运搬运完成后产生一个DMA传输完成中断通知CPU。CPU解放出来处理更复杂的业务逻辑。结论对于STM32F030 SPI从机只要数据量不是极小都推荐使用DMA模式。它能提供最稳定的性能尤其是在需要处理不定长或突发数据块时。4.2 DMA双缓冲配置与实现单DMA缓冲区有个问题当DMA正在搬运数据到缓冲区A时主机又发来了新数据就会发生覆盖。双缓冲Double Buffer或循环缓冲Circular Buffer模式可以解决这个问题。STM32的DMA支持双缓冲模式Double Buffer Mode但更通用和简单的做法是使用DMA循环模式Circular Mode配合足够大的缓冲区并结合“半传输完成”HT和“传输完成”TC中断来实现类似双缓冲的管理。我的方案使用DMA循环模式设置一个较大的缓冲区例如256字节在HT和TC中断中处理数据。当DMA填充了缓冲区的前一半128字节时触发HT中断。在中断中你可以安全地读取/处理这前128字节的数据而此时DMA正在向后一半后128字节填充数据。当DMA填充完整个缓冲区256字节时触发TC中断。此时你可以处理后128字节的数据而DMA已经自动绕回缓冲区开头继续填充。这样就形成了一个“乒乓”操作只要处理数据的速度快于SPI接收的速度就不会丢失数据。#define SPI_RX_BUFFER_SIZE 256 __ALIGNED(4) uint8_t spi_rx_buffer[SPI_RX_BUFFER_SIZE]; // 对齐到4字节避免任何对齐问题 void SPI1_DMA_Init(void) { __HAL_RCC_DMA1_CLK_ENABLE(); hdma_spi1_rx.Instance DMA1_Channel2; // 查手册确定SPI1_RX对应的DMA通道F030是Channel2 hdma_spi1_rx.Init.Direction DMA_PERIPH_TO_MEMORY; hdma_spi1_rx.Init.PeriphInc DMA_PINC_DISABLE; hdma_spi1_rx.Init.MemInc DMA_MINC_ENABLE; hdma_spi1_rx.Init.PeriphDataAlignment DMA_PDATAALIGN_BYTE; // 与SPI数据位宽一致 hdma_spi1_rx.Init.MemDataAlignment DMA_MDATAALIGN_BYTE; hdma_spi1_rx.Init.Mode DMA_CIRCULAR; // 循环模式 hdma_spi1_rx.Init.Priority DMA_PRIORITY_HIGH; HAL_DMA_Init(hdma_spi1_rx); __HAL_LINKDMA(hspi1, hdmarx, hdma_spi1_rx); // 使能DMA的HT和TC中断 HAL_DMA_Start_IT(hdma_spi1_rx, (uint32_t)(SPI1-DR), (uint32_t)spi_rx_buffer, SPI_RX_BUFFER_SIZE); // 启动SPI DMA接收 __HAL_SPI_ENABLE(hspi1); SET_BIT(hspi1.Instance-CR2, SPI_CR2_RXDMAEN); // 使能SPI RX DMA请求 } // DMA中断服务程序 void DMA1_Channel2_3_IRQHandler(void) { HAL_DMA_IRQHandler(hdma_spi1_rx); } // HAL库的回调函数 void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi) { if(hspi-Instance SPI1) { // 传输完成中断处理 spi_rx_buffer 的后半部分数据 process_spi_data(spi_rx_buffer[SPI_RX_BUFFER_SIZE/2], SPI_RX_BUFFER_SIZE/2); } } void HAL_SPI_RxHalfCpltCallback(SPI_HandleTypeDef *hspi) { if(hspi-Instance SPI1) { // 半传输完成中断处理 spi_rx_buffer 的前半部分数据 process_spi_data(spi_rx_buffer, SPI_RX_BUFFER_SIZE/2); } }4.3 发送数据从机响应的策略从机不仅要接收还要发送数据响应主机。发送的时机很关键必须在主机时钟到来之前将数据放入SPI的发送数据寄存器DR。使用DMA可以完美解决这个问题。我们可以配置另一个DMA通道用于发送SPI_TX并将其设置为内存到外设模式。当主机发起通信拉低NSS并开始产生SCK时SPI外设会自动从DR寄存器中取出数据通过MISO线发送出去。如果我们提前用DMA把要发送的数据填充到DR寄存器那么整个过程就是自动的。关键点从机的发送DMA通常需要在每次通信会话开始时被触发。一种常见的做法是在SPI的NSS下降沿中断如果支持或SPI的RXNE中断中启动发送DMA。但更优雅的方式是利用SPI和DMA的联动使能SPI的TX DMA请求SPI_CR2的TXDMAEN位然后启动DMA。DMA会在SPI的TXE发送缓冲区空事件发生时自动搬运下一个数据到DR。uint8_t spi_tx_buffer[RESPONSE_DATA_LEN]; // 准备要发送的数据 void prepare_response_data(void) { // 根据接收到的命令填充 spi_tx_buffer // ... } void start_spi_transmit(void) { // 确保SPI和DMA已初始化且TXDMAEN已使能 HAL_DMA_Start_IT(hdma_spi1_tx, (uint32_t)spi_tx_buffer, (uint32_t)(SPI1-DR), RESPONSE_DATA_LEN); // 注意对于从机不需要调用 HAL_SPI_Transmit_DMA因为通信的启动权在主机。 // 我们只是准备好了数据等待主机来读。 // 但需要确保SPI的发送缓冲区是空的以便DMA能立即开始填充。 // 有时可能需要先向DR写一个哑元数据dummy data来“启动”发送端。 // 更常见的做法是在SPI初始化并使能后就启动发送DMA循环模式让它等待。 // 当主机发起通信时数据会自动流出。 }注意事项从机的发送DMA如果配置为循环模式且缓冲区数据不变那么主机会一直读到重复的数据。这适合固定响应的场景。如果需要动态响应需要在每次通信后更新发送缓冲区并可能需要在NSS上升沿通信结束时复位DMA的传输计数器。5. 关键问题排查与实战调试技巧即使配置看起来完美实际调试中还是会遇到各种问题。下面是我在STM32F030 SPI从机开发中遇到的一些典型问题及解决方法。5.1 通信完全无反应或数据全错这是最常见的问题。请按以下清单逐项检查电气连接用万用表检查SCK、MOSI、MISO、NSS、GND是否连接牢固有无短路/断路。这是最基本也最容易被忽略的。电源与地确保主从设备共地。电平是否匹配STM32F030是3.3V如果主机是5V系统需要电平转换。时钟与相位CPOL/CPHA99%的通信失败源于此。务必使用逻辑分析仪确认主机时序并严格匹配。尝试四种模式组合。GPIO复用功能确认SPI引脚是否正确配置为复用功能AF并且AF编号正确STM32F030的SPI1通常是AF0。SPI和DMA时钟使能确认在初始化代码中已经使能了__HAL_RCC_SPI1_CLK_ENABLE()和__HAL_RCC_DMA1_CLK_ENABLE()。NSS信号如果使用硬件NSS用示波器看主机拉低NSS后STM32这边是否检测到。有些主机NSS信号可能脉冲太短。尝试在主机端延长NSS低电平时间。软件片选时序如果使用软件NSS检查控制NSS引脚和SSI位的代码是否精确是否在主机SCK开始前就绪在SCK结束后才释放。5.2 数据错位或字节顺序不对FirstBit设置检查SPI_FIRSTBIT_MSB/LSB是否与主机匹配。如果反了读到的数据位序就是颠倒的。数据位宽确认DataSize8bit/16bit一致。如果主机发8位从机按16位读就会错位。DMA数据对齐如前所述确保DMA的PeriphDataAlignment和MemDataAlignment与SPI的DataSize匹配。8位对应BYTE16位对应HALFWORD。5.3 DMA传输不启动或只传输一次DMA工作模式如果希望持续接收必须设置为循环模式DMA_CIRCULAR。单次模式DMA_NORMAL传输完指定数量后就会停止。SPI DMA请求使能除了初始化DMA还必须使能SPI的DMA请求。对于接收是SPI_CR2寄存器的RXDMAEN位对于发送是TXDMAEN位。HAL库中HAL_SPI_Receive_DMA和HAL_SPI_Transmit_DMA函数内部会设置这些位。但如果像我们之前例子中手动启动DMA就需要手动设置SET_BIT(hspi1.Instance-CR2, SPI_CR2_RXDMAEN);缓冲区地址和长度检查DMA初始化时传入的内存地址和长度是否正确。长度单位是“数据项”的数量对于8位数据1个数据项1字节。5.4 系统进入Hard Fault在Cortex-M0上非对齐访问是触发Hard Fault的常见原因。结构体对齐如果你在SPI中断或DMA回调中访问了包含uint16_t或uint32_t成员且未做对齐声明的结构体指针就可能出错。使用__attribute__((packed))或__packed关键字时要格外小心或者使用__ALIGNED宏强制对齐。数组越界DMA传输长度设置过大超过了缓冲区实际大小导致写穿缓冲区破坏栈或堆。中断优先级冲突SPI中断、DMA中断的优先级配置不当可能导致嵌套中断处理出错。确保关键中断如DMA有合适的优先级。调试Hard Fault在Hard Fault中断处理函数中可以读取SCB-CFSR配置故障状态寄存器、SCB-HFSR硬故障状态寄存器等来定位原因。或者在调试器中查看Call Stack找到触发故障前的最后一条指令。5.5 使用逻辑分析仪进行协议级调试没有比逻辑分析仪更强大的SPI调试工具了。推荐使用Saleae Logic或类似产品。连接将分析仪的通道分别连接到SCK、MOSI、MISO、NSS。设置在软件中添加SPI协议分析器设置正确的CPOL、CPHA、位序。抓取触发一次通信抓取波形。分析看NSS信号是否在数据帧前后有明确的下降沿和上升沿看SCK信号频率是否在STM32 SPI支持的范围内空闲电平是否符合CPOL设置看MOSI和MISO信号数据是否在正确的时钟边沿符合CPHA稳定数据值是否符合预期对比MOSI主机发送和你的程序解析出的数据对比MISO从机发送和你的程序准备发送的数据。任何不一致都能直接定位问题。通过以上系统的配置、实现和排查方法你应该能够为STM32F030构建出一个坚固耐用的SPI从机通信模块。这套方案不仅适用于F030其原理和思路也适用于其他STM32系列甚至其他ARM Cortex-M芯片。嵌入式开发就是这样一个不断踩坑、填坑、总结的过程希望我的这些经验能让你少走些弯路。最后记住当通信不通时沉住气从最基础的电源、地线、信号连接查起再到时序配置一步步缩小范围问题总能解决。本文还有配套的精品资源点击获取
返回列表