最近,在给我们组流完的片子设计一个PCB,找一个MCU作为控制器与我们的芯片相连,对芯片进行控制、数据输入和输出。PCB的面积有要求,大概在两个大拇指指甲盖的大小多一点。
为了面积需求,在立创商场开始挑选起MCU。正好看到了STM32G031G8U6(UFQFPN28封装)这个芯片,面积、flash、引脚和价格都挺合适的,遂使用该芯片来设计PCB。
在采购物料时,遇到了一点小小的阻碍,在立创商场提交订单时被要求联系客服处理。原因是有些物料(ST、TI、YAGEO和muRata)不能开学校的发票,不仅是芯片还包括电阻电容,学校被狠狠制裁了。
下面记录了一些大家在设计和使用该芯片时可能遇到的问题。
1、 晶振的设计
首先,在STM32G031x4/x6/x8数据手册的第5章节电气特性中给出了如下一张图,使用了一个无源晶振加上两个电容,连接到芯片的两个引脚上。如果你采用如下设计来引入一个高速外部时钟,那么大概率会出现问题。
因为,从数据手册的引脚描述来看,PC14和PC15这两个引脚只能够支持低速外部时钟这样设计(OSC32_IN和OSC32_OUT分别接入32.768kHz的无源晶振两端即可),而不支持这样设计高速时钟(OSC_IN只能使用单端的有源晶振输入,OSC_EN只是控制有源晶振是否使能)。其实,大家在用STM32CubeMX的时候配置RCC时,也可以发现这一点。
1.1 LSE设计
有关低速外部时钟的设计,使用无源晶振即可完成设计(使用有源晶振也可以),无源晶振两端连接两个15pF的电容接地,同时两端再接入stm32芯片即可。原理图摘自STM32G031G8U6_stm32g031g8u6原理图-CSDN博客。
在STM32CubeMX的配置如下图所示,不勾选旁路时钟来源,在低速时钟部分选择晶振即可。在时钟配置页面的红色框中,可以看出无源晶振是双端与芯片相连的。
1.2 HSE设计
有关高速外部时钟的设计,对于stm32g031g8u6只能使用有源晶振(或者其他设备产生的时钟)设计,我在设计中使用的扬兴晶振的8M的有源晶振(OT7EL89CJI-111YLC-8M),原理图如下图所示。PC14引脚作为8M的时钟输入,PC15引脚作为晶振的使能。
在STM32CubeMX的配置如下图所示,勾选旁路时钟来源,勾选OSC enable。在时钟配置页面的红色框中,可以看出有源晶振的时钟是单端进入芯片的。
2、 SWD接口无法被检测
SWD接口是stm32芯片提供的用来下载和调试程序的接口,芯片独立供电的情况下只需要SWCLK、SWDIO和GND三根线即可。
由于PCB面积的限制,我只留了SWD接口进行下载程序,并没有预留其他下载程序的方式。当我收到PCB并完成焊接后,Keil无法检测到我的SWD接口,于是开启漫长的找问题过程。过程中,看到了许多大佬的文章,也是不断加深了我的理解。
我手上有两个调试器,分别是ST-Link和CMSIS-DAP,都无法检测SWD接口。一开始,我认为是芯片虚焊(确实是虚焊,但就是没有发现),重新焊了一片之后用ST-Link检测,依旧无法检测。从此,我误入歧途,不仅仔细阅读了芯片数据手册,还看了许多博客和论坛。最终,我得出了一个错误的结论,该芯片出厂的时候SWD接口是关闭的(实际上出厂即可使用SWD接口)。
于是,我重新画了一块PCB,将STM32G031G8U6的所有引脚都引了出来,也保留了串口下载程序的方式。完成焊接后,上电用串口下载程序没有问题,用ST-Link还是检测不到,折腾了一上午发现我的ST-Link坏掉了,CMSIS-DAP可以检测SWD接口(悔不当初,我怎么不早点用CMSIS-DAP)。
2.1 SWD检测指南
STM32G031系列的全新芯片可以直接通过SWD口进行程序下载,但还是建议大家在设计PCB的时候保留多种下载程序的方式。在使用一块新的芯片时,如果遇到SWD口无法检测,可以从以下几个方面进行尝试:
(1)确认自己的调试器(ST-Link、CMSIS-DAP等)是否正常,可以对手头上好的开发板进行程序下载,确保调试器本身没有问题。如果调试器出现问题,一般SWCLK或SWDIO的端口电压也有问题,可以使用万用表测量进行确认。
(2)下载或更新调试器的驱动程序,确保设备管理器中没有未知(带叹号)的设备输入。
(3)确认STM32芯片上电(推荐单独供电,不用调试器进行供电),确认SWCLK、SWDIO和GND的连接没有问题(确保连接线没有问题)。
(4)确保芯片供电稳定,BOOT模式配置正确。
(5)检测芯片的焊接情况(尤其是QFN类型封装),重新焊接一块新的芯片就行尝试。
如果是已经使用过的芯片,先从上面4个方面进行尝试,不行的话在考虑下面的方法:
(1)PA13和PA14引脚是否被复用成普通的IO口进行使用,即引脚被锁住了。可以通过STM32CubeMX重新配置成SWD接口,并用串口重新编程芯片。
在没有预留串口下载程序的情况下。如果调试器带有复位引脚且PCB板引出了复位引脚,可以把复位引脚也插上去,然后如下图一样配置,就可以正常下载程序。原理是芯片复位后,PA13和PA14默认功能为SWD接口。如果PCB板没有引出复位引脚,也可以手动按键复位,但是成功率不是特别高。
遇到Flash读写保护的情况,可以参考下面这篇博客。STM32的Flash读写保护,SWD引脚锁的各种解决办法汇总(2021-10-21) - STM32F407 - 硬汉嵌入式论坛 - Powered by Discuz!
H7-TOOL脱机烧录解除读写保护和各种遇到情况解决办法汇总,含SWD接口锁,低功耗和看门狗(2023-08-01) - H7-TOOL开发工具 - 硬汉嵌入式论坛 - Powered by Discuz!
(2)对于STM32G031G8U6这款芯片,其VDD和VDDA是一个引脚同时供电。对于其他类型的32芯片,VDDA和VBAT引脚供电不正常也会导致SWD接口无法检测。参考STM32的SWD烧录模式No Target Connected 错误的一种情况-CSDN博客。
2.2 STM32G031G8U6的BOOT模式
不同于STM32F系列的芯片,它们的BOOT模式依靠外部的BOOT1和BOOT0引脚的电平来决定。然而,STM32G031G8U6的BOOT模式是通过选项字节(芯片内部的寄存器)进行配置,如下图所示。
- Main Flash memory:主闪存,用来存储用户代码。一般而言,SWD就是在这里下载程序。
- System memory:系统存储区,芯片出厂自带的程序。串口等下载方式就是从这里启动。
- Embbeded SRAM:内存,存储用户的数据代码。
当nBOOT_SEL bit为0时,芯片启动由nBOOT1 bit(内部寄存器)和BOOT0 pin(外部引脚)共同决定;当nBOOT_SEL bit为1时,芯片启动由nBOOT1 bit(内部寄存器)和nBOOT0 bit(内部寄存器)共同决定。
芯片出厂后,默认nBOOT_SEL = 1 , nBOOT0 bit = 1,即从主闪存启动。但是,芯片启动会检查闪存地址0x080000000(用户程序起始地址)的数据,如果数据为0xFFFFFFFF则表示用户程序为空,此时会从System memory启动。芯片出厂没有下载程序,都会从System memory启动。参考STM32G0系列的启动配置与程序下载_stm32g0包-CSDN博客
当拿到一块新的STM32G031G8U6芯片时,既可以通过SWD接口下载程序,也是可以通过串口等方式下载程序(可以下载程序的方式如下图所示)。
如果直接用SWD接口下载完程序后,再想通过串口下载程序就比较麻烦,需要在程序中配置nBOOT_SEL = 1,让进入System memory由外部的PA14-BOOT0来决定。参考大佬的博客,STM32G0系列的启动配置与程序下载_stm32g0包-CSDN博客
如果想要方便地保留两种下载程序的方式,推荐使用STM32CubeProgrammer一开始使用串口进行连接,然后根据红框的指引直接取消勾选nBOOT_SEL,点击应用Apply后即可。
在配置nBOOT_SEL为0后,想要进入system memory用串口下载程序的方式如下:
(1)将PA14-BOOT0引脚用跳帽或杜邦线接高电平3.3V。
(2)按下复位按键后松手。
(3)使用STM32CubeProgrammer进行串口连接,此时会读取到主闪存里面的代码数据。
(4)打开新的代码文件.hex,下载程序。
(5)拔掉跳帽或杜邦线,再次按下复位按键,程序运行。
相比于串口下载程序,使用SWD接口下载程序简单得多。在设计电路时,一般将PA14-BOOT0引脚下拉到地,然后将SWCLK、SWDIO和GND连接正确即可下载程序。
3、 原理图和PCB设计
为了面积足够小,使用的电阻电容都是0201的封装,焊接的难度还是不小的。相比于电阻电容,不推荐大家用0201的发光二极管,因为看背面的正负极把人眼睛都看花了。如果不是面积需求,大家还是尽量用0402和0603的封装吧。
下面以后来设计的STM32G031G8U6开发板进行介绍,将所有的引脚引了出来。原理图非常简单,只有CH340X和stm32g031g8u6两个芯片,如下图所示。
芯片的PA2、PA3引脚连接到CH340芯片,用于提供串口下载程序的方式。芯片的时钟输入使用外部的8M有源晶振,将PA14-BOOT0接口用10k电阻下拉至地。下面是PCB的效果展示。
R1和R2电阻没有0603的封装了,就用0201的焊上去了,大家可以看看和R4的大小对比。上下两排由于设计时选错了封装(间距选成2mm了),现在连排针都焊不上去,大家画PCB切莫粗心啊。右上角的排针是用于SWD接口调试的,建议将3V3放在SWCLK旁边,这样只需要一个跳帽即可拉高PA14-BOOT0,从而进入system memory使用串口下载模式。
4、 代码相关
4.1 while(1)循环要加延时
while(1){}循环中需要添加延时,没有延时程序将无法正确执行。如下图,使用串口接受中断进行触发。串口从PC端收到一个字节数据,中断触发后将数据重新发送给PC端,并反转LED电平。如果没有红色框中的延时,中断可以正常触发,但是不能正确运行程序。
有大佬知道产生这个现象的原因吗?是否是处理器底层的设计问题,欢迎在评论区讨论。
4.2 用定时器设计us级延时
HAL库只给我们提供了ms级的延时,但在很多情况下us级延时使用的很多。下面提供一种基于定时器设计us级别延时的简单方法,如下图所示。
选择时钟来源,一般可以选择内部时钟,这边选择的是APB总线上的64M时钟。因此,需要对64M时钟进行预分频,分频至1M即可,即计数1次的时间为1us。
由于定时器的计数位宽是16bit,所以函数的最大延时是65535us。延时函数的设计思路简单,首先将定时器的计数器置零,开启定时器并获取计数器数值进行比较,计数器数值达到延时需求时暂停计数器,最后退出延时函数。
void Delay_us(uint16_t Delay) { uint16_t cnt = 0; __HAL_TIM_SET_COUNTER(&htim1,0);//inital count 0 HAL_TIM_Base_Start(&htim1); while(cnt < Delay) { cnt = __HAL_TIM_GET_COUNTER(&htim1); } HAL_TIM_Base_Stop(&htim1); }以上就是对STM32G031G8U6的使用总结,希望对大家有帮助。笔者水平有限,文章中可能会出现问题,欢迎大家在评论区进行纠正。