289 lines
8.3 KiB
C++
289 lines
8.3 KiB
C++
/*
|
|
* Can.h
|
|
*
|
|
* Created on: 01 июня 2015 г.
|
|
* Author: esaulenko
|
|
*/
|
|
|
|
#ifndef DRIVERS_CAN_CAN_H_
|
|
#define DRIVERS_CAN_CAN_H_
|
|
|
|
|
|
#include <stdint.h>
|
|
#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 <int N>
|
|
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<TCanPkt, 16> TRxBuf;
|
|
typedef CircularBuffer<TCanPktTxInt, 32> 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_ */
|