嵌入式开发--STM32G431无法正常运行程序,BOOT0与CAN冲突_stm32g431 boot
故障现象
今天开发STM32G431时遇到一个问题,板子打样回来后,焊接完成,可以烧程序,可以读FLASH,却死活不能运行,也不能进仿真调试。
故障定位
经过排查,发现将隔离芯片π121M31拆除,MCU可以进入正常工作状态,可以进仿真调试。所以确定故障与相关引脚有关。
原理图如下:
用到的引脚是PB8和PB9。
PB8是兼用于BOOT0,所以将PB8用一个100K的电阻下拉到地,这个方式以前用过没有问题。
CAN相关的电路如下:
这个电路以前也用过,也没有问题。
由此基本可以确定故障是由于BOOT0的电平变高,导致MCU进入了内部BOOTLOAD模式或SRAM模式,这个就没有深究了,可以确定的是没有运行FLASH的程序。
测量U9的4脚输出为高电平,由此确定故障原因,就是BOOT0脚在复位时处于高电平状态,导致MCU不能进入FLASH程序运行。
问题解决
尝试将PB8连接的下拉电阻改为10K,无效。
尝试U8的1脚断开,MCU可以正常工作。于是考虑将U8的供电改为缓启动方式。
电源缓启动是解决了,MCU还是不能正常工作。
原因也很简单,上电复位的RC电路时间常数和这个一模一样,这就导致缓启动没有产生效果。
于是再改电路,将电阻改为36K,电容改为20uF,时间常数从原先的0.1秒变为0.72秒,多出来的0.62秒就是实际的缓启动时间。
更改之后,电路正常工作,可以正常启动进调试,缓启动后,U8上的电压也能达到正常的3.3V。
需要注意的是,软件中需要增加一个延时,不然的话,在缓启动期间收发数据,就会造成数据丢失。
再次改进
按上图虽然可以正常启动,但是只能在上电时工作一次。在带电调试时,需要频繁的按复位键和进Debug,这时上面的电路就不能工作了。因为当按下复位键时,+3.3V电源依然存在,RC充电电路并没有一个放电的过程。继续改进如下:
按下复位键时,RESET被拉低到地,这时PQ3导通,将PC17放电, PQ2的栅源电位为0,PQ2截止,PQ2的漏极无输出。
松开复位键后,RESET电压上升 ,PQ3逐渐截止,PC17和PR7就开始了重新充电的过程,这样+3.3_DELAY就会有一个低电平的持续时间,此时PC17和PR7的取值可以变小,时间常数可以按图取到0.1秒甚至更小。
其他类似的不启动问题,也可以参照这个解决方法。
CAN参数配置
顺便记录一下CAN的参数配置,主时钟频率170M,CAN波特率为1MHz
下面是CubeMX生成的初始化函数
void MX_FDCAN1_Init(void){ hfdcan1.Instance = FDCAN1; hfdcan1.Init.ClockDivider = FDCAN_CLOCK_DIV1; hfdcan1.Init.FrameFormat = FDCAN_FRAME_CLASSIC; hfdcan1.Init.Mode = FDCAN_MODE_NORMAL; hfdcan1.Init.AutoRetransmission = DISABLE; hfdcan1.Init.TransmitPause = DISABLE; hfdcan1.Init.ProtocolException = DISABLE; hfdcan1.Init.NominalPrescaler = 17; hfdcan1.Init.NominalSyncJumpWidth = 2; hfdcan1.Init.NominalTimeSeg1 = 7; hfdcan1.Init.NominalTimeSeg2 = 2; hfdcan1.Init.DataPrescaler = 17; hfdcan1.Init.DataSyncJumpWidth = 2; hfdcan1.Init.DataTimeSeg1 = 7; hfdcan1.Init.DataTimeSeg2 = 2; hfdcan1.Init.StdFiltersNbr = 0; hfdcan1.Init.ExtFiltersNbr = 0; hfdcan1.Init.TxFifoQueueMode = FDCAN_TX_FIFO_OPERATION; if (HAL_FDCAN_Init(&hfdcan1) != HAL_OK) { Error_Handler(); }}
初始化代码
在主while(1)循环之前,加入下面这个函数的运行,以初始化接收邮箱
void LL_can_init(void){ FDCAN_FilterTypeDef sFilterConfig; CanTxHeader.Identifier = 0x604; CanTxHeader.IdType = FDCAN_STANDARD_ID; CanTxHeader.TxFrameType = FDCAN_DATA_FRAME; CanTxHeader.DataLength = 8; CanTxHeader.ErrorStateIndicator = FDCAN_ESI_ACTIVE; CanTxHeader.BitRateSwitch = FDCAN_BRS_OFF; CanTxHeader.FDFormat = FDCAN_CLASSIC_CAN; CanTxHeader.TxEventFifoControl = FDCAN_NO_TX_EVENTS; CanTxHeader.MessageMarker = 0; sFilterConfig.IdType = FDCAN_STANDARD_ID; sFilterConfig.FilterIndex = 0; sFilterConfig.FilterType = FDCAN_FILTER_RANGE_NO_EIDM; sFilterConfig.FilterConfig = FDCAN_FILTER_TO_RXFIFO0; sFilterConfig.FilterID1 = 0x000; sFilterConfig.FilterID2 = 0x7ff; if(HAL_FDCAN_ConfigFilter(&hfdcan1, &sFilterConfig) != HAL_OK) { /* Filter configuration Error */ Error_Handler(); } HAL_FDCAN_ActivateNotification(&hfdcan1, FDCAN_IT_RX_FIFO0_NEW_MESSAGE, 0);}
发送函数
//发送CAN报文u8 LL_can_send_data(u16 id, u8 len, u8* data){ CanTxHeader.Identifier = id; CanTxHeader.DataLength = len; // 将消息添加到发送队列 if(HAL_FDCAN_AddMessageToTxFifoQ(&hfdcan1, &CanTxHeader, data) != HAL_OK) { Error_Handler(); } HAL_Delay(10); return 0;}
中断函数
在CubeMX初始化时需要勾选使能中断的选项, 然后中断会自动开启
void FDCAN1_IT0_IRQHandler(void){ /* USER CODE BEGIN FDCAN1_IT0_IRQn 0 */ /* USER CODE END FDCAN1_IT0_IRQn 0 */ HAL_FDCAN_IRQHandler(&hfdcan1); /* USER CODE BEGIN FDCAN1_IT0_IRQn 1 */ // 接收CAN报文 HAL_FDCAN_GetRxMessage(&hfdcan1, FDCAN_RX_FIFO0, &CanRxHeader, CanRxData); /* USER CODE END FDCAN1_IT0_IRQn 1 */}