本帖最后由 SnailWillow 于 2021-4-17 11:59 编辑

【前言】
上篇完成了开箱报告,对华大的 HC32F460 开发板有了初步了解,从开发生态、官网资源、手册及软硬件资料等方面给大家做了介绍,非常感谢原厂和EEWorld 对我提到的意见做了详尽回复。此篇主要针对 HC32F460 该颗芯片的开发流程和一些试用过的通用外设做简单记录,分享给大家欢迎拍砖 。

【J-Flash下载】
刚装好官方pack包的情况下,有可能在J-Flash里面找不到对应的芯片设备,那该如何是好?这是由于SEGGER官方还未将华大所有的设备信息添加到驱动程序中,好在华大提供了补丁包,通过改写devices描述和添加下载算法的方式即可使用J-Link和J-Flash 对HC32F460进行调试烧录,具体的烧录方法与其它芯片操作流程一致,在此不做过多赘述。工具包以附件形式提供给大家,有需要的朋友可以拿去使用。主要需要按照下图描述拷贝补丁包:
watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3N1Y2tfbW9yZQ==,size_16,color_FFFFFF,t_70.jpg
watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3N1Y2tfbW9yZQ==,size_16,color_FFFFFF,t_70.jpg

【CAN控制器】

HC32F460的CAN控制器模块遵循 CAN 总线协议 2.0A 和 2.0B 协议并向上兼容 CAN-FD。具有 8 组独立的筛选器,有4 个 STB 以及 10 个 RB 可以理解为一个 4 级 FIFO 和一个 10 级 FIFO,接收和发送FIFO 完全由硬件控制。支持最高通信波特率 1Mbit/s,这么看起来 这个CAN模块功能挺齐全而且还能支持CAN-FD,先来看看官方例程中的CAN通信实验。

CAN例程包括了回环模式和普通模式的中断、轮训模式测试程序,很好奇难道CAN 不支持DMA方式?在手册中也没有明确找到DMA对应的所有通道到底是什么,可能没有看仔细吧。
142739gj4sz7gy9pqi8m1w.png.thumb.jpg

先打开个中断方式的样例进行测试,CAN_RX和CAN_TX对应的引脚号是 PB06/PB07 :

程序中的初始化代码如下:
//<<System clk initial
  •     SysClkConfig();
  •     //<<Enable can peripheral clock and buffer(ram)
  •     stcRamCfg.enRamOpMd = HighSpeedMd;
  •     stcRamCfg.enCan = DynamicCtl;
  •     PWC_RamCfg(&stcRamCfg);
  •     PWC_Fcg1PeriphClockCmd(PWC_FCG1_PERIPH_CAN, Enable);
  •     //<<CAN GPIO config
  •     PORT_SetFunc(PortB, Pin06, Func_Can1_Rx, Disable);
  •     PORT_SetFunc(PortB, Pin07, Func_Can1_Tx, Disable);
  •     PORT_ResetBits(PortD, Pin15);
  •     PORT_OE(PortD, Pin15, Enable);
  •     //<<Can bit time config
  •     stcCanInitCfg.stcCanBt.PRESC = 1u-1u;
  •     stcCanInitCfg.stcCanBt.SEG_1 = 5u-2u;
  •     stcCanInitCfg.stcCanBt.SEG_2 = 3u-1u;
  •     stcCanInitCfg.stcCanBt.SJW   = 3u-1u;
  •     stcCanInitCfg.stcWarningLimit.CanErrorWarningLimitVal = 10u;
  •     stcCanInitCfg.stcWarningLimit.CanWarningLimitVal = 16u-1u;
  •     stcCanInitCfg.enCanRxBufAll  = CanRxNormal;
  •     stcCanInitCfg.enCanRxBufMode = CanRxBufNotStored;
  •     stcCanInitCfg.enCanSAck      = CanSelfAckEnable;
  •     stcCanInitCfg.enCanSTBMode   = CanSTBFifoMode;
  •     CAN_Init(&stcCanInitCfg);
  •     //<<Can filter config
  •     stcFilter.enAcfFormat = CanAllFrames;
  •     stcFilter.enFilterSel = CanFilterSel1;
  •     stcFilter.u32CODE     = 0x00000000u;
  •     stcFilter.u32MASK     = 0x1FFFFFFFu;
  •     CAN_FilterConfig(&stcFilter, Enable);
  •     //<<Can Irq Enable
  •     CAN_IrqCmd(CanRxIrqEn, Enable);
  •     stcIrqRegiConf.enIRQn = Int000_IRQn;
  •     stcIrqRegiConf.enIntSrc = INT_CAN_INT;
  •     stcIrqRegiConf.pfnCallback = &CAN_RxIrqCallBack;
  •     enIrqRegistration(&stcIrqRegiConf);
  •     NVIC_SetPriority(stcIrqRegiConf.enIRQn, DDL_IRQ_PRIORITY_DEFAULT);
  •     NVIC_ClearPendingIRQ(stcIrqRegiConf.enIRQn);
  •     NVIC_EnableIRQ(stcIrqRegiConf.enIRQn);
  • 复制代码
    先是初始化系统时钟和CAN时钟,并且开启CAN 时钟进入高速模式 ;
    接着初始化CAN TX / RX 引脚,这里复用功能选择 disable 着实令人生疑 ,不应该是enable才对么? 而且没有明白 PD15置低电平起到啥作用 ;
    然后再对CAN结构体模块进行初始化,波特率配置成了 1M ,这个作为例程来讲确实有点高,可能比较自信吧 。还对CAN的滤波器做了配置,屏蔽码code寄存器中应该也是 0代表相关 1代表无关的 ;
    最后由于需要用中断方式接收处理数据,将CAN_RX 的中断服务开起来了,中断调用处理方式也是类似ST一样在一个总的中断服务处理函数文件中定义,并且进行回调,这里的回调函数为  CAN_RxIrqCallBack ,在 hc32f46x_interrupts.c 文件中的 IRQ000_Handler 中断服务函数中被系统调用,而且 采用的是给中断入口函数数组赋初始值的方式 将回调函数注册成功的,整个中断处理的这套逻辑还是做得不错的 。
    void CAN_RxIrqCallBack(void)
  • {
  •     if(true == CAN_IrqFlgGet(CanRxIrqFlg))
  •     {
  •         CAN_IrqFlgClr(CanRxIrqFlg);
  •         CAN_IrqCmd(CanRxIrqEn, Disable);
  •         CAN_Receive(&stcRxFrame);
  •         u8RxFlag = true;
  •     }
  • }
  • 复制代码
    说句实话,初始化的一大段代码直接放在main的开头而不用初始化函数封装起来,这个实在不能接受原厂这样干,希望后面能有所调整和优化吧。CAN中断样例的应用层是这样写的,在接收到一帧数据之后,判断是否是数据帧,如果是数据帧,则发送接收到的数据。可以接起CAN盒子利用上位机,每1ms间隔连发500次给板子看板子回复数据情况,由于手边没有工具暂不验证了。

    【中断控制器(INTC)】

    通过手册可以知道,中断控制器(INTC)的功能有以下:
    1. 选择中断事件请求作为中断输入到 NVIC,唤醒 WFI;
    2. 选择中断事件请求作为事件输入,唤醒 WFE
    3. 选择中断事件请求作为低功耗模式(休眠模式和停止模式)的唤醒条件;
    4. 外部管脚 NMI 和 EIRQ 的中断控制功能;
    5. 软件中断的中断/事件选择功能。

    前面CAN例程也涉及到了中断控制器的使用,也有大致提及它的整个写法与ST 还是很不一样的。
    第一步需要给 NVIC->IP赋值,这个是选择的IRQ通道号 ;
    第二步需要设置中断优先级,也是对应的序号越小的优先级越高 ;
    第三步本来直接使能通道即可,但是在华大ddl库例程中每次使能通道前会清除相应的标志位,可能是因为硬件不支持“未使能中断,中断标志位自动清除” 。

    结合前面例程来看 有比较重要的几句代码:
    typedef void (*func_ptr_t)(void);
    func_ptr_t IrqHandler[IRQ_NUM_MAX] = {NULL};
    en_result_t enIrqRegistration(const stc_irq_regi_conf_t *pstcIrqRegiConf)
  • {
  •     // todo, assert ...
  •     stc_intc_sel_field_t *stcIntSel;
  •     en_result_t enRet = Ok;
  •     //DDL_ASSERT(NULL != pstcIrqRegiConf->pfnCallback);
  •     DDL_ASSERT(IS_NULL_POINT(pstcIrqRegiConf->pfnCallback));
  •     /* IRQ032~127 whether out of range */
  •     if (((((pstcIrqRegiConf->enIntSrc/32)*6 + 32) > pstcIrqRegiConf->enIRQn) || \
  •         (((pstcIrqRegiConf->enIntSrc/32)*6 + 37) < pstcIrqRegiConf->enIRQn)) && \
  •         (pstcIrqRegiConf->enIRQn >= 32))
  •     {
  •         enRet = ErrorInvalidParameter;
  •     }
  •     else
  •     {
  •         stcIntSel = (stc_intc_sel_field_t *)((uint32_t)(&M4_INTC->SEL0)         +   \
  •                                              (4u * pstcIrqRegiConf->enIRQn));
  •         if (0x1FFu == stcIntSel->INTSEL)
  •         {
  •             stcIntSel->INTSEL = pstcIrqRegiConf->enIntSrc;
  •             IrqHandler[pstcIrqRegiConf->enIRQn] = pstcIrqRegiConf->pfnCallback;
  •         }
  •         else
  •         {
  •             enRet = ErrorUninitialized;
  •         }
  •     }
  •     return enRet;
  • }
  • 复制代码
    IrqHandler[pstcIrqRegiConf->enIRQn] = pstcIrqRegiConf->pfnCallback;  这就是将 pfnCallback 这个回调函数的函数指针赋值给 IrqHandler[pstcIrqRegiConf->enIRQn] 这个指针,相当于调用了 IrqHandler这个函数的话就等于调用了 pfnCallback 这个回调函数。在赋初值的时候需要注意,不同的回调函数不能够使用同一个中断向量,这样会造成只有一个中断服务函数起到作用而其它没有正确被注册的问题。

    【写在最后】

    限于篇幅,本次将评估 ADC TIMER UART等外设功能过程藏在自己心里,有机会再分享和学习,接下来点屏。
    HC32xxx J-Flash V2.0.zip (128.05 KB, 下载次数: 4)
    全部回复 5
    • 286 主题
    • 1005 帖子
    • 3761 积分
    身份:LV5 资深技术员
    E币:9171
    • 249 主题
    • 954 帖子
    • 3987 积分
    身份:版主
    E币:9148
    • 0 主题
    • 438 帖子
    • 1999 积分
    身份:LV4 高级技术员
    E币:1088
    • 0 主题
    • 438 帖子
    • 1999 积分
    身份:LV4 高级技术员
    E币:1088
    • 0 主题
    • 438 帖子
    • 1999 积分
    身份:LV4 高级技术员
    E币:1088
    回复楼主
    您需要登录后才可以评论 登录 立即注册