canard_stm32.h
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2017 UAVCAN Team
3  *
4  * Distributed under the MIT License, available in the file LICENSE.
5  *
6  * Author: Pavel Kirienko <pavel.kirienko@zubax.com>
7  */
8 
9 #ifndef CANARD_STM32_H
10 #define CANARD_STM32_H
11 
12 #include <canard.h>
13 #include <string.h> // NOLINT
14 
15 
16 #ifdef __cplusplus
17 extern "C"
18 {
19 #endif
20 
25 #if !defined(CANARD_STM32_USE_CAN2)
26 # define CANARD_STM32_USE_CAN2 0
27 #endif
28 
33 #if !defined(CANARD_STM32_DEBUG_INNER_PRIORITY_INVERSION)
34 # define CANARD_STM32_DEBUG_INNER_PRIORITY_INVERSION 1
35 #endif
36 
41 #define CANARD_STM32_ERROR_UNSUPPORTED_BIT_RATE 1000
42 #define CANARD_STM32_ERROR_MSR_INAK_NOT_SET 1001
43 #define CANARD_STM32_ERROR_MSR_INAK_NOT_CLEARED 1002
44 #define CANARD_STM32_ERROR_UNSUPPORTED_FRAME_FORMAT 1003
45 
54 #define CANARD_STM32_NUM_ACCEPTANCE_FILTERS 14U
55 
71 typedef enum
72 {
77 
81 typedef struct
82 {
86 
91 typedef struct
92 {
96 
103 typedef struct
104 {
110 
131 int16_t canardSTM32Init(const CanardSTM32CANTimings* const timings,
132  const CanardSTM32IfaceMode iface_mode);
133 
143 int16_t canardSTM32Transmit(const CanardCANFrame* const frame);
144 
153 int16_t canardSTM32Receive(CanardCANFrame* const out_frame);
154 
167  const uint8_t num_filter_configs);
168 
173 
189 static inline
190 int16_t canardSTM32ComputeCANTimings(const uint32_t peripheral_clock_rate,
191  const uint32_t target_bitrate,
192  CanardSTM32CANTimings* const out_timings)
193 {
194  if (target_bitrate < 1000)
195  {
197  }
198 
199  CANARD_ASSERT(out_timings != NULL); // NOLINT
200  memset(out_timings, 0, sizeof(*out_timings));
201 
202  /*
203  * Hardware configuration
204  */
205  static const uint8_t MaxBS1 = 16;
206  static const uint8_t MaxBS2 = 8;
207 
208  /*
209  * Ref. "Automatic Baudrate Detection in CANopen Networks", U. Koppe, MicroControl GmbH & Co. KG
210  * CAN in Automation, 2003
211  *
212  * According to the source, optimal quanta per bit are:
213  * Bitrate Optimal Maximum
214  * 1000 kbps 8 10
215  * 500 kbps 16 17
216  * 250 kbps 16 17
217  * 125 kbps 16 17
218  */
219  const uint8_t max_quanta_per_bit = (uint8_t)((target_bitrate >= 1000000) ? 10 : 17); // NOLINT
220  CANARD_ASSERT(max_quanta_per_bit <= (MaxBS1 + MaxBS2));
221 
222  static const uint16_t MaxSamplePointLocationPermill = 900;
223 
224  /*
225  * Computing (prescaler * BS):
226  * BITRATE = 1 / (PRESCALER * (1 / PCLK) * (1 + BS1 + BS2)) -- See the Reference Manual
227  * BITRATE = PCLK / (PRESCALER * (1 + BS1 + BS2)) -- Simplified
228  * let:
229  * BS = 1 + BS1 + BS2 -- Number of time quanta per bit
230  * PRESCALER_BS = PRESCALER * BS
231  * ==>
232  * PRESCALER_BS = PCLK / BITRATE
233  */
234  const uint32_t prescaler_bs = peripheral_clock_rate / target_bitrate;
235 
236  /*
237  * Searching for such prescaler value so that the number of quanta per bit is highest.
238  */
239  uint8_t bs1_bs2_sum = (uint8_t)(max_quanta_per_bit - 1); // NOLINT
240 
241  while ((prescaler_bs % (1U + bs1_bs2_sum)) != 0)
242  {
243  if (bs1_bs2_sum <= 2)
244  {
245  return -CANARD_STM32_ERROR_UNSUPPORTED_BIT_RATE; // No solution
246  }
247  bs1_bs2_sum--;
248  }
249 
250  const uint32_t prescaler = prescaler_bs / (1U + bs1_bs2_sum);
251  if ((prescaler < 1U) || (prescaler > 1024U))
252  {
253  return -CANARD_STM32_ERROR_UNSUPPORTED_BIT_RATE; // No solution
254  }
255 
256  /*
257  * Now we have a constraint: (BS1 + BS2) == bs1_bs2_sum.
258  * We need to find such values so that the sample point is as close as possible to the optimal value,
259  * which is 87.5%, which is 7/8.
260  *
261  * Solve[(1 + bs1)/(1 + bs1 + bs2) == 7/8, bs2] (* Where 7/8 is 0.875, the recommended sample point location *)
262  * {{bs2 -> (1 + bs1)/7}}
263  *
264  * Hence:
265  * bs2 = (1 + bs1) / 7
266  * bs1 = (7 * bs1_bs2_sum - 1) / 8
267  *
268  * Sample point location can be computed as follows:
269  * Sample point location = (1 + bs1) / (1 + bs1 + bs2)
270  *
271  * Since the optimal solution is so close to the maximum, we prepare two solutions, and then pick the best one:
272  * - With rounding to nearest
273  * - With rounding to zero
274  */
275  uint8_t bs1 = (uint8_t)(((7 * bs1_bs2_sum - 1) + 4) / 8); // Trying rounding to nearest first // NOLINT
276  uint8_t bs2 = (uint8_t)(bs1_bs2_sum - bs1); // NOLINT
277  CANARD_ASSERT(bs1_bs2_sum > bs1);
278 
279  {
280  const uint16_t sample_point_permill = (uint16_t)(1000U * (1U + bs1) / (1U + bs1 + bs2)); // NOLINT
281 
282  if (sample_point_permill > MaxSamplePointLocationPermill) // Strictly more!
283  {
284  bs1 = (uint8_t)((7 * bs1_bs2_sum - 1) / 8); // Nope, too far; now rounding to zero
285  bs2 = (uint8_t)(bs1_bs2_sum - bs1);
286  }
287  }
288 
289  const bool valid = (bs1 >= 1) && (bs1 <= MaxBS1) && (bs2 >= 1) && (bs2 <= MaxBS2);
290 
291  /*
292  * Final validation
293  * Helpful Python:
294  * def sample_point_from_btr(x):
295  * assert 0b0011110010000000111111000000000 & x == 0
296  * ts2,ts1,brp = (x>>20)&7, (x>>16)&15, x&511
297  * return (1+ts1+1)/(1+ts1+1+ts2+1)
298  */
299  if ((target_bitrate != (peripheral_clock_rate / (prescaler * (1U + bs1 + bs2)))) ||
300  !valid)
301  {
302  // This actually means that the algorithm has a logic error, hence assert(0).
303  CANARD_ASSERT(0); // NOLINT
305  }
306 
307  out_timings->bit_rate_prescaler = (uint16_t) prescaler;
308  out_timings->max_resynchronization_jump_width = 1; // One is recommended by UAVCAN, CANOpen, and DeviceNet
309  out_timings->bit_segment_1 = bs1;
310  out_timings->bit_segment_2 = bs2;
311 
312  return 0;
313 }
314 
315 #ifdef __cplusplus
316 }
317 #endif
318 #endif
CanardSTM32AcceptanceFilterConfiguration::id
uint32_t id
Definition: canard_stm32.h:93
canardSTM32Init
int16_t canardSTM32Init(const CanardSTM32CANTimings *const timings, const CanardSTM32IfaceMode iface_mode)
Definition: canard_stm32.c:168
uavcan::uint64_t
std::uint64_t uint64_t
Definition: std.hpp:27
uavcan::uint32_t
std::uint32_t uint32_t
Definition: std.hpp:26
canardSTM32ConfigureAcceptanceFilters
int16_t canardSTM32ConfigureAcceptanceFilters(const CanardSTM32AcceptanceFilterConfiguration *const filter_configs, const uint8_t num_filter_configs)
Definition: canard_stm32.c:449
CanardSTM32CANTimings
Definition: canard_stm32.h:103
CanardSTM32AcceptanceFilterConfiguration
Definition: canard_stm32.h:91
uavcan::uint16_t
std::uint16_t uint16_t
Definition: std.hpp:25
uavcan::int16_t
std::int16_t int16_t
Definition: std.hpp:30
canardSTM32GetStats
CanardSTM32Stats canardSTM32GetStats(void)
Definition: canard_stm32.c:565
CanardSTM32IfaceModeNormal
@ CanardSTM32IfaceModeNormal
Normal mode.
Definition: canard_stm32.h:73
uavcan::uint8_t
std::uint8_t uint8_t
Definition: std.hpp:24
canardSTM32Transmit
int16_t canardSTM32Transmit(const CanardCANFrame *const frame)
Definition: canard_stm32.c:281
CanardSTM32Stats::error_count
uint64_t error_count
Definition: canard_stm32.h:84
CanardSTM32IfaceModeAutomaticTxAbortOnError
@ CanardSTM32IfaceModeAutomaticTxAbortOnError
Abort pending TX if a bus error has occurred.
Definition: canard_stm32.h:75
CanardSTM32CANTimings::bit_rate_prescaler
uint16_t bit_rate_prescaler
Definition: canard_stm32.h:105
CanardSTM32Stats::rx_overflow_count
uint64_t rx_overflow_count
Definition: canard_stm32.h:83
frame
uavcan::CanFrame frame
Definition: can.cpp:78
CanardSTM32IfaceModeSilent
@ CanardSTM32IfaceModeSilent
Do not affect the bus, only listen.
Definition: canard_stm32.h:74
CanardSTM32CANTimings::bit_segment_2
uint8_t bit_segment_2
[1, 16]
Definition: canard_stm32.h:107
CanardSTM32CANTimings::max_resynchronization_jump_width
uint8_t max_resynchronization_jump_width
[1, 8]
Definition: canard_stm32.h:108
CanardSTM32AcceptanceFilterConfiguration::mask
uint32_t mask
Definition: canard_stm32.h:94
CANARD_STM32_ERROR_UNSUPPORTED_BIT_RATE
#define CANARD_STM32_ERROR_UNSUPPORTED_BIT_RATE
Definition: canard_stm32.h:41
NULL
#define NULL
Nullzeiger.
Definition: utils.h:64
CanardSTM32Stats
Definition: canard_stm32.h:81
canardSTM32ComputeCANTimings
static int16_t canardSTM32ComputeCANTimings(const uint32_t peripheral_clock_rate, const uint32_t target_bitrate, CanardSTM32CANTimings *const out_timings)
Definition: canard_stm32.h:190
CanardSTM32CANTimings::bit_segment_1
uint8_t bit_segment_1
[1, 1024]
Definition: canard_stm32.h:106
canardSTM32Receive
int16_t canardSTM32Receive(CanardCANFrame *const out_frame)
Definition: canard_stm32.c:387
CanardSTM32IfaceMode
CanardSTM32IfaceMode
Definition: canard_stm32.h:71


uavcan_communicator
Author(s):
autogenerated on Fri Dec 13 2024 03:10:02