Overview of the CAN controller of LPC1768/1769 (with library function download address)

Publisher:科技飞翔Latest update time:2016-12-26 Source: eefocusKeywords:LPC1768  CAN controller Reading articles on mobile phones Scan QR code
Read articles on your mobile phone anytime, anywhere
1. Background:
        Use LPC1769 to do CAN transmission and reception. Here is a summary and record of using LPC1769 CAN controller for transmission and reception, in preparation for the next
    Get started quickly for the first time development.
        Note: LPC1768/1769 are basically the same except for the maximum frequency they support.

2. Main text:
        First, here is a block diagram of the LPC1769 CAN controller:


  .


        As can be seen from the figure above, the entire CAN controller has a CPU on one end and a CAN transceiver on the other end:
     The CAN transceiver is responsible for the communication of CAN data with the CAN network. The CAN kernel module parses and encapsulates the data to be sent to the CAN transceiver and received from the CAN
   The data sent by the transceiver, the CAN core work here is completed by the hardware itself.
     The CPU can set the CAN controller status and read interrupt information and interrupt status through the APB bus.
     There are 3 send buffers (mailboxes) in total, which ensures that at least 3 sets of concurrent CAN data can be sent; 2 receive buffers
   The CPU can process the received data of one mailbox while using another mailbox to receive data on the network.
     The LPC1769 CAN acceptance filter is quite special. It is a device independent of the CAN controller and is also a peripheral.
   What is special is that it is a peripheral that serves the CAN controller. The significance of this is that the acceptance filtering no longer requires software.
   To do anything, the table lookup algorithm is implemented directly by hardware, saving precious CPU resources. Since it is also an independent peripheral, it can be used
   It is also quite complicated, and the length of this article is limited, so I will not go into details for now. I will write another blog next time.
     At this point, the structure of the LPC1769 CAN has been introduced. Next, we will explain what needs to be done to enable it to start sending and receiving CAN data correctly.
        CAN1/2 uses the following registers to set up:
        a) Power enable: In the PCONP register, set PCAN1/2.
        Note: On reset, CAN1/2 will be enabled (PCAN1/2=0).
        b) Clock enable: Select PCLK_CAN1/2 and PCLK_ACF for the acceptance filter in the PCLK_SEL0 register.
        Note: If the required CAN baud rate must be higher than 100 kbit/s (see Table 16.12), then IRC cannot be selected.
     as a clock source.
        c) Wake-up: The CAN controller is able to wake up the microcontroller from Power-down mode.
        d) Pins: The CAN1/2 pins are selected through the PINSEL register and the pin mode is selected through the PINMODE register.
        e) Interrupt: CAN interrupt is enabled through CAN1/2IER register. Interrupt is enabled by enabling
        This is achieved using the corresponding Interrupt Set Enable register.
        f) CAN controller initialization: set in the CANNOD register.

        The above is the CAN controller initialization process introduced in the data sheet. In plain words: "a)" CAN is a peripheral device of LPC1769. To make it work, you must first set PCONP. The various bits of this register determine the peripheral
            Whether the clock is turned on or off. If a peripheral is not in use, turn it off to save power.
       To use CAN, first turn on the CAN peripheral clock. "b)" Secondly, if the peripherals are to work properly, they all need a suitable clock frequency, which is determined by PCLK_SEL01.
            "c)" In order to further reduce the power consumption of the MCU, when there is no data transmission on the CAN network, there is no CAN interrupt processing, and the corresponding
       If the sleep bit is set to "1", the CAN peripheral will enter the sleep state. If a dominant bit appears on the CAN bus, the CAN peripheral will come out of the sleep state.
       At the same time, if the relevant bits have been configured and the entire MCU enters power-down or deep sleep mode, the CAN
       It can also wake up the MCU. "d)" Configure the CAN transmit and receive pins. Needless to say, tell the CAN controller which pin to use to transmit and receive CAN data. "e)" Configure various interrupt enable conditions for CAN. Here, the transmit/receive interrupt and error interrupt are enabled; and configure the NVIC internal
            CAN peripheral interrupt. "f)" Configure CAN related parameters, such as baud rate, etc.
        At this point, the CAN controller initialization part is completed, and the receiving and sending functions, as well as the interrupt function, are still needed to realize the CAN receiving and sending.
    , and error management.
        Of course, there is a lot to say about the baud rate parameter settings in the CAN controller initialization part. This article is limited in space and will not be described in detail next time.
    Let me start another blog to introduce it.
        CAN interrupt function: /*----------------- INTERRUPT SERVICE ROUTINES --------------------------*/
        /****************************************************** *********************//**
         * @brief CAN_IRQ Handler, control receive message operation
         * param[in] none
         * @return none
         *************************************************** ************************/
        void CAN_IRQHandler()
        {
            uint8_t IntStatus;
            uint32_t data1; /* get interrupt status
             * Note that: Interrupt register CANICR will be reset after read.
             * So function "CAN_IntGetStatus" should be call only one time */
            // The following function obtains the register data of CAN1ICR/CAN2ICR, which indicates the source of the interrupt
            IntStatus = CAN_IntGetStatus(LPC_CAN1);if((IntStatus>>0)&0x01) {// Receive interrupt }
            ... // The omitted content is to parse the interrupt information according to the interrupt source data of each bit of the register.
       // IntStatus = CAN_IntGetStatus(LPC_CAN2);
       // if(...) ... }
        
        CAN receiving function:
        This function is a library function provided by NXP. The download link of the library function is in the third part of this article. The content of this function is nothing more than
    During the interruption, check whether there is any information in the two receiving mailboxes. If there is, extract the information. /************************************************************************//**
     * @briefReceive message data
     * @param[in] CANx pointer to LPC_CAN_TypeDef, should be:
     * - LPC_CAN1: CAN1 peripheral
     * - LPC_CAN2: CAN2 peripheral
     * @param[in] CAN_Msg point to the CAN_MSG_Type Struct, it will contain received
     * message information such as: ID, DLC, RTR, ID Format
     * @return Status:
     * - SUCCESS: receive message successfully
     * - ERROR: receive message unsuccessfully
     *************************************************** *******************/
    Status CAN_ReceiveMsg (LPC_CAN_TypeDef *CANx, CAN_MSG_Type *CAN_Msg)
    {
        uint32_t data;
    
        CHECK_PARAM(PARAM_CANx(CANx));    
        //check status of Receive Buffer
        if((CANx->SR &0x00000001))
        { /* Receive message is available */
            /* Read frame informations */
            CAN_Msg->format = (uint8_t)(((CANx->RFS) & 0x80000000)>>31);
            CAN_Msg->type = (uint8_t)(((CANx->RFS) & 0x40000000)>>30);
            CAN_Msg->len = (uint8_t)(((CANx->RFS) & 0x000F0000)>>16);    
    
            /* Read CAN message identifier */
            CAN_Msg->id = CANx->RID;    
            /* Read the data if received message was DATA FRAME */
            if (CAN_Msg->type == DATA_FRAME)
            { /* Read first 4 data bytes */
                data = CANx->RDA; *((uint8_t *) &CAN_Msg->dataA[0])= data & 0x000000FF; *((uint8_t *) &CAN_Msg->dataA[1])= (data & 0x0000FF00)>>8; ; *((uint8_t *) &CAN_Msg->dataA[2])= (data & 0x00FF0000)>>16; *((uint8_t *) &CAN_Msg->dataA[3])= (data & 0xFF000000)>>24;    
                /* Read second 4 data bytes */
                data = CANx->RDB; *((uint8_t *) &CAN_Msg->dataB[0])= data & 0x000000FF; *((uint8_t *) &CAN_Msg->dataB[1])= (data & 0x0000FF00)>>8; *((uint8_t *) &CAN_Msg->dataB[2])= (data & 0x00FF0000)>>16; *((uint8_t *) &CAN_Msg->dataB[3])= (data & 0xFF000000)>>24;    
            /*release receive buffer*/
            CANx->CMR = 0x04;
            } else
            { /* Received Frame is a Remote Frame, not have data, we just receive
                 * message information only */
                CANx->CMR = 0x04; /*release receive buffer*/
                return SUCCESS;
            }
        } else
        { // no receive message available
            return ERROR;
        } return SUCCESS;
    }
        
        CAN sending function:
        This function is also a library function, that is, it queries the status of three sending mailboxes in turn. If the mailbox status is empty, the data is filled into the mailbox
    The sending flag is set, and then the CAN core module hardware automatically sends it. The sending priority can be configured in the register and will not be described in detail.
    I don't want to make the article too long, so I'll omit the code part 2/3 of the mailbox query. /************************************************************************//**
     * @brief Send message data
     * @param[in] CANx pointer to LPC_CAN_TypeDef, should be:
     * - LPC_CAN1: CAN1 peripheral
     * - LPC_CAN2: CAN2 peripheral
     * @param[in] CAN_Msg point to the CAN_MSG_Type Structure, it contains message
     * information such as: ID, DLC, RTR, ID Format
     * @return Status:
     * - SUCCESS: send message successfully
     * - ERROR: send message unsuccessfully
     *************************************************** *******************/
    Status CAN_SendMsg (LPC_CAN_TypeDef *CANx, CAN_MSG_Type *CAN_Msg)
    {
        uint32_t data;
        CHECK_PARAM(PARAM_CANx(CANx));
        CHECK_PARAM(PARAM_ID_FORMAT(CAN_Msg->format)); if(CAN_Msg->format==STD_ID_FORMAT)
        {
            CHECK_PARAM(PARAM_ID_11(CAN_Msg->id));
        } else
        {
            CHECK_PARAM(PARAM_ID_29(CAN_Msg->id));
        }
        CHECK_PARAM(PARAM_DLC(CAN_Msg->len));
        CHECK_PARAM(PARAM_FRAME_TYPE(CAN_Msg->type));    
        //Check status of Transmit Buffer 1
        if (CANx->SR & (1<<2))
        { /* Transmit Channel 1 is available */
            /* Write frame informations and frame data into its CANxTFI1,
             * CANxTID1, CANxTDA1, CANxTDB1 register */
            CANx->TFI1 &= ~0x000F0000;
            CANx->TFI1 |= (CAN_Msg->len)<<16; if(CAN_Msg->type == REMOTE_FRAME)
            {
                CANx->TFI1 |= (1<<30); //set bit RTR } else
            {
                CANx->TFI1 &= ~(1<<30);
            } if(CAN_Msg->format == EXT_ID_FORMAT)
            {
                CANx->TFI1 |= (0x80000000); //set bit FF } else
            {
                CANx->TFI1 &= ~(0x80000000);
            }    
            /* Write CAN ID*/
            CANx->TID1 = CAN_Msg->id;    
            /*Write first 4 data bytes*/
            data = (CAN_Msg->dataA[0])|(((CAN_Msg->dataA[1]))<<8)|
             ((CAN_Msg->dataA[2])<<16)|((CAN_Msg->dataA[3])<<24);
            CANx->TDA1 = data;    
            /*Write second 4 data bytes*/
            data = (CAN_Msg->dataB[0])|(((CAN_Msg->dataB[1]))<<8)|
            ((CAN_Msg->dataB[2])<<16)|((CAN_Msg->dataB[3])<<24);
            CANx->TDB1 = data;    
             /*Write transmission request*/
             // Note the value and set send mailbox 1 to inform the hardware that the information in mailbox 1 has been filled and can be sent.
             CANx->CMR = 0x21; return SUCCESS;
        } //check status of Transmit Buffer 2
        else if(CANx->SR & (1<<10))
        { /* Transmit Channel 2 is available */
            /* Write frame informations and frame data into its CANxTFI2,
             * CANxTID2, CANxTDA2, CANxTDB2 register */
             ... /*Write transmission request*/
             // Note the value and set send mailbox 2 to inform the hardware that the information in mailbox 2 has been filled and can be sent.
            CANx->CMR = 0x41; return SUCCESS;
        } //check status of Transmit Buffer 3
        else if (CANx->SR & (1<<18))
        { /* Transmit Channel 3 is available */
            /* Write frame informations and frame data into its CANxTFI3,
             * CANxTID3, CANxTDA3, CANxTDB3 register */
             ... /*Write transmission request*/
             // Note the value and set send mailbox 3 to inform the hardware that the information in mailbox 3 has been filled and can be sent.
            CANx->CMR = 0x81; return SUCCESS;
        } else
        { // All mailboxes are not idle and cannot be sent
            return ERROR;
        }
    }

    At this point, with the initialization part, CAN interrupt function, CAN sending and receiving functions, the sending and receiving of CAN data is realized.
    Filtering is based on baud rate and CAN bus error handling. I will write a blog post about this in detail next time.

3. Reference Documents
    LPC175x_6x CMSIS-Compliant Standard Peripheral Firmware Driver Library (Keil, IAR, GNU)
      https://www.lpcware.com/content/nxpfile/lpc175x6x-cmsis-compliant-standard-peripheral-firmware-driver-library-keil-iar-gnu So far, the record is complete.


Keywords:LPC1768  CAN controller Reference address:Overview of the CAN controller of LPC1768/1769 (with library function download address)

Previous article:LPC1769 CAN self-test mode
Next article:Cotex-M3 core LPC17xx series clock and its configuration method

Recommended ReadingLatest update time:2024-11-22 21:34

LPC1768 ADC for beginners
To use the ADC function, select PCADC in PCONP and select the corresponding pin as the ADC pin in PINSEL.    LPC1768 has 8 pins multiplexed as A/D input pins.    12-bit primary-secondary approximation analog-to-digital converter;     Measuring range: 0~VREFP (usually 3V; not exceeding VDDA); Registers to use:
[Microcontroller]
Latest Microcontroller Articles
Change More Related Popular Components

EEWorld
subscription
account

EEWorld
service
account

Automotive
development
circle

About Us Customer Service Contact Information Datasheet Sitemap LatestNews


Room 1530, 15th Floor, Building B, No.18 Zhongguancun Street, Haidian District, Beijing, Postal Code: 100190 China Telephone: 008610 8235 0740

Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号