Hi Jan,
are you sure about this effect of the reset() function? I did not see anything related in the code:
/** Reset CAN interface.
*
* To use after error overflow.
*/
void can_reset(can_t *obj)
{
can_mode(obj, MODE_RESET);
HAL_FDCAN_ResetTimeoutCounter(&obj->CanHandle);
HAL_FDCAN_ResetTimestampCounter(&obj->CanHandle);
}
There is at least no obvious call to some frequency related setting. This is just a first impression from my side. Of course, this might be wrong.
In the meantime, I had a first look how the frequency settings are processed in the the function can_frequency() and in the CAN object initialization with default frequency of 100kHz.
For the NucleoG474RE the initialization is done within the function _can_init_freq_direct(can_t *obj, const can_pinmap_t *pinmap, int hz) which - apart from some pin mapping operations - performs some timing related calculations and applies general CAN settings.
In the function int can_frequency(can_t *obj, int f) also calculations are done but apparently with a focus to timing related settings.
So far so good.
There is a small difference in the timing calculations in both routines when determining the so called nominal prescaler:
_can_init_freq_direct(…):
// !When the sample point should be lower than 50%, this must be changed to
// !IS_FDCAN_NOMINAL_TSEG2(ntq/nominalPrescaler), since
// NTSEG2 and SJW max values are lower. For now the sample point is fix @75%
while (!IS_FDCAN_NOMINAL_TSEG1(ntq / nominalPrescaler)) {
nominalPrescaler ++;
if (!IS_FDCAN_NOMINAL_PRESCALER(nominalPrescaler)) {
error("Could not determine good nominalPrescaler. Bad clock value\n");
}
}
can_frequency(…):
// !When the sample point should be lower than 50%, this must be changed to
// !IS_FDCAN_DATA_TSEG2(ntq/nominalPrescaler), since
// NTSEG2 and SJW max values are lower. For now the sample point is fix @75%
while (!IS_FDCAN_DATA_TSEG1(ntq / nominalPrescaler)) {
nominalPrescaler ++;
if (!IS_FDCAN_NOMINAL_PRESCALER(nominalPrescaler)) {
error("Could not determine good nominalPrescaler. Bad clock value\n");
}
}
When using this for a frequency of 100kHz, this leads to different settings for the nominalPrecaler and to all timing related settings.
- nominalPrescaler = 7 (_can_init_freq_direct)
- nominalPrescaler = 49 (can_frequency)
I am not familiar with CAN bus timings so far, but this does not look good.
Therefore, I changed the non-working code in can_frequency() to the working one in _can_init_freq_direct(),
i.e:
//while (!IS_FDCAN_DATA_TSEG1(ntq / nominalPrescaler)) {
while (!IS_FDCAN_NOMINAL_TSEG1(ntq / nominalPrescaler)) {
Of course, applying a frequency of 100kHz now worked and did not “break” the transmissions any longer.
But also a change of the transmission frequency to 125kHz (on both sides: NucleoG474RE + LPC4088) led to working transmissions in my simple setup.
I used my workaround (IS_FDCAN_NOMINAL_TSEG1) now also in my application setup.
Now, the original issue is gone and I can perform the CAN bus transmissions from NucleoG474RE side with no errors (tested with 100kHz and 125kHz).
Many thanks, Jan, for your support! Your answers and suggestions made my day .
Still, I try to understand why it works now and why the original code was written as it was - and how this could lead to the “symptoms” I first observed…