code wiki / (root) / nx_robot_signal.nx

nx_robot_signal.nx source

↩ module page · 94 lines · 4299 B

1// nx_robot_signal.nx -- SOVEREIGN hardware SIGNAL/REGISTER rung (the lowest robot-control layer, 2// beneath the driver). A real stepper driver chip (A4988/DRV8825 class) does NOT consume an integer 3// "output" -- it consumes a STEP/DIR digital WAVEFORM on GPIO pins: a rising edge on STEP = one motor 4// micro-step, DIR level = direction. A servo/ESC consumes a PWM bit pattern. This rung MODELS the 5// GPIO register and GENERATES those actual signals from the pulse plan (nx_robot_step, the rung above 6// feeds DOWN into this one) -- building from the hardware rung up. 100% Nishi, integer-only. 7// NEVER-BRICK (#26) BY CONSTRUCTION at the register level: 8// * a write to a NON-allowed pin is REJECTED (can't poke arbitrary hardware registers); 9// * a pin level is normalized to {0,1} (can't write a garbage register value); 10// * PWM duty is clamped to [0, PERIOD] (can't command an out-of-range / >100% pulse). 11// GPIO modeled as arrays (pins[bit]=level, allowed[bit]=writable?) = a faithful register model with 12// no undefined bit-twiddling. Binding pins[] to a real board's MMIO base address is the bench step. 13// license_tier: ORIGINAL expect_exit: 0 14import "nx_syscalls.nx" 15import "nx_robot_step.nx" 16 17const SIG_STEP_BIT: i64 = 0 18const SIG_DIR_BIT: i64 = 1 19const SIG_PWM_PERIOD: i64 = 100 20 21// allocate a GPIO model: returns pins[]; caller also passes an allowed[] mask. 22func gpio_new(nbits: i64) -> *i64 { 23 let p: *i64 = sys_mmap(nbits * 8) as *i64 24 var i: i64 = 0 25 while i < nbits { p[i] = 0; i = i + 1 } 26 return p 27} 28 29// FAIL-SAFE register write: reject disallowed pins, normalize level to {0,1}. returns level written, or -1 if rejected. 30func gpio_write(pins: *i64, allowed: *i64, bit: i64, level: i64) -> i64 { 31 if allowed[bit] == 0 { return 0 - 1 } // never-brick: only declared pins are writable 32 var v: i64 = 0 33 if level != 0 { v = 1 } // normalize -> no garbage register value 34 pins[bit] = v 35 return v 36} 37// UNSAFE raw write (neg-control only): no mask, no normalize -> models poking an arbitrary register. 38func gpio_write_raw(pins: *i64, bit: i64, level: i64) -> i64 { pins[bit] = level; return level } 39func gpio_read(pins: *i64, bit: i64) -> i64 { return pins[bit] } 40 41// Generate the STEP/DIR waveform for one axis from its pulse plan. Records every register write into 42// trace[] (flat: trace[2*k]=bit, trace[2*k+1]=level). Sets DIR once, then per planned pulse emits a 43// STEP rising edge (1) then falling edge (0). Returns the number of register writes. 44func gen_step_dir(puls: *i64, naxes: i64, nt: i64, axis: i64, dir: i64, 45 pins: *i64, allowed: *i64, trace: *i64) -> i64 { 46 var w: i64 = 0 47 var dlevel: i64 = 0 48 if dir < 0 { dlevel = 1 } 49 gpio_write(pins, allowed, SIG_DIR_BIT, dlevel) 50 trace[2 * w] = SIG_DIR_BIT; trace[2 * w + 1] = dlevel; w = w + 1 51 var t: i64 = 0 52 while t < nt { 53 if puls[t * naxes + axis] == 1 { 54 gpio_write(pins, allowed, SIG_STEP_BIT, 1) 55 trace[2 * w] = SIG_STEP_BIT; trace[2 * w + 1] = 1; w = w + 1 56 gpio_write(pins, allowed, SIG_STEP_BIT, 0) 57 trace[2 * w] = SIG_STEP_BIT; trace[2 * w + 1] = 0; w = w + 1 58 } 59 t = t + 1 60 } 61 return w 62} 63 64// count rising edges (0->1) of a given bit in a waveform trace = motor steps actually emitted 65func count_rising(trace: *i64, nw: i64, bit: i64) -> i64 { 66 var c: i64 = 0 67 var prev: i64 = 0 68 var k: i64 = 0 69 while k < nw { 70 if trace[2 * k] == bit { 71 let lv: i64 = trace[2 * k + 1] 72 if prev == 0 { if lv == 1 { c = c + 1 } } 73 prev = lv 74 } 75 k = k + 1 76 } 77 return c 78} 79 80// Generate a PWM bit pattern over SIG_PWM_PERIOD slots from a duty value; duty clamped to [0,PERIOD] 81// (never-brick). pat[i] = 1 for the first (clamped duty) slots. returns the actual (clamped) duty. 82func gen_pwm(duty: i64, pat: *i64) -> i64 { 83 var d: i64 = duty 84 if d < 0 { d = 0 } 85 if d > SIG_PWM_PERIOD { d = SIG_PWM_PERIOD } 86 var i: i64 = 0 87 while i < SIG_PWM_PERIOD { if i < d { pat[i] = 1 } else { pat[i] = 0 } i = i + 1 } 88 return d 89} 90func count_high(pat: *i64, n: i64) -> i64 { 91 var c: i64 = 0; var i: i64 = 0 92 while i < n { if pat[i] == 1 { c = c + 1 } i = i + 1 } 93 return c 94}