HC32开发笔记

记录,为日后遇到类似问题提供思路。

常见问题&解决办法

时钟初始化过程中,进入到ddl异常中断,死循环

/**
 * @brief DDL assert error handle function
 * @param [in] file                     Point to the current assert the wrong file.
 * @param [in] line                     Point line assert the wrong file in the current.
 * @retval None
 */
__WEAKDEF void DDL_AssertHandler(const char *file, int line)
{
    /* Users can re-implement this function to print information */
    DDL_Printf("Wrong parameters value: file %s on line %d\r\n", file, line);

    for (;;) {
    }
}

卡在这个for死循环里面了,当执行 CLK_SetClockDiv() 函数时进入DDL_AssertHandler死循环,通常是因为触发了芯片的断言(Assert)机制,表明配置参数存在非法情况。

解决办法:参考了deepseek的建议,开始排查,排查了是否时钟分频参数设置错误、时钟配置寄存器可能被写保护。很幸运,确实是时钟还在写保护状态导致。解锁保护后时钟配置正常执行。

延时函数不准确、串口发送数据与PC端接受到的数据不匹配。

解决办法:发现是未正确初始化时钟导致。初始化时钟后问题解决。

J-Flash 每次打开报错 device tle9863qxw20: flash bank 0x11000000: no loader specified

解决办法:C:\Users\你的用户名\AppData\Roaming\SEGGER\JLinkDevices\JLinkDevices.xml 删除问题不复现,应该是文件中芯片地址配置错误导致

jlinkdevices.xml文件本用于J-Link识别芯片型号及硬件参数,并关联对应的Flash算法文件(.FLM)。但多次修改该文件仍报异常,删除后问题不复现。主要用HC32F460系列单片机,jlink默认的有对应的芯片类型可以用,可以暂时不用额外添加

J-Flash 添加非默认芯片

以HC32F170JATA为例:

  1. 从华大官网找到对应的芯片包,从芯片包里找到.FLM文件,这里搜索以下网上也有别人整理好的,含芯片配置文件和烧录算法;
  2. 用记事本打开JLinkDevices.xml文件,根据HC32F170JATA芯片的实际情况,将支持包内JLinkDevices.xml中的描述代码段修改,因为这里之前用别人的一直报错,打算自己重新写一下。 JLinkDevices.xml文件如下:
     <Device>
     <!-- 1. 基础信息:告诉 JLink 芯片内核是 Cortex-M0+,以及 RAM 大小和地址 -->
     <ChipInfo Vendor="XHSC" Name="HC32L17x"  WorkRAMAddr="0x20000000" WorkRAMSize="0x4000" Core="JLINK_CORE_CORTEX_M0"/>
    
     <!-- 2. 烧录算法:告诉 JLink Flash 的地址、大小,以及最重要的算法文件 (.FLM) 的存放位置 -->
     <FlashBankInfo Name="Flash_128K" BaseAddr="0x0" MaxSize="0x20000" Loader="Devices/HDSC/HC32L17x_128KB.FLM" LoaderType="FLASH_ALGO_TYPE_OPEN" AlwaysPresent="1"/>
     </Device>
    
  3. 找到你电脑上JLink的安装目录C:\Program Files\SEGGER\JLink或者C:\Users\你的用户名\AppData\Roaming\SEGGER\JLink,将.FLM和JLinkDevices.xml拷贝进去。
    • 好像在J-FlashJLink 7.62后优化了手动增加新MCU型号支持方法,在用户AppData下增加芯片1
  4. 这样重新打开J-Flash就可以找到新增芯片

改了程序下载地址之后程序起不来

问题背景: 有客户需要定制程序,需要我们提供我们软件BSP,他们自己写应用控制逻辑。当完成业务逻辑剥离后打算测试,发现程序一直跑飞,未按照预期运行,尝试DEBUG,直接运行,发现已经跑飞了,反汇编窗口跳转到了0xF404D0F8 AAAA ADD r2, sp, #0x2A8,跑飞!!单步运行后无法看堆栈信息,提示“Could not stop Cortex-M device! Please check the JTAG cable”,然后DEBUG就自动退出了!!

首先很明显确定已经跑飞了,根据我单步调试的结果问题再初始化阶段。0xF404D0F8这块不是正常程序代码地址。

尝试重启,能够稳定复现。回顾了一下我的操作,主要是移除了应用层代码,修改了程序烧录起始地址。因为不需要bootloader了,让程序直接从0开始进入。比较了下代码,没有BSP层没有大改动,程序是批量过的,考虑暂时先排除代码层面问题。

尝试屏蔽了部分初始化程序,问题仍然存在。

向大佬沟通,考虑中断跑飞了,使用__disable_irq();在初始化后屏蔽中断,问题复现。尝试在初始化前屏蔽中断问消失!缩小范围为中断问题。

查看中断向量表,#define VECT_TAB_OFFSET (0x0UL),逻辑上看中断向量表为0,没有问题。但是发现外面套了层宏。但是全局搜索都没有找到这个宏。

/* Vector Table base offset field */
#ifndef VECT_TAB_OFFSET
    #ifndef USE_OTA_FUNC
    #define VECT_TAB_OFFSET                 (0x0UL)     /*!< This value must be a multiple of 0x400. */
#else
    #define VECT_TAB_OFFSET                 (0x4000UL)     /*!< This value must be a multiple of 0x400. */
#endif

A thousand years later,仍然没找到问题,裂开了。尝试直接屏蔽此段代码,直接定义中断向量表偏移地址设置为0,故障消失。淦!

最中找到在Keil中定义了该宏,导致中断向量表错误,初始化后,进入错误中断程序地址跑飞。

跑飞常见原因:

  • 栈溢出,超出了为栈分配的空间,把旁边的数据给“踩”了。当用到旁边的数据后,程序乱掉。
  • 野指针,程序跑到了一个无效的地址。
  • 向量表错误,CPU在收到中断请求时,查了一个错误地址,导致跳到了错误的地方去执行代码。
  • 之前还遇到过供电不稳的,也又可能跑飞。
  • 也有可能Flash程序读取错误,坏块之类的。导致程序跑飞。
  • 。。。

AI战士的滑铁卢日常,联合体错误使用导致CAN通信异常问题

最近一个新项目,需要用到CAN通信。现在的MCU CAN模块已经非常集成,内部自带控制器,支持报文过滤、FIFO、自动收发,外部只需接一个CAN收发器,通过寄存器读写数据,稳定可靠。

按理说,CAN发送这种基础功能,代码写过无数遍了,闭着眼睛都能写。于是偷懒让AI帮忙重构老代码,抽离公用层,简化逻辑,重新生成一个发送函数。

/**
 * @brief  CAN发送数据
 * @param  id: CAN ID
 * @param  data: 8字节数据指针
 * @retval None
 */
void CanSendData(uint32_t id, uint8_t *data)
{
    stc_can_tx_frame_t stcTx;
    int32_t i32Ret;

    //填充发送帧
    stcTx.u32ID = id;
    stcTx.IDE = 1;
    stcTx.DLC = 8;
    stcTx.u32Ctrl = 0; // 错误,联合体内容被清空


    //复制数据
    if(data != NULL)
    {
        for(uint8_t i = 0; i < 8; i++)
        {
            stcTx.au8Data[i] = data[i];
        }
    }

    //发送
    CAN_FillTxFrame(CAN_UNIT, CAN_TX_BUF_PTB, &stcTx);
    CAN_StartTx(CAN_UNIT, CAN_TX_REQ_PTB);
}

代码非常简洁清晰:配ID格式和数据长度,最后填数据、发送。但偏偏就是发不出去。排查接线、时钟、寄存器都没问题,甚至开始怀疑硬件本身。

尝试DEBUG单步调试,发现判断为ID错误,通过打印变量,发现整个控制字相关的配置(IDE、DLC)都没有正确写入。

追根溯源,问题出在驱动库中stc_can_tx_frame_t结构体的定义上,先配置了DLC、IDE后再清空了u32Ctrl导致。真是一个愚蠢的操作,使用联合体在操作同一块内存。

AI在老项目中看到有xxx.u32Ctrl = 0这行代码,想都没想就复制过来了。还顺手调整了顺序。也是太相信AI了,给AI反馈错误信息,AI也是胡乱分析,最后只好自己来。

/**
 * @brief CAN TX frame data structure.
 */
typedef struct {
    uint32_t u32ID;                         /*!< 11 bits standard ID or 29 bits extended ID, depending on IDE. */
    union {
        uint32_t u32Ctrl;
        struct {
            uint32_t DLC: 4;                /*!< Data length code. Length of the data segment of data frame.
                                                 It should be zero while the frame is remote frame.
                                                 This parameter can be a value of @ref CAN_Data_Length_Code */
            uint32_t BRS: 1;                /*!< Bit rate switch. */
            uint32_t FDF: 1;                /*!< CAN FD frame. */
            uint32_t RTR: 1;                /*!< Remote transmission request bit.
                                                 It is used to distinguish between data frames and remote frames. */
            uint32_t IDE: 1;                /*!< Identifier extension flag.
                                                 It is used to distinguish between standard format and extended format.
                                                 This parameter can be a 1 or 0. */
            uint32_t RSVD: 24;              /*!< Reserved bits. */
        };
    };
    uint8_t au8Data[8U];                    /*!< TX data payload. */
} stc_can_tx_frame_t;

又尝试了一下,AI也是能发现的,不过需要把错误描述精确到CAN ID错误。如果无法有效的描述现象,只是回答CAN无法收发数据,像这种隐性问题AI分析也困难。

重构第一步就应该确保重构前功能正常,先做好环境的测试验证工作,不是撸起袖子就干!

参考资料

  1. 痞子衡嵌入式. (2024). 痞子衡嵌入式:从JLink V7.62开始优化了手动增加新MCU型号支持方法. https://www.cnblogs.com/henjay724/p/18203031 

results matching ""

    No results matching ""