이제 두개의 ECU를 이용하여 Tx, Rx를 한번 해보도록 하겠습니다.
참고로 이글은 CAN 관련하여 연재하여 글을 쓰고 있습니다.
아래 글들을 미리 읽고 오시면 좋을 것 같습니다.
1) CAN이란 무엇인가?
https://embeddedchallenge.tistory.com/57
2) CAN의 CAN Controller/Transceiver 전압 레벨 (High Speed CAN)
https://embeddedchallenge.tistory.com/59
3) CAN 정보전달 방식
https://embeddedchallenge.tistory.com/60
4) CAN Frame 분석
https://embeddedchallenge.tistory.com/61
5) CAN Arbitration
https://embeddedchallenge.tistory.com/62
6) CAN 구현 및 동작 수행 1편 (TC275 MCU 예제코드 포팅)
https://embeddedchallenge.tistory.com/450
7) CAN 구현 및 동작 수행 3편 (CAN 초기화 코드 분석)
https://embeddedchallenge.tistory.com/452
그러면 이제 다시 시작해 보도록 하겠습니다.
아래 글에서 만든 CAN 초기화 코드를 조금 수정해 보도록 하겠습니다.
7) CAN 구현 및 동작 수행 3편 (CAN 초기화 코드 분석) https://embeddedchallenge.tistory.com/452 |
불필요한 구조체는 제거하였고
Object에 값을 쉽게 넣을 수 있도록
전역변수를 배열로 변경하였습니다.
또한 Tx와 Rx를 구분하여 코드를 만들었습니다.
/***********************************************************************/
/*Define*/
/***********************************************************************/
#define ECU1_TX_OBJ_NUM 10u
#define ECU1_RX_OBJ_NUM 10u
/***********************************************************************/
/*Typedef*/
/***********************************************************************/
typedef struct
{
IfxMultican_Can CanEcu1;
IfxMultican_Can_Node CanEcu1Node;
IfxMultican_Can_MsgObj CanEcu1MsgTxObj[ECU1_TX_OBJ_NUM];
IfxMultican_Can_MsgObj CanEcu1MsgRxObj[ECU1_RX_OBJ_NUM];
} Ecu1Can;
또한 초기화 코드를 아래와 같이 수정하였습니다.
void Driver_Can_Init(void)
{
/* create module config */
IfxMultican_Can_Config canConfig;
IfxMultican_Can_initModuleConfig(&canConfig, &MODULE_CAN);
/* initialize module */
IfxMultican_Can_initModule(&stEcu1Can.CanEcu1, &canConfig);
/* create CAN node config */
IfxMultican_Can_NodeConfig canNodeConfig;
IfxMultican_Can_Node_initConfig(&canNodeConfig, &stEcu1Can.CanEcu1);
canNodeConfig.baudrate = 500000UL; /*500kbps*/
canNodeConfig.nodeId = (IfxMultican_NodeId)((int)IfxMultican_NodeId_0);
canNodeConfig.rxPin = &IfxMultican_RXD0B_P20_7_IN;
canNodeConfig.rxPinMode = IfxPort_InputMode_pullUp;
canNodeConfig.txPin = &IfxMultican_TXD0_P20_8_OUT;
canNodeConfig.txPinMode = IfxPort_OutputMode_pushPull;
IfxMultican_Can_Node_init(&stEcu1Can.CanEcu1Node, &canNodeConfig);
/* create message object config */
IfxMultican_Can_MsgObjConfig canMsgObjConfig;
IfxMultican_Can_MsgObj_initConfig(&canMsgObjConfig, &stEcu1Can.CanEcu1Node);
canMsgObjConfig.msgObjId = 0;
canMsgObjConfig.messageId = 0x100;
canMsgObjConfig.acceptanceMask = 0x7FFFFFFFUL;
canMsgObjConfig.frame = IfxMultican_Frame_transmit;
canMsgObjConfig.control.messageLen = IfxMultican_DataLengthCode_8;
canMsgObjConfig.control.extendedFrame = FALSE;
canMsgObjConfig.control.matchingId = TRUE;
/* initialize message object */
IfxMultican_Can_MsgObj_init(&stEcu1Can.CanEcu1MsgTxObj[0], &canMsgObjConfig);
}
뭐 크게 변경한것은 아니고요
변수이름만 조금 바뀌었네요 ㅎㅎ
또한 오브젝트를 설정하는 부분을 나누었는데요
Create message object config 라는 부분을 함수로 만들어서
Tx와 Rx 등록이 쉽게 이루어질수 있도록 코드 변경을 해보겠습니다.
void Driver_Can_Init(void)
{
/* create module config */
IfxMultican_Can_Config canConfig;
IfxMultican_Can_initModuleConfig(&canConfig, &MODULE_CAN);
/* initialize module */
IfxMultican_Can_initModule(&stEcu1Can.CanEcu1, &canConfig);
/* create CAN node config */
IfxMultican_Can_NodeConfig canNodeConfig;
IfxMultican_Can_Node_initConfig(&canNodeConfig, &stEcu1Can.CanEcu1);
canNodeConfig.baudrate = 500000UL; /*500kbps*/
canNodeConfig.nodeId = (IfxMultican_NodeId)((int)IfxMultican_NodeId_0);
canNodeConfig.rxPin = &IfxMultican_RXD0B_P20_7_IN;
canNodeConfig.rxPinMode = IfxPort_InputMode_pullUp;
canNodeConfig.txPin = &IfxMultican_TXD0_P20_8_OUT;
canNodeConfig.txPinMode = IfxPort_OutputMode_pushPull;
IfxMultican_Can_Node_init(&stEcu1Can.CanEcu1Node, &canNodeConfig);
/*Object Enrollment*/
Driver_Can_EnrollObject(0u, 0x100, IfxMultican_Frame_transmit, IfxMultican_DataLengthCode_8, FALSE, &stEcu1Can.CanEcu1MsgTxObj[0]);
Driver_Can_EnrollObject(1u, 0x101, IfxMultican_Frame_transmit, IfxMultican_DataLengthCode_8, FALSE, &stEcu1Can.CanEcu1MsgTxObj[1]);
Driver_Can_EnrollObject(2u, 0x102, IfxMultican_Frame_transmit, IfxMultican_DataLengthCode_8, FALSE, &stEcu1Can.CanEcu1MsgTxObj[2]);
}
static void Driver_Can_EnrollObject(int32_t msgObjId, uint32_t msgId, uint8_t frameType, uint8_t msgDlc, uint32_t extendedFrame, IfxMultican_Can_MsgObj* pArrObjNum)
{
/* create message object config */
IfxMultican_Can_MsgObjConfig canMsgObjConfig;
IfxMultican_Can_MsgObj_initConfig(&canMsgObjConfig, &stEcu1Can.CanEcu1Node);
canMsgObjConfig.msgObjId = msgObjId;
canMsgObjConfig.messageId = msgId;
canMsgObjConfig.frame = frameType;
canMsgObjConfig.control.messageLen = msgDlc;
canMsgObjConfig.control.extendedFrame = extendedFrame;
canMsgObjConfig.acceptanceMask = 0x7FFFFFFFUL;
canMsgObjConfig.control.matchingId = TRUE;
/* initialize message object */
IfxMultican_Can_MsgObj_init(pArrObjNum, &canMsgObjConfig);
}
이렇게 등록을 하면 Tx와 Rx 등록이 편하게 등록할수가 있습니다.
코드도 조금더 깨끗해 지고요.
지금 저는 3개의 Tx 오브젝트를 할당하였습니다.
이제 물리적으로 TC275보드 2개를 이용하여 CAN을 연결하고
ECU2에서 0x200 ID로 10ms마다 CAN을 Tx해보도록 하겠습니다.
그리고 계측 포인트는 아래 그림에서 빨강색 박스를 친 부분을 계측해 보도록 하겠습니다.
ECU2은 0x200메세지를 ECU1에게 전달해 주고
저는 지금 ECU1의 빨강 박스의 부분을 계측하고 있는 것입니다.
지금 ECU1의 Tx라인에서 내려간것이 보이시나요?
ECU1은 지금 Rx항목으로 0x200 ID를 등록하지 않았습니다.
하지만 ECU1은 정상적인 CAN Rx를 수신하였기 때문에
자동적으로 Ack부분을 Low로 내려주고 있는것을 볼 수 있습니다.
만일 아무도 ECU1을 CAN Node에서 제거하면
아무도 Ack를 내려줄수 있는 ECU가 없기 때문에
ECU2는 10ms 간격보다 더 훨씬빠르게
약 50us 안되서 계속 동일한 메시지를 Tx합니다.
그러면 ECU1에서 자동적으로 Ack를 내려주기는 하였지만
아직 0x200의 ID가 왔을때
이 메세지의 데이터 정보를 획득하도록 설정하지는 않았기 때문에
데이터는 그냥 흘려버립니다.
이제, 미리 오브젝트 Rx설정을 하여
0x200메시지가 왔을때 이 데이터를 가지고 올수 있도록
Rx 설정을 한번 해보도록 하겠습니다.
'Embedded SW > Embedded SW Introduction' 카테고리의 다른 글
CAN 구현 및 동작 수행 6편 (계측된 CAN Frame을 상세 분석) (0) | 2022.09.14 |
---|---|
CAN 구현 및 동작 수행 5편 (CAN Rx 구현) (0) | 2022.09.14 |
CAN 구현 및 동작 수행 3편 (CAN 초기화 코드 분석) (0) | 2022.09.14 |
CAN 구현 및 동작 수행 2편 (CAN 측정 환경 및 장비 설명) (0) | 2022.09.13 |
CAN 구현 및 동작 수행 1편 (TC275 MCU 예제코드 포팅) (1) | 2022.09.13 |
댓글