This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

EK-TM4C123GXL: Arm-based microcontrollers forum

Part Number: EK-TM4C123GXL

Hey guys I am currently working on connecting EK-TM4C123GXL and ESP32 devkit v1 through CAN communication. However, my ESP32 could not receive any data after uploading the exmaple CAN_mirror code provided by Arduino. I am currently using MCP2562 as my CAN transceivers. 

Is the communication between these two boards through CAN possible?

Please help me out. Thanks. 

  • Hello Sheng,

    What CAN protocol is being used? CAN 2.0 A/B? Or CAN FD?

    If the protocols are supported on TM4C then it should work with right configuration.

    Also what is the code running on the EK-TM4C123GXL?

    Best Regards,

    Ralph Jacobi

  • Hello Ralph,
    The protocol being used by the ESP32 microcontroller is CAN 2.0. 

    Currently I am using this configuration to connect my ESP32 to TM4C123GXL.

    The code I am currently using sends data packaged in CAN frame.

    Thanks.

  • Hello Sheng,

    From what I see in the MCP2562 datasheet the VDD input is 5V but the CAN lines are driving around ~2.5-3.3V right? Just want to verify that.

    I would need to see your code to comment further as the hardware & protocol used seems fine - have you looked at our app note which provides some CAN examples too?

    This is the app note https://www.ti.com/lit/pdf/spna244 and the BoosterPack used has the MCP2551 so I would expect the code there should work cleanly with it on the TM4C side as we already tested that.

    Best Regards,

    Ralph Jacobi

  • Hello Ralph,  

    The code for both Tivaware and ESP32 are attach below for your reference.

    //For Tivaware

    #include <stdlib.h>
    #include <stdint.h>
    #include <stdbool.h>
    #include "inc/hw_can.h"
    #include "inc/hw_ints.h"
    #include "inc/hw_memmap.h"
    #include "inc/hw_nvic.h"
    #include "inc/hw_types.h"
    #include "driverlib/can.h"
    #include "driverlib/debug.h"
    #include "driverlib/fpu.h"
    #include "driverlib/gpio.h"
    #include "driverlib/interrupt.h"
    #include "driverlib/pin_map.h"
    #include "driverlib/rom.h"
    #include "driverlib/sysctl.h"
    #include "driverlib/systick.h"
    #include "driverlib/uart.h"
    #include "utils/uartstdio.h"

    /* These header files define the messages that will be sent on the CAN bus */
    #include "CANMsg.h"

    #ifdef DEBUG
    void
    __error__(char *pcFilename, uint32_t ui32Line)
    {
    }
    #endif


    /* A counter that keeps track of the number of times the RX interrupt has
    * occurred, which should match the number of TX messages that were sent. */
    volatile uint32_t g_ui32MsgCount = 0;

    /* A flag to indicate that some transmission error occurred. */
    volatile bool g_bErrFlag = 0;

    /* Timer counter (in 1/10s) */
    volatile int32_t g_timeds;


    /* Delay for x milliseconds */
    void Delay(uint32_t ui32mSeconds)
    {
    SysCtlDelay(ui32mSeconds*16000 / 3);
    }

    /* This function is the interrupt handler for the CAN peripheral. It checks
    * for the cause of the interrupt, and maintains a count of all messages that
    * have been received. */
    void CANIntHandler(void) {
    uint32_t ui32Status;

    /* Read the CAN interrupt status to find the cause of the interrupt */
    ui32Status = CANIntStatus(CAN0_BASE, CAN_INT_STS_CAUSE);

    /* If the cause is a controller status interrupt, then get the status */
    if(ui32Status == CAN_INT_INTID_STATUS) {
    /* Read the controller status. */
    ui32Status = CANStatusGet(CAN0_BASE, CAN_STS_CONTROL);

    /* Set a flag to indicate some errors may have occurred. */
    g_bErrFlag = 1;
    }

    /* Check if the cause is message object 1, which what we are using for receiving messages. */
    else if(ui32Status == 1) {
    /* Getting to this point means that the RX interrupt occurred on
    * message object 1, and the message reception is complete. Clear the
    * message object interrupt. */
    CANIntClear(CAN0_BASE, 1);

    /* Increment a counter to keep track of how many messages have been received. */
    g_ui32MsgCount++;

    /* Since a message was received, clear any error flags. */
    g_bErrFlag = 0;
    }
    }


    /* Configure the UART and its pins. This must be called before UARTprintf(). */
    void ConfigureUART(void) {
    /* Enable the GPIO Peripheral used by the UART. */
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);

    /* Enable UART0 */
    SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);

    /* Configure GPIO Pins for UART mode. */
    GPIOPinConfigure(GPIO_PA0_U0RX);
    GPIOPinConfigure(GPIO_PA1_U0TX);
    GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);

    /* Use the internal 16MHz oscillator as the UART clock source. */
    UARTClockSourceSet(UART0_BASE, UART_CLOCK_PIOSC);

    /* Initialize the UART for console I/O.
    * NOTE: The baud rate is 115200 - this must be same in Putty etc */
    UARTStdioConfig(0, 115200, 16000000);
    }


    void ConfigureCAN(void) {
    /* For this example CAN0 is used with RX and TX pins on pins B4 and B5.
    * GPIO port B needs to be enabled so these pins can be used. */
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);

    /* Enable these pins as CAN pins */
    GPIOPinConfigure(GPIO_PB4_CAN0RX);
    GPIOPinConfigure(GPIO_PB5_CAN0TX);

    /* Configure these pins as CAN pins */
    GPIOPinTypeCAN(GPIO_PORTB_BASE, GPIO_PIN_4 | GPIO_PIN_5);

    /* Enable the CAN peripheral */
    SysCtlPeripheralEnable(SYSCTL_PERIPH_CAN0);

    // Initialise the CAN controller
    CANInit(CAN0_BASE);

    /* Set CAN clock to 500 kHz */
    CANBitRateSet(CAN0_BASE, SysCtlClockGet(), 500000);

    /* Enable interrupts on the CAN peripheral. */
    CANIntEnable(CAN0_BASE, CAN_INT_MASTER | CAN_INT_ERROR | CAN_INT_STATUS);

    /* Enable the CAN interrupt on the processor (NVIC). */
    IntEnable(INT_CAN0);

    /* Enable the CAN for operation. */
    CANEnable(CAN0_BASE);
    }


    /* Sends a CANMsg using the microcontroller's CANperipheral */
    void SendCANMsg( CANMsg *msg ) {
    tCANMsgObject sCANMessage;

    /* Fill CAN message object with message */
    sCANMessage.ui32MsgID = msg->ID;
    sCANMessage.ui32MsgIDMask = 0;
    sCANMessage.ui32Flags = MSG_OBJ_TX_INT_ENABLE;
    sCANMessage.ui32MsgLen = 8;
    sCANMessage.pui8MsgData = msg->payload;

    /* Send message */
    //UARTprintf("%d",sCANMessage);
    CANMessageSet( CAN0_BASE, 1, &sCANMessage, MSG_OBJ_TYPE_TX );
    }


    void SysTickHandler(void) {
    g_timeds++;
    }


    int main(void) {
    CANMsg msg;

    /* Set the clocking to run directly from the external crystal/oscillator. */
    SysCtlClockSet(SYSCTL_SYSDIV_1 | SYSCTL_USE_OSC | SYSCTL_OSC_MAIN |
    SYSCTL_XTAL_16MHZ);

    /* Initialize the UART. */
    ConfigureUART();

    /* Initialize the CAN message handler. */
    ConfigureCAN();

    /* Start a timers that counts in 0.1s intervals */
    SysTickPeriodSet(SysCtlClockGet() / 10);

    IntMasterEnable();
    SysTickIntEnable();
    SysTickEnable();

    /* You'll need a terminal listening to the relevant COM port to see this text */
    UARTprintf("Beginning CAN packet transmission...\n");

    while(1) {
    /* Generate a send some CAN messages */
    GenerateMPPT1OutputPowerMessage2( &msg, 12, 3 );
    SendCANMsg( &msg );
    Delay( 100 );
    GenerateMPPT1OutputPowerMessage( &msg, 115, 4 );

    SendCANMsg( &msg );
    Delay( 100 );

    /* You could add others here ... */
    }

    //return(0);
    }

    //Esp32 code

    #include <Arduino.h>
    #include <ESP32CAN.h>
    #include <CAN_config.h>

    CAN_device_t CAN_cfg; // CAN Config
    const int rx_queue_size = 10; // Receive Queue size

    void setup() {
    Serial.begin(115200);
    Serial.println("Mirror Demo - ESP32-Arduino-CAN");
    CAN_cfg.speed = CAN_SPEED_500KBPS;
    //CAN_cfg.clock = 16000000;
    CAN_cfg.tx_pin_id = GPIO_NUM_5;
    CAN_cfg.rx_pin_id = GPIO_NUM_4;
    CAN_cfg.rx_queue = xQueueCreate(rx_queue_size, sizeof(CAN_frame_t));

    // Init CAN Module
    ESP32Can.CANInit();
    }

    void loop() {
    CAN_frame_t rx_frame;
    //receive next CAN frame from queue
    Serial.printf("0x%08X",rx_frame.MsgID);
    if (xQueueReceive(CAN_cfg.rx_queue, &rx_frame, 3 * portTICK_PERIOD_MS) == pdTRUE) {

    if (rx_frame.FIR.B.FF == CAN_frame_std) {
    printf("New standard frame");
    }
    else {
    printf("New extended frame");
    }

    if (rx_frame.FIR.B.RTR == CAN_RTR) {
    printf(" RTR from 0x%08X, DLC %d\r\n", rx_frame.MsgID, rx_frame.FIR.B.DLC);
    }
    else {
    printf(" from 0x%08X, DLC %d, Data ", rx_frame.MsgID, rx_frame.FIR.B.DLC);
    for (int i = 0; i < rx_frame.FIR.B.DLC; i++) {

    printf("0x%02X ", rx_frame.data.u8[i]);

    }
    printf("\n");
    }

    //respond to sender
    ESP32Can.CANWriteFrame(&rx_frame);
    }

    }

    I have tried with two Tivaware boards and they were able to communicate with each other. After I swapped the receiver side with ESP32 it does not work. I will look into the document you sent to me.

    Thanks!

    Regards,

    Choo

  • Hello Choo,

    Thanks! I haven't had a chance to review this yet but I should be able to tomorrow or otherwise defer to my colleague.

    Best Regards,

    Ralph Jacobi

  • Hello Choo,

    I have tried with two Tivaware boards and they were able to communicate with each other. After I swapped the receiver side with ESP32 it does not work. I will look into the document you sent to me.

    I see, so that would indicate that at least for TM4C to TM4C the configuration is correct. I wouldn't expect there to need to be a different configuration to send a data packet to the ESP32. The Baud Rate is one area that I could think of but that seems to be set fine.

    Have you tried to monitor the signals on the bus and compare what is successful for TM4C to TM4C vs what isn't working for TM4C to ESP32? I feel like that would give us the most data here because if it works TM4C to TM4C than either the signal will be different between that and TM4C to ESP32 which would give an indicator of the root cause or the signals look the same and it would confirm the ESP32 isn't receiving the packet correctly.

    Code wise, I reviewed your implementation but nothing stood out to me as an issue which would make sense given the TM4C to TM4C test was successful.

    Best Regards,

    Ralph Jacobi