Giter Site home page Giter Site logo

Comments (9)

nopnop2002 avatar nopnop2002 commented on August 24, 2024

What clock crystal were the bit timings calculated with?

int result = ComputeCANTimings(HAL_RCC_GetPCLK1Freq(), target_bitrate, &timings);
typedef struct
{
    uint16_t baud_rate_prescaler;                /// [1 to 1024]
    uint8_t time_segment_1;                      /// [1 to 16]
    uint8_t time_segment_2;                      /// [1 to 8]
    uint8_t resynchronization_jump_width;        /// [1 to 4] (recommended value is 1)
} CAN_bit_timing_config_t;

#define CAN_STM32_ERROR_UNSUPPORTED_BIT_RATE     1000
#define CAN_STM32_ERROR_MSR_INAK_NOT_SET         1001
#define CAN_STM32_ERROR_MSR_INAK_NOT_CLEARED     1002
#define CAN_STM32_ERROR_UNSUPPORTED_FRAME_FORMAT 1003

/*
 * Calculation of bit timing dependent on peripheral clock rate
 */
int16_t ComputeCANTimings(const uint32_t peripheral_clock_rate,
                          const uint32_t target_bitrate,
                          CAN_bit_timing_config_t* const out_timings)
{
    if (target_bitrate < 1000)
    {
        return -CAN_STM32_ERROR_UNSUPPORTED_BIT_RATE;
    }

    assert(out_timings != NULL);  // NOLINT
    memset(out_timings, 0, sizeof(*out_timings));

    /*
     * Hardware configuration
     */
    static const uint8_t MaxBS1 = 16;
    static const uint8_t MaxBS2 = 8;

    /*
     * Ref. "Automatic Baudrate Detection in CANopen Networks", U. Koppe, MicroControl GmbH & Co. KG
     *      CAN in Automation, 2003
     *
     * According to the source, optimal quanta per bit are:
     *   Bitrate        Optimal Maximum
     *   1000 kbps      8       10
     *   500  kbps      16      17
     *   250  kbps      16      17
     *   125  kbps      16      17
     */
    const uint8_t max_quanta_per_bit = (uint8_t)((target_bitrate >= 1000000) ? 10 : 17);    // NOLINT
    assert(max_quanta_per_bit <= (MaxBS1 + MaxBS2));

    static const uint16_t MaxSamplePointLocationPermill = 900;

    /*
     * Computing (prescaler * BS):
     *   BITRATE = 1 / (PRESCALER * (1 / PCLK) * (1 + BS1 + BS2))       -- See the Reference Manual
     *   BITRATE = PCLK / (PRESCALER * (1 + BS1 + BS2))                 -- Simplified
     * let:
     *   BS = 1 + BS1 + BS2                                             -- Number of time quanta per bit
     *   PRESCALER_BS = PRESCALER * BS
     * ==>
     *   PRESCALER_BS = PCLK / BITRATE
     */
    const uint32_t prescaler_bs = peripheral_clock_rate / target_bitrate;

    /*
     * Searching for such prescaler value so that the number of quanta per bit is highest.
     */
    uint8_t bs1_bs2_sum = (uint8_t)(max_quanta_per_bit - 1);    // NOLINT

    while ((prescaler_bs % (1U + bs1_bs2_sum)) != 0)
    {
        if (bs1_bs2_sum <= 2)
        {
            return -CAN_STM32_ERROR_UNSUPPORTED_BIT_RATE;          // No solution
        }
        bs1_bs2_sum--;
    }

    const uint32_t prescaler = prescaler_bs / (1U + bs1_bs2_sum);
    if ((prescaler < 1U) || (prescaler > 1024U))
    {
        return -CAN_STM32_ERROR_UNSUPPORTED_BIT_RATE;              // No solution
    }

    /*
     * Now we have a constraint: (BS1 + BS2) == bs1_bs2_sum.
     * We need to find such values so that the sample point is as close as possible to the optimal value,
     * which is 87.5%, which is 7/8.
     *
     *   Solve[(1 + bs1)/(1 + bs1 + bs2) == 7/8, bs2]  (* Where 7/8 is 0.875, the recommended sample point location *)
     *   {{bs2 -> (1 + bs1)/7}}
     *
     * Hence:
     *   bs2 = (1 + bs1) / 7
     *   bs1 = (7 * bs1_bs2_sum - 1) / 8
     *
     * Sample point location can be computed as follows:
     *   Sample point location = (1 + bs1) / (1 + bs1 + bs2)
     *
     * Since the optimal solution is so close to the maximum, we prepare two solutions, and then pick the best one:
     *   - With rounding to nearest
     *   - With rounding to zero
     */
    uint8_t bs1 = (uint8_t)(((7 * bs1_bs2_sum - 1) + 4) / 8);       // Trying rounding to nearest first  // NOLINT
    uint8_t bs2 = (uint8_t)(bs1_bs2_sum - bs1);  // NOLINT
    assert(bs1_bs2_sum > bs1);

    {
        const uint16_t sample_point_permill = (uint16_t)(1000U * (1U + bs1) / (1U + bs1 + bs2));  // NOLINT

        if (sample_point_permill > MaxSamplePointLocationPermill)   // Strictly more!
        {
            bs1 = (uint8_t)((7 * bs1_bs2_sum - 1) / 8);             // Nope, too far; now rounding to zero
            bs2 = (uint8_t)(bs1_bs2_sum - bs1);
        }
    }

    const bool valid = (bs1 >= 1) && (bs1 <= MaxBS1) && (bs2 >= 1) && (bs2 <= MaxBS2);

    /*
     * Final validation
     * Helpful Python:
     * def sample_point_from_btr(x):
     *     assert 0b0011110010000000111111000000000 & x == 0
     *     ts2,ts1,brp = (x>>20)&7, (x>>16)&15, x&511
     *     return (1+ts1+1)/(1+ts1+1+ts2+1)
     */
    if ((target_bitrate != (peripheral_clock_rate / (prescaler * (1U + bs1 + bs2)))) ||
        !valid)
    {
        // This actually means that the algorithm has a logic error, hence assert(0).
        assert(0);  // NOLINT
        return -CAN_STM32_ERROR_UNSUPPORTED_BIT_RATE;
    }

    out_timings->baud_rate_prescaler = (uint16_t) prescaler;
    out_timings->resynchronization_jump_width = 1;      // One is recommended by UAVCAN, CANOpen, and DeviceNet
    out_timings->time_segment_1 = bs1;
    out_timings->time_segment_2 = bs2;

    if (DEBUG) {
      Serial.print("target_bitrate=");
      Serial.println(target_bitrate);
      Serial.print("peripheral_clock_rate=");
      Serial.println(peripheral_clock_rate);
  
      Serial.print("timings.baud_rate_prescaler=");
      Serial.println(out_timings->baud_rate_prescaler);
      Serial.print("timings.time_segment_1=");
      Serial.println(out_timings->time_segment_1);
      Serial.print("timings.time_segment_2=");
      Serial.println(out_timings->time_segment_2);
      Serial.print("timings.resynchronization_jump_width=");
      Serial.println(out_timings->resynchronization_jump_width);
    }
    return 0;
}

from arduino-stm32-can.

TGlev avatar TGlev commented on August 24, 2024

hi, thanks for the code.

We are monitoring the CANTX/CANRX lines and we can see messages coming in on CANRX but there is absolutely no activity on CANTX. We are expecting the STM32 to atleast ACK the incoming CAN message...

Weird thing is, the message does arrive in the code but there is no ACK so the sender just keeps on sending it...

from arduino-stm32-can.

nopnop2002 avatar nopnop2002 commented on August 24, 2024

Can you configure the sender and receiver with two stm32s and see the difference?

from arduino-stm32-can.

TGlev avatar TGlev commented on August 24, 2024

We found the problem. Turns out the HSE crystal on our PCB was not enabled in software thus we were using the internal RC circuit as clock.

This works fine if you have two of the same STM32s on the same bus, but once you add a CAN bus device with a different clock (like our STM32H7 boards) the communication starts getting weird.

We managed to use some code generated by STM32CubeIde to get our HSE working and setup and now we are happily sharing a CAN bus with multiple STM32F446s and multiple STM32H7s. Thanks for your help and thanks for your amazing work on this library!

from arduino-stm32-can.

PCrnjak avatar PCrnjak commented on August 24, 2024

We found the problem. Turns out the HSE crystal on our PCB was not enabled in software thus we were using the internal RC circuit as clock.

This works fine if you have two of the same STM32s on the same bus, but once you add a CAN bus device with a different clock (like our STM32H7 boards) the communication starts getting weird.

We managed to use some code generated by STM32CubeIde to get our HSE working and setup and now we are happily sharing a CAN bus with multiple STM32F446s and multiple STM32H7s. Thanks for your help and thanks for your amazing work on this library!

Hey! I am glad you found a solution to your problem. I am also using this library and using the same MCU (stm32f446) and external crystal. Could you share your solution or code? My setup is working but I am getting a lot of transmission errors. Thank you!

from arduino-stm32-can.

nopnop2002 avatar nopnop2002 commented on August 24, 2024

@PCrnjak

The stm32f446 sample is for STM32F4 that operates with the following clocks.

F_CPU=180000000
HAL_RCC_GetPCLK1Freq=45000000

I only have this clock board.

It will not work with any other clock.

from arduino-stm32-can.

nopnop2002 avatar nopnop2002 commented on August 24, 2024

@TGlev

Can you share your STM32H7 CAN transmit/receive source code?

from arduino-stm32-can.

PCrnjak avatar PCrnjak commented on August 24, 2024

@PCrnjak

The stm32f446 sample is for STM32F4 that operates with the following clocks.

F_CPU=180000000
HAL_RCC_GetPCLK1Freq=45000000

I only have this clock board.

It will not work with any other clock.

Ok thank you. It is working fine now and also got it working for stm32f103c. Can you tell me is CAN msg autoretransmission enabled or disabled in your code? Also how could we set those bits by ourselves?

from arduino-stm32-can.

nopnop2002 avatar nopnop2002 commented on August 24, 2024

@PCrnjak

Can you tell me is CAN msg autoretransmission enabled or disabled in your code?

https://github.com/nopnop2002/Arduino-STM32-CAN/blob/master/stm32f103/stm32f103.ino#L327

https://github.com/nopnop2002/Arduino-STM32-CAN/blob/master/stm32f103/stm32f103.ino#L328

from arduino-stm32-can.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.