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.

AM3359 DCAN RX Problem

Other Parts Discussed in Thread: TMDSICE3359, AM3359

Hello,

We are currently developing a driving simulator. In this purpose, we needed a device used as interface between all the components of the simulator.

We bought the TMDSICE3359 : http://www.ti.com/tool/tmdsice3359 as development board.

We communicate with a CANOpen device, we decided to use the Starterware library (AM335X_StarterWare_02_00_01_01) because of the proposed DCAN example. 

But unfortunately after trying, we couldn’t make the dcanTxRx example to work.

We asked on the forum and we were told by an employee that it might exist an issue with our board. 

Thus (because we needed to continue our work), we switched to the SYS/BIOS framework. In there, we found another implementation of the DCAN derived from the Starterware library.

Using that, we were able to do the biggest part of the work, the DCAN TX is working but impossible the make the DCAN RX work.

What we want : is a function « void RXdcan() » waiting to return the first received data frame read by the board.

What we have : is a function waiting for the receiving interrupt to read the data but there is no interrupt when we feed the board with data.

As we have the TXdcan working (because of the differential pair), we know that there is no hardware issue but only something wrong in our software.

We are not sure of how to configure the Receive Message Object and how to make it work

You will find the main piece of code below :

#include <stdio.h>
#include <types.h>
#include <unistd.h>

#include "appl_cnfg.h"

#include "osdrv_utils.h"
#include "osdrv_version.h"

#include "board.h"
#include "board_support.h"

#include "hw_types.h"
#include "interrupt.h"

// UART
#include "console_utils.h"

// DCAN
#include "dcan.h"

/******************************************************************************
**                       INTERNAL MACRO DEFINITIONS
******************************************************************************/

#define CAN_DATA_BYTES_MAX_SIZE           (8u)
#define CAN_NUM_OF_MSG_OBJS               (64u)

#define CAN_RX_MSG_ID                     (0u)
#define CAN_TX_MSG_ID                     (0u)

#define DCAN_ERROR_OCCURED                (0x8000u)
#define DCAN_NO_INT_PENDING               (0x00000000u)

#define DCAN_BIT_RATE                     (1000000u)
#define DCAN_IN_CLK                       (24000000u)
can_frame entry;

/******************************************************************************
**                     FUNCTION DEFINITIONS
******************************************************************************/

static void ConfigureDCAN(void){
    /* Enable the DCAN0 module clock */
    DCANModuleClkConfig();
    /* Perform the pinmux for DCAN0 */
    DCANPinMuxSetUp(0);
    /* Initialize the DCAN message RAM */
    DCANMsgRAMInit(0);
    /* Reset the DCAN module */
    DCANReset(SOC_DCAN_0_REGS);
    /* Enter the Initialization mode of CAN controller */
    DCANSetMode(SOC_DCAN_0_REGS, DCAN_MODE_INIT);
    /* Configure the bit timing values for CAN communication */
    CANSetBitTiming(SOC_DCAN_0_REGS, DCAN_IN_CLK, DCAN_BIT_RATE);
    /* Start the CAN transfer */
	DCANSetMode(SOC_DCAN_0_REGS, DCAN_MODE_NORMAL);
	/* Enable the error interrupts */
    DCANIntrEnable(SOC_DCAN_0_REGS, DCAN_INTR_MASK_ERROR);
    /* Enable the interrupt line 0 of DCAN module */
    DCANIntrLineEnable(SOC_DCAN_0_REGS, DCAN_INTR_LINE_NUM_0, TRUE);
}

static void RXDCAN(unsigned int rxID, uint32_t * rxdata, int dlc){

    entry.flag = DCAN_MSG_DIR_RX;
    entry.id = rxID;
    entry.dlc = dlc;

    CANMsgObjectConfig(SOC_DCAN_0_REGS, &entry);

    uint32_t msgNum;

    while(1){

    	msgNum = DCANIntrStatus(SOC_DCAN_0_REGS, DCAN_INTR_LINE_NUM_0);

		if((msgNum != DCAN_NO_INT_PENDING) && ((msgNum != DCAN_ERROR_OCCURED))) {

			/* Get the number of the message object which caused the interrupt */
			msgNum = DCANIntrStatus(SOC_DCAN_0_REGS, DCAN_INTR_LINE_NUM_0);
			CONSOLEUtilsPrintf("%d\n",msgNum);

			if((msgNum >= (CAN_NUM_OF_MSG_OBJS/2)) && (msgNum < CAN_NUM_OF_MSG_OBJS)){

				/* Read a received message from message RAM to interface register */
				CANReadMsgObjData(SOC_DCAN_0_REGS, msgNum, rxdata, DCAN_IF_REG_NUM_2);

				/* Clear the Interrupt pending status */
				CANClrIntPndStat(SOC_DCAN_0_REGS, msgNum, DCAN_IF_REG_NUM_2);
                /* Disable the receive interrupt of the message object */
                CANRxIntDisable(SOC_DCAN_0_REGS, msgNum, DCAN_IF_REG_NUM_2);
                /* Invalidate the receive message object */
                CANInValidateMsgObject(SOC_DCAN_0_REGS, msgNum, DCAN_IF_REG_NUM_2);

				CONSOLEUtilsPrintf("RX\n");

				break;
			}

			if(msgNum < (CAN_NUM_OF_MSG_OBJS/2)){

				/* Clear the Interrupt pending status */
				CANClrIntPndStat(SOC_DCAN_0_REGS, msgNum, DCAN_IF_REG_NUM_1);
                /* Disable the transmit interrupt of the message object */
                CANTxIntDisable(SOC_DCAN_0_REGS, msgNum, DCAN_IF_REG_NUM_1);
                /* Invalidate the receive message object */
                CANInValidateMsgObject(SOC_DCAN_0_REGS, msgNum, DCAN_IF_REG_NUM_1);

                CONSOLEUtilsPrintf("TX\n");
			}
			else {
				CONSOLEUtilsPrintf("ERROR\n");
			}
		}
	}
}

static void TXDCAN(unsigned int txID, uint32_t * txdata, int dlc){

    entry.flag = DCAN_MSG_DIR_TX;
    entry.id = txID;
    entry.dlc = dlc;
    entry.data = txdata;

    CANMsgObjectConfig(SOC_DCAN_0_REGS, &entry);
}

static void StartDRIVER(void){
	// NMT Start Remote Node
    uint32_t data1 = 0x2001;
    TXDCAN(0x000,&data1,2);

    // set the DRIVER to RUN
    uint32_t data2 = 0x000F;
    TXDCAN(0x220,&data2,2);

    // set the DRIVER to PROFILE TORQUE
    uint32_t data3[2] = {0x0060602F, 0x000004};
    TXDCAN(0x620,&data3,7);
}

static void WriteTorque(double trq){
	// INITIALIZATION TORQUE = 0;
	uint32_t data[2] = {0x0060712B, 0x000000};

	// set TORQUE to HEX data
	double trqpercent = trq/10.0*100;
	double temp = trqpercent*10;

	data[2] = 0;

	// Write TORQUE
	TXDCAN(0x620,&data,7);
}

void taskFxn(){

	int init = 0;
    char t_str[50];
    char theta_str[50];
    char torque_str[50];

    double theta,thetap,thetapp;
    double torque;

    /* Initialize the BOARD & LCD */
    BOARDInit(NULL);
    Board_pinMuxConfig(am335xIceV2Mux);
    board_init(BOARD_LCD_DISPLAY);
    Board_setLCDScroll(0);
    Board_clearLCDString();
    Board_setLCDString((uint8_t *) "TFE_HAPTIC", 0);
    Board_setLCDString((uint8_t *) "HAPTIC_ICE V1", 1);
    Board_setLCDScroll(0);

    /* Initialize the UART console */
    CONSOLEUtilsInit();
    CONSOLEUtilsSetType(CONSOLE_UTILS_TYPE_UART);
    CONSOLEUtilsPrintf("TI Industrial SDK Version - ");
    CONSOLEUtilsPrintf(IND_SDK_VERSION);
    CONSOLEUtilsPrintf("\n\rDevice name \t: ");
    CONSOLEUtilsPrintf(SOCGetSocFamilyName());
    CONSOLEUtilsPrintf("\n\rChip Revision \t: ");
    CONSOLEUtilsPrintf(Board_getChipRevision());
    sprintf(t_str, "%d MHz", Board_getArmClockRate());
    CONSOLEUtilsPrintf("\n\rARM Clock rate \t: ");
    CONSOLEUtilsPrintf(t_str);
    CONSOLEUtilsPrintf("\n\rHAPTIC_ICE SOFTWARE on ICE AM3359 V2 EVM BOARD\n");

    /* Configure DCAN to be usable */
    ConfigureDCAN();

    /* Send CAN FRAMES to initialize DRIVER */
    StartDRIVER();

    uint32_t testRX;
    RXDCAN(0x000, &testRX, 8);

    CONSOLEUtilsPrintf("%x\n",testRX);

    while(init != 1)
    	CONSOLEUtilsScanf("%d", &init);

    theta = 0.35;
    thetap = 1.42;
    thetapp = 97.68;

    usleep(10);

    while(init == 1){

    	// RECEPTION DES COORDONNES DU DRIVER

    	// CONVERSION ET ENVOI DES COORDONNEES
    	sprintf(theta_str, "%f %f %f \n", theta, thetap, thetapp);
    	CONSOLEUtilsPrintf("%s",theta_str);

    	// RECEPTION DU COUPLE
    	CONSOLEUtilsScanf("%s", &torque_str);
    	torque = atof(torque_str);
    	sprintf(t_str, "TORQUE: %.2f Nm", torque);

    	// AFFICHAGE DU COUPLE
    	Board_setLCDScroll(0);
        Board_clearLCDString();
        Board_setLCDString((uint8_t *)"HAPTIC_ICE V1", 0);
        Board_setLCDString((uint8_t *) t_str, 1);
        Board_setLCDScroll(0);

    	// ENVOI DU FEEDBACK AU DRIVER
        WriteTorque(1);

    }
}

int main(){

    Task_Handle task;
    Error_Block eb;

    SDKMMUInit(applMmuEntries);

    Error_init(&eb);
    task = Task_create(taskFxn, NULL, &eb);
    if (task == NULL){
        printf("Task_create() failed!\n");
        BIOS_exit(0);
    }

    BIOS_start();
    return(0);
}

Thank you for the help,

Nicola De Lellis

  • Hi,

    I will notify the RTOS team about this.
  • Nicola,

    There is a DCAN diagnostics example in the K2G RTOS package. K2G is a different device family compared to the AM3359, but the DCAN peripheral is the same. 

    Please take a look at that code and do a comparison with the configuration to see if that helps.

    http://software-dl.ti.com/processor-sdk-rtos/esd/K2G/latest/index_FDS.html The code is under:

    C:\ti\pdk_k2g_1_0_1\packages\ti\board\diag\dcan

    Lali

  • Hello Lalindra,

    After some research, I found that my error was coming from the missing initialization of the 32 receiving message object of my IF2 register.

    I checked the register and they weren’t configured, even after what I thought would do it.

    It wrote a piece of code looping on the 32 mailboxes (a bit like the function "buildRxPackets" proposed in your K2G package).

    All seems to work fine for the moment.

    Thank you,

    Nicola

  • Nicola,

    Thanks for the update and glad that you got it working.
    Could you please post your working code here so that others can also benefit? Would be really helpful. Thanks!

    Lali
  • Hello Lalindra,

    Here is the function I added to my previous code to make it work.

    void buildRxPackets(uint32_t baseAddr)
    {
    	uint32_t count;
    	can_frame entry;
    	uint32_t id_offset;
    
        id_offset = 32;
    
    	for(count = 1; count <= CAN_NUM_OF_MSG_OBJS/2; count++)
    	{
    		entry.id = count + id_offset;
    		entry.flag = DCAN_MSG_DIR_RX;
    
    		CANRxObjectConfig(baseAddr, &entry);
    	}
    }

    It's only use is to configure all the receiving mailboxes before using them.

    The exact location where I added it is here :

    static void ConfigureDCAN(void){
    
    	int index;
    
        /* Enable the DCAN0 module clock */
        DCANModuleClkConfig();
        /* Perform the pinmux for DCAN0 */
        DCANPinMuxSetUp(0);
        /* Initialize the DCAN message RAM */
        DCANMsgRAMInit(0);
        /* Reset the DCAN module */
        DCANReset(SOC_DCAN_0_REGS);
        /* Enter the Initialization mode of CAN controller */
        DCANSetMode(SOC_DCAN_0_REGS, DCAN_MODE_INIT);
    	/* Enable the write access to the DCAN configuration registers */
    	DCANConfigRegWriteAccessControl(SOC_DCAN_0_REGS, DCAN_CONF_REG_WR_ACCESS_ENABLE);
        /* Configure the bit timing values for CAN communication */
        CANSetBitTiming(SOC_DCAN_0_REGS, DCAN_IN_CLK, DCAN_BIT_RATE);
        /* Disable the write access to the DCAN configuration registers */
        DCANConfigRegWriteAccessControl(SOC_DCAN_0_REGS, DCAN_CONF_REG_WR_ACCESS_DISABLE);
        /* Invalidate all message objects in the message RAM */
    	for(index = 1; index <= CAN_NUM_OF_MSG_OBJS; index++){
    		CANInValidateMsgObject(SOC_DCAN_0_REGS, index, DCAN_IF_REG_NUM_2);
    	}
    	/* Initializing all the reveive message objects */
    	buildRxPackets(SOC_DCAN_0_REGS);
    	/* Start the CAN transfer */
    	DCANSetMode(SOC_DCAN_0_REGS, DCAN_MODE_NORMAL);
    	/* Enable the error interrupts */
        DCANIntrEnable(SOC_DCAN_0_REGS, DCAN_INTR_MASK_ERROR);
        /* Enable the interrupt line 0 of DCAN module */
        DCANIntrLineEnable(SOC_DCAN_0_REGS, DCAN_INTR_LINE_NUM_0, TRUE);
    }

    Nicola