Hi everyone,
I want to develop my CAN driver for the UT32M0R500 micrcontroller. I send a CAN frame on the principal bus. I should get the the send frame signal on the Tx pin.
However, when I tested it, it produced the the following result.
The green signal is the generated signal on the Tx pin.
I tried to modify my code and I tried to add a transciever to look at the CAN HIGH, but nothing has changed (the transciever return a 0 signal... It seems that it does not understand the Tx input)
So I decided to inspire my code from the example provided by CAES : it produces the same thing.
I directly tested the exemple provided by CAES : it produces the same thing.
Then, I wrote the simpliest test as possible that follows :
MAIN.C
#include "typesGeneral.h" #include "canRegisterTypes.h" #define C_CAN_MODE_RESET 0x01 #define C_CAN_ACCEPTANCE_CODE_RESET_VALUE 0x00 #define C_CAN_ACCEPTANCE_MASK_RESET_VALUE 0x00 #define C_CAN_COMMAND_START_TRANSMIT 0x01 #define C_CAN_SJW_SHIFT_LEFT (6) #define C_CAN_SAM_SHIFT_LEFT (7) #define C_CAN_TSEG2_SHIFT_LEFT (4) #define C_CAN_TXID_1_ID_SHIFT_RIGHT (3) #define C_CAN_TXID_2_ID_SHIFT_LEFT (5) #define C_CAN_SFF_ID_1_TX_SHIFT_RIGHT (3) #define C_CAN_SFF_ID_2_TX_SHIFT_LEFT (5) /* ------------------------------------------------------------------------- */ // Nominal CAN base /* ------------------------------------------------------------------------- */ volatile static t_canRegisters *s_canNominal = (t_canRegisters *) 0x40023000; typedef struct { // Bus timing 1 t_int8u syncJumpWidth : 2; t_int8u baudRatePreScalar : 6; // Bus timing 2 t_int8u sampleMode : 1; t_int8u timeSegment2 : 3; t_int8u timeSegment1 : 4; // Hardware Address t_int8u hardwareAddress; } t_canInitData; /* ------------------------------------------------------------------------- */ // MAIN /* ------------------------------------------------------------------------- */ int main() { volatile t_canRegisters *l_can; t_canInitData l_canInitData; /* Init of the timings */ l_canInitData.syncJumpWidth = 0; l_canInitData.baudRatePreScalar= 24; l_canInitData.sampleMode = 0; l_canInitData.timeSegment1 = 4; l_canInitData.timeSegment2 = 3; l_canInitData.hardwareAddress = 0xAA; /* Choose the nominal CAN*/ l_can = s_canNominal; /* Enter reset mode */ l_can->can.control = C_CAN_MODE_RESET; l_can->can.command = 0x00; /* Init acceptance masks */ l_can->can.acceptCode = C_CAN_ACCEPTANCE_CODE_RESET_VALUE; l_can->can.acceptMask = C_CAN_ACCEPTANCE_MASK_RESET_VALUE; /* Init of the timings */ l_can->can.busTiming_0 = (l_canInitData.syncJumpWidth<<C_CAN_SJW_SHIFT_LEFT) | (l_canInitData.baudRatePreScalar); l_can->can.busTiming_1 = (l_canInitData.sampleMode<<C_CAN_SAM_SHIFT_LEFT) | (l_canInitData.timeSegment2<<C_CAN_TSEG2_SHIFT_LEFT) |(l_canInitData.timeSegment1); // Set operating mode l_can->can.control &= (~C_CAN_MODE_RESET); /* Set ID, RTR and DLC in the register */ l_can->can.TX_ID_1 = 0x00; l_can->can.TX_ID_2 = 0x08; /* Change the data in the TX buffer */ l_can->can.TX_data[0] = 1; l_can->can.TX_data[1] = 2; l_can->can.TX_data[2] = 3; l_can->can.TX_data[3] = 4; l_can->can.TX_data[4] = 5; l_can->can.TX_data[5] = 6; l_can->can.TX_data[6] = 7; l_can->can.TX_data[7] = 8; while(1) { // Set operating mode l_can->can.control &= (~C_CAN_MODE_RESET); /* Start can transmission*/ l_can->can.command = C_CAN_COMMAND_START_TRANSMIT; } return(0); }
TYPESGENERAL.H
/** * @file typesGeneral.h * * @brief Native types and main constants redefinition * * @details This file redefines the CPU architecture native types and the main constants * (True / False / Null pointer) to be used in the whole project. * * @addtogroup generalities * @{ */ #ifndef INC_TYPES_GENERAL_H #define INC_TYPES_GENERAL_H /* ------------------------------------------------------------------------- */ // CONSTANTS DEFINITION /* ------------------------------------------------------------------------- */ /** * @brief Definition of the TRUE value */ #ifndef C_TRUE #define C_TRUE (1 == 1) #endif /** * @brief Definition of the FALSE value */ #ifndef C_FALSE #define C_FALSE (!C_TRUE) #endif /** * @brief Definition of the NULL-pointer value */ #ifndef C_NULL #define C_NULL ((void*) 0L) #endif /* ------------------------------------------------------------------------- */ // TYPES DEFINITION /* ------------------------------------------------------------------------- */ /** * @brief 8-bit signed integer */ typedef signed char t_int8; /** * @brief 8-bit unsigned integer */ typedef unsigned char t_int8u; /** * @brief 16-bit signed integer */ typedef signed short t_int16; /** * @brief 16-bit unsigned integer */ typedef unsigned short t_int16u; /** * @brief 32-bit signed integer */ typedef signed long t_int32; /** * @brief 32-bit unsigned integer */ typedef unsigned long t_int32u; /** * @brief 64-bit unsigned integer */ typedef unsigned long long t_int64u; /** * @brief Boolean type */ typedef unsigned short t_bool; #endif /* INC_TYPES_GENERAL_H */ /** @}*/
CANREGISTERTYPES.H
/** * @file canRegisterTypes.h * * @brief Define all the registers used by the CAN peripheral. * * @addtogroup can * @{ */ #ifndef INC_CAN_TYPES_DEF_H #define INC_CAN_TYPES_DEF_H /* ------------------------------------------------------------------------- */ // FILE INCLUSION /* ------------------------------------------------------------------------- */ #include "typesGeneral.h" /* ------------------------------------------------------------------------- */ // PRIVATE CONSTANTS DEFINITION /* ------------------------------------------------------------------------- */ #define C_CAN_BUF_SIZE 8 /* ------------------------------------------------------------------------- */ // TYPES DEFINITION /* ------------------------------------------------------------------------- */ /*------------------------ BASI-CAN -----------------------*/ typedef struct { t_int8u control; /*!< Offset: 0x00: Control Register (R/W) */ t_int8u command; /*!< 0x01: Command ( /W) */ t_int8u status; /*!< 0x02: Status (R/ ) */ t_int8u interrupt; /*!< 0x03: Interrupt (reset on read, except bit0) (R/ ) */ t_int8u acceptCode; /*!< 0x04: Acceptance Code: RESET MODE ONLY (R/W) */ t_int8u acceptMask; /*!< 0x05: Acceptance Mask: RESET MODE ONLY (R/W) */ t_int8u busTiming_0; /*!< 0x06: Bus Timing 0: RESET MODE ONLY (R/W) */ t_int8u busTiming_1; /*!< 0x07: Bus Timing 1: RESET MODE ONLY (R/W) */ t_int8u reserved_0; /*!< 0x08: reserved (R/ ) */ t_int8u reserved_1; /*!< 0x09: reserved (R/ ) */ t_int8u TX_ID_1; /*!< 0x0A: Transmit ID 1: OPERATE MODE ONLY (R/W) */ t_int8u TX_ID_2; /*!< 0x0B: Transmit ID 2: OPERATE MODE ONLY (R/W) */ t_int8u TX_data[C_CAN_BUF_SIZE]; /*!< 0x0C..0x13: Transmit Data Regs: OPERATE MODE ONLY (R/W) */ t_int8u RX_ID_1; /*!< 0x14: Receive ID 1 (R/ ) */ t_int8u RX_ID_2; /*!< 0x15: Receive ID 2 (R/ ) */ t_int8u RX_data[C_CAN_BUF_SIZE]; /*!< 0x16..0x1D: Receive Data Regs (R/ ) */ t_int8u reserved_2; /*!< 0x1E: reserved (R/ ) */ t_int8u clockDivider; /*!< 0x1F: Clock Divider (R/W) */ } t_basiCan; /*------------------------ PELI-CAN -----------------------*/ typedef struct { t_int8u frameInfo; /*!< Offset: 0x10: Frame Info Register: RX=R/O, TX=W/O (R/W) */ t_int8u ID_1; /*!< 0x11: Transmit ID 1: RX=R/O, TX=W/O (R/W) */ t_int8u ID_2; /*!< 0x12: Transmit ID 2: RX=R/O, TX=W/O (R/W) */ t_int8u data[C_CAN_BUF_SIZE]; /*!< 0x13..0x1A: Data: RX=R/O, TX=W/O (R/W) */ t_int8u nextFrameInfo; /*!< 0x1B: Next Frame Info: RECEIVE-PATH ONLY (R/ ) */ t_int8u nextId1; /*!< 0x1C: Next Frame ID1: RECEIVE-PATH ONLY (R/ ) */ } t_peliCanSff; typedef struct { t_int8u frameInfo; /*!< Offset: 0x10: Frame Info Register: RX=R/O, TX=W/O (R/W) */ t_int8u ID_1; /*!< 0x11: Transmit ID 1: RX=R/O, TX=W/O (R/W) */ t_int8u ID_2; /*!< 0x12: Transmit ID 2: RX=R/O, TX=W/O (R/W) */ t_int8u ID_3; /*!< 0x13: Transmit ID 3: RX=R/O, TX=W/O (R/W) */ t_int8u ID_4; /*!< 0x14: Transmit ID 4: RX=R/O, TX=W/O (R/W) */ t_int8u data[C_CAN_BUF_SIZE]; /*!< 0x15..0x1C: Data: RX=R/O, TX=W/O (R/W) */ } t_peliCanEff; typedef struct { t_int8u acceptCode_0; /*!< Offset: 0x10: Acceptance Code 0 Register (R/W) */ t_int8u acceptCode_1; /*!< 0x11: Acceptance Code 1 (R/W) */ t_int8u acceptCode_2; /*!< 0x12: Acceptance Code 2 (R/W) */ t_int8u acceptCode_3; /*!< 0x13: Acceptance Code 3 (R/W) */ t_int8u acceptMask_0; /*!< 0x14: Acceptance Mask 0 (R/W) */ t_int8u acceptMask_1; /*!< 0x15: Acceptance Mask 1 (R/W) */ t_int8u acceptMask_2; /*!< 0x16: Acceptance Mask 2 (R/W) */ t_int8u acceptMask_3; /*!< 0x17: Acceptance Mask 3 (R/W) */ t_int8u reserved_0; /*!< 0x18: reserved (R/ ) */ t_int8u reserved_1; /*!< 0x19: reserved (R/ ) */ t_int8u reserved_2; /*!< 0x1A: reserved (R/ ) */ t_int8u reserved_3; /*!< 0x1B: reserved (R/ ) */ t_int8u reserved_4; /*!< 0x1C: reserved (R/ ) */ } t_peliCanAccept; typedef struct { t_int8u mode; /*!< Offset: 0x00: Mode Register (R/W) */ t_int8u command; /*!< 0x01: Command ( /W) */ t_int8u status; /*!< 0x02: Status (R/ ) */ t_int8u interrupt; /*!< 0x03: Interrupt (reset on read, except bit0) (R/ ) */ t_int8u interruptEnable; /*!< 0x04: Interrupt Enable (R/W) */ t_int8u reserved_0; /*!< 0x05: reserved (R/ ) */ t_int8u busTiming_0; /*!< 0x06: Bus Timing 0 (see "** note" below) (R/W) */ t_int8u busTiming_1; /*!< 0x07: Bus Timing 1 ("** note") (R/W) */ t_int8u reserved_1; /*!< 0x08: reserved (R/ ) */ t_int8u reserved_2; /*!< 0x09: reserved (R/ ) */ t_int8u reserved_3; /*!< 0x0A: reserved (R/ ) */ t_int8u arbitrationLostCapture; /*!< 0x0B: Arbitration Lost Capture (R/ ) */ t_int8u errorCodeCapture; /*!< 0x0C: Error Code Capture (R/ ) */ t_int8u errorWarningLimit; /*!< 0x0D: Error Warning Limit ("** note") (R/W) */ t_int8u receiveErrorCounter; /*!< 0x0E: Receive Error Counter ("** note") (R/W) */ t_int8u transmitErrorCounter; /*!< 0x0F: Transmit Error Counter ("** note") (R/W) */ union { t_peliCanSff SFF_Frame; /*!< 0x10..0x1C: SFF Frame: OPERATE MODE ONLY */ t_peliCanEff EFF_Frame; /*!< 0x10..0x1C: EFF Frame: OPERATE MODE ONLY */ t_peliCanAccept AcceptCodeMask; /*!< 0x10..0x1C: Acceptance Code/Mask: RESET MODE ONLY */ }; t_int8u RXMessageCounter; /*!< 0x1D: Receive Message Counter (R/ ) */ t_int8u reserved_4; /*!< 0x1E: reserved (R/ ) */ t_int8u ClockDivider; /*!< 0x1F: Clock Divider (R/W) */ } t_peliCan; // ** note: writeable in RESET MODE only /*------------------------ BASIC-CAN vs PELI-CAN Determination ------------------------ */ // used to set/determine (a) "BasiCAN vs PeliCAN" and (b) "SFF vs EFF" (EFF available in PeliCAN only) typedef struct { t_int8u reset; /*!< 0x00: SET bit0 to reset (R/W) */ t_int8u reserved_0[15]; /*!< 0x01..0x0F: reserved (R/ ) */ t_int8u FrameInfo; /*!< 0x10: Frame Info Register (check bit7 for EFF) (R/W) */ t_int8u reserved_1[14]; /*!< 0x11..0x1E: reserved (R/ ) */ t_int8u canMode; /*!< 0x1F: Clock Divider (check bit7 for PeliCAN) (R/W) */ } t_genericCanAccess; /*------------------------ BASIC-CAN / PELI-CAN ------------------------ */ typedef struct { //union //{ t_basiCan can; //t_peliCan can; //t_genericCanAccess GenericCAN_Access; //}; } t_canRegisters; #endif /** @}*/
....... And the result whas exactly the same !!!
Do you see any clear error that could generate this strange behaviour ?
According to tou, what could be the origin of the problem ?
I thank you for your help by advance.
Best regards.
Rémi G
A CAN node cannot live on its own. At the very least, it expects to read its own signal back on CAN_RX, and at the corresponding point in the frame it requires an ACKnowledge signal from some other node to believe that it's doing everything correctly. For your situation, that means at the very least you have to enable enough of your transceiver that it echoes back to the RX line. Then you need some other node for your node to talk to.
Thank you, I didn't know about that ! I connected the Tx and the Rx together and it works !