• S32K CAN收发标准数据帧配置(纯C 不用SDK带的驱动)


    由于S32K144 CAN功能众多,协议上既支持CAN FD,又支持传统CAN 2.0,存储消息既支持FIFO机制,又支持邮箱机制,还支持DMA,可配置can消息缓存数量及分类众多,比较建议先直接用一种的简单方式,再由简入繁,不论是看文档,还是调试都会容易得多。

    本文主要讲解如何用纯C配置S32K144 CAN收发功能(FIFO中断接收),如何配置比特率,可以接收任意CAN ID,也可以指定过滤CAN ID。使用了SDK RTM3.0.0的中断管理文件interrupt_manager.h/c, 来管理CPU中断(响应)。

    运行环境

    MCU: S32K144 LQFP100, IDE: S32DS for ARM 2018.R1

    SDK: None, PCBA: 要求使用外部晶振8M(如果不是需要自己配置bit rate)

    CAN收发器:NXP TJA1044(使用如TJA1043等低功耗方案时,需要在发送CAN报文前配置好CAN收发器相关引脚,以便能正常收发报文,否则MCU CAN模块ESR/ECR会报错)

    配置说明

    CAN引脚:PTC2 - CAN0_RX, PTC3 - CAN0_TX

    CAN bit rate = 500kbps

    CAN发送: MB8 (中断);

    CAN接收FIFO中断(MB0~5), CAN ID过滤表(MB6~7,FIFO默认选择);

    1.时钟配置(略)

    关于如何配置bus clock,可以参见我写的另一篇文章 S32K144之时钟配置 , 里面也包含了bus clock 80M, OSC 8M, 如何验证以及端口配置的讲解。

    2.CAN Port配置

    根据板子实际使用CAN引脚决定。我手上板子实际使用PTC2, PTC3作为CAN收发功能。

    PTC2&PTC3 IO Map截图

      

    /**
     * CAN Port Initialization
     */
    void Port_CanInit(void)
    {
        // Enable clock to PORTC
        if(PCC->PCCn[PCC_PORTC_INDEX] & PCC_PCCn_PR_MASK)
        {
            PCC->PCCn[PCC_PORTC_INDEX] |= PCC_PCCn_CGC(1); // Clock enabled to PORTC
        }
    
        // Set MUX
        // PTC2 - CAN0_RX
        PORT_CAN->PCR[PORT_CAN_RX_IDX] = PORT_PCR_MUX(0b00000011); // Port C2: MUX = ALT3, CAN0_RX
        // PTC3 - CAN0_TX
        PORT_CAN->PCR[PORT_CAN_TX_IDX] = PORT_PCR_MUX(0b00000011); // Port C3: MUX = ALT3, CAN0_TX
    }

    3.CAN0配置

    1)bit rate

    初始化,时钟选择8M OSC时钟(时钟源是8M外部晶振),CAN 比特率bit rate = 500kbps 

    1 CAN Bit Time = (1 + (PROPSEG + PSEG1 + 2) + (PSEG2 + 1)) * Tq
    
    

    而Tq=1/8M = 1/8 us,不妨取PROPSEG = 6, PSEG1 = 3, PSEG2 = 3。这里PROPSEG ,PSEG1 ,PSEG2 只是其中一组可行参数,具体如何配置还要看车厂要求,车厂一般都会有自己的CAN节点通讯规范来规定CAN底层参数的。

    传统CAN 2.0帧1bit time组成示意图

    2)CAN0初始化

    使用FIFO中断接收,1MB(message buffer)占用4word,每个word对应4byte。其中前面2个word表示长度、时间戳、IDE、RTR、CAN ID等信息,后2个word表示CAN数据段8byte。

    FIFO接收缓存:默认MB0~5,读取数据接口:MB0(下图红框)。M6~7默认是CAN ID过滤表元素0~1,MB8~37是可配置ID过滤表元素2~127。

    中断机制:FIFO接收缓存MB0~5,当有任意一个CAN成功接收后,会产生事件标志CAN_IFLAG1[BUF5I];

    当接收到从4个到5个时,会产生事件标志CAN_IFLAG1[BUF6I];

    当接收满5个后,还接收到新CAN消息,会产生事件标志CAN_IFLAG1[BUF7I],表示发生溢出;

    另外,RM提到,使用FIFO时,要使用单独ID过滤mask,而不能用global mask。

    MB缓存大小有关宏定义

    #define MSG_BUF_SIZE        4u    /* 1 Msg Buffer Size : CAN0->RAMn[i] use 4word(1word=4byte). 4word = 2word header, 2word data*/
    #define MB_FIFO_NUM         6u    /* MB Size used for FIFO engine: MB0~5 */
    #define MB_FIFO_IDX_TX      8u    /* MB for transmitting CAN message*/
    #define MB_FIFO_IDX_RX      6u    /* MB for receiving CAN message*/
    

    CAN0初始化,主要步骤参考S32K RM CAN初始化章节:FlexCAN initialization sequence

    /**
     * CAN configuration, set baud rate = 500Kbps
     *
     * @note CAN Baud rate calculation
     * Tq = (PRESDIV + 1) / f_canclk = 1 / 8M
     *
     * 1 CAN Bit Time = (1 + (PROPSEG + PSEG1 + 2) + (PSEG2 + 1)) * Tq
     * = (1 + (6 + 3 + 2) + (3 + 1) * 1/8M
     * = 16 * 1/8M = 2us
     *
     * Baud Rate = 1/2us = 500Kbps
     *
     * configure 1MB = 8 CAN->RAMn = 32byte
     * MB6 ~ FIFO Rx
     * MB8 ~ Tx
     */
    void Can0_Init()
    {
        PCC->PCCn[PCC_FlexCAN0_INDEX] |= PCC_PCCn_CGC(1); // Clock enabled to CAN0 module
    
        // Step0: Go to Freeze mode
        // Step0-1: After reset, disable can module
        CAN_DisableModule(CAN0); // Disable module before selecting clock
    
        // Step0-2: Select clock source
        CAN0->CTRL1 &= ~CAN_CTRL1_CLKSRC_MASK; // CLKSRC = 0: Clock source = the oscillator clock. (SOSCDIV2_CLK = 8MHz)
    
        // Step0-3: Enable can module, then flexCAN automatically enters Freeze mode
        CAN_EnableModule(CAN0); // Enable module
    
        // Step0-4: Check whether current mode is Freeze mode
        CAN_EnableFreezeMode(CAN0);
        while(!((CAN0->MCR & CAN_MCR_FRZACK_MASK) >> CAN_MCR_FRZACK_SHIFT)){} // Wait for FRZACK = 1, to ensure next operation in Freeze mode
    //    while(!(CAN0->MCR & CAN_MCR_NOTRDY_MASK)){} // Wait for NOTRDY = 1, to ensure next operation in Disable mode/Stop mode/Freeze mode.
    
        // Step1: Initialize MCR
        CAN0->MCR |=
                CAN_MCR_IRMQ_MASK // a: IRMQ=1, enable the individual filtering per MB and reception queue features
                | CAN_MCR_WRNEN_MASK // b: WRNEN=1, enable the warning interrupts
                | CAN_MCR_SRXDIS_MASK // c: SRXDIS=1, disable frame self reception
                | CAN_MCR_RFEN_MASK // d: RFEN=1, Enable the Rx FIFO, MBs 0 to 5 cannot be used for normal reception and transmission(they have been uesed for the FIFO engine)
                // e: DMA=0, dont use DMA
                // f: PNET_EN=0, dont use pretended networking
                | CAN_MCR_AEN_MASK// g: AEN=1, use Tx Abort mechanism
                // h: PRIOEN=0, dont use Local Priority feature
                | CAN_MCR_IDAM(0)// IDAM=0, ID Acceptance Mode=Format A: One full ID (standard and extended) per ID filter table element.
                | CAN_MCR_MAXMB(32) // MAXMB = Rx FIFO + ID filter table space(CTRL2[REFN]), default=16
                ;
    
        // Step2: Initialize CTRL1 or CBT
        // The CAN bit variables in CTRL1 and in CBT are stored in the same register.
        // Configure for CAN bit rate = 500 Kbps, 16 time quanta for 1 bit
        CAN0->CTRL1 = CAN_CTRL1_PRESDIV(0) // Tq = fcanclk / prediv = 8MHz / 1 = 8MHz
                | CAN_CTRL1_RJW(0b11) // RJW: since Phase_Seg2 >=4, RJW+1=4 so RJW=3.
                | CAN_CTRL1_PSEG1(0b011) // Phase Segment 1 = PSEG1 + 1
                | CAN_CTRL1_PSEG2(0b011) // Phase Segment 2 = PSEG2 + 1
                | CAN_CTRL1_PROPSEG(0b110) // Propagation Segment = PROPSEG + 1
                | CAN_CTRL1_SMP(1);
                // LBUF=0, Buffer with highest priority is transmitted first.(MCR[LPRIOEN] + LBUF => transmit priority)
    
        // Step3: Initialize MB
        // MB & Rx Individual Mask registers are not affected by reset, so they are not initialized automatically.
        // payload=8, MB0~5 used for FIFO engine(contains message received but not read)
        // CAN0: clear 32 message buffer x 4 words/msg, buf = 128 words
        // CAN0 contains 32MBs
        for(int i = 32; i < CAN_RAMn_COUNT; i ++)
        {
            CAN0->RAMn[i] = 0;
        }
    
        // Step4: Initialize RXIMRn(Rx Individual Mask registers)
        // In FRZ mode, init CAN0 16 individual msg buf filters . there are total 32MBs for CAN0
        for(int i = 0; i < 32; i ++)
        {
            CAN0->RXIMR[i] = 0xFFFFFFFF; // check all ID bits for incoming messages
    //        CAN0->RXIMR[i] = 0; // dont care every bit
        }
    
    //    CAN0->RXMGMASK = 0xFFFFFFFF; // Global acceptance mask. When MCR[IRMQ] set, it has no effect; When MCR[IRMQ] cleared, it will mask the mailbox filter bits. check all ID bits
    
    //    CAN0->FDCTRL &= ~CAN_FDCTRL_MBDSR0_MASK; // MBDSR0 = 0, Selects 8 bytes per message buffer. 32 MBs with 8 bytes payload
    
        // enable interrupt
        CAN0->CTRL1 |= CAN_CTRL1_RWRNMSK_MASK; // enable Rx warning interrupt
        CAN0->IMASK1 |= CAN_IMASK1_BUF31TO0M(1 << MB_FIFO_IDX_RX); /* Buffer MB i Mask: Open FIFO receives interrupt */
        CAN0->IMASK1 |= CAN_IMASK1_BUF31TO0M(1 << MB_FIFO_IDX_TX); /* MB8 interrupt mask*/
        CAN0->IMASK1 |= CAN_IMASK1_BUF31TO0M(1 << 5);
    
        // set the ID Table, assuming CTRL2[RFFN=0]
        CAN0->RAMn[ MB_FIFO_NUM*MSG_BUF_SIZE + 0] = (0x55 &0x7FF) << 19; // ID filter table element 0
        CAN0->RAMn[ MB_FIFO_NUM*MSG_BUF_SIZE + 1] = (0x56 &0x7FF) << 19; // element 1
        CAN0->RAMn[ MB_FIFO_NUM*MSG_BUF_SIZE + 2] = (0x57 &0x7FF) << 19; // element 2
        CAN0->RAMn[ MB_FIFO_NUM*MSG_BUF_SIZE + 3] = (0x58 &0x7FF) << 19; // element 3
    
        CAN0->RAMn[ MB_FIFO_NUM*MSG_BUF_SIZE + 4] = (0x59 &0x7FF) << 19; // element 4
        CAN0->RAMn[ MB_FIFO_NUM*MSG_BUF_SIZE + 5] = (0x5A &0x7FF) << 19; // element 5
        CAN0->RAMn[ MB_FIFO_NUM*MSG_BUF_SIZE + 6] = (0x5B &0x7FF) << 19; // element 6
        CAN0->RAMn[ MB_FIFO_NUM*MSG_BUF_SIZE + 7] = (0x5C &0x7FF) << 19; // element 7
    
        // Step7: nagate HALT
        CAN0->MCR &= ~CAN_MCR_HALT_MASK;       /* Negate HALT bit */
    
        CAN_DisableFreezeMode(CAN0);
        while((CAN0->MCR & CAN_MCR_FRZACK_MASK) >> CAN_MCR_FRZACK_SHIFT) {}  // Wait for FRZACK = 0
    
        while((CAN0->MCR & CAN_MCR_NOTRDY_MASK) >> CAN_MCR_NOTRDY_SHIFT) {} // Wait for NOTRDY = 0, FlexCAN module is either in Normal mode, Listen-Only mode, or Loop-Back mode.
    
        INT_SYS_ClearPending(CAN0_ORed_0_15_MB_IRQn);
        INT_SYS_EnableIRQ(CAN0_ORed_0_15_MB_IRQn);
        INT_SYS_SetPriority(CAN0_ORed_0_15_MB_IRQn, 0xA0);
    }

    3)CAN0发送

    将can id,8byte数据,数据长度写入硬件缓存MB,准备发送

    /**
     * Transmit message once using MB8
     * @param id CAN id
     * @param [in] pData data to be sent
     * @param length length of data to be sent, unit: byte
     */
    void Can0_Tx(uint32_t canId, uint8_t *pData, uint8_t length)
    {
        if(!pData)
            return;
    
        /*MB8 word1*/
        CAN0->RAMn[MB_FIFO_IDX_TX*MSG_BUF_SIZE + 1] = ((canId & 0x7FF) << 18u); // std id
    
        /*MB8 word2*/
        CAN0->RAMn[MB_FIFO_IDX_TX*MSG_BUF_SIZE + 2] =
                CAN_RAMn_DATA_BYTE_0(pData[0])
                | CAN_RAMn_DATA_BYTE_1(pData[1])
                | CAN_RAMn_DATA_BYTE_2(pData[2])
                | CAN_RAMn_DATA_BYTE_3(pData[3]);
        /*MB8 word3*/
        CAN0->RAMn[MB_FIFO_IDX_TX*MSG_BUF_SIZE + 3] =
                CAN_RAMn_DATA_BYTE_0(pData[4])
                | CAN_RAMn_DATA_BYTE_1(pData[5])
                | CAN_RAMn_DATA_BYTE_2(pData[6])
                | CAN_RAMn_DATA_BYTE_3(pData[7]);
    
        /* MB0 word 0: */
        /* EDL,BRS,ESI=0: CANFD not used */
        /* CODE=0xC: Activate msg buf to transmit */
        /* IDE=0: Standard ID */
        /* SRR=1 Tx frame (not req'd for std ID) */
        /* RTR = 0: data, not remote tx request frame*/
        /* DLC = 8 bytes */
        uint32_t code = 0b1100;
        CAN0->RAMn[MB_FIFO_IDX_TX*MSG_BUF_SIZE + 0] = CAN_WMBn_CS_CODE(code)
                | CAN_WMBn_CS_SRR(1)
                | CAN_WMBn_CS_RTR(0)
                | CAN_WMBn_CS_DLC(length);
    
    //    while(!(CAN0->IFLAG1 & (1 << 8u))){} // Wait for CAN0 MB8 flag // 相当于等待发送完毕, 这里没必要, 如需要在发送完毕后做些什么, 可以放到中断里面
    //    CAN0->IFLAG1 |= 1 << 8u; // Clear CAN0 8 flag without clearing other.
    }

    发送完成中断处理(发送完成后捕捉中断,可用于继续进行某些动作,比如从发送列表中继续发送下一帧)

    uint32_t txCouner = 0;
    void CAN0_ORed_0_15_MB_IRQHandler()
    {
        if(CAN0->IFLAG1 & (1 << MB_FIFO_IDX_TX))
        {
            CAN0->IFLAG1 |= 1 << MB_FIFO_IDX_TX; /* Clear CAN0 MB8 flag */
            txCouner ++;
        }
    }

    4)CAN0中断接收

    注意要在中断处理函数之前,就enable相应的中断

    typedef struct
    {
        uint32_t id;
        uint32_t dlc;
        uint8_t data[8];
        uint32_t timestamp;
    }CAN_StdFrame, *CAN_StdFramePtr;

    volatile static CAN_StdFrame rxStdFrame = {0};
    uint32_t txCouner = 0; uint32_t rxCounter = 0; void CAN0_ORed_0_15_MB_IRQHandler() { // Tx completed interrupt if(CAN0->IFLAG1 & (1 << MB_FIFO_IDX_TX)) { CAN0->IFLAG1 |= 1 << MB_FIFO_IDX_TX; /* Clear CAN0 MB8 flag */ txCouner ++; } // Rx warning interrupt - MB0~5 full(unread message increase to 5 from 4) if(CAN0->IFLAG1 & (1 << MB_FIFO_IDX_RX)) { CAN0->IFLAG1 |= 1 << MB_FIFO_IDX_RX; /* Clear CAN0 MB6 flag */ } // when received CAN message by FIFO (MB0~5), interrupt flag set by IFLAG5(not IFLAG0~4) if(CAN0->IFLAG1 & (1 << 5)) { // read can message first rxStdFrame.id = (CAN0->RAMn[1] >> 18) & 0x7FF; rxStdFrame.dlc = (CAN0->RAMn[0] >> 16) & 0xF; rxStdFrame.timestamp = (CAN0->RAMn[0] ) & 0xFF; rxStdFrame.data[0] = (CAN0->RAMn[2] >> 24) & 0xFF; rxStdFrame.data[1] = (CAN0->RAMn[2] >> 16) & 0xFF; rxStdFrame.data[2] = (CAN0->RAMn[2] >> 8) & 0xFF; rxStdFrame.data[3] = (CAN0->RAMn[2]) & 0xFF; rxStdFrame.data[4] = (CAN0->RAMn[3] >> 24) & 0xFF; rxStdFrame.data[5] = (CAN0->RAMn[3] >> 16) & 0xFF; rxStdFrame.data[6] = (CAN0->RAMn[3] >> 8) & 0xFF; rxStdFrame.data[7] = (CAN0->RAMn[3]) & 0xFF; rxCounter ++; // then clear MB5 interrupt flag CAN0->IFLAG1 |= 1 << 5; /* Clear CAN0 MB5 flag*/ } // Rx overflow - MB0~5 full if(CAN0->IFLAG1 & (1 << 7)) { CAN0->IFLAG1 |= 1 << 7; /* Clear CAN0 MB6 flag*/ } }

    参考: 

    S32K系列S32K144学习笔记——CAN

  • 相关阅读:
    iOS push
    iOS Beta 升级或降级
    Charles SSL
    看懂UML类图和时序图
    UML示例图 zt
    一个二维码-->网址-->iOS/Android跳转
    获取Shell脚本当前的目录
    编辑请求内容 Charles
    adjustsFontSizeToFitWidth 与 NSLineBreakByCharWrapping 无法共用
    js数据类型
  • 原文地址:https://www.cnblogs.com/fortunely/p/12755948.html
Copyright © 2020-2023  润新知