• S32K148_CAN驱动(裸机开发)


    hello,大家好。今天我又来啦,今天记录一下S32K148-CAN裸机驱动编写,有错误地方欢迎大家指正。

    CAN的发送接收在S32K148中主要有三种方式,一种是邮箱机制(mailbox),一种FIFO方式,还有一种DMA方式。邮箱方式较为简单,也比较好理解。我的想法是先搞懂一种实现方式,再去满满研究其他方法。

    邮箱机制主要涉及到一下寄存器:

     

     还有一个RAMn[n]寄存器。

    具体每个寄存器的功能数据手册有详细介绍,我就不逐个叙述了。直接根据我的demo程序来作简要介绍。

    CAN的初始化主要包括:

    1)PCC时钟使能

    2)CAN发送引脚和接收引脚的复用配置

    3)CAN模块程序使能,同时进入冻结模式

    4)配置时钟,波特率,MB清0,接收MB的掩码配置,接收MB的code配置

    5)接收或发送报文中断使能

    #define MSG_BUF_SIZE        4      /* Msg Buffer Size. (CAN 2.0AB: 2 hdr +  2 data= 4 words)1MB = 4words */
    #define MB_FIFO_IDX_TX      16u   /* MB for transmitting CAN message*/
    #define MB_FIFO_IDX_RX      6u    /* MB for transmitting CAN message*/
    #define MB_FIFO_NUM         6u    /* MB0~MB5 for FIFO engine*/
    复制代码
    void can2_init(void)
    {
        PCC->PCCn[PCC_PORTB_INDEX] |= 1<<30;
        /*PIN MUX
         * PTB12 CAN2 RX
         * PTB13 CAN2 TX*/
        PORTB->PCR[12] |= 1<<10;
        PORTB->PCR[13] |= 1<<10;
        /*CAN2 init*/
        /*PCC FOR CAN2*/
        PCC->PCCn[PCC_FlexCAN2_INDEX] |= 1<<30;
        /*CAN2 cfg*/
        CAN2->MCR |= 1<<31;         //mdis=1,disable module
        CAN2->CTRL1 &=~(1<<13);     //CLKSRC=0,Clock Source = SOSCDIV2
        CAN2->MCR &=~(1<<31);       //mdis=0,ENable module
    
        //等待进入冻结模式
        while( (CAN2->MCR & (1<<24))>>24 == 0 );
    
        CAN2->CTRL1 = 0x01DB0006;                   //250k,rjw=11,psg1=011,psg2=011,propsg=110,clk=0,presdiv=1,配置时钟and波特率
        for(uint8_t i=24; i<128; i++ )
        {                                           /* CAN2: clear 32 msg bufs x 4 words/msg buf = 128 words */
            CAN2->RAMn[i] = 0;                      /* Clear msg buf word */
        }
        for(uint8_t i=0; i<32; i++ )
        {                                              /* In FRZ mode, init CAN2 16 msg buf filters */
            CAN2->RXIMR[i] = 0xFFFFFFFF;              /* Check all ID bits for incoming messages */
        }
    
        CAN2->RXMGMASK = 0x00000000;                   /* Global acceptance mask:  all ID bits DON'T CARE receive all ID message*/
    
    
        CAN2->RAMn[ 0*MSG_BUF_SIZE + 0] = 0x04000000;     /* Msg Buf 4, word 0: Enable for reception     */
                                                         /* EDL,BRS,ESI=0: CANFD not used                 */
                                                         /* CODE=4: MB set to RX inactive                 */
                                                         /* IDE=0: Standard ID                             */
                                                         /* SRR, RTR, TIME STAMP = 0: not applicable     */
        //CAN2->RAMn[ 0*MSG_BUF_SIZE + 0] = 0x04200000;     /* Msg Buf 4, word 0: Enable for reception     */
                                                         /* EDL,BRS,ESI=0: CANFD not used                 */
                                                         /* CODE=4: MB set to RX inactive                 */
                                                         /* IDE=1: extend ID                             */
                                                         /* SRR, RTR, TIME STAMP = 0: not applicable     */
    
    
        CAN2->MCR = (0x0000001f) | (1<<17);             /*SRXDIS=1,MAXMB=32*/
    
         CAN2->MCR &= ~CAN_MCR_HALT_MASK;                    /* Negate HALT bit */
        /*发送和接收message中断使能*/
         CAN2->IMASK1 |= (1<<16)|(1<<0);
         /*bus off中断使能*/
         CAN2->CTRL1 |= (1<<15);
        while ((CAN2->MCR && CAN_MCR_FRZACK_MASK) >> CAN_MCR_FRZACK_SHIFT);/* Good practice: wait for FRZACK to clear (not in freeze mode) */
        while ((CAN2->MCR && CAN_MCR_NOTRDY_MASK) >> CAN_MCR_NOTRDY_SHIFT);/* Good practice: wait for NOTRDY to clear (module ready) */
        //注册接收中断向量
        S32_NVIC_EnableIRQ(CAN2_ORed_0_15_MB_IRQn);
        S32_NVIC_EnableIRQ(CAN2_ORed_16_31_MB_IRQn);
        //注册bus off中断向量
        S32_NVIC_EnableIRQ(CAN2_ORed_IRQn);
    }
    复制代码

    CAN初始化过程中,需要注意地方在于接收掩码如何配置(原则:0表示不关心,1表示关心),其次配置好接收MB的选择同时使能相应MB的接收中断。这里面CAN发送很简单,主要针对CAN报文接收问题。

    发送函数,注意标准帧和扩展帧的设置

    复制代码
    void can2_send_8Byte(uint8_t data[], uint8_t datalength, uint32_t id, uint8_t id_mode)
    {
        uint8_t i;
        uint8_t data_tem[datalength];
        for(i=0;i)
        {
            data_tem[i] = data[i];
        }
        //CAN2->IFLAG1 |= 0xFFFF0000; //clear all transmit flag
        //wait bus idle
    //    while( (CAN2->ESR1 & (1<<7))>>7 == 0 );
        //data input
        CAN2->RAMn[MB_FIFO_IDX_TX*MSG_BUF_SIZE + 2] = data_tem[0]<<24 | data_tem[1]<<16 | data_tem[2]<<8 | data_tem[3];
        CAN2->RAMn[MB_FIFO_IDX_TX*MSG_BUF_SIZE + 3] = data_tem[4]<<24 | data_tem[5]<<16 | data_tem[6]<<8 | data_tem[7];
        //ID cfg
        if(id_mode == StandardID)
        {
            CAN2->RAMn[MB_FIFO_IDX_TX*MSG_BUF_SIZE + 1] = id<<18;
            CAN2->RAMn[MB_FIFO_IDX_TX*MSG_BUF_SIZE + 0] = 0x0C480000;   //CODE=1100,SRR=1,IDE=0,RTR=0,DLC=1000
        }else
        {
            CAN2->RAMn[MB_FIFO_IDX_TX*MSG_BUF_SIZE + 1] = id;
            CAN2->RAMn[MB_FIFO_IDX_TX*MSG_BUF_SIZE + 0] = 0x0C680000;   //CODE=1100,SRR=1,IDE=1,RTR=0,DLC=1000
        }
    }
    复制代码

    接收函数

    复制代码
    void can2_receive_8Byte(uint8_t id_mode)
    {
        can2_RecMessage.length = (CAN2->RAMn[0*MSG_BUF_SIZE + 0] >> 16) & 0xF;
        if(id_mode == StandardID)
        {
            can2_RecMessage.id = (CAN2->RAMn[0*MSG_BUF_SIZE + 1] >> 18) & 0x7FF;
        }else
        {
            can2_RecMessage.id = (CAN2->RAMn[0*MSG_BUF_SIZE + 1]) & 0x1FFFFFFF;
        }
        can2_RecMessage.data[0] = (CAN2->RAMn[0*MSG_BUF_SIZE + 2]) >> 24;
        can2_RecMessage.data[1] = ((CAN2->RAMn[0*MSG_BUF_SIZE + 2]) >> 16) & 0xFF;
        can2_RecMessage.data[2] = ((CAN2->RAMn[0*MSG_BUF_SIZE + 2]) >> 8) & 0xFF;
        can2_RecMessage.data[3] = (CAN2->RAMn[0*MSG_BUF_SIZE + 2]) & 0xFF;
        can2_RecMessage.data[4] = (CAN2->RAMn[0*MSG_BUF_SIZE + 3]) >> 24;
        can2_RecMessage.data[5] = ((CAN2->RAMn[0*MSG_BUF_SIZE + 3]) >> 16) & 0xFF;
        can2_RecMessage.data[6] = ((CAN2->RAMn[0*MSG_BUF_SIZE + 3]) >> 8) & 0xFF;
        can2_RecMessage.data[7] = (CAN2->RAMn[0*MSG_BUF_SIZE + 3]) & 0xFF;
    }
    复制代码

    这个时候还不能接收,因为我需要把这个接收函数放到中断函数中,因为我配置的接收MB为0,所以接收中断函数是CAN2_ORed_0_15_MB_IRQHandler();

    复制代码
    void CAN2_ORed_0_15_MB_IRQHandler(void)
    {
            gpio_reverse(PTe, 22);
            can2_receive_8Byte(StandardID);
            CAN2->IFLAG1 |= 0x0000FFFF;//清除标志位
    }
    复制代码

    每次接收到报文后,进入中断,在接收中断函数里读取报文ID和DATA。注意在中断函数里清除相应的MB标志位,即可进行下一次接收中断。

    本次我设置的接收全局掩码设置都为0x0,且设置的标准帧。所以对于所有的标准帧ID报文,我都可以接收。

     

  • 相关阅读:
    避免数据泄露风险!NineData提供SQL开发规范和用户访问量管理
    一体箱型无线型振弦传感器采集采发仪常见的注意事项
    UE5:如何解决背景图片被拉伸的问题?
    纷享销客数字化营销能力(三):全渠道获客
    java--拼图游戏
    Python:实现modular exponential模指数算法(附完整源码)
    URDF+Gazebo+Rviz仿真
    百度智能云千帆推出大模型普惠计划,0成本切换
    Netty常用类与接口
    linux的“>”和“>>”
  • 原文地址:https://www.cnblogs.com/taotaonihao/p/16487578.html