AIK3NJJOAMB2QEYWLVK7B3E4ZMVGPBPPPZD2TGEBZCNM4Y6KI2XQC
IPLSYOCQIAQLB6HXL6YBJ5ZKKESCSRO7S7P5SF6I367M6HEJJRNQC
TXSGLYOVYQ77EG23PAVW62MBJRHS2WTVAVNQ3NYVBDGKNMSYS7DAC
RIKRRTK5ZNVTCDJBS2O54P36TSQXENEZ2DYXJ3WPFW7ZQ6CF4DMQC
GSIKHOXLB6QJELAYIGDFLRIG6DRIQFMZG6ZCQ54BNB7FIDBVI5PAC
6GJR2V3AYCEJWLBP2KMTWUNO332MG5OFEUNPCNSSNF5BJKXA3VTQC
UAB3QWX6I6PF4BRKRV6C7QKQMEYESRIALOFSOP3P5NAX2SHXABTQC
TKNYDMLX6VQSCEFDUY6VTMJPSOEOSWVC3YLDHHD7R4K4RVP3I7KAC
KIS6Z2AJQC7NOS2NAATBHNSM5G336VCPQKAZ6O5ALPNL7SSCBWDQC
const std = @import("std");
const microzig = @import("microzig");
const rp2xxx = microzig.hal;
const main = @import("main.zig");
const log = std.log.scoped(.motor);
pub const MotorDriverType = enum {
l293,
bdr6133,
};
pub fn MotorDriver(comptime driver: MotorDriverType) type {
switch (driver) {
.l293 => return L293,
.bdr6133 => return BDR6133,
}
}
const L293 = struct {
fwd: rp2xxx.gpio.Pin,
bwd: rp2xxx.gpio.Pin,
speed: rp2xxx.pwm.Pwm,
fn stop(self: @This()) void {
self.fwd.put(1);
self.bwd.put(1);
log.debug("Motor stopped", .{});
}
fn freerun(self: @This()) void {
self.speed.set_level(0);
log.debug("Motor in freerun mode", .{});
}
fn forward(self: @This(), level: u16) void {
self.fwd.put(1);
self.bwd.put(0);
self.speed.set_level(level);
log.debug("Motor is moving forward: {d}", .{level});
}
};
const BDR6133 = struct {};
pub fn tester(comptime driver: MotorDriverType) !void {
const md = MotorDriver(driver){
.fwd = main.pins.mot1,
.bwd = main.pins.mot2,
.speed = main.pins.speed,
};
const pwm_period = 125_000_000 / (@as(usize, main.cv.PWM_period) * 100 + 10_000);
var level: usize = pwm_period * 65 / 100;
while (level < pwm_period) : (level += pwm_period / 50) {
md.forward(@truncate(level));
rp2xxx.time.sleep_ms(2000);
{ // Measure Back-EMF
// Prepare ADC
rp2xxx.adc.apply(.{
.sample_frequency = null,
.round_robin = null,
.temp_sensor_enabled = false,
.fifo = .{ .dreq_enabled = false, .irq_enabled = false, .shift = false },
}); // apply calls enable
rp2xxx.adc.select_input(main.pins.m1emf);
// Switch to free running mode
md.freerun();
rp2xxx.time.sleep_us(100);
// Actual measurring
const emf = main.cv.manufacturer.emf;
rp2xxx.adc.start(.free_running);
var emfs: [std.math.maxInt(u8)]u12 = undefined;
for (0..emf.iterations) |i| {
if (rp2xxx.adc.fifo.has_overflowed()) {
std.log.debug("ADC overflow, clearing...", .{});
rp2xxx.adc.fifo.clear_overflowed();
}
while (rp2xxx.adc.fifo.is_empty()) {
asm volatile ("" ::: "memory");
}
emfs[i] = try rp2xxx.adc.fifo.pop();
// TODO: check if we should sort right here
}
// Measuring done, switch the motor back on
rp2xxx.adc.set_enabled(false);
md.forward(@truncate(level));
// std.log.debug("Raw EMF values: {any}", .{emfs});
// Sort results, so we can cut out the low and high part
std.sort.pdq(u12, emfs[0..emf.iterations], {}, less);
// Calculate average EMF
var sum: u32 = 0;
for (emf.low_cutoff..emf.iterations - emf.high_cutoff) |i| {
sum += emfs[i];
}
const m1emf = sum / (emf.iterations - emf.low_cutoff - emf.high_cutoff);
std.log.debug("Motor1 average EMF: {d}", .{m1emf});
}
}
}
fn less(_: void, a: u12, b: u12) bool {
return a < b;
}
{ // Motor stuff
const PWM_WRAP = 125_000_000 / (150 * 100 + 10_000) - 1; // 125MHz -> 25kHz
const EMF_ARRAY_SIZE = 100;
const EMF_CUTOUT = 15;
// TODO: max output is wrap+1 (5000)
// minimum: core1.c: get_initial_level
pins.speed.slice().set_wrap(PWM_WRAP);
pins.speed.slice().enable();
pins.speed.slice().set_phase_correct(false);
// pins.speed.slice().set_clk_div(1, 0);
// stop
pins.mot1.put(1);
pins.mot2.put(1);
std.log.debug("Motor stopped for {d} ms", .{1000});
rp2xxx.time.sleep_ms(1000);
pins.mot1.put(1);
pins.mot2.put(0);
// start
var level: usize = PWM_WRAP / 2;
while (level < PWM_WRAP) : (level += 100) {
pins.speed.set_level(@truncate(level));
rp2xxx.time.sleep_ms(2000);
{ // Measure Back-EMF
// Prepare ADC
rp2xxx.adc.apply(.{
.sample_frequency = null,
.round_robin = null,
.temp_sensor_enabled = false,
.fifo = .{ .dreq_enabled = false, .irq_enabled = false, .shift = false },
}); // apply calls enable
rp2xxx.adc.select_input(pins.m1emf);
// Actual measurring
rp2xxx.adc.start(.free_running);
var emfs: [EMF_ARRAY_SIZE]u12 = undefined;
for (0..EMF_ARRAY_SIZE) |i| {
if (rp2xxx.adc.fifo.has_overflowed()) {
std.log.debug("ADC overflow, clearing...", .{});
rp2xxx.adc.fifo.clear_overflowed();
}
while (rp2xxx.adc.fifo.is_empty()) {
asm volatile ("" ::: "memory");
}
emfs[i] = try rp2xxx.adc.fifo.pop();
// TODO: check if we should sort right here
}
// 125MHz -> 25kHz
pins.speed.slice().set_wrap(@intCast(125_000_000 / (@as(u32, cv.PWM_period) * 100 + 10_000) - 1));
pins.speed.slice().enable();
pins.speed.slice().set_phase_correct(false);
pins.speed.slice().set_clk_div(1, 0);
// Measuring done, switch the motor back on
rp2xxx.adc.set_enabled(false);
pins.speed.set_level(@truncate(level));
// std.log.debug("Raw EMF values: {any}", .{emfs});
// Sort results, so we can cut out the low and high part
std.sort.pdq(u12, &emfs, {}, less);
// try motor.tester(board.motor_driver);
// Calculate average EMF
var sum: u32 = 0;
for (EMF_CUTOUT..EMF_ARRAY_SIZE - EMF_CUTOUT) |i| {
sum += emfs[i];
}
const m1emf = sum / (EMF_ARRAY_SIZE - 2 * EMF_CUTOUT);
std.log.info("Motor1 average EMF: {d}", .{m1emf});
}
}
}
const BackEMF = packed struct {
iterations: u8 = 100, // Number of measurements to calculate Back-EMF
delay_us: u8 = 100, // Delay before measurement start
low_cutoff: u8 = 15, // Number of discarded elements on the low side
high_cutoff: u8 = 15, // Number of discarded elements on the high side
};