/* * Can.h * * Created on: 01 июня 2015 г. * Author: esaulenko */ #ifndef DRIVERS_CAN_CAN_H_ #define DRIVERS_CAN_CAN_H_ #include #include "CommonTypes.h" #ifndef CAN_FIRMWARE #include "SysTimer.h" #include "Buffer.h" #include "scmRTOS.h" #endif struct TCanPkt { uint32_t id; uint8_t data[8]; uint8_t data_len; TCanPkt() { } TCanPkt (uint32_t pkt_id): id(pkt_id) { } // принимает строку, заполняет данные пакета. Неуказанные данные заполняются нулями template inline void SetData (const char (&data_str)[N]) { int data_size = (N <= 8) ? (N - 1) : 8; for (int i = 0; i < data_size; i++) data[i] = data_str[i]; for (int i = data_size; i < 8; i++) data[i] = 0x00; } inline void SetData (uint8_t A) { data_len = 1; data[0] = A; data[1] = 0; data[2] = 0; data[3] = 0; data[4] = 0; data[5] = 0; data[6] = 0; data[7] = 0; } inline void SetData (uint8_t A, uint8_t B) { data_len = 2; data[0] = A; data[1] = B; data[2] = 0; data[3] = 0; data[4] = 0; data[5] = 0; data[6] = 0; data[7] = 0; } inline void SetData (uint8_t A, uint8_t B, uint8_t C) { data_len = 3; data[0] = A; data[1] = B; data[2] = C; data[3] = 0; data[4] = 0; data[5] = 0; data[6] = 0; data[7] = 0; } inline void SetData (uint8_t A, uint8_t B, uint8_t C, uint8_t D) { data_len = 4; data[0] = A; data[1] = B; data[2] = C; data[3] = D; data[4] = 0; data[5] = 0; data[6] = 0; data[7] = 0; } inline void SetData (uint8_t A, uint8_t B, uint8_t C, uint8_t D, uint8_t E) { data_len = 5; data[0] = A; data[1] = B; data[2] = C; data[3] = D; data[4] = E; data[5] = 0; data[6] = 0; data[7] = 0; } inline void SetData (uint8_t A, uint8_t B, uint8_t C, uint8_t D, uint8_t E, uint8_t F) { data_len = 6; data[0] = A; data[1] = B; data[2] = C; data[3] = D; data[4] = E; data[5] = F; data[6] = 0; data[7] = 0; } inline void SetData (uint8_t A, uint8_t B, uint8_t C, uint8_t D, uint8_t E, uint8_t F, uint8_t G) { data_len = 7; data[0] = A; data[1] = B; data[2] = C; data[3] = D; data[4] = E; data[5] = F; data[6] = G; data[7] = 0; } inline void SetData (uint8_t A, uint8_t B, uint8_t C, uint8_t D, uint8_t E, uint8_t F, uint8_t G, uint8_t H) { data_len = 8; data[0] = A; data[1] = B; data[2] = C; data[3] = D; data[4] = E; data[5] = F; data[6] = G; data[7] = H; } }; struct TCanInit { uint32_t baudrate; // "сырое" значение регистра BTR, см. TCanBaudrate uint8_t mode; // в наст. момент не используется. TODO Должно быть RO / RW uint64_t filters[27]; // массив со значениями для пар регистров; заполняется Filters::xxx }; class CCan { public: enum TCanState : uint8_t { CanActive, CanRxOnly, // внешний драйвер выключен CanSleep, // внешний драйвер выключен, модуль в спящем режиме CanInitError = 0xFE, CanBusOff = 0xFF, }; /* TIME QUANTUM FREQUENCY: Ftq = Ntq * Fbaud where 8 <= Ntq <= 25, and Ntq - is integer! BAUD RATE PRESCALER: BRP = (Fcan/Ftq)–1 INDIVIDUAL BIT TIME SEGMENTS: (Bit Time) = (Sync Segment) + (Time Segment 1) + (Time Segment 2) where (Sync Segment) = 1*Tq (constant) (Time Segment 2) ~= 30% of Nominal Bit Time = Ntq/3 (Time Segment 2) > 1*Tq (Time Segment 1) > 3*Tq (Time Segment 1) > (Time Segment 2) (Time Segment 1) <= (Time Segment 2)+8 (Synchronous Jump Width) <= (Time Segment 2) Table of Parameters: --------+-----------------------------------------------------+ BRP@Fcan| Ntq | 9MHz |25|24|23|22|21|20|19|18|17|16|15|14|13|12|11|10| 9| 8| --------+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 500.000 | | | | | | | | 0| | | | | | | | | 1| | 250.000 | | | | | | | | 1| | | | | | 2| | | 3| | 125.000 | | 2| | | | | | 3| | | | | | 5| | | 7| 8| 100.000 | | | | | | | | 4| | | 5| | | | | 8| 9| | 83.333 | | | | | | | | 5| | | | | | 8| | |11| | 50.000 | | | | | | 8| | 9| | |11| | |14| |17|19| | 33.333 | | | | | | | |14| | |17| | | | |26|29| | 20.000 |17| | | | | | |24| | |29| | | | |44|49| | 15.000 |23|24| | | |29| | | | |39| | |49| |59| |74| 10.000 |35| | | | |44| |49| | |59| | |74| |89|99| | --------+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ */ #define CAN_BTR(BRP,TSEG1,TSEG2,SJW) (((((((SJW)&0x03)<<4)|((TSEG2)&0x07))<<4)|((TSEG1)&0x0F))<<16)|((BRP)&0x3FF) // значения регистра BTR enum TCanBaudrate { CanBaudrate500 = CAN_BTR(0,10,5,3), CanBaudrate250 = CAN_BTR(1,10,5,3), // CanBaudrate125 = CAN_BTR(2,14,7,3), CanBaudrate125 = CAN_BTR(3,10,5,3), CanBaudrate100 = CAN_BTR(4,10,5,3), CanBaudrate83 = CAN_BTR(5,10,5,3), // CanBaudrate50 = CAN_BTR(8,11,6,3), CanBaudrate50 = CAN_BTR(9,10,5,3), CanBaudrate33 = CAN_BTR(14,10,5,3), CanBaudrate20 = CAN_BTR(17,15,7,3), // CanBaudrate20 = CAN_BTR(24,10,5,3), CanBaudrate15 = CAN_BTR(23,15,7,3), // CanBaudrate15 = CAN_BTR(24,14,7,3), // CanBaudrate15 = CAN_BTR(29,11,6,3), CanBaudrate10 = CAN_BTR(35,15,7,3), // CanBaudrate10 = CAN_BTR(44,11,6,3), // CanBaudrate10 = CAN_BTR(49,10,5,3), }; #ifndef CAN_FIRMWARE CCan (); uint32_t Init (TCanChannel aCh, const TCanInit * apInit); uint32_t Send (TCanChannel aCh, TCanPkt * apPkt, uint32_t aTimeout); void ReceivedIsr (TCanChannel aCh, TCanPkt * apPkt); uint32_t ProcessQueue (); uint32_t GetRcv (TCanChannel aCh, TCanPkt * apPkt); uint32_t GetRcvTimeout (TCanChannel aCh) { return _rx_tmr[aCh].Value(); } #endif // CAN_FIRMWARE // объявление фильтров при инициализации struct Filter { // добавить пару идентификаторов для точного соответствия static constexpr uint64_t List11 (uint16_t id1, uint16_t id2) { return ((uint64_t) (IdStd (id1) | 0x01) << 32) | (uint64_t) (IdStd (id2) | 0x01); } static constexpr uint64_t List29 (uint32_t id1, uint32_t id2) { return ((uint64_t) (IdExt (id1) | 0x01) << 32) | (uint64_t) (IdExt (id2) | 0x01); } // добавить один идентификатор static constexpr uint64_t List11 (uint16_t id1) { return ((uint64_t) (IdStd (id1) | 0x01) << 32) | (uint64_t) (IdStd (id1) | 0x01); } static constexpr uint64_t List29 (uint32_t id1) { return ((uint64_t) (IdExt (id1) | 0x01) << 32) | (uint64_t) (IdExt (id1) | 0x01); } // добавить один идентификатор с маской static constexpr uint64_t Mask11 (uint16_t id, uint16_t mask) { return ((uint64_t) (IdStd (id)) << 32) | (uint64_t) (IdStd (mask) | 0x01); } static constexpr uint64_t Mask29 (uint32_t id, uint32_t mask) { return ((uint64_t) (IdExt (id)) << 32) | (uint64_t) (IdExt (mask) | 0x01); } private: // формирование ID для фильтров static constexpr uint32_t IdStd (uint16_t id) { return (id & 0x7FFul) << 21; } static constexpr uint32_t IdExt (uint32_t id) { return ((id & 0x1FFFFFFFul) << 3) | 0x04; } }; #ifndef CAN_FIRMWARE private: uint8_t sleep_en; bool IsSleepEn (TCanChannel aCh) { return sleep_en & aCh; } // очередь пакетов на отправку - тот же TCanPkt, но с таймером struct TCanPktTxInt: public TCanPkt { uint32_t timeout; TimerMs tmr; }; typedef CircularBuffer TRxBuf; typedef CircularBuffer TTxBuf; TRxBuf _rx_buf[2]; TTxBuf _tx_buf[2]; uint32_t TxByTimeout (TCanChannel aCh); bool IsTxQueueEmpty (TCanChannel aCh); TCanState _state[2]; // Send() и обработка очереди вызываются из разных потоков, нужна защита OS::TMutex can_mutex; // сбрасывается по приёму любого пакета TimerMs _rx_tmr[2]; #endif // CAN_FIRMWARE }; extern CCan gCan; #endif /* DRIVERS_CAN_CAN_H_ */