이제 CAN 초기화 코드를 한번 분석해 보는 시간을 가져 보도록 하겠습니다.
참고로 CAN에 대해서 지금 글 연재를 하고 있습니다.
이 글을 읽으시는 분들은
아래 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 구현 및 동작 수행 2편 (CAN 측정 환경 및 장비 설명)
https://embeddedchallenge.tistory.com/451
CAN은 Controller Area Network의 약어입니다.
즉, Electric Control Unit(ECU)끼리
정보를 전달할때 사용하는 방식입니다.
당연히, ECU안에서 정보전달을 할때도 사용할수 있습니다.
하지만 ECU안에서는 보통 SPI, I2C통신방법을 사용하여 정보를 전달합니다.
이제 분석할 CAN 초기화 코드는
인피니언사에서 제공하는 예제코드이며
TC275에 포팅하여 적용된 소스입니다.
그리고 위의 CAN Controller라고 적혀있는
MCU안에 있는 CAN 주변기기를 동작시키기 위한
코드입니다.
그런데, 제가 개발하는 과정에서 아래 글에서
CAN Transceiver를 사용하기 위해서는
먼저 MCU 에서 Digital 출력을 주어야 한다고 이야기 하였습니다.
6) CAN 구현 및 동작 수행 1편 (TC275 MCU 예제코드 포팅) https://embeddedchallenge.tistory.com/450 |
따라서 먼저 MCU에서 P20.6을 Digital Output으로 설정하여
이것을 Low로 만들어 보도록 하겠습니다.
void Driver_Port_Init(void)
{
/*P00_5 Digital Output*/
IfxPort_setPinModeOutput(IfxPort_P00_5.port, IfxPort_P00_5.pinIndex, IfxPort_OutputMode_pushPull, IfxPort_OutputIdx_general);
IfxPort_setPinLow(IfxPort_P00_5.port, IfxPort_P00_5.pinIndex);
/*P20_6 Digital Output*/
IfxPort_setPinModeOutput(IfxPort_P20_6.port, IfxPort_P20_6.pinIndex, IfxPort_OutputMode_pushPull, IfxPort_OutputIdx_general);
IfxPort_setPinLow(IfxPort_P20_6.port, IfxPort_P20_6.pinIndex);
}
위의 코드는 MCU안에서 p20.6번 핀을
Digital Output으로 설정하고 Low로 출력해 주고 있는 것을 볼 수 있습니다.
이 핀은 CAN Transceiver의 Enable Pin으로 연결이 되어 있어서
이것을 Low로 내려주어야지 Transceiver가 정상 동작합니다.
물론 이것은 Transceiver에 따라 다릅니다 ㅎㅎ
이제 CAN Controller 초기화에 앞서서
잠시 TC27x안에 들어 있는 CAN Controller Spec에 대해 알아볼게요!
TC275 MCU안에는 CAN모듈이 1개 존재합니다.
그리고 이 모듈안에는 노드 4개가 존재하고 있다는 것을 알 수 있습니다.
노드가 4개 있다는 것은 CAN을 독립적으로 4개 사용할수 있다고 생각하시면 됩니다.
그리고 4개의 노드에서 256개의 오브젝트를 공유하여 사용할수 있도록 되어 있네요.
오브젝트가 무엇인가?
예를 들어 제가 ECU1에서 ECU2에게 메시지 2개를 보내고
1개를 수신 받으려고 합니다.
이때 사용되는 오브젝트는 3개입니다.
Tx 2개
Rx 1개
256개의 오브젝트가 있다는 것은
정말 이 MCU에서 많은 CAN Tx, Rx 메시지를 할당할수 있다는 것을 뜻합니다.
그리고 1Mpbs까지 지원되는 CAN Controller이네요!
CAN FD의 Data Baudrate는 5Mbps까지 속도 지원이 된다고 나와 있습니다.
CAN FD는 추후 다루어 보도록 하겠습니다.
이것은 CAN에서 조금더 많은양의 데이터를 넣어 보내기 위해 고안된 방법인데요
요즘 많이 사용하고 있는 방법입니다.
우선 저는 CAN FD를 사용하지 않고, High Speed CAN만을 이용하여
사용해 보도록 할것입니다!
이제 드디어 초기화 코드를 한번 확인해 보도록 할게요!
void Driver_Can_Init(void)
{
/* create module config */
IfxMultican_Can_Config canConfig;
IfxMultican_Can_initModuleConfig(&canConfig, &MODULE_CAN);
/* initialize module */
IfxMultican_Can_initModule(&g_MulticanBasic.drivers.can, &canConfig);
/* create CAN node config */
IfxMultican_Can_NodeConfig canNodeConfig;
IfxMultican_Can_Node_initConfig(&canNodeConfig, &g_MulticanBasic.drivers.can);
canNodeConfig.baudrate = 500000; /*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(&g_MulticanBasic.drivers.canSrcNode, &canNodeConfig);
}
/* Source Message object */
{
/* create message object config */
IfxMultican_Can_MsgObjConfig canMsgObjConfig;
IfxMultican_Can_MsgObj_initConfig(&canMsgObjConfig, &g_MulticanBasic.drivers.canSrcNode);
canMsgObjConfig.msgObjId = 3;
canMsgObjConfig.messageId = 0x251;
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(&g_MulticanBasic.drivers.canSrcMsgObj, &canMsgObjConfig);
}
}
인피니언의 MCU는 자유도가 높은 많고
복잡도도 다른 MCU보다 높습니다.
따라서 ILLD(Infienon Low Level Driver)를 사용하여
CAN Driver를 초기화해 주고 있는 것이 보입니다.
결국 저 API를 인피니언사에서 제공해주고 있고
IfxMultican_Can_MsgObj_init(&g_MulticanBasic.drivers.canSrcMsgObj, &canMsgObjConfig);
이 APi를 통해서 CAN Controller 레지스터에 값을 적어주게 됩니다.
그러면 우리는 canMsgObjConfig 구조체에
CAN을 초기화 하기 위한 파라미터를 잘 기입해 주면 됩니다.
물론, ILLD에 의존하지 않고
CAN Driver 레지스터에서 이루어지는 설계를 직접하실수 있어야합니다.
그런데 인피니언이 타 MCU보다 이렇게 직접설계를하기 좀 까다롭게 되어 있습니다.ㅎㅎ
참고만 해주세요.
우선 앞서 말씀드린것 처럼
구조체에 우리가 원하는 파라미터만 잘 설정해 주면 될것 같습니다.
canNodeConfig.baudrate = 500000;
500kbps로 설정해주고
canNodeConfig.rxPin = &IfxMultican_RXD0B_P20_7_IN;
canNodeConfig.txPin = &IfxMultican_TXD0_P20_8_OUT;
Rx,Tx 핀 설정을 해주고
canMsgObjConfig.msgObjId = 3;
canMsgObjConfig.messageId = 0x251;
canMsgObjConfig.acceptanceMask = 0x7FFFFFFFUL;
canMsgObjConfig.frame = IfxMultican_Frame_transmit;
canMsgObjConfig.control.messageLen = IfxMultican_DataLengthCode_8;
canMsgObjConfig.control.extendedFrame = FALSE;
canMsgObjConfig.control.matchingId = TRUE;
메시지 오브젝트를 3번을 사용하고
메시지의 ID는 0x251로 설정하고
이 오브젝트를 Tx로 사용할것이며
CAN Tx할때 Frame안에 DataSize는 8바이트로 할것이고
Extended ID가 아닌 Stardard ID를 사용할 것이다!
이렇게 설정이 되도록 되어 있습니다.
그리고 위에서 나오지는 않지만
Sampling 포인트를 설정하는 부분도 있습니다.
그러면 저 파라미터 설정에 맞게 아래 함수가 실행되며 레지스터에 필요한
값을 쓰게 됩니다.
IfxMultican_Can_MsgObj_init(&g_MulticanBasic.drivers.canSrcMsgObj, &canMsgObjConfig);
이제 위에 CAN을 초기화할때 설정되는 파라미터의 의미를 조금더 자세히 분석해 보도록 하겠습니다.
1. Sampling Point 와 Baud Rate 설정
위의 예제코드는 500Kpbs의 Baud Rate를 가지도록 설정이 되어 있습니다.이것은 하나의 비트의 주파수를 나타내고 있는것으로1/주파수 = 주기1/500000 = 0.000002따라서 하나의 비트를 표현하기 위해서 2us가 사용되고 있음을 알수 있습니다.아래 계측한 파형을 한번 볼까요?하나의 비트를 표현하는데 2us가 필요합니다.
다시 말씀드리지만 MCU는 전압을 이용하여 통신합니다.
2us마다 전압을 변경하여 하나의 CAN Frame을 만드는 것입니다.
그리고 하나의 프레임을 쏠때 보통 얼마의 시간이 걸리는지 한번 알아보도록 할게요!
위의 그림을 보면 하나의 프레임을 발사하는데 212us정도가 걸리네요!
그렇다면 1ms마다 CAN을 Tx할때 5개면 꽉차는 것입니다.
따라서 CAN Tx를 주기적으로 할때 보통 최소주기는 10ms주기로 Tx를 많이 발사하도록
CAN Matirx 설계를 합니다.
그리고 Sampling point가 무엇을 의미하는 정리해 보도록 하겠습니다.
Sampling Point를 80%로 설정했는데
이것은 2us안에 표현되는 전압을 디지털값으로 취득할때
사용되는 포인트 입니다.
지금 80%로 설정이 되었다는 것은 아래에서 빨강색 부분을 취득하였고
이것이 1을 포현하는 전압보다 높아서 아래와 같이 1로 표시가 된 것입니다.
다시말해 아래 High 상태가 된지 80%되는 시점에서
CAN Controller가 아날로그전압을 취득하여 이산화 하라는 뜻입니다.
샘플링 포인트는 나중에 조금더 레지스터 단위에서 다루면 좋을 것 같습니다.
이제 Object 초기화 설정에 대해서 알아보도록 하겠습니다.
2. 메시지 ID 설정
지금 0x251이라는 메시지가 계속 나가고 있습니다.
CAN Controller 에서 Tx를 하지만 다른 ECU에서 Ack를 내려주지 않기 때문에
계속 내보내고 있는 것입니다.
CAN 메시지를 전달할때는 ID를 넣어서 전달합니다.
소포를 보낼때 이름을 적어서 보낸다고 생각하시면 됩니다.
그래서 0x251이라고 이름붙인 메시지를 상대편에서 받고
아 0x251이 왔네!
라고 판단이 되면
그 메시지 안에 들어있는 데이터를 획득하면 되는 것입니다.
0x251은 제가 임의로 넣은 ID입니다.
3. Message Object 할당
canMsgObjConfig.msgObjId = 3;
메시지 오브젝트가 256개 있다고 했지요?
이중에 3번 오브젝트에 0x251을 날리도록
오브젝트를 설정한 것입니다.
따라서 이 오브젝트를 Tx로 사용할 것이기 때문에
IfxMultican_Frame_transmit
설정을 하였고
이 오브젝트에 담을 데이터크기는 8바이트로 설정할 것입니다.
canMsgObjConfig.frame = IfxMultican_Frame_transmit;
canMsgObjConfig.control.messageLen = IfxMultican_DataLengthCode_8;
canMsgObjConfig.control.extendedFrame = FALSE;
보이시나요?
CAN Frame안에 데이터 영역이 빨강박스로 존재하고 있는것을 알 수 있습니다.
그리고 그 크기가 8바이트 입니다.
그리고 우리는 extended frame을 사용하지 않고
standard Frame을 사용할 것입니다.
이유는 0x251로 아이디를 설정했기 때문입니다.
Extended frame은 나중에 CAN ID가 부족해서 추가로 ID를 늘리기 위한 방법으로
해당 프레임을 설정할 경우
CAN Frame이 조금 변형되어 나가게 됩니다. ㅎㅎ
마지막으로 아래 그림은 Object를 0으로 변경하고
ID를 0x100으로 변경하여 전송한 그림입니다.
해당 프로젝트 소스는 아래 네이버 카페에서 다운로드 가능하오니
참고하세요!
https://cafe.naver.com/binaryembedded/132
이제 Tx에대한 초기화 분석에 대해서 대략적인 내용을 알게 되었습니다.
이제 2개의 보드를 이용해서 메시지를 한번 주고 받아 보도록 하겠습니다.
'Embedded SW > Embedded SW Introduction' 카테고리의 다른 글
CAN 구현 및 동작 수행 5편 (CAN Rx 구현) (0) | 2022.09.14 |
---|---|
CAN 구현 및 동작 수행 4편 (ECU 2개를 이용한 Tx, Rx) (0) | 2022.09.14 |
CAN 구현 및 동작 수행 2편 (CAN 측정 환경 및 장비 설명) (0) | 2022.09.13 |
CAN 구현 및 동작 수행 1편 (TC275 MCU 예제코드 포팅) (1) | 2022.09.13 |
SPI를 설계할때 꼭 알아야할 핵심 사항 정리(TC275 MCU) (0) | 2022.09.12 |
댓글