ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
ra8_canfd_timing.c
Go to the documentation of this file.
1
34
35#include <stdint.h>
36
37#include "ra8_attributes.h"
38#include "ra8_canfd.h"
39#include "ra8_canfd_regs.h"
40#include "ra8_cgc.h"
41#include "ra8_check.h"
42#include "ra8_err.h"
43#include "ra8_hal_internal.h"
44#include "ra8_log.h"
45
46static const char* s_tag = "CANFD";
47
63
74typedef struct {
75 uint32_t prescaler;
76 uint32_t tseg1;
77 uint32_t tseg2;
78 uint32_t sjw;
80
102static ra8_err_t internal_solve_timing(uint32_t clock_hz,
103 uint32_t bitrate_bps,
104 uint32_t prescaler_max,
106{
107 /* mcdc-deactivated: both args are validated by ra8_canfd_init upstream; defensive duplicate. */
108 if ((bitrate_bps == 0U) || (clock_hz == 0U)) {
110 }
111 for (uint32_t tq = k_ra8_canfd_tq_search_hi; tq >= k_ra8_canfd_tq_search_lo; tq--) {
112 const uint32_t denom = bitrate_bps * tq;
113 if ((clock_hz % denom) != 0U) {
114 continue;
115 }
116 const uint32_t prescaler = clock_hz / denom;
117 if (prescaler > prescaler_max) {
118 continue;
119 }
120 /* 75% sample point: TSEG1 = 3*(tq-1)/4, TSEG2 = tq - 1 - TSEG1. */
121 const uint32_t tseg1 = ((tq - 1U) * 3U) / 4U;
122 const uint32_t tseg2 = (tq - 1U) - tseg1;
123 const uint32_t sjw = (tseg2 < k_ra8_canfd_sjw_max) ? tseg2 : k_ra8_canfd_sjw_max;
124 out->prescaler = prescaler;
125 out->tseg1 = tseg1;
126 out->tseg2 = tseg2;
127 out->sjw = sjw;
128 return k_ra8_ok;
129 }
131}
132
151static uint32_t internal_pack_ncfg(const ra8_canfd_timing_t* t)
152{
153 const uint32_t brp_field = ((t->prescaler - 1U) & k_ra8_cncfg_mask_nbrp)
154 << (uint32_t)k_ra8_cncfg_shift_nbrp;
155 const uint32_t tseg1_field = (t->tseg1 & k_ra8_cncfg_mask_ntseg1)
156 << (uint32_t)k_ra8_cncfg_shift_ntseg1;
157 const uint32_t tseg2_field = (t->tseg2 & k_ra8_cncfg_mask_ntseg2)
158 << (uint32_t)k_ra8_cncfg_shift_ntseg2;
159 const uint32_t sjw_field = ((t->sjw - 1U) & k_ra8_cncfg_mask_nsjw)
160 << (uint32_t)k_ra8_cncfg_shift_nsjw;
161 return brp_field | tseg1_field | tseg2_field | sjw_field;
162}
163
183static uint32_t internal_pack_dcfg(const ra8_canfd_timing_t* t)
184{
185 const uint32_t brp_field = ((t->prescaler - 1U) & k_ra8_dcfg_mask_dbrp)
186 << (uint32_t)k_ra8_dcfg_shift_dbrp;
187 const uint32_t tseg1_field = (t->tseg1 & k_ra8_dcfg_mask_dtseg1)
188 << (uint32_t)k_ra8_dcfg_shift_dtseg1;
189 const uint32_t tseg2_field = (t->tseg2 & k_ra8_dcfg_mask_dtseg2)
190 << (uint32_t)k_ra8_dcfg_shift_dtseg2;
191 const uint32_t sjw_field = ((t->sjw - 1U) & k_ra8_dcfg_mask_dsjw)
192 << (uint32_t)k_ra8_dcfg_shift_dsjw;
193 return brp_field | tseg1_field | tseg2_field | sjw_field;
194}
195
196ra8_err_t ra8_canfd_set_bitrate(uint8_t channel, uint32_t bitrate_bps, uint32_t data_bitrate_bps)
197{
198 volatile r_canfd_t* reg = ra8_canfd(channel);
199 RA8_CHECK_NULL_PTR(reg, s_tag, "channel out of range");
200
201 uint32_t pclka_hz = 0U;
202 const ra8_err_t clk_err = ra8_cgc_get_clock_hz(k_ra8_clock_id_pclka, &pclka_hz);
203 if (clk_err != k_ra8_ok) {
204 return clk_err;
205 }
206
207 /* Nominal phase: 10-bit prescaler ceiling = 1024. */
208 ra8_canfd_timing_t nominal = {};
209 const ra8_err_t n_err =
210 internal_solve_timing(pclka_hz, bitrate_bps, k_ra8_canfd_prescaler_max, &nominal);
211 if (n_err != k_ra8_ok) {
212 return n_err;
213 }
214
215 /* NCFG / DCFG are only writable in CH_RESET or CH_HALT. Use
216 * CH_RESET: halt is a graceful transition that waits for any
217 * in-flight TX to finish, and on internal-loopback bring-up the
218 * channel may be stuck trying to TX onto a bus with no
219 * acknowledger -- halt never converges. CH_RESET is the
220 * immediate abort path, which is what FSP r_canfd does too.
221 * HUM Ch 41 "CFDCnNCFG.NTSEG2" p 2706 */
223 if (halt_err != k_ra8_ok) {
224 return halt_err;
225 }
226
227 /* HUM Ch 41 "CFDCnNCFG" p 2705 */
228 reg->CFDC[0].NCFG = internal_pack_ncfg(&nominal);
229
230 if ((data_bitrate_bps != 0U) && (data_bitrate_bps > bitrate_bps)) {
231 /* Data phase: 8-bit prescaler ceiling = 256. */
232 ra8_canfd_timing_t data = {};
233 const ra8_err_t d_err =
234 internal_solve_timing(pclka_hz, data_bitrate_bps, k_ra8_canfd_data_prescaler_max, &data);
235 if (d_err != k_ra8_ok) {
236 /* Best-effort: return the channel to CH_OPERATION so the
237 * caller does not observe a half-applied edit. */
239 return d_err;
240 }
241 /* HUM Ch 41 "CFDCnDCFG" p 2785 */
242 reg->CFDC2[0].DCFG = internal_pack_dcfg(&data);
243 }
244
246 if (op_err != k_ra8_ok) {
247 return op_err;
248 }
249
250 ra8_log_info_val(s_tag, "set_bitrate bps", bitrate_bps);
251 return k_ra8_ok;
252}
253
275static ra8_err_t internal_program_data_phase(volatile r_canfd_t* reg, uint32_t data_bitrate)
276{
277 if (data_bitrate == 0U) {
279 }
280 uint32_t pclka_hz = 0U;
281 const ra8_err_t clk_err = ra8_cgc_get_clock_hz(k_ra8_clock_id_pclka, &pclka_hz);
282 if (clk_err != k_ra8_ok) {
283 return clk_err;
284 }
285 ra8_canfd_timing_t data = {};
286 const ra8_err_t err =
287 internal_solve_timing(pclka_hz, data_bitrate, k_ra8_canfd_data_prescaler_max, &data);
288 if (err != k_ra8_ok) {
289 return err;
290 }
291 /* HUM Ch 41 "CFDCnDCFG" p 2785 */ /* "CFDCnDCFG" */
292 reg->CFDC2[0].DCFG = internal_pack_dcfg(&data);
293 return k_ra8_ok;
294}
295
296ra8_err_t ra8_canfd_set_brs(uint8_t channel, uint32_t fast_bitrate)
297{
298 volatile r_canfd_t* reg = ra8_canfd(channel);
299 RA8_CHECK_NULL_PTR(reg, s_tag, "channel out of range");
300 return internal_program_data_phase(reg, fast_bitrate);
301}
static const char * s_tag
Logging / check tag.
Definition ra8_app.c:17
Annotation-attribute framework macros for ra8-firmware.
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).
ra8_err_t priv_ra8_canfd_internal_set_channel_mode(volatile r_canfd_t *reg, ra8_chmdc_mode_t mode)
Drive CFDC[0].CTR.CHMDC and wait for the matching status bit.
Definition ra8_canfd.c:138
CANFD Lite driver (bit-timing, TX, RX, error state).
CANFD controller register layout for the Renesas RA8D2.
@ k_ra8_chmdc_operation
Bus operation mode.
@ k_ra8_chmdc_reset
Reset mode.
@ k_ra8_cncfg_mask_ntseg2
[31:25] 7-bit TSEG2 field.
@ k_ra8_cncfg_mask_ntseg1
[24:17] 8-bit TSEG1 field.
@ k_ra8_cncfg_mask_nsjw
[16:10] 7-bit SJW field.
@ k_ra8_cncfg_mask_nbrp
[9:0] 10-bit prescaler field.
@ k_ra8_canfd_sjw_max
Nominal SJW cap.
@ k_ra8_canfd_prescaler_max
Largest valid nominal prescaler.
@ k_ra8_canfd_data_prescaler_max
Largest valid data prescaler (8-bit).
@ k_ra8_cncfg_shift_ntseg1
RA8 cncfg shift ntseg1.
@ k_ra8_cncfg_shift_nsjw
RA8 cncfg shift nsjw.
@ k_ra8_cncfg_shift_ntseg2
RA8 cncfg shift ntseg2.
@ k_ra8_cncfg_shift_nbrp
RA8 cncfg shift nbrp.
static volatile r_canfd_t * ra8_canfd(uint8_t channel)
Get pointer to CANFD instance N (0..1).
@ k_ra8_dcfg_shift_dbrp
RA8 dcfg shift dbrp.
@ k_ra8_dcfg_shift_dtseg1
RA8 dcfg shift dtseg1.
@ k_ra8_dcfg_shift_dtseg2
RA8 dcfg shift dtseg2.
@ k_ra8_dcfg_shift_dsjw
RA8 dcfg shift dsjw.
@ k_ra8_dcfg_mask_dbrp
[7:0] 8-bit DBRP.
@ k_ra8_dcfg_mask_dtseg1
[12:8] 5-bit DTSEG1.
@ k_ra8_dcfg_mask_dsjw
[27:24] 4-bit DSJW.
@ k_ra8_dcfg_mask_dtseg2
[19:16] 4-bit DTSEG2.
static uint32_t internal_pack_ncfg(const ra8_canfd_timing_t *t)
Pack a resolved timing triple into the CFDC[0].NCFG layout.
static uint32_t internal_pack_dcfg(const ra8_canfd_timing_t *t)
Pack a resolved timing triple into the CFDC2[0].DCFG layout.
ra8_err_t ra8_canfd_set_bitrate(uint8_t channel, uint32_t bitrate_bps, uint32_t data_bitrate_bps)
Programme nominal (and optional data) bit-timing registers.
ra8_err_t ra8_canfd_set_brs(uint8_t channel, uint32_t fast_bitrate)
Configure the CAN-FD bit-rate-switch (BRS) data-phase rate.
ra8_canfd_timing_search_t
Quanta-search window owned by the bit-timing solver.
@ k_ra8_canfd_tq_search_hi
Largest time-quanta count tried.
@ k_ra8_canfd_tq_search_lo
Smallest time-quanta count tried.
static ra8_err_t internal_solve_timing(uint32_t clock_hz, uint32_t bitrate_bps, uint32_t prescaler_max, ra8_canfd_timing_t *out)
Walk candidate TQ-per-bit counts until one yields an integer prescaler.
static ra8_err_t internal_program_data_phase(volatile r_canfd_t *reg, uint32_t data_bitrate)
Re-derive the data-phase timing triple and pack it into DCFG.
High-level Clock Generation Circuit driver.
ra8_err_t ra8_cgc_get_clock_hz(ra8_clock_id_t id, uint32_t *out_hz)
Query the current frequency of a clock-tree domain.
Definition ra8_cgc.c:132
@ k_ra8_clock_id_pclka
PCLKA.
Definition ra8_cgc.h:73
Validation and Error-Checking Macros for ra8-firmware.
#define RA8_CHECK_NULL_PTR(ptr, tag, message)
Reject nullptr pointer, returning k_ra8_err_null_ptr.
Definition ra8_check.h:243
Error Code Definitions for ra8-firmware.
@ k_ra8_err_invalid_arg
Invalid function argument.
Definition ra8_err.h:152
@ k_ra8_ok
Success – operation completed with all postconditions satisfied.
Definition ra8_err.h:119
ra8_err_codes_t ra8_err_t
Canonical error-return type used by every ra8-firmware API.
Definition ra8_err.h:546
Cross-translation-unit private helpers shared inside ra8_hal.
Lightweight Logging Interface for ra8-firmware.
#define ra8_log_info_val(tag, message, value)
RA8 log info val.
Definition ra8_log.h:366
volatile uint32_t DCFG
+0x000 Data Bitrate Config.
volatile uint32_t NCFG
+0x000 Nominal Bitrate Config.
r_canfd_cfdc_t CFDC[1]
CFDC register.
r_canfd_cfdc2_t CFDC2[1]
CFDC2 register (offset 0x100 (0x20)).
Resolved nominal / data phase bit-timing fields.
uint32_t sjw
Sync jump width (pre-subtract-1).
uint32_t tseg2
Phase segment 2 (pre-subtract-1).
uint32_t prescaler
Prescaler integer (pre-subtract-1).
uint32_t tseg1
Phase segment 1 (pre-subtract-1).