* refined clock configuration, uart works with clk_peri at xosc frequency

* fix pll_sys configuration
wch-ch32v003
Matt Knight 2 years ago committed by GitHub
parent f75a019aa5
commit f0e51f8302
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -1,25 +1,25 @@
const microzig = @import("microzig");
const regs = microzig.chip.regsisters;
const regs = microzig.chip.registers;
pub const gpio = @import("hal/gpio.zig");
pub const clocks = @import("hal/clocks.zig");
pub const multicore = @import("hal/multicore.zig");
pub const time = @import("hal/time.zig");
pub const uart = @import("hal/uart.zig");
pub const clock_config = clocks.GlobalConfiguration.init(.{
.sys = .{ .source = .src_xosc },
.sys = .{
.source = .pll_sys,
.freq = 125_000_000,
},
.ref = .{ .source = .src_xosc },
.peri = .{ .source = .clk_sys },
//.sys = .{
// .source = .pll_sys,
// .freq = 125_000_000,
//},
//.usb = .{ .source = .pll_usb },
//.adc = .{ .source = .pll_usb },
//.rtc = .{ .source = .pll_usb },
//.peri = .{ .source = .clk_sys },
});
pub fn init() void {
// TODO: resets need to be reviewed here
clock_config.apply();
gpio.reset();
}
pub fn getCpuId() u32 {

@ -83,6 +83,10 @@ pub const Generator = enum {
regs.CLOCKS.base_address,
);
fn getRegs(generator: Generator) *volatile GeneratorRegs {
return &generators[@enumToInt(generator)];
}
pub fn hasGlitchlessMux(generator: Generator) bool {
return switch (generator) {
.sys, .ref => true,
@ -93,7 +97,7 @@ pub const Generator = enum {
pub fn enable(generator: Generator) void {
switch (generator) {
.ref, .sys => {},
else => generators[@enumToInt(generator)].ctrl |= (1 << 11),
else => generator.getRegs().ctrl |= (1 << 11),
}
}
@ -101,14 +105,14 @@ pub const Generator = enum {
if (generator == .peri)
return;
generators[@enumToInt(generator)].div = div;
generator.getRegs().div = div;
}
pub fn getDiv(generator: Generator) u32 {
if (generator == .peri)
return 1;
return generators[@enumToInt(generator)].div;
return generator.getRegs().div;
}
// The bitfields for the *_SELECTED registers are actually a mask of which
@ -118,17 +122,17 @@ pub const Generator = enum {
//
// Some mention that this is only for the glitchless mux, so if it is non-glitchless then return true
pub fn selected(generator: Generator) bool {
return (0 != generators[@enumToInt(generator)].selected);
return (0 != generator.getRegs().selected);
}
pub fn clearSource(generator: Generator) void {
generators[@enumToInt(generator)].ctrl &= ~@as(u32, 0x3);
generator.getRegs().ctrl &= ~@as(u32, 0x3);
}
pub fn disable(generator: Generator) void {
switch (generator) {
.sys, .ref => {},
else => generators[@enumToInt(generator)].ctrl &= ~@as(u32, 1 << 11),
else => generator.getRegs().ctrl &= ~@as(u32, 1 << 11),
}
}
@ -147,15 +151,17 @@ pub const Generator = enum {
}
pub fn setSource(generator: Generator, src: u32) void {
const gen_regs = generator.getRegs();
const mask = ~@as(u32, 0x3);
const ctrl_value = generators[@enumToInt(generator)].ctrl;
generators[@enumToInt(generator)].ctrl = (ctrl_value & mask) | src;
const ctrl_value = gen_regs.ctrl;
gen_regs.ctrl = (ctrl_value & mask) | src;
}
pub fn setAuxSource(generator: Generator, auxsrc: u32) void {
const gen_regs = generator.getRegs();
const mask = ~@as(u32, 0x1e0);
const ctrl_value = generators[@enumToInt(generator)].ctrl;
generators[@enumToInt(generator)].ctrl = (ctrl_value & mask) | (auxsrc << 5);
const ctrl_value = gen_regs.ctrl;
gen_regs.ctrl = (ctrl_value & mask) | (auxsrc << 5);
}
};
@ -264,16 +270,20 @@ fn auxSrcValue(generator: Generator, source: Source) u32 {
}
pub const GlobalConfiguration = struct {
xosc_configured: bool,
sys: ?Configuration,
ref: ?Configuration,
usb: ?Configuration,
adc: ?Configuration,
rtc: ?Configuration,
peri: ?Configuration,
pll_sys: ?pll.Configuration,
pll_usb: ?pll.Configuration,
xosc_configured: bool = false,
sys: ?Configuration = null,
ref: ?Configuration = null,
usb: ?Configuration = null,
adc: ?Configuration = null,
rtc: ?Configuration = null,
peri: ?Configuration = null,
gpout0: ?Configuration = null,
gpout1: ?Configuration = null,
gpout2: ?Configuration = null,
gpout3: ?Configuration = null,
pll_sys: ?pll.Configuration = null,
pll_usb: ?pll.Configuration = null,
pub const Option = struct {
source: Source,
@ -287,19 +297,61 @@ pub const GlobalConfiguration = struct {
adc: ?Option = null,
rtc: ?Option = null,
peri: ?Option = null,
gpout0: ?Option = null,
gpout1: ?Option = null,
gpout2: ?Option = null,
gpout3: ?Option = null,
// TODO: allow user to configure PLLs to optimize for low-jitter, low-power, or manually specify
};
pub fn getFrequency(config: GlobalConfiguration, source: Source) ?u32 {
return switch (source) {
.src_xosc => xosc_freq,
.src_rosc => rosc_freq,
.clk_sys => if (config.sys) |sys_config| sys_config.output_freq else null,
.clk_usb => if (config.usb) |usb_config| usb_config.output_freq else null,
.clk_ref => if (config.ref) |ref_config| ref_config.output_freq else null,
.pll_sys => if (config.pll_sys) |pll_sys_config| pll_sys_config.frequency() else null,
.pll_usb => if (config.pll_usb) |pll_usb_config| pll_usb_config.frequency() else null,
else => null,
};
}
/// this function reasons about how to configure the clock system. It will
/// assert if the configuration is invalid
pub fn init(comptime opts: Options) GlobalConfiguration {
var xosc_configured = false;
var pll_sys: ?pll.Configuration = null;
var pll_usb: ?pll.Configuration = null;
var config = GlobalConfiguration{};
// I THINK that if either pll is configured here, then that means
// that the ref clock generator MUST use xosc to feed the PLLs?
config.ref = if (opts.ref) |ref_opts| ref_config: {
assert(ref_opts.source == .src_xosc);
break :ref_config .{
.generator = .ref,
.input = .{
.source = ref_opts.source,
.freq = config.getFrequency(ref_opts.source).?,
.src_value = srcValue(.ref, ref_opts.source),
.auxsrc_value = auxSrcValue(.ref, ref_opts.source),
},
.output_freq = config.getFrequency(ref_opts.source).?,
};
} else if (config.pll_sys != null or config.pll_usb != null) ref_config: {
config.xosc_configured = true;
break :ref_config .{
.generator = .ref,
.input = .{
.source = .src_xosc,
.freq = xosc_freq,
.src_value = srcValue(.ref, .src_xosc),
.auxsrc_value = auxSrcValue(.ref, .src_xosc),
},
.output_freq = xosc_freq,
};
} else null;
return GlobalConfiguration{
// the system clock can either use rosc, xosc, or the sys PLL
.sys = if (opts.sys) |sys_opts| sys_config: {
config.sys = if (opts.sys) |sys_opts| sys_config: {
var output_freq: ?u32 = null;
break :sys_config .{
.generator = .sys,
@ -315,7 +367,7 @@ pub const GlobalConfiguration = struct {
};
},
.src_xosc => input: {
xosc_configured = true;
config.xosc_configured = true;
output_freq = sys_opts.freq orelse xosc_freq;
assert(output_freq.? <= xosc_freq);
break :input .{
@ -326,16 +378,16 @@ pub const GlobalConfiguration = struct {
};
},
.pll_sys => input: {
xosc_configured = true;
config.xosc_configured = true;
output_freq = sys_opts.freq orelse 125_000_000;
assert(output_freq.? <= 125_000_000);
assert(output_freq.? == 125_000_000); // if using pll use 125MHz for now
// TODO: proper values for 125MHz
pll_sys = .{
.refdiv = 2,
.vco_freq = 1_440_000_000,
config.pll_sys = .{
.refdiv = 1,
.fbdiv = 125,
.postdiv1 = 6,
.postdiv2 = 5,
.postdiv2 = 2,
};
break :input .{
@ -352,21 +404,21 @@ pub const GlobalConfiguration = struct {
},
.output_freq = output_freq.?,
};
} else null,
} else null;
// to keep things simple for now, we'll make it so that the usb
// generator can only be hooked up to the usb PLL, and only have
// one configuration for the usb PLL
.usb = if (opts.usb) |usb_opts| usb_config: {
assert(pll_usb == null);
config.usb = if (opts.usb) |usb_opts| usb_config: {
assert(config.pll_usb == null);
assert(usb_opts.source == .pll_usb);
xosc_configured = true;
pll_usb = .{
config.xosc_configured = true;
config.pll_usb = .{
.refdiv = 1,
.vco_freq = 1_440_000_000,
.postdiv1 = 6,
.postdiv2 = 5,
.fbdiv = 40,
.postdiv1 = 5,
.postdiv2 = 2,
};
break :usb_config .{
@ -379,25 +431,7 @@ pub const GlobalConfiguration = struct {
},
.output_freq = 48_000_000,
};
} else null,
// I THINK that if either pll is configured here, then that means
// that the ref clock generator MUST use xosc to feed the PLLs?
.ref = if (opts.ref) |_|
unreachable // don't explicitly configure for now
else if (pll_sys != null or pll_usb != null) ref_config: {
xosc_configured = true;
break :ref_config .{
.generator = .ref,
.input = .{
.source = .src_xosc,
.freq = xosc_freq,
.src_value = srcValue(.ref, .src_xosc),
.auxsrc_value = auxSrcValue(.ref, .src_xosc),
},
.output_freq = xosc_freq,
};
} else null,
} else null;
// for the rest of the generators we'll make it so that they can
// either use the ROSC, XOSC, or sys PLL, with whatever dividing
@ -405,17 +439,24 @@ pub const GlobalConfiguration = struct {
// adc requires a 48MHz clock, so only ever let it get hooked up to
// the usb PLL
.adc = if (opts.adc) |adc_opts| adc_config: {
config.adc = if (opts.adc) |adc_opts| adc_config: {
assert(adc_opts.source == .pll_usb);
xosc_configured = true;
config.xosc_configured = true;
// TODO: some safety checks for overwriting this
pll_usb = .{
if (config.pll_usb) |pll_usb| {
assert(pll_usb.refdiv == 1);
assert(pll_usb.fbdiv == 40);
assert(pll_usb.postdiv1 == 5);
assert(pll_usb.postdiv2 == 2);
} else {
config.pll_usb = .{
.refdiv = 1,
.vco_freq = 1_440_000_000,
.postdiv1 = 6,
.postdiv2 = 5,
.fbdiv = 40,
.postdiv1 = 5,
.postdiv2 = 2,
};
}
break :adc_config .{
.generator = .usb,
@ -427,33 +468,49 @@ pub const GlobalConfiguration = struct {
},
.output_freq = 48_000_000,
};
} else null,
} else null;
.rtc = if (opts.rtc) |_|
config.rtc = if (opts.rtc) |_|
unreachable // TODO
else
null,
null;
.peri = if (opts.peri) |peri_opts| peri_config: {
config.peri = if (opts.peri) |peri_opts| peri_config: {
if (peri_opts.source == .src_xosc)
xosc_configured = true;
config.xosc_configured = true;
break :peri_config .{
.generator = .peri,
.input = .{
.source = peri_opts.source,
.freq = xosc_freq,
.freq = config.getFrequency(peri_opts.source) orelse
@compileError("you need to configure the source: " ++ @tagName(peri_opts.source)),
.src_value = srcValue(.peri, peri_opts.source),
.auxsrc_value = auxSrcValue(.peri, peri_opts.source),
},
.output_freq = xosc_freq,
.output_freq = if (peri_opts.freq) |output_freq|
output_freq
else
config.getFrequency(peri_opts.source).?,
};
} else null,
} else null;
.xosc_configured = xosc_configured,
.pll_sys = pll_sys,
.pll_usb = pll_usb,
};
config.gpout0 = if (opts.gpout0) |gpout0_opts| .{
.generator = .gpout0,
.input = .{
.source = gpout0_opts.source,
.freq = config.getFrequency(gpout0_opts.source) orelse
@compileError("you need to configure the source: " ++ @tagName(gpout0_opts.source)),
.src_value = srcValue(.gpout0, gpout0_opts.source),
.auxsrc_value = auxSrcValue(.gpout0, gpout0_opts.source),
},
.output_freq = if (gpout0_opts.freq) |output_freq|
output_freq
else
config.getFrequency(gpout0_opts.source).?,
} else null;
return config;
}
/// this is explicitly comptime to encourage the user to have separate
@ -476,7 +533,7 @@ pub const GlobalConfiguration = struct {
if (config.sys) |sys| switch (sys.input.source) {
.pll_usb, .pll_sys => {
regs.CLOCKS.CLK_SYS_CTRL.modify(.{ .SRC = 0 });
while (regs.CLOCKS.CLK_SYS_SELECTED.* == 0) {}
while (!Generator.sys.selected()) {}
},
else => {},
};
@ -484,7 +541,7 @@ pub const GlobalConfiguration = struct {
if (config.ref) |ref| switch (ref.input.source) {
.pll_usb, .pll_sys => {
regs.CLOCKS.CLK_REF_CTRL.modify(.{ .SRC = 0 });
while (regs.CLOCKS.CLK_REF_SELECTED.* == 0) {}
while (!Generator.ref.selected()) {}
},
else => {},
};
@ -495,10 +552,15 @@ pub const GlobalConfiguration = struct {
//// initialize clock generators
if (config.ref) |ref| ref.apply(config.sys);
if (config.sys) |sys| sys.apply(config.sys);
if (config.usb) |usb| usb.apply(config.sys);
if (config.adc) |adc| adc.apply(config.sys);
if (config.rtc) |rtc| rtc.apply(config.sys);
if (config.peri) |peri| peri.apply(config.sys);
if (config.gpout0) |gpout0| gpout0.apply(config.sys);
if (config.gpout1) |gpout1| gpout1.apply(config.sys);
if (config.gpout2) |gpout2| gpout2.apply(config.sys);
if (config.gpout3) |gpout3| gpout3.apply(config.sys);
}
};
@ -522,13 +584,12 @@ pub const Configuration = struct {
// source frequency has to be faster because dividing will always reduce.
assert(input.freq >= output_freq);
const div = @intCast(u32, (@intCast(u64, input.freq) << 8) / 8);
const div = @intCast(u32, (@intCast(u64, input.freq) << 8) / output_freq);
// check divisor
if (div > generator.getDiv())
generator.setDiv(div);
// TODO what _is_ an aux source?
if (generator.hasGlitchlessMux() and input.src_value == 1) {
generator.clearSource();
while (!generator.selected()) {}
@ -557,17 +618,18 @@ pub const Configuration = struct {
}
};
// NOTE: untested
pub fn countFrequencyKhz(source: Source, comptime clock_config: GlobalConfiguration) u32 {
const ref_freq = clock_config.ref.?.output_freq;
// wait for counter to be done
while (CLOCKS.FC0_STATUS.read().RUNNING == 1) {}
CLOCKS.FC0_REF_KHZ.* = ref_freq / 1000;
CLOCKS.FC0_INTERVAL.* = 10;
CLOCKS.FC0_MIN_KHZ.* = 0;
CLOCKS.FC0_MAX_KHZ.* = std.math.maxInt(u32);
CLOCKS.FC0_SRC.* = @enumToInt(source);
CLOCKS.FC0_REF_KHZ.raw = ref_freq / 1000;
CLOCKS.FC0_INTERVAL.raw = 10;
CLOCKS.FC0_MIN_KHZ.raw = 0;
CLOCKS.FC0_MAX_KHZ.raw = std.math.maxInt(u32);
CLOCKS.FC0_SRC.raw = @enumToInt(source);
while (CLOCKS.FC0_STATUS.read().DONE != 1) {}

@ -131,6 +131,10 @@ pub inline fn put(comptime gpio: u32, value: u1) void {
}
}
pub inline fn toggle(comptime gpio: u32) void {
regs.SIO.GPIO_OUT_XOR.raw = (1 << gpio);
}
pub inline fn setFunction(comptime gpio: u32, function: Function) void {
const pad_bank_reg = comptime std.fmt.comptimePrint("GPIO{}", .{gpio});
@field(regs.PADS_BANK0, pad_bank_reg).modify(.{

@ -7,9 +7,13 @@ const xosc_freq = microzig.board.xosc_freq;
pub const Configuration = struct {
refdiv: u6,
vco_freq: u32,
fbdiv: u32,
postdiv1: u3,
postdiv2: u3,
pub fn frequency(config: Configuration) u32 {
return @as(u32, xosc_freq) / config.refdiv * config.fbdiv / config.postdiv1 / config.postdiv2;
}
};
pub const PLL = enum {
@ -41,15 +45,15 @@ pub const PLL = enum {
}
pub fn apply(pll: PLL, comptime config: Configuration) void {
const pll_regs = pll.getRegs();
const ref_freq = xosc_freq / @as(u32, config.refdiv);
const fbdiv = @intCast(u12, config.vco_freq / ref_freq);
assert(fbdiv >= 16 and fbdiv <= 320);
assert(config.fbdiv >= 16 and config.fbdiv <= 320);
assert(config.postdiv1 >= 1 and config.postdiv1 <= 7);
assert(config.postdiv2 >= 1 and config.postdiv2 <= 7);
assert(config.postdiv2 <= config.postdiv1);
assert(ref_freq <= config.vco_freq / 16);
const pll_regs = pll.getRegs();
const ref_freq = xosc_freq / @as(u32, config.refdiv);
const vco_freq = ref_freq * config.fbdiv;
assert(ref_freq <= vco_freq / 16);
// 1. program reference clock divider
// 2. program feedback divider
@ -60,7 +64,7 @@ pub const PLL = enum {
// do not bother a PLL which is already configured
if (pll.isLocked() and
config.refdiv == pll_regs.cs.read().REFDIV and
fbdiv == pll_regs.fbdiv_int.read() and
config.fbdiv == pll_regs.fbdiv_int.read() and
config.postdiv1 == pll_regs.prim.read().POSTDIV1 and
config.postdiv2 == pll_regs.prim.read().POSTDIV2)
{
@ -71,7 +75,7 @@ pub const PLL = enum {
// load vco related dividers
pll_regs.cs.modify(.{ .REFDIV = config.refdiv });
pll_regs.fbdiv_int.modify(fbdiv);
pll_regs.fbdiv_int.modify(config.fbdiv);
// turn on PLL
pll_regs.pwr.modify(.{ .PD = 0, .VCOPD = 0 });

@ -0,0 +1,212 @@
const std = @import("std");
const microzig = @import("microzig");
const gpio = @import("gpio.zig");
const clocks = @import("clocks.zig");
const assert = std.debug.assert;
const regs = microzig.chip.registers;
pub const WordBits = enum {
five,
six,
seven,
eight,
};
pub const StopBits = enum {
one,
two,
};
pub const Parity = enum {
none,
even,
odd,
};
pub const Config = struct {
clock_config: clocks.GlobalConfiguration,
tx_pin: u32,
rx_pin: u32,
baud_rate: u32,
word_bits: WordBits = .eight,
stop_bits: StopBits = .one,
parity: Parity = .none,
};
pub const UartRegs = extern struct {
dr: u32,
rsr: u32,
reserved0: [4]u32,
fr: @typeInfo(@TypeOf(regs.UART0.UARTFR)).Pointer.child,
resertev1: [1]u32,
ilpr: u32,
ibrd: u32,
fbrd: u32,
lcr_h: @typeInfo(@TypeOf(regs.UART0.UARTLCR_H)).Pointer.child,
cr: @typeInfo(@TypeOf(regs.UART0.UARTCR)).Pointer.child,
ifls: u32,
imsc: u32,
ris: u32,
mis: u32,
icr: u32,
dmacr: @typeInfo(@TypeOf(regs.UART0.UARTDMACR)).Pointer.child,
periphid0: u32,
periphid1: u32,
periphid2: u32,
periphid3: u32,
cellid0: u32,
cellid1: u32,
cellid2: u32,
cellid3: u32,
padding: [4069]u32,
};
const uarts = @intToPtr(*volatile [2]UartRegs, regs.UART0.base_address);
comptime {
assert(@sizeOf(UartRegs) == (regs.UART1.base_address - regs.UART0.base_address));
}
pub const UART = enum {
uart0,
uart1,
const WriteError = error{};
pub const Writer = std.io.Writer(UART, WriteError, write);
pub fn writer(uart: UART) Writer {
return .{ .context = uart };
}
fn getRegs(uart: UART) *volatile UartRegs {
return &uarts[@enumToInt(uart)];
}
pub fn init(comptime id: u32, comptime config: Config) UART {
const uart: UART = switch (id) {
0 => .uart0,
1 => .uart1,
else => @compileError("there is only uart0 and uart1"),
};
assert(config.baud_rate > 0);
uart.reset();
const uart_regs = uart.getRegs();
const peri_freq = config.clock_config.peri.?.output_freq;
uart.setBaudRate(config.baud_rate, peri_freq);
uart.setFormat(config.word_bits, config.stop_bits, config.parity);
uart_regs.cr.modify(.{
.UARTEN = 1,
.TXE = 1,
.RXE = 1,
});
uart_regs.lcr_h.modify(.{ .FEN = 1 });
// - always enable DREQ signals -- no harm if dma isn't listening
uart_regs.dmacr.modify(.{
.TXDMAE = 1,
.RXDMAE = 1,
});
// TODO comptime assertions
gpio.setFunction(config.tx_pin, .uart);
gpio.setFunction(config.rx_pin, .uart);
return uart;
}
pub fn isReadable(uart: UART) bool {
return (0 == uart.getRegs().fr.read().RXFE);
}
pub fn isWritable(uart: UART) bool {
return (0 == uart.getRegs().fr.read().TXFF);
}
// TODO: implement tx fifo
pub fn write(uart: UART, payload: []const u8) WriteError!usize {
const uart_regs = uart.getRegs();
for (payload) |byte| {
while (!uart.isWritable()) {}
uart_regs.dr = byte;
}
return payload.len;
}
pub fn readWord(uart: UART) u8 {
const uart_regs = uart.getRegs();
while (!uart.isReadable()) {}
return @truncate(u8, uart_regs.dr);
}
pub fn reset(uart: UART) void {
switch (uart) {
.uart0 => {
regs.RESETS.RESET.modify(.{ .uart0 = 1 });
regs.RESETS.RESET.modify(.{ .uart0 = 0 });
while (regs.RESETS.RESET_DONE.read().uart0 != 1) {}
},
.uart1 => {
regs.RESETS.RESET.modify(.{ .uart1 = 1 });
regs.RESETS.RESET.modify(.{ .uart1 = 0 });
while (regs.RESETS.RESET_DONE.read().uart1 != 1) {}
},
}
}
pub fn setFormat(
uart: UART,
word_bits: WordBits,
stop_bits: StopBits,
parity: Parity,
) void {
const uart_regs = uart.getRegs();
uart_regs.lcr_h.modify(.{
.WLEN = switch (word_bits) {
.eight => @as(u2, 0b11),
.seven => @as(u2, 0b10),
.six => @as(u2, 0b01),
.five => @as(u2, 0b00),
},
.STP2 = switch (stop_bits) {
.one => @as(u1, 0),
.two => @as(u1, 1),
},
.PEN = if (parity != .none) @as(u1, 1) else @as(u1, 0),
.EPS = switch (parity) {
.even => @as(u1, 1),
.odd => @as(u1, 0),
else => @as(u1, 0),
},
});
}
fn setBaudRate(uart: UART, baud_rate: u32, peri_freq: u32) void {
assert(baud_rate > 0);
const uart_regs = uart.getRegs();
const baud_rate_div = (8 * peri_freq / baud_rate);
var baud_ibrd = baud_rate_div >> 7;
const baud_fbrd = if (baud_ibrd == 0) baud_fbrd: {
baud_ibrd = 1;
break :baud_fbrd 0;
} else if (baud_ibrd >= 65535) baud_fbrd: {
baud_ibrd = 65535;
break :baud_fbrd 0;
} else ((baud_rate_div & 0x7f) + 1) / 2;
uart_regs.ibrd = baud_ibrd;
uart_regs.fbrd = baud_fbrd;
// just want a write, don't want to change these values
uart_regs.lcr_h.modify(.{});
}
};

@ -44,14 +44,12 @@ pub const VectorTable = extern struct {
};
pub const registers = struct {
/// System Control Space
pub const SCS = struct {
pub const base_address = 0xe000e000;
/// System Tick Timer
pub const SysTick = struct {
/// address: 0xe000e010
/// SysTick Control and Status Register
pub const CTRL = @intToPtr(*volatile Mmio(32, packed struct {
@ -134,7 +132,6 @@ pub const registers = struct {
/// Nested Vectored Interrupt Controller
pub const NVIC = struct {
/// address: 0xe000e100
/// Interrupt Set Enable Register
pub const ISER = @intToPtr(*volatile u32, base_address + 0x100);
@ -158,7 +155,6 @@ pub const registers = struct {
/// System Control Block
pub const SCB = struct {
/// address: 0xe000ed00
pub const CPUID = @intToPtr(*volatile Mmio(32, packed struct {
REVISION: u4,
@ -343,7 +339,6 @@ pub const registers = struct {
/// Memory Protection Unit
pub const MPU = struct {
/// address: 0xe000ed90
/// MPU Type Register
pub const TYPE = @intToPtr(*volatile Mmio(32, packed struct {

Loading…
Cancel
Save