사용 보드 : F429ZI
프로그램 : CubeIDE
Controller Area Network
2개 선(CAN_H, CAN_L) 으로 여러 대 장치와 통신 가능
안정적인 에러 처리
차동신호 -> GND 불필요, 외부 노이즈에 강함(noise tollerance)
(기존 GND 모터제어할 때 모터속도에 따라 전압 레벨이 불안정해짐 - 통제힘듬)
Twisted Pair Cable 권장 -> 장거리
CAN Transceiver 필요(전기적 레벨이 다름)
보드와 Tx-Tx, Rx-Rx 끼리 연결
양 끝에 종단 저항 120Ω을 달아줘야함 (통신선의 임피던스 일치)
비동기식 멀티 마스터 방식으로 통신 (동시에 모든 노드가 데이터 수신 가능)
데이터의 아이디(메세지 구분)가 있고 버스에 아이디 필터가 있음
Std ID : 11bit (CAN 2.0A)
Ext ID : 29bit (CAN 2.0B)
Filter_ID_Mask 모드
Filter_ID_List 모드
통신 속도(타임퀀텀) : 1 bit를 보내는데 걸리는 시간 (CAN 2.0B 최대 1Mbps)
선로의 길이가 길어지면 통신속도를 낮춰야함 (예- 500Kbps)
한 프레임 당 8 Byte까지 데이터 송신 가능 -> 인터럽트 CPU 부담 감소
DLC : Data Length Code 데이터의 길이를 표시
CRC : Cyclic Redundancy Check (순환 중복 검사) 오류 체크 기능
ACK : Acknowledge 응답
EOF : End Of Frame 통신 종료
Remote Frame : 데이터를 요청할 때 사용(ID : 내가 원하는 메세지의 아이디)
APB1 클럭/prescaler => 시간 -> 1 타임 퀀텀 [ Time Quantum(Quanta) ]
SYNC_SEG -> 1 타임 퀀텀
BIT SEGMENT 1 -> 1~16 타임 퀀텀
BIT SEGMENT 2 -> 1~8 타임 퀀텀
SAMPLE POINT는 전체 비트 타임의 75% 정도로 해줘야함(70~80%)
예) 500kbps -> 초당 500k bit -> 1bit 당 2us
APB1 = 45Mhz
Prescaler = 9
9/45Mhz = 0.2 us
1bit에 0.2us * 10개 = 2us, 10개의 타임 퀀텀
SYNC_SEG + BS1 + BS2 = 10
SAMPLE POINT => (SYNC_SEG + BS1)/10 = 0.75 (75%)
BS1 : 6 개 타임퀀텀 (2안 : 7개)
BS2 : 3 개 타임퀀텀 (2안 : 2개)
설정한 Filter ID와 일치하는 ID의 메세지만 수신
Filter Mask ID 와 Filter ID
Filter Mask ID 의 bit 1 이면 -> Filter ID 와 메세지 ID 반드시 일치
Filter Mask ID 의 bit 0 이면 -> 상관없이 다 받아들임
& 연산 안됨
Mask ID가 1인 부분의 Filter ID 값을 동일하게 가져온다.
Time Triggered Communication : 데이터 8 byte 중 7, 8번에 시간 정보를 추가
Automatic Bus-Off Management : 에러를 내는 장치 차단
수신 데이터 저장 FIFO 2개가 있음
RX0, RX1 Interrupt
CAN1 RX0 interrupts 사용 할 예정
Generate Code를 한다.
다음 코드 추가
CAN_FilterTypeDef canFilter1;
CAN_RxHeaderTypeDef canRxHeader;
CAN_TxHeaderTypeDef canTxHeader;
uint8_t can1Rx0Data[8];
uint32_t TxMailBox;
uint8_t can1Tx0Data[8];
canRxHeader :수신받은 데이터의 헤더 정보 저장
Transmit
canTxHeader 부분에는
ID
RTR(Remote Transmission Request)
IDE(IDentifier Extention)
DLC(Data Length Code) : 데이터 길이
정보가 들어있다.
RTR
1 이면 Remote Frame : 데이터 요청
0 이면 Data Frame : 데이터 송신
IDE
1 이면 29 bit Extended ID
0 이면 11 bit Standartd ID
Time Triggered Communication -> Disable 했기 때문에 TransmitGlobalTime는 사용 X
can.h
아래와 같이 매크로가 되어 있기 때문에 16 진법으로 작성 안해도 된다.
수신할 때는 Filter 를 설정하여 받을 데이터를 정한다.
Driver -> STM32F4xx_HAL_Driver -> Inc -> stm32f4xx_hal_can.h 에
CAN_FilterTypeDef 구조체가 있다.
can.c 나 can.h 에 CAN_FilterTypeDef 누르고 F3 하면 바로 들어가짐
FilterIdHigh
FilterIdLow
FilterMaskIdHigh
FilterMaskIdLow
FilterFIFOAssignment : FIFO channel 0, channel 1, ID 저장소
FilterBank : (FilterMaskId + FilterId) 의 개수
FilterMode : Mask Mode, List Mode
FilterScale : 16 bit, 32 bit
FilterActivation : 사용 유무
SlaveStartFilterBank : Dual CAN 때 사용
FilterScale 에 따라서
32 bit 는 IdHigh 16 bit + IdLow 16 bit, MaskIdHigh 16 bit + MaskIdLow 16 bit -> 1쌍(2개)
16 bit 는
IdHigh 16 bit 한개 + MaskIdHigh 16bit 한개,
IdLow 16 bit 한개 + MaskIdLow 16bit 한개 -> 2 쌍(4개)
하지만 Single CAN 에서는 High 나 Low 하나만 쓰기 때문에 2개 다 같게 설정해준다.
Rx 또한 매크로가 다 있어서 찾아서 사용하면 된다.
buttonFlag 는 버튼을 눌렀을 때 인터럽트 발생 시 상태
can1_rx0_flag 는 CAN 수신 인터럽트 CALLBACK 발생 시 상태
CAN 통신을 시작할 때는
HAL_CAN_Start(사용할 can 주소);
CAN 송신 부분이다.
버튼을 눌러 데이터를 송신한다.
canTxHeader 구조체에
StdId, RTR, IDE, DLE 정하고
보낼 데이터를 만들어서
TxMailBox 에 넣는다 (MailBox 는 주소(Id)가 적혀있는 택배상자 정도로 생각된다.)
HAL_CAN_GetMailboxesFreeLevel(&hcan1) 은 3개의 MailBox 중 비어있는 곳을 사용한다는 것이다.
HAL_CAN_AddTxMessage(설정한 CAN 채널, Tx헤더주소, 보낼 데이터, 사용할 TxMailBox)
를 통해서 메세지를 전송한다.
------------------------------------------------------------------------
can1_rx0_flag 는 수신인터럽트가 발생할 때 1로 변경됨
if문은 수신 인터럽트가 발생했을 때 데이터를 받는 부분이다.
16 bit라서 High, Low 중 하나만 쓰면 되어서 같은 값을 넣어줬다.
<<5 시프트 연산자는 StdID 가 11 bit 로 되어있는데
보내는 데이터 한줄은 16 bit 이기 때문이다.
FIFO (First In First Out) 은 자료구조 Queue 의 형태를 말한다.
FilterBank 는 FilterMastId + FilterId 조합을 몇 개를 사용할 것인지 말한다.
(single CAN 0~13, dual CAN 0~27) 로 1개를 사용할 경우 0을 입력한다.
HAL_CAN_ActiveNotification(설정한 CAN 채널, FIFO0에 처리할 수신 메세지가 있는지 있으면 인터럽트 발생) -> 수신 인터럽트
HAL_GPIO_EXTI_Callback()
-> 버튼 눌렀을 때 인터럽트
HAL_CAN_RxFifo0MsgPendingCallback()
-> 수신 인터럽트 발생 시 작업