ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
main.c
Go to the documentation of this file.
1
68
69#include <stdint.h>
70
71#include "ra8_attributes.h"
72#include "ra8_board_ek_ra8d2.h"
73#include "ra8_boot_entry.h"
74#include "ra8_cgc.h"
75#include "ra8_err.h"
76#include "ra8_gpio_constants.h"
77#include "ra8_gpt.h"
78#include "ra8_isr.h"
79#include "ra8_mstp.h"
80#include "ra8_port_constants.h"
81#include "ra8_port_utils.h"
82#include "ra8_time.h"
83
105
120
135
147// TODO(board-rev): no public GTIOC0A on EK-RA8D2 v1; pins conflict with debug UART per UM. Use P105/P103/Pmod-GTIOC10A or a custom carrier board.
151
153static const uint8_t s_motor_3phase_msg_prefix[] = "duty UVW ";
154static const uint8_t s_motor_3phase_msg_sep[] = " ";
155static const uint8_t s_motor_3phase_msg_eol[] = "\r\n";
156
169
171static uint16_t s_motor_3phase_step;
172
191{
192 while (1) {
193 __asm__ volatile("wfi");
194 }
195}
196
225{
226 /* Use a Q16 representation of pi and 2*pi for the Bhaskara math. */
227 enum : uint64_t {
228 k_q16_pi = 205887ULL,
229 k_q16_two_pi = 411775ULL,
230 k_q16_5_pi_sq = 3236018ULL,
231 k_q16_one = 65536ULL,
232 k_q16_numer_k = 16ULL,
233 k_q16_denom_k = 4ULL,
234 };
235 const uint64_t period_u64 = k_motor_3phase_period;
236 const uint64_t half_period = k_motor_3phase_half_period;
237
238 for (uint16_t i = 0U; i < k_motor_3phase_sine_size; i++) {
239 const uint64_t theta = ((uint64_t)i * k_q16_two_pi) / k_motor_3phase_sine_size;
240 bool neg = false;
241 uint64_t x = theta;
242 if (x > k_q16_pi) {
243 x = x - k_q16_pi;
244 neg = true;
245 }
246 const uint64_t pi_minus_x = k_q16_pi - x;
247 const uint64_t numer = k_q16_numer_k * x * pi_minus_x;
248 const uint64_t denom_part = k_q16_denom_k * x * pi_minus_x;
249 const uint64_t denom = k_q16_5_pi_sq - denom_part;
250 const uint64_t sin_q16 = (denom > 0ULL) ? (numer / denom) : 0ULL;
251 const uint64_t scaled = (sin_q16 * half_period) / k_q16_one;
252 uint64_t duty = neg ? (half_period - scaled) : (half_period + scaled);
253 if (duty > period_u64) {
254 duty = period_u64;
255 }
256 s_motor_3phase_sine[i] = (uint32_t)duty;
257 }
258}
259
284{
285 ra8_err_t err =
287 if (err != k_ra8_ok) {
288 return err;
289 }
290 err = ra8_pfs_route_peripheral(s_motor_3phase_pin_v, k_ra8_psel_gpt0, "motor_3phase.gtioc1a");
291 if (err != k_ra8_ok) {
292 return err;
293 }
294 return ra8_pfs_route_peripheral(s_motor_3phase_pin_w, k_ra8_psel_gpt0, "motor_3phase.gtioc2a");
295}
296
319{
320 enum : uint8_t {
321 k_phase_count = 3U,
322 };
323 const ra8_gpt_pwm_pin_cfg_t pin_cfg = {
324 .output_enable = true,
325 .polarity = k_ra8_gpt_pol_active_high,
326 .stop_level = k_ra8_gpt_stop_low,
327 .disable_on_fault = k_ra8_gpt_disable_high_z,
328 };
329 const uint8_t channels[k_phase_count] = {
333 };
334 for (uint8_t i = 0U; i < k_phase_count; i++) {
335 ra8_err_t err = ra8_gpt_pwm_pin_configure(channels[i], k_ra8_gpt_pin_a, &pin_cfg);
336 if (err != k_ra8_ok) {
337 return err;
338 }
340 if (err != k_ra8_ok) {
341 return err;
342 }
343 }
344 return k_ra8_ok;
345}
346
387
412
434{
435 /* MSTP enable is now performed in internal_motor_3phase_init_clocks_and_led so
436 * the canonical CGC -> MSTP -> IOPORT -> TIME -> peripheral order is
437 * preserved (see audit_init_order). */
438 const ra8_gpt_three_phase_cfg_t three_phase_cfg = {
441 .prescaler = k_ra8_gpt_ps_div_1,
442 .period_counts = k_motor_3phase_period,
443 .initial_duty_u = k_motor_3phase_half_period,
444 .initial_duty_v = k_motor_3phase_half_period,
445 .initial_duty_w = k_motor_3phase_half_period,
446 };
447 if (ra8_gpt_three_phase_open(&three_phase_cfg) != k_ra8_ok) {
449 }
452 }
453
456
457 /* Initial test pattern: 50 % duty on all three phases. */
462 }
463}
464
488RA8_INTERNAL static uint32_t internal_motor_3phase_u32_to_dec(uint32_t value, uint8_t* buf)
489{
490 enum : uint8_t {
491 k_ascii_zero = 0x30U,
492 k_radix = 10U,
493 k_max_digits = 10U,
494 };
495 uint8_t tmp[k_max_digits];
496 uint32_t n = 0U;
497 if (value == 0U) {
498 buf[0] = k_ascii_zero;
499 return 1U;
500 }
501 while (value > 0U) {
502 tmp[n] = (uint8_t)(k_ascii_zero + (uint8_t)(value % k_radix));
503 n++;
504 value /= k_radix;
505 }
506 for (uint32_t i = 0U; i < n; i++) {
507 buf[i] = tmp[n - 1U - i];
508 }
509 return n;
510}
511
533RA8_INTERNAL static void
534internal_motor_3phase_print_duty(uint32_t u_duty, uint32_t v_duty, uint32_t w_duty)
535{
536 enum : uint8_t {
537 k_dec_buf = 12U,
538 };
539 uint8_t digits[k_dec_buf];
540 uint32_t n = 0U;
541
543 (size_t)(sizeof(s_motor_3phase_msg_prefix) - 1U));
544 n = internal_motor_3phase_u32_to_dec(u_duty, digits);
545 (void)ra8_board_uart_console_write(digits, (size_t)n);
547 (size_t)(sizeof(s_motor_3phase_msg_sep) - 1U));
548 n = internal_motor_3phase_u32_to_dec(v_duty, digits);
549 (void)ra8_board_uart_console_write(digits, (size_t)n);
551 (size_t)(sizeof(s_motor_3phase_msg_sep) - 1U));
552 n = internal_motor_3phase_u32_to_dec(w_duty, digits);
553 (void)ra8_board_uart_console_write(digits, (size_t)n);
555 (size_t)(sizeof(s_motor_3phase_msg_eol) - 1U));
556}
557
580RA8_INTERNAL static void
581internal_motor_3phase_advance(uint32_t* out_u, uint32_t* out_v, uint32_t* out_w)
582{
583 const uint16_t i_u = s_motor_3phase_step;
584 const uint16_t i_v =
586 const uint16_t i_w =
588 *out_u = s_motor_3phase_sine[i_u];
589 *out_v = s_motor_3phase_sine[i_v];
590 *out_w = s_motor_3phase_sine[i_w];
592}
593
605void main(void)
606{
610
612
613 uint32_t print_accum_ms = 0U;
614
615 while (1) {
616 uint32_t u_duty = 0U;
617 uint32_t v_duty = 0U;
618 uint32_t w_duty = 0U;
619
620 internal_motor_3phase_advance(&u_duty, &v_duty, &w_duty);
621
622 if (ra8_gpt_three_phase_set_duty(u_duty, v_duty, w_duty) != k_ra8_ok) {
623 break;
624 }
625
626 print_accum_ms += k_motor_3phase_update_ms;
627 if (print_accum_ms >= k_motor_3phase_print_period) {
628 print_accum_ms = 0U;
629 internal_motor_3phase_print_duty(u_duty, v_duty, w_duty);
631 }
632
634 }
635
637}
void main(void)
Secure fallback main entry point.
Definition main.c:37
static uint16_t s_motor_3phase_step
Current sine-table phase index (advances each update tick).
Definition main.c:171
static void internal_motor_3phase_print_duty(uint32_t u_duty, uint32_t v_duty, uint32_t w_duty)
Print "duty UVW <u> <v> <w>\\r\\n" over SCI8.
Definition main.c:534
static const ra8_port_pin_t s_motor_3phase_pin_v
Definition main.c:149
static const ra8_port_pin_t s_motor_3phase_pin_u
Placeholder pin identifiers for the three GTIOCnA outputs.
Definition main.c:148
static void internal_motor_3phase_init_pwm(void)
Open the GPT three-phase block, configure pins, prime duty.
Definition main.c:433
static const ra8_port_pin_t s_motor_3phase_pin_w
Definition main.c:150
static ra8_err_t internal_motor_3phase_pin_configure_all(void)
Configure GTIOR for the three GTIOCnA outputs (active high).
Definition main.c:318
static const uint8_t s_motor_3phase_msg_prefix[]
Diagnostic banner emitted every 100 ms.
Definition main.c:153
static void internal_motor_3phase_advance(uint32_t *out_u, uint32_t *out_v, uint32_t *out_w)
Advance the U/V/W phase by one update tick.
Definition main.c:581
static uint32_t internal_motor_3phase_u32_to_dec(uint32_t value, uint8_t *buf)
Convert a 32-bit unsigned integer into ASCII decimal.
Definition main.c:488
motor_3phase_sine_t
Sine LUT size and step bookkeeping.
Definition main.c:129
@ k_motor_3phase_sine_size
Motor 3phase sine size.
Definition main.c:130
@ k_motor_3phase_phase_120
256 / 3 ~= 85.3 (truncated).
Definition main.c:132
@ k_motor_3phase_phase_240
2 * 256 / 3 ~= 170.6.
Definition main.c:133
@ k_motor_3phase_sine_mask
Motor 3phase sine mask.
Definition main.c:131
motor_3phase_config_t
Compile-time settings for the three-phase motor demo.
Definition main.c:96
@ k_motor_3phase_revolution_ms
Motor 3phase revolution ms.
Definition main.c:103
@ k_motor_3phase_half_period
Motor 3phase half period.
Definition main.c:99
@ k_motor_3phase_baud
Motor 3phase baud.
Definition main.c:97
@ k_motor_3phase_print_period
Motor 3phase print period.
Definition main.c:102
@ k_motor_3phase_dead_time
Motor 3phase dead time.
Definition main.c:100
@ k_motor_3phase_update_ms
Motor 3phase update ms.
Definition main.c:101
@ k_motor_3phase_period
Motor 3phase period.
Definition main.c:98
static void internal_motor_3phase_panic_halt(void)
Halt forever in WFI – used as a panic stop on init failure.
Definition main.c:190
motor_3phase_channel_t
Channel assignments for U/V/W phases.
Definition main.c:115
@ k_motor_3phase_ch_u
Motor 3phase channel u.
Definition main.c:116
@ k_motor_3phase_ch_v
Motor 3phase channel v.
Definition main.c:117
@ k_motor_3phase_ch_w
Motor 3phase channel w.
Definition main.c:118
static ra8_err_t internal_motor_3phase_pins_init(void)
Route the three GTIOC pins.
Definition main.c:283
static void internal_motor_3phase_init_clocks_and_led(void)
Bring CGC + SysTick + LED1 up.
Definition main.c:364
static const uint8_t s_motor_3phase_msg_sep[]
Definition main.c:154
static void internal_motor_3phase_init_console(void)
Open the J-Link OB console (SCI8 @ 115200 8N1).
Definition main.c:406
static const uint8_t s_motor_3phase_msg_eol[]
Definition main.c:155
static void internal_motor_3phase_build_sine(void)
Build the sine LUT using a Bhaskara I approximation.
Definition main.c:224
static uint32_t s_motor_3phase_sine[k_motor_3phase_sine_size]
Compile-time sine table, normalised to 0..period.
Definition main.c:168
Annotation-attribute framework macros for ra8-firmware.
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).
Board-support layer for the Renesas EK-RA8D2 v1 evaluation kit.
ra8_err_t ra8_board_led_toggle(ra8_board_led_id_t led)
Toggle led's output state.
ra8_err_t ra8_board_led_init(ra8_board_led_id_t led)
Configure led as a digital output, initial level low (off).
@ k_ra8_board_led1
LED1, BLUE, P600 (jumper E27).
ra8_err_t ra8_board_uart_console_write(const uint8_t *data, size_t len)
Polled blocking write to the J-Link OB VCOM console.
ra8_err_t ra8_board_uart_console_init(uint32_t baud)
Configure SCI8 + PD02/PD03 as the debug-console UART.
Boot entry points shared between a vector table and its startup code.
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_cpuclk0
Cortex-M85 CPUCLK0.
Definition ra8_cgc.h:70
ra8_err_t ra8_cgc_init(void)
Configure the clock tree to a safe default.
Definition ra8_cgc.c:727
Error Code Definitions for ra8-firmware.
@ 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
PSEL codes for peripheral pin routing on the RA8D2.
@ k_ra8_psel_gpt0
00011b: GPT timer I/O (GTIOCnA/B).
Full-featured General PWM Timer (GPT) driver.
ra8_err_t ra8_gpt_pwm_pin_configure(uint8_t channel, ra8_gpt_pwm_pin_t pin, const ra8_gpt_pwm_pin_cfg_t *cfg)
Configure GTIOR for one PWM output pin.
Definition ra8_gpt.c:678
@ k_ra8_gpt_stop_low
OnDFLT = 0 -> stop level low.
Definition ra8_gpt.h:171
ra8_err_t ra8_gpt_dead_time_set(uint8_t channel, uint32_t rising_dt, uint32_t falling_dt)
Programme the dead-time value pair for complementary PWM.
Definition ra8_gpt.c:716
@ k_ra8_gpt_pin_a
GTIOCnA – compare register A path.
Definition ra8_gpt.h:146
@ k_ra8_gpt_disable_high_z
POEG fault -> Hi-Z.
Definition ra8_gpt.h:183
ra8_err_t ra8_gpt_three_phase_set_duty(uint32_t u_duty, uint32_t v_duty, uint32_t w_duty)
Atomically update U/V/W compare values via the shadow buffer.
Definition ra8_gpt.c:833
@ k_ra8_gpt_mode_triangle_pwm
Triangle-wave PWM symmetric.
Definition ra8_gpt.h:56
ra8_err_t ra8_gpt_three_phase_open(const ra8_gpt_three_phase_cfg_t *cfg)
Open three GPT channels as a phase-synchronized U/V/W triple.
Definition ra8_gpt.c:799
@ k_ra8_gpt_pol_active_high
Output is high while duty < count.
Definition ra8_gpt.h:160
@ k_ra8_gpt_ps_div_1
PCLKD / 1.
Definition ra8_gpt.h:66
NVIC + ICU IELSR allocator.
void ra8_isr_globals_enable(void)
Globally enable maskable interrupts (PRIMASK = 0).
Definition ra8_isr.c:439
Ref-counted Module Stop Control wrapper for the RA8D2.
ra8_err_t ra8_mstp_init(void)
Re-establish the ra8_mstp ref-count table from current hardware state.
Definition ra8_mstp.c:291
Typed Port / Pin Constants for the RA8D2 IOPORT Module.
ra8_port_pin_t
Packed (port << 8) | pin pin identifier.
@ k_ra8_port_4
RA8 port 4.
#define RA8_PIN(port, pin)
Build a ra8_port_pin_t from explicit port / pin indices.
@ k_ra8_pin_10
RA8 pin 10.
@ k_ra8_pin_9
RA8 pin 9.
@ k_ra8_pin_8
RA8 pin 8.
High-level GPIO helpers on top of the PORT + PFS register layer.
ra8_err_t ra8_pfs_route_peripheral(ra8_port_pin_t pin, ra8_psel_t psel, const char *owner)
Route a pin to a non-IRQ peripheral function via PFS.PSEL.
Definition gpio.c:238
SysTick-based tick counter, delay and timestamp helpers.
ra8_err_t ra8_time_init(uint32_t cpu_hz)
Initialise SysTick for a 1 kHz tick interrupt.
Definition ra8_time.c:59
void ra8_delay_ms(uint32_t ms)
Busy-wait for at least ms milliseconds.
Definition ra8_time.c:129
Configuration descriptor for ra8_gpt_pwm_pin_configure.
Definition ra8_gpt.h:199
Configuration descriptor for ra8_gpt_three_phase_open.
Definition ra8_gpt.h:238