No successful CAN bus sending with NucleoG474RE

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 :smile:.

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…