打印

有关HC32F460的CAN通讯问题

[复制链接]
8477|26
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
Wtt小菜鸟|  楼主 | 2021-10-31 16:28 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
我尝试使用HC32F460来进行CAN通讯,但是在使用例程的时候始终无法进行正常的CAN通讯,想请教一下是不是哪里配置错误导致的问题。
选用的是20MHz外部晶振,主频与例程相同配至200MHz。
以下是有关CAN的配置
static void CanInitConfig(void)
{
    stc_can_init_config_t stcCanInitCfg;
    stc_can_filter_t astcFilters[CAN_FILTERS_COUNT] = \
    {
        {0x00000000ul, 0x1FFFFFFFul, CanFilterSel1, CanAllFrames}
    };

    //<< Enable can peripheral clock and buffer(ram)
    PWC_RamOpMdConfig(HighSpeedMd);
    PWC_RamPwrdownCmd(PWC_RAMPWRDOWN_CAN, Enable);
    PWC_Fcg1PeriphClockCmd(PWC_FCG1_PERIPH_CAN, Enable);

    //<< CAN GPIO config  这里是自己配置的两个端口
    PORT_SetFunc(PortB, Pin02, Func_Can1_Rx, Disable);
    PORT_SetFunc(PortB, Pin10, Func_Can1_Tx, Disable);

    //64pin没有PD15,所以屏蔽了以下两句
    //PORT_ResetBits(PortD, Pin15);
    //PORT_OE(PortD, Pin15, Enable);

    MEM_ZERO_STRUCT(stcCanInitCfg);
    //<< Can bit time config  这边跟例程相同选用1MHz波特率
    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;

    stcCanInitCfg.pstcFilter     = astcFilters;
    stcCanInitCfg.u8FilterCount  = CAN_FILTERS_COUNT;

    CAN_Init(&stcCanInitCfg);
}

因为通讯不上,我又尝试使用CAN内部回环模式通信的例程,想看看能不能进行内部通讯,但是仍然失败,且一直在while (false == CAN_Irq**Get(CanTxPrimaryIrq**))这一句循环,没有发送成功。因此想请教一下可能是什么原因造成的呢?

使用特权

评论回复
沙发
Wtt小菜鸟|  楼主 | 2021-11-1 12:11 | 只看该作者
下面是有关通讯部分的函数,主要就是卡在while (false == CAN_Irq**Get(CanTxPrimaryIrq**));这一句,好像无法发送出去
static void CanTxRx(void)
{
    stc_can_txframe_t stcTxFrame;
    stc_can_rxframe_t stcRxFrame;
    uint8_t u8Idx = 0u;

    MEM_ZERO_STRUCT(stcTxFrame);
    MEM_ZERO_STRUCT(stcRxFrame);

    //<<Can Tx 1st
    stcTxFrame.StdID = 0x123ul;
    for(u8Idx = 0u; u8Idx < 0x08u; u8Idx++)
    {
        stcTxFrame.Data[u8Idx] = u8Idx;
    }

    stcTxFrame.Control_f.DLC = 0x08ul;
    stcTxFrame.Control_f.IDE = 0x00ul;
    CAN_SetFrame(&stcTxFrame);
    CAN_TransmitCmd(CanPTBTxCmd);
    //<< Wait transmitting done.
    while (false == CAN_Irq**Get(CanTxPrimaryIrq**));
    CAN_Irq**Clr(CanTxPrimaryIrq**);

    while(1)
    {
        if(true == CAN_Irq**Get(CanRxIrq**))
        {
            CAN_Irq**Clr(CanRxIrq**);
            //<< Rx
            CAN_Receive(&stcRxFrame);
            //<< Tx
            CAN_SetFrame(&stcTxFrame);
            CAN_TransmitCmd(CanPTBTxCmd);
            //<< Wait transmitting done.
            while (false == CAN_Irq**Get(CanTxPrimaryIrq**));
            CAN_Irq**Clr(CanTxPrimaryIrq**);
        }
    }
}

使用特权

评论回复
板凳
Wtt小菜鸟|  楼主 | 2021-11-1 12:11 | 只看该作者
有没有大佬可以告知一下,可能是哪些地方没有配置正确呢

使用特权

评论回复
地板
wubangmi| | 2021-11-1 13:38 | 只看该作者
F460的CAN时钟来自外部高频晶振,CAN的最大波特率只支持1MHZ,你外部晶振用的是20MHZ,代码里CAN的时钟分频是1,所以在时钟源这部分你搞错了。

使用特权

评论回复
5
Wtt小菜鸟|  楼主 | 2021-11-1 14:00 | 只看该作者
wubangmi 发表于 2021-11-1 13:38
F460的CAN时钟来自外部高频晶振,CAN的最大波特率只支持1MHZ,你外部晶振用的是20MHZ,代码里CAN的时钟分频 ...

哦哦,就是说实际上CAN的时钟采用的也就是我的外部20MHz的晶振是吗,好的谢谢大佬,十分感谢解惑,我再去尝试一下

使用特权

评论回复
6
Wtt小菜鸟|  楼主 | 2021-11-1 14:11 | 只看该作者
wubangmi 发表于 2021-11-1 13:38
F460的CAN时钟来自外部高频晶振,CAN的最大波特率只支持1MHZ,你外部晶振用的是20MHZ,代码里CAN的时钟分频 ...

还有个问题想请教一下您,这个F460的CAN时钟配置具体是在哪的呢,还是说PWC_Fcg1PeriphClockCmd(PWC_FCG1_PERIPH_CAN, Enable)这条语句开启外围时钟就表示使用了外部的来自Xtal(我之前配的就是Xtal时钟)的时钟源是吗。

使用特权

评论回复
7
Wtt小菜鸟|  楼主 | 2021-11-1 14:37 | 只看该作者
Wtt小菜鸟 发表于 2021-11-1 14:00
哦哦,就是说实际上CAN的时钟采用的也就是我的外部20MHz的晶振是吗,好的谢谢大佬,十分感谢解惑,我再去 ...

您好,我根据您的建议对CAN时钟的进行重新的分配,其配置如下:
stcCanInitCfg.stcCanBt.PRESC = 1u-1u;
stcCanInitCfg.stcCanBt.SEG_1 = 16u-2u;
stcCanInitCfg.stcCanBt.SEG_2 = 4u-1u;
stcCanInitCfg.stcCanBt.SJW   = 3u-1u;
将其配置成了1MHz的波特率进行传输,但仍然卡在while (false == CAN_Irq**Get(CanTxPrimaryIrq**));这条语句,想知道是这样配置会有什么其他问题吗,还是说有其他地方也配置错误的,为了便于查找,我把我的系统时钟初始化配置放置如下:
void BSP_CLK_Init(void)
{
    stc_clk_sysclk_cfg_t    stcSysClkCfg;
    stc_clk_xtal_cfg_t      stcXtalCfg;
    stc_clk_mpll_cfg_t      stcMpllCfg;
    stc_sram_config_t       stcSramConfig;

    MEM_ZERO_STRUCT(stcSysClkCfg);
    MEM_ZERO_STRUCT(stcXtalCfg);
    MEM_ZERO_STRUCT(stcMpllCfg);
    MEM_ZERO_STRUCT(stcSramConfig);

    /* Set bus clk div. */
    stcSysClkCfg.enHclkDiv  = ClkSysclkDiv1;
    stcSysClkCfg.enExclkDiv = ClkSysclkDiv2;
    stcSysClkCfg.enPclk0Div = ClkSysclkDiv1;
    stcSysClkCfg.enPclk1Div = ClkSysclkDiv2;
    stcSysClkCfg.enPclk2Div = ClkSysclkDiv4;
    stcSysClkCfg.enPclk3Div = ClkSysclkDiv4;
    stcSysClkCfg.enPclk4Div = ClkSysclkDiv2;
    CLK_SysClkConfig(&stcSysClkCfg);

    /* Config Xtal and Enable Xtal */
    stcXtalCfg.enMode = ClkXtalModeOsc;
    stcXtalCfg.enDrv = ClkXtalLowDrv;
    stcXtalCfg.enFastStartup = Enable;
    CLK_XtalConfig(&stcXtalCfg);
    CLK_XtalCmd(Enable);

    /* sram init include read/write wait cycle setting */
    stcSramConfig.u8SramIdx = Sram12Idx | Sram3Idx | SramHsIdx | SramRetIdx;
    stcSramConfig.enSramRC = SramCycle2;
    stcSramConfig.enSramWC = SramCycle2;
    SRAM_Init(&stcSramConfig);

    /* flash read wait cycle setting */
    EFM_Unlock();
    EFM_SetLatency(EFM_LATENCY_5);
    EFM_Lock();

    /* MPLL config (XTAL / pllmDiv * plln / PllpDiv = 200M). */
    stcMpllCfg.pllmDiv = 5ul;
    stcMpllCfg.plln    = 100ul;
    stcMpllCfg.PllpDiv = 2ul;
    stcMpllCfg.PllqDiv = 2ul;
    stcMpllCfg.PllrDiv = 2ul;
    CLK_SetPllSource(ClkPllSrcXTAL);
    CLK_MpllConfig(&stcMpllCfg);

    /* Enable MPLL. */
    CLK_MpllCmd(Enable);
    /* Wait MPLL ready. */
    while(Set != CLK_GetFlagStatus(ClkFlagMPLLRdy))
    {
        ;
    }
    /* Switch driver ability */
    PWC_HS2HP();
    /* Switch system clock source to MPLL. */
    CLK_SetSysClkSource(CLKSysSrcMPLL);
}

请问一下可能是哪里出了什么问题吗

使用特权

评论回复
8
wubangmi| | 2021-11-1 15:14 | 只看该作者
本帖最后由 wubangmi 于 2021-11-1 15:16 编辑
Wtt小菜鸟 发表于 2021-11-1 14:37
您好,我根据您的建议对CAN时钟的进行重新的分配,其配置如下:
stcCanInitCfg.stcCanBt.PRESC = 1u-1u;
...

从代码里看你XTAL已经使能了,主频倍频也没错,那么CAN的时钟也就已经开了。
但是CAN还有一个采样点问题,就是SEG_1和SEG_2,你时钟对了,但是采样点不对,你还是通信不成功
你现在的采样点是(1+16)/(1+16+4)=80.95%,例程里的采样点是(1+5)/(1+5+3)=66.67%。你可能需要匹配采样点的问题跟你的那个通信设备



使用特权

评论回复
9
Wtt小菜鸟|  楼主 | 2021-11-1 15:45 | 只看该作者
wubangmi 发表于 2021-11-1 15:14
从代码里看你XTAL已经使能了,主频倍频也没错,那么CAN的时钟也就已经开了。
但是CAN还有一个采样点问题, ...

您好,是这样的,因为通讯不成功,所以我现在使用的是有关CAN内部回环通讯的例程来进行内部的通讯尝试。也就是说我没有接外部设备,然后程序是一直卡在确认发送标志位这一个循环里,也就是while (false == CAN_Irq**Get(CanTxPrimaryIrq**))这一串代码,我点进去之后发现是判断其RTIF寄存器TPIF位的内容,其比较方式如下:
bool CAN_Irq**Get(en_can_irq_flag_type_t enCanIrq**Type)
{
    volatile uint32_t *u32pIE = NULL;
    bool bRet = false;
    DDL_ASSERT(IS_CAN_IRQ_FLAG_VALID(enCanIrq**Type));
    u32pIE = (volatile uint32_t*)(&M4_CAN->RTIE);//这里例程是取值RTIE后共32位的值。
    //这里enCanIrq**Type=0x00000800,比较的是RTIF的TPIF位,用于判断是否发送成功。
    if( *u32pIE & enCanIrq**Type)
    {
        bRet = true;
    }
    return bRet;
}
这一步始终是return false,就是说我始终没有发送成功。想请问一下这也跟采样点是相关联的是吗,如果采样点不对的话是否也会导致发送未完成呢。

使用特权

评论回复
10
wubangmi| | 2021-11-1 16:32 | 只看该作者
Wtt小菜鸟 发表于 2021-11-1 15:45
您好,是这样的,因为通讯不成功,所以我现在使用的是有关CAN内部回环通讯的例程来进行内部的通讯尝试。 ...

你是不是搞错了例程啊,用内部回环模式,我没看到下面这个函数啊
//<< Loop back internal
    CAN_ModeConfig(CanExternalLoopBackMode, Enable);

使用特权

评论回复
11
Wtt小菜鸟|  楼主 | 2021-11-1 16:35 | 只看该作者
wubangmi 发表于 2021-11-1 16:32
你是不是搞错了例程啊,用内部回环模式,我没看到下面这个函数啊
//

您好,有这个函数,我忘记放上来了,给您看一下完整的有关CAN设置的函数内容:
static void CanInitConfig(void)
{
    stc_can_init_config_t stcCanInitCfg;
    stc_can_filter_t astcFilters[CAN_FILTERS_COUNT] = \
    {
        {0x00000000ul, 0x1FFFFFFFul, CanFilterSel1, CanAllFrames}
    };

    //<< Enable can peripheral clock and buffer(ram)
    PWC_RamOpMdConfig(HighSpeedMd);
    PWC_RamPwrdownCmd(PWC_RAMPWRDOWN_CAN, Enable);
    PWC_Fcg1PeriphClockCmd(PWC_FCG1_PERIPH_CAN, Enable);

    //<< CAN GPIO config
    PORT_SetFunc(PortB, Pin02, Func_Can1_Rx, Disable);
    PORT_SetFunc(PortB, Pin10, Func_Can1_Tx, Disable);
    //PORT_ResetBits(PortD, Pin15);
    //PORT_OE(PortD, Pin15, Enable);

    MEM_ZERO_STRUCT(stcCanInitCfg);
    //<< Can bit time config
    stcCanInitCfg.stcCanBt.PRESC = 1u-1u;
    stcCanInitCfg.stcCanBt.SEG_1 = 13u-2u;
    stcCanInitCfg.stcCanBt.SEG_2 = 7u-1u;
    stcCanInitCfg.stcCanBt.SJW   = 3u-1u;

    stcCanInitCfg.stcWarningLimit.CanErrorWarningLimitVal = 10u;
    stcCanInitCfg.stcWarningLimit.CanWarningLimitVal = 16u-1u;

    stcCanInitCfg.enCanRxBufAll  = CanRxAll;
    stcCanInitCfg.enCanRxBufMode = CanRxBufNotStored;
    stcCanInitCfg.enCanSAck      = CanSelfAckEnable;
    stcCanInitCfg.enCanSTBMode   = CanSTBFifoMode;

    stcCanInitCfg.pstcFilter     = astcFilters;
    stcCanInitCfg.u8FilterCount  = CAN_FILTERS_COUNT;

    CAN_Init(&stcCanInitCfg);

    //<< Loop back internal
    CAN_ModeConfig(CanExternalLoopBackMode, Enable);
}

使用特权

评论回复
12
Wtt小菜鸟|  楼主 | 2021-11-1 17:25 | 只看该作者
wubangmi 发表于 2021-11-1 16:32
你是不是搞错了例程啊,用内部回环模式,我没看到下面这个函数啊
//

您好,我现在尝试使用内部回环模式的时候,发现可以正常通讯,但是外部回环模式仍然卡在之前那个while循环当中,您知道这可能与什么设置有关系吗。

使用特权

评论回复
13
Wtt小菜鸟|  楼主 | 2021-11-1 20:52 | 只看该作者
有没有大哥可以告诉我可能是哪里有问题的呀,找了两天了还是不知道什么问题导致的,自闭了

使用特权

评论回复
14
Wtt小菜鸟|  楼主 | 2021-11-2 09:53 | 只看该作者
别沉呀,有没有哪位比较熟悉华大芯片的或者比较熟悉CAN通讯的大佬,麻烦告知一下小弟哪里出问题了

使用特权

评论回复
15
wubangmi| | 2021-11-2 11:18 | 只看该作者
Wtt小菜鸟 发表于 2021-11-2 09:53
别沉呀,有没有哪位比较熟悉华大芯片的或者比较熟悉CAN通讯的大佬,麻烦告知一下小弟哪里出问题了 ...

两种方式,按需采用其中的一种:
1、在例程里屏蔽所有以下等待发送中断的代码
//    //<< Wait transmitting done.
//    while (false == CAN_Irq**Get(CanTxPrimaryIrq**));
//    CAN_Irq**Clr(CanTxPrimaryIrq**);

2、在CAN初始化后增加发送中断使能函数,其他代码不改动
CAN_IrqCmd(CanTxPrimaryIrqEn, Enable);

使用特权

评论回复
16
Wtt小菜鸟|  楼主 | 2021-11-2 19:59 | 只看该作者
wubangmi 发表于 2021-11-2 11:18
两种方式,按需采用其中的一种:
1、在例程里屏蔽所有以下等待发送中断的代码
//    // ...

您好,我根据您给的建议进行了简单的尝试,但仍然无法实现CAN的外部回环通讯,不仅发送中断没有正常标志,接收中断标志位同样如此,因此怀疑数据根本没有发出去,所以猜想是否是时钟或者波特率设置出现了什么问题,想请教一下您,CAN总线的时钟源是来自外部高速振荡器,那么哪个函数可以具体表示CAN时钟源的选择呢,还有就是,如果我不使用Xtal,采用内部振荡器,那么CAN总线的时钟源又该怎么设置呢

使用特权

评论回复
17
wubangmi| | 2021-11-2 21:07 | 只看该作者
Wtt小菜鸟 发表于 2021-11-2 19:59
您好,我根据您给的建议进行了简单的尝试,但仍然无法实现CAN的外部回环通讯,不仅发送中断没有正常标志 ...

CAN时钟只能来自外部高速晶振,不能用内部。
我看你说用内部回环可以了,那把内部回环改成外部回环的就行了,其他的都不用改,我今天特意用例程跑了下,都是通的。

使用特权

评论回复
18
Wtt小菜鸟|  楼主 | 2021-11-5 10:07 | 只看该作者
wubangmi 发表于 2021-11-2 21:07
CAN时钟只能来自外部高速晶振,不能用内部。
我看你说用内部回环可以了,那把内部回环改成外部回环的就行 ...

好的,麻烦您了,最终找到问题所在,其设置没有问题,只不过这款芯片的PB2引脚并无CAN功能的复用,所以将管脚改至PH2后可以正常跑了,十分感谢您的解答

使用特权

评论回复
19
lxllidong| | 2021-11-12 13:37 | 只看该作者
本帖最后由 lxllidong 于 2021-11-12 14:05 编辑

大神,我也碰到类似的问题 :用官方的demo + 开发板,程序改成间隔20ms发送,示波器可以抓到gpio口的电平变化报文~~~但是把管脚改成PH02/PC13其他什么也不变,示波器在PH02/PC13上什么也没抓到~~~

使用特权

评论回复
20
lxllidong| | 2021-11-12 13:56 | 只看该作者
直接在官方demo上把引脚改成PH02/PC13也不行,示波器抓不到信号~但是官方的demo配置却可以跑,好奇怪!!!

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

1

主题

13

帖子

0

粉丝