adc bindings, mostly there but not quite (#14)

wch-ch32v003
Matt Knight 2 years ago committed by GitHub
parent 29aee14fd2
commit 7c8d430237
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -63,6 +63,7 @@ fn root() []const u8 {
}
pub const Examples = struct {
adc: microzig.EmbeddedExecutable,
blinky: microzig.EmbeddedExecutable,
blinky_core1: microzig.EmbeddedExecutable,
gpio_clk: microzig.EmbeddedExecutable,

@ -0,0 +1,38 @@
//! This example takes periodic samples of the temperature sensor and
//! prints it to the UART using the stdlib logging facility.
const std = @import("std");
const microzig = @import("microzig");
const rp2040 = microzig.hal;
const adc = rp2040.adc;
const time = rp2040.time;
const temp_sensor: adc.Input = .temperature_sensor;
const uart_id = 0;
const baud_rate = 115200;
const uart_tx_pin = 0;
const uart_rx_pin = 1;
pub const log = rp2040.uart.log;
pub fn init() void {
rp2040.clock_config.apply();
rp2040.gpio.reset();
adc.init();
temp_sensor.init();
const uart = rp2040.uart.UART.init(uart_id, .{
.baud_rate = baud_rate,
.tx_pin = uart_tx_pin,
.rx_pin = uart_rx_pin,
.clock_config = rp2040.clock_config,
});
rp2040.uart.initLogger(uart);
}
pub fn main() void {
while (true) : (time.sleepMs(1000)) {
const sample = temp_sensor.read();
std.log.info("temp value: {}", .{sample});
}
}

@ -1,6 +1,7 @@
const microzig = @import("microzig");
const regs = microzig.chip.registers;
pub const adc = @import("hal/adc.zig");
pub const pins = @import("hal/pins.zig");
pub const gpio = @import("hal/gpio.zig");
pub const clocks = @import("hal/clocks.zig");

@ -0,0 +1,194 @@
//! NOTE: no settling time is needed when switching analog inputs
const std = @import("std");
const assert = std.debug.assert;
const microzig = @import("microzig");
const ADC = microzig.chip.registers.ADC;
const rp2040 = microzig.hal;
const gpio = rp2040.gpio;
const resets = rp2040.resets;
pub const temperature_sensor = struct {
pub inline fn init() void {
setTempSensorEnabled(true);
}
pub inline fn deinit() void {
setTempSensorEnabled(false);
}
pub inline fn readRaw() u16 {
return Input.read(.temperature_sensor);
}
// One-shot conversion returning the temperature in Celcius
pub inline fn read(comptime T: type, comptime Vref: T) T {
// TODO: consider fixed-point
const raw = @intToFloat(T, readRaw());
const voltage: T = Vref * raw / 0x0fff;
return (27.0 - ((voltage - 0.706) / 0.001721));
}
};
pub const Input = enum(u3) {
ain0,
ain1,
ain2,
ain3,
temperature_sensor,
/// Setup the GPIO pin as an ADC input
pub fn init(comptime input: Input) void {
switch (input) {
.temperature_sensor => setTempSensorEnabled(true),
else => {
const gpio_num = @as(u32, @enumToInt(input)) + 26;
gpio.setFunction(gpio_num, .@"null");
// TODO: implement these, otherwise adc isn't going to work.
//gpio.disablePulls(gpio_num);
//gpio.setInputEnabled(gpio_num, false);
},
}
}
/// Disables temp sensor, otherwise it does nothing if the input is
/// one of the others.
pub inline fn deinit(input: Input) void {
switch (input) {
.temperature_sensor => setTempSensorEnabled(true),
else => {},
}
}
/// Single-shot, blocking conversion
pub fn read(input: Input) u12 {
// TODO: not sure if setting these during the same write is
// correct
ADC.CS.modify(.{
.AINSEL = @enumToInt(input),
.START_ONCE = 1,
});
// wait for the
while (ADC.CS.read().READY == 0) {}
return ADC.RESULT.read();
}
};
pub const InputMask = InputMask: {
const enum_fields = @typeInfo(Input).Enum.fields;
var fields: [enum_fields.len]std.builtin.Type.StructField = undefined;
const default_value: u1 = 0;
for (enum_fields) |enum_field, i|
fields[i] = std.builtin.Type.StructField{
.name = enum_field.name,
.field_type = u1,
.default_value = &default_value,
.is_comptime = false,
.alignment = 1,
};
break :InputMask @Type(.{
.Struct = .{
.layout = .Packed,
.fields = &fields,
.backing_integer = std.meta.Int(.Unsigned, enum_fields.len),
.decls = &.{},
.is_tuple = false,
},
});
};
/// Initialize ADC hardware
pub fn init() void {
resets.reset(&.{.adc});
ADC.CS.write(.{
.EN = 1,
.TS_EN = 0,
.START_ONCE = 0,
.START_MANY = 0,
.READY = 0,
.ERR = 0,
.ERR_STICKY = 0,
.AINSEL = 0,
.RROBIN = 0,
});
while (ADC.CS.read().READY == 0) {}
}
/// Enable/disable ADC interrupt
pub inline fn irqSetEnabled(enable: bool) void {
// TODO: check if this works
ADC.INTE.write(.{ .FIFO = if (enable) @as(u1, 1) else @as(u1, 0) });
}
/// Select analog input for next conversion.
pub inline fn selectInput(input: Input) void {
ADC.CS.modify(.{ .AINSEL = @enumToInt(input) });
}
/// Get the currently selected analog input. 0..3 are GPIO 26..29 respectively,
/// 4 is the temperature sensor.
pub inline fn getSelectedInput() Input {
// TODO: ensure that the field shouldn't have other values
return @intToEnum(Input, ADC.CS.read().AINSEL);
}
/// Set to true to power on the temperature sensor.
pub inline fn setTempSensorEnabled(enable: bool) void {
ADC.CS.modify(.{ .TS_EN = if (enable) @as(u1, 1) else @as(u1, 0) });
}
/// Sets which of the inputs are to be run in round-robin mode. Setting all to
/// 0 will disable round-robin mode but `disableRoundRobin()` is provided so
/// the user may be explicit.
pub inline fn setRoundRobin(comptime enabled_inputs: InputMask) void {
ADC.CS.modify(.{ .RROBIN = @bitCast(u5, enabled_inputs) });
}
/// Disable round-robin sample mode.
pub inline fn disableRoundRobin() void {
ADC.CS.modify(.{ .RROBIN = 0 });
}
/// Enable free-running sample mode.
pub inline fn run(enable: bool) void {
ADC.CS.modify(.{ .START_MANY = if (enable) @as(u1, 1) else @as(u1, 0) });
}
/// TODO: implement
pub inline fn setClkDiv() void {}
/// The fifo is 4 samples long, if a conversion is completed and the FIFO is
/// full, the result is dropped.
pub const fifo = struct {
/// TODO: implement
pub inline fn setup() void {
// There are a number of considerations wrt DMA and error detection
}
/// TODO: implement
/// Return true if FIFO is empty.
pub inline fn isEmpty() bool {}
/// TODO: implement
/// Read how many samples are in the FIFO.
pub inline fn getLevel() u8 {}
/// TODO: implement
/// Pop latest result from FIFO.
pub inline fn get() u16 {}
/// TODO: implement
/// Block until result is available in FIFO, then pop it.
pub inline fn getBlocking() u16 {}
/// TODO: implement
/// Wait for conversion to complete then discard results in FIFO.
pub inline fn drain() void {}
};
Loading…
Cancel
Save