Skip to content

Commit a17efa5

Browse files
rework calculation of timing configuration
1 parent 39afe0e commit a17efa5

File tree

1 file changed

+34
-31
lines changed

1 file changed

+34
-31
lines changed

STM32_CAN.cpp

+34-31
Original file line numberDiff line numberDiff line change
@@ -682,47 +682,50 @@ bool STM32_CAN::lookupBaudrate(CAN_HandleTypeDef *CanHandle, int baud, const T(&
682682

683683
void STM32_CAN::calculateBaudrate(CAN_HandleTypeDef *CanHandle, int baud)
684684
{
685-
/* this function calculates the needed Sync Jump Width, Time segments 1 and 2 and prescaler values based on the set baud rate and APB1 clock.
686-
This could be done faster if needed by calculating these values beforehand and just using fixed values from table.
687-
The function has been optimized to give values that have sample-point between 75-94%. If some other sample-point percentage is needed, this needs to be adjusted.
688-
More info about this topic here: http://www.bittiming.can-wiki.info/
689-
*/
690-
int sjw = 1;
691-
int bs1 = 5; // optimization. bs1 smaller than 5 does give too small sample-point percentages.
692-
int bs2 = 1;
693-
int prescaler = 1;
694-
695-
uint32_t frequency = getAPB1Clock();
685+
uint8_t bs1;
686+
uint8_t bs2;
687+
uint16_t prescaler;
688+
689+
const uint32_t frequency = getAPB1Clock();
696690

697691
if (frequency == 48000000) {
698692
if (lookupBaudrate(CanHandle, baud, BAUD_RATE_TABLE_48M)) return;
699693
} else if (frequency == 45000000) {
700694
if (lookupBaudrate(CanHandle, baud, BAUD_RATE_TABLE_45M)) return;
701695
}
702696

703-
while (sjw <= 4) {
704-
while (prescaler <= 1024) {
705-
while (bs2 <= 3) { // Time segment 2 can get up to 8, but that causes too small sample-point percentages, so this is limited to 3.
706-
while (bs1 <= 15) { // Time segment 1 can get up to 16, but that causes too big sample-point percenages, so this is limited to 15.
707-
int calcBaudrate = (int)(frequency / (prescaler * (sjw + bs1 + bs2)));
708-
709-
if (calcBaudrate == baud)
710-
{
711-
setBaudRateValues(CanHandle, prescaler, bs1, bs2, sjw);
712-
return;
713-
}
714-
bs1++;
715-
}
716-
bs1 = 5;
717-
bs2++;
697+
/* this loop seeks a precise baudrate match, with the sample point positioned
698+
* at between ~75-95%. the nominal bit time is produced from N time quanta,
699+
* running at the prescaled clock rate (where N = 1 + bs1 + bs2). this algorithm
700+
* prefers the lowest prescaler (most time quanter per bit).
701+
*
702+
* many configuration sets can be discarded due to an out-of-bounds sample point,
703+
* or being unable to reach the desired baudrate.
704+
*
705+
* for the best chance at interoperability, we use the widest SJW possible.
706+
*
707+
* for more details + justification, see: https://github.com/pazi88/STM32_CAN/pull/41
708+
*/
709+
for (prescaler = 1; prescaler <= 1024; prescaler += 1) {
710+
const uint32_t can_freq = frequency / prescaler;
711+
const uint32_t baud_min = can_freq / (1 + 5 + 16);
712+
713+
/* skip all prescaler values that can't possibly achieve the desired baudrate */
714+
if (baud_min > baud) continue;
715+
716+
for (bs2 = 1; bs2 <= 5; bs2 += 1) {
717+
for (bs1 = (bs2 * 3) - 1; bs1 <= 16; bs1 += 1) {
718+
const uint32_t baud_cur = can_freq / (1 + bs1 + bs2);
719+
720+
if (baud_cur != baud) continue;
721+
722+
setBaudRateValues(CanHandle, prescaler, bs1, bs2, 4);
723+
return;
718724
}
719-
bs1 = 5;
720-
bs2 = 1;
721-
prescaler++;
722725
}
723-
bs1 = 5;
724-
sjw++;
725726
}
727+
728+
/* uhoh, failed to calculate an acceptable baud rate... */
726729
}
727730

728731
uint32_t STM32_CAN::getAPB1Clock()

0 commit comments

Comments
 (0)