Skip to content

Instantly share code, notes, and snippets.

@Lauszus
Last active March 29, 2022 13:27
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Lauszus/30ce8c9f8bc2bdaf8c42c5e1712aac39 to your computer and use it in GitHub Desktop.
Save Lauszus/30ce8c9f8bc2bdaf8c42c5e1712aac39 to your computer and use it in GitHub Desktop.
Python port of the "FLEXCAN_CalculateImprovedTimingValues" function from the NXP SDK
#!/usr/bin/env python3
#
# Copyright (c) 2015, Freescale Semiconductor, Inc.
# Copyright 2016-2021 NXP
# Copyright 2022 Kristian Sloth Lauszus
# All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
# Python port of the "FLEXCAN_CalculateImprovedTimingValues" function from the NXP SDK
import sys
def FLEXCAN_GetSegments(bitRate, tqNum):
IDEAL_SP_LOW = 750
IDEAL_SP_MID = 800
IDEAL_SP_HIGH = 875
IDEAL_SP_FACTOR = 1000
MIN_TIME_SEGMENT1 = 2
MIN_TIME_SEGMENT2 = 2
# TODO: These should ideally not be hardcoded, as they are MCU dependent
seg1Max = (0x380000 >> 19) + 1 # MAX_PSEG1
proSegMax = 7 + 1 # MAX_PROPSEG
sjwMAX = (0xC00000 >> 22) + 1 # MAX_RJW
if bitRate == 1000000:
ideal_sp = IDEAL_SP_LOW
elif bitRate >= 800000:
ideal_sp = IDEAL_SP_MID
else:
ideal_sp = IDEAL_SP_HIGH
# Calculates phaseSeg2
phaseSeg2 = tqNum - (tqNum * ideal_sp) // IDEAL_SP_FACTOR
if phaseSeg2 < MIN_TIME_SEGMENT2:
phaseSeg2 = MIN_TIME_SEGMENT2
elif phaseSeg2 > seg1Max:
phaseSeg2 = seg1Max
# Calculates phaseSeg1 and propSeg
seg1Temp = tqNum - phaseSeg2 - 1
if seg1Temp > (seg1Max + proSegMax):
phaseSeg2 += seg1Temp - seg1Max - proSegMax
propSeg = proSegMax
phaseSeg1 = seg1Max
elif seg1Temp > proSegMax:
propSeg = proSegMax
phaseSeg1 = seg1Temp - proSegMax
else:
propSeg = seg1Temp - 1
phaseSeg1 = 1
# Try to make phaseSeg1 equal to phaseSeg2
if phaseSeg1 < phaseSeg2:
seg1Temp = proSegMax - propSeg if (phaseSeg2 - phaseSeg1) > (proSegMax - propSeg) else phaseSeg2 - phaseSeg1
propSeg -= seg1Temp
phaseSeg1 += seg1Temp
else:
seg1Temp = proSegMax - propSeg if (phaseSeg1 - phaseSeg2) > (proSegMax - propSeg) else phaseSeg1 - phaseSeg2
propSeg += seg1Temp
phaseSeg1 -= seg1Temp
# rJumpwidth (SJW) is the minimum value of phaseSeg1 and phaseSeg2
rJumpwidth = phaseSeg2 if phaseSeg1 > phaseSeg2 else phaseSeg1
if rJumpwidth > sjwMAX:
rJumpwidth = sjwMAX
phaseSeg1 -= 1
phaseSeg2 -= 1
propSeg -= 1
rJumpwidth -= 1
return propSeg, phaseSeg1, phaseSeg2, rJumpwidth
def print_timing(bitRate, sourceClock_Hz, propSeg, phaseSeg1, phaseSeg2, rJumpwidth, preDivider):
tq = (preDivider + 1) / sourceClock_Hz * 1e9
quantum = 1 + (propSeg + 1) + (phaseSeg1 + 1) + (phaseSeg2 + 1)
sample_point_percent = (1 + (propSeg + 1) + (phaseSeg1 + 1)) / quantum * 100.
print('Bit-rate: {} kbit/s, clock source: {} MHz, TQ: {:.1f} ns, quantum: {}, Prs: {}, PhS1: {}, PhS2: {}, SJW: {}, BRP: {}, sample point: {:.1f} %'.format(bitRate // 1000, sourceClock_Hz * 1e-6, tq, quantum, propSeg + 1, phaseSeg1 + 1, phaseSeg2 + 1, rJumpwidth + 1, preDivider + 1, sample_point_percent))
def FLEXCAN_CalculateImprovedTimingValues(bitRate, sourceClock_Hz):
spTemp = 1000
pdivMAX = 255
tqMin = 8 # CTRL1_MIN_TIME_QUANTA
tqNum = 25 # CTRL1_MAX_TIME_QUANTA
fgRet = False
while tqNum >= tqMin:
clk = bitRate * tqNum
if clk > sourceClock_Hz:
tqNum -= 1
continue
if (sourceClock_Hz // clk * clk) != sourceClock_Hz:
tqNum -= 1
continue
preDividerTemp = (sourceClock_Hz // clk) - 1
if preDividerTemp > pdivMAX:
print('The frequency of source clock is too large or the bit rate is too small, the pre-divider could not handle it')
break
propSegTemp, phaseSeg1Temp, phaseSeg2Temp, rJumpwidthTemp = FLEXCAN_GetSegments(bitRate, tqNum)
# Determine whether the calculated timing configuration can get the optimal sampling point
if (((phaseSeg2Temp + 1) * 1000) // tqNum) < spTemp:
spTemp = ((phaseSeg2Temp + 1) * 1000) // tqNum
fgRet = True
preDivider, propSeg, phaseSeg1, phaseSeg2, rJumpwidth = preDividerTemp, propSegTemp, phaseSeg1Temp, phaseSeg2Temp, rJumpwidthTemp
# print_timing(bitRate, sourceClock_Hz, propSeg, phaseSeg1, phaseSeg2, rJumpwidth, preDivider)
tqNum -= 1
if fgRet:
print_timing(bitRate, sourceClock_Hz, propSeg, phaseSeg1, phaseSeg2, rJumpwidth, preDivider)
return propSeg, phaseSeg1, phaseSeg2, rJumpwidth, preDivider
else:
print('Failed to find bit timing for bit-rate: {} kbit/s, clock source: {} MHz'.format(bitRate // 1000, sourceClock_Hz * 1e-6))
assert False
if __name__ == '__main__':
# Adjust these to match your setup or give them as command line arguments
if len(sys.argv) > 1:
bitRate = int(sys.argv[1])
sourceClock_Hz = int(sys.argv[2])
else:
bitRate = 500_000 # 500 kbit/s
sourceClock_Hz = 60_000_000 # 60 MHz
FLEXCAN_CalculateImprovedTimingValues(bitRate, sourceClock_Hz)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment