Battery-Emulator/Software/ACAN2515Settings.cpp
2023-08-27 22:47:11 +03:00

176 lines
9.1 KiB
C++

//··································································································
// A CAN driver for MCP2515
// by Pierre Molinaro
// https://github.com/pierremolinaro/acan2515
//··································································································
#include "ACAN2515Settings.h"
//··································································································
// CAN Settings
//··································································································
ACAN2515Settings::ACAN2515Settings (const uint32_t inQuartzFrequency,
const uint32_t inWhishedBitRate,
const uint32_t inTolerancePPM) :
mQuartzFrequency (inQuartzFrequency) {
if (mDesiredBitRate != inWhishedBitRate) {
mDesiredBitRate = inWhishedBitRate ;
const uint32_t clock = mQuartzFrequency / 2 ;
uint32_t TQCount = 25 ; // TQCount: 5 ... 25
uint32_t smallestError = UINT32_MAX ;
uint32_t bestBRP = 64 ; // Setting for slowest bit rate
uint32_t bestTQCount = 25 ; // Setting for slowest bit rate
uint32_t BRP = clock / inWhishedBitRate / TQCount ;
//--- Loop for finding best BRP and best TQCount
while ((TQCount >= 5) && (BRP <= 64)) {
//--- Compute error using BRP (caution: BRP should be > 0)
if (BRP > 0) {
const uint32_t error = clock - inWhishedBitRate * TQCount * BRP ; // error is always >= 0
if (error < smallestError) {
smallestError = error ;
bestBRP = BRP ;
bestTQCount = TQCount ;
}
}
//--- Compute error using BRP+1 (caution: BRP+1 should be <= 64)
if (BRP < 64) {
const uint32_t error = inWhishedBitRate * TQCount * (BRP + 1) - clock ; // error is always >= 0
if (error < smallestError) {
smallestError = error ;
bestBRP = BRP + 1 ;
bestTQCount = TQCount ;
}
}
//--- Continue with next value of TQCount
TQCount -- ;
BRP = clock / (inWhishedBitRate * TQCount) ;
}
//--- Set the BRP
mBitRatePrescaler = (uint8_t) bestBRP ;
//--- Compute PS2
const uint32_t PS2 = (bestTQCount + 1) / 3 ; // Always 2 <= PS2 <= 8
mPhaseSegment2 = (uint8_t) PS2 ;
//--- Compute the remaining number of TQ once PS2 and SyncSeg are removed
const uint32_t propSegmentPlusPhaseSegment1 = bestTQCount - PS2 - 1 /* Sync Seg */ ;
//--- Set PS1 to half of remaining TQCount
const uint32_t PS1 = propSegmentPlusPhaseSegment1 / 2 ; // Always 1 <= PS1 <= 8
mPhaseSegment1 = (uint8_t) PS1 ;
//--- Set PS to what is left
mPropagationSegment = (uint8_t) (propSegmentPlusPhaseSegment1 - PS1) ; // Always 1 <= PropSeg <= 8
//--- Set SJW to PS2, with a maximum value of 4
mSJW = (mPhaseSegment2 > 4) ? 4 : (mPhaseSegment2 - 1) ; // Always 2 <= RJW <= 4, and RJW <= mPhaseSegment2
//--- Triple sampling ?
mTripleSampling = (inWhishedBitRate <= 125000) && (mPhaseSegment1 >= 2) ;
//--- Final check of the configuration
const uint32_t W = bestTQCount * mDesiredBitRate * mBitRatePrescaler ;
const uint64_t diff = (clock > W) ? (clock - W) : (W - clock) ;
const uint64_t ppm = (uint64_t) (1000UL * 1000UL) ; // UL suffix is required for Arduino Uno
mBitRateClosedToDesiredRate = (diff * ppm) <= (((uint64_t) W) * inTolerancePPM) ;
}
} ;
//··································································································
static uint32_t bitrateFrom (const uint32_t inQuartzFrequency, // In Hertz
const uint8_t inBitRatePrescaler, // 1...64
const uint8_t inPropagationSegment, // 1...8
const uint8_t inPhaseSegment1, // 1...8
const uint8_t inPhaseSegment2) {// 2...8
const uint8_t TQ = 1 + inPropagationSegment + inPhaseSegment1 + inPhaseSegment2 ;
return inQuartzFrequency / inBitRatePrescaler / TQ / 2 ;
}
//··································································································
ACAN2515Settings::ACAN2515Settings (const uint32_t inQuartzFrequency, // In Hertz
const uint8_t inBitRatePrescaler, // 1...64
const uint8_t inPropagationSegment, // 1...8
const uint8_t inPhaseSegment1, // 1...8
const uint8_t inPhaseSegment2, // 2...8
const uint8_t inSJW) : // 1...4
mQuartzFrequency (inQuartzFrequency),
mDesiredBitRate (bitrateFrom (inQuartzFrequency, inBitRatePrescaler, inPropagationSegment, inPhaseSegment1, inPhaseSegment2)),
mPropagationSegment (inPropagationSegment),
mPhaseSegment1 (inPhaseSegment1),
mPhaseSegment2 (inPhaseSegment2),
mSJW (inSJW),
mBitRatePrescaler (inBitRatePrescaler),
mBitRateClosedToDesiredRate (true) {
} ;
//··································································································
uint32_t ACAN2515Settings::actualBitRate (void) const {
const uint32_t TQCount = 1 /* Sync Seg */ + mPropagationSegment + mPhaseSegment1 + mPhaseSegment2 ;
return mQuartzFrequency / mBitRatePrescaler / TQCount / 2 ;
}
//··································································································
bool ACAN2515Settings::exactBitRate (void) const {
const uint32_t TQCount = 1 /* Sync Seg */ + mPropagationSegment + mPhaseSegment1 + mPhaseSegment2 ;
return mQuartzFrequency == (mDesiredBitRate * mBitRatePrescaler * TQCount * 2) ;
}
//··································································································
uint32_t ACAN2515Settings::ppmFromDesiredBitRate (void) const {
const uint32_t TQCount = 1 /* Sync Seg */ + mPropagationSegment + mPhaseSegment1 + mPhaseSegment2 ;
const uint32_t W = TQCount * mDesiredBitRate * mBitRatePrescaler * 2 ;
const uint64_t diff = (mQuartzFrequency > W) ? (mQuartzFrequency - W) : (W - mQuartzFrequency) ;
const uint64_t ppm = (uint64_t) (1000UL * 1000UL) ; // UL suffix is required for Arduino Uno
return (uint32_t) ((diff * ppm) / W) ;
}
//··································································································
uint32_t ACAN2515Settings::samplePointFromBitStart (void) const {
const uint32_t TQCount = 1 /* Sync Seg */ + mPropagationSegment + mPhaseSegment1 + mPhaseSegment2 ;
const uint32_t samplePoint = 1 /* Sync Seg */ + mPropagationSegment + mPhaseSegment1 - mTripleSampling ;
const uint32_t partPerCent = 100 ;
return (samplePoint * partPerCent) / TQCount ;
}
//··································································································
uint16_t ACAN2515Settings::CANBitSettingConsistency (void) const {
uint16_t errorCode = 0 ; // Means no error
if (mBitRatePrescaler == 0) {
errorCode |= kBitRatePrescalerIsZero ;
}else if (mBitRatePrescaler > 64) {
errorCode |= kBitRatePrescalerIsGreaterThan64 ;
}
if (mPropagationSegment == 0) {
errorCode |= kPropagationSegmentIsZero ;
}else if (mPropagationSegment > 8) {
errorCode |= kPropagationSegmentIsGreaterThan8 ;
}
if (mPhaseSegment1 == 0) {
errorCode |= kPhaseSegment1IsZero ;
}else if ((mPhaseSegment1 == 1) && mTripleSampling) {
errorCode |= kPhaseSegment1Is1AndTripleSampling ;
}else if (mPhaseSegment1 > 8) {
errorCode |= kPhaseSegment1IsGreaterThan8 ;
}
if (mPhaseSegment2 < 2) {
errorCode |= kPhaseSegment2IsLowerThan2 ;
}else if (mPhaseSegment2 > 8) {
errorCode |= kPhaseSegment2IsGreaterThan8 ;
}
if (mSJW == 0) {
errorCode |= kSJWIsZero ;
}else if (mSJW > 4) {
errorCode |= kSJWIsGreaterThan4 ;
}
if (mSJW >= mPhaseSegment2) {
errorCode |= kSJWIsGreaterThanOrEqualToPhaseSegment2 ;
}
if (mPhaseSegment2 > (mPropagationSegment + mPhaseSegment1)) {
errorCode |= kPhaseSegment2IsGreaterThanPSPlusPS1 ;
}
return errorCode ;
}
//··································································································