Add SPI read function (#38)

wch-ch32v003
Vlad Panazan 1 year ago committed by GitHub
parent b0e346608e
commit 08779dfe02
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

2
deps/microzig vendored

@ -1 +1 @@
Subproject commit dabc9325cdee394ff66e28c91803cb814954b157 Subproject commit ceaa9ddcb080d0687ce2109f23db7db376ac911e

@ -520,7 +520,7 @@ pub const GlobalConfiguration = struct {
if (@field(config, field.name)) |pin_config| { if (@field(config, field.name)) |pin_config| {
const gpio_num = @enumToInt(@field(Pin, field.name)); const gpio_num = @enumToInt(@field(Pin, field.name));
const pull = pin_config.pull orelse continue; const pull = pin_config.pull orelse continue;
if (comptime pin_config.getDirection() != .in) if (comptime pin_config.get_direction() != .in)
@compileError("Only input pins can have pull up/down enabled"); @compileError("Only input pins can have pull up/down enabled");
gpio.set_pull(gpio_num, pull); gpio.set_pull(gpio_num, pull);

@ -8,6 +8,7 @@ const gpio = @import("gpio.zig");
const clocks = @import("clocks.zig"); const clocks = @import("clocks.zig");
const resets = @import("resets.zig"); const resets = @import("resets.zig");
const time = @import("time.zig"); const time = @import("time.zig");
const util = @import("util.zig");
const SpiRegs = microzig.chip.types.peripherals.SPI0; const SpiRegs = microzig.chip.types.peripherals.SPI0;
@ -78,11 +79,11 @@ pub const SPI = enum {
return spi; return spi;
} }
pub fn is_writable(spi: SPI) bool { pub inline fn is_writable(spi: SPI) bool {
return spi.get_regs().SSPSR.read().TNF == 1; return spi.get_regs().SSPSR.read().TNF == 1;
} }
pub fn is_readable(spi: SPI) bool { pub inline fn is_readable(spi: SPI) bool {
return spi.get_regs().SSPSR.read().RNE == 1; return spi.get_regs().SSPSR.read().RNE == 1;
} }
pub fn transceive(spi: SPI, src: []const u8, dst: []u8) usize { pub fn transceive(spi: SPI, src: []const u8, dst: []u8) usize {
@ -106,7 +107,7 @@ pub const SPI = enum {
return src.len; return src.len;
} }
// Write len bytes directly from src to the SPI, and discard any data received back /// Write len bytes directly from src to the SPI, and discard any data received back
pub fn write(spi: SPI, src: []const u8) usize { pub fn write(spi: SPI, src: []const u8) usize {
const spi_regs = spi.get_regs(); const spi_regs = spi.get_regs();
// Write to TX FIFO whilst ignoring RX, then clean up afterward. When RX // Write to TX FIFO whilst ignoring RX, then clean up afterward. When RX
@ -114,26 +115,50 @@ pub const SPI = enum {
// push-on-full, but continues shifting. Safe if SSPIMSC_RORIM is not set. // push-on-full, but continues shifting. Safe if SSPIMSC_RORIM is not set.
for (src) |s| { for (src) |s| {
while (!spi.is_writable()) { while (!spi.is_writable()) {
std.log.debug("SPI not writable!", .{}); util.tight_loop_contents();
} }
spi_regs.SSPDR.write_raw(s); spi_regs.SSPDR.write_raw(s);
} }
// Drain RX FIFO, then wait for shifting to finish (which may be *after* // Drain RX FIFO, then wait for shifting to finish (which may be *after*
// TX FIFO drains), then drain RX FIFO again // TX FIFO drains), then drain RX FIFO again
while (spi.is_readable()) { while (spi.is_readable()) {
_ = spi_regs.SSPDR.raw; _ = spi_regs.SSPDR.read();
} }
while (spi.get_regs().SSPSR.read().BSY == 1) { while (spi_regs.SSPSR.read().BSY == 1) {
std.log.debug("SPI busy!", .{}); util.tight_loop_contents();
} }
while (spi.is_readable()) { while (spi.is_readable()) {
_ = spi_regs.SSPDR.raw; _ = spi_regs.SSPDR.read();
} }
// Don't leave overrun flag set // Don't leave overrun flag set
peripherals.SPI0.SSPICR.modify(.{ .RORIC = 1 }); peripherals.SPI0.SSPICR.modify(.{ .RORIC = 1 });
return src.len; return src.len;
} }
/// Read len bytes directly from the SPI to dst.
/// repeated_tx_data is output repeatedly on SO as data is read in from SI.
/// Generally this can be 0, but some devices require a specific value here,
/// e.g. SD cards expect 0xff
pub fn read(spi: SPI, repeated_tx_data: u8, dst: []u8) usize {
const spi_regs = spi.get_regs();
const fifo_depth = 8;
var rx_remaining = dst.len;
var tx_remaining = dst.len;
while (rx_remaining > 0 or tx_remaining > 0) {
if (tx_remaining > 0 and spi.is_writable() and rx_remaining < tx_remaining + fifo_depth) {
spi_regs.SSPDR.write_raw(repeated_tx_data);
tx_remaining -= 1;
}
if (rx_remaining > 0 and spi.is_readable()) {
const bytes = std.mem.asBytes(&spi_regs.SSPDR.read().DATA);
dst[dst.len - rx_remaining] = bytes[0];
rx_remaining -= 1;
}
}
return dst.len;
}
fn set_baudrate(spi: SPI, baudrate: u32, freq_in: u32) u64 { fn set_baudrate(spi: SPI, baudrate: u32, freq_in: u32) u64 {
const spi_regs = spi.get_regs(); const spi_regs = spi.get_regs();
// Find smallest prescale value which puts output frequency in range of // Find smallest prescale value which puts output frequency in range of
@ -143,9 +168,9 @@ pub const SPI = enum {
if (freq_in < (prescale + 2) * 256 * baudrate) break; if (freq_in < (prescale + 2) * 256 * baudrate) break;
} }
std.debug.assert(prescale <= 254); //Freq too low std.debug.assert(prescale <= 254); //Freq too low
// Find largest post-divide which makes output <= baudrate. Post-divide is // Find largest post-divide which makes output <= baudrate. Post-divide is
// an integer in the range 1 to 256 inclusive. // an integer in the range 1 to 256 inclusive.
var postdiv: u64 = 256; var postdiv: u64 = 256;
while (postdiv > 1) : (postdiv -= 1) { while (postdiv > 1) : (postdiv -= 1) {
if (freq_in / (prescale * (postdiv - 1)) > baudrate) break; if (freq_in / (prescale * (postdiv - 1)) > baudrate) break;

Loading…
Cancel
Save