[sw, tock] Added timer demo
Adds a simple timer demo that displays a binary counter on the FPGA LEDs
connected to GPIO pins 7-15 and prints "opentitan" in ASCII art over the
UART.
Signed-off-by: Jon Flatley <jflat@google.com>
diff --git a/sw/device/tock/boards/opentitan/src/counter_demo.rs b/sw/device/tock/boards/opentitan/src/counter_demo.rs
new file mode 100644
index 0000000..6f7a5e0
--- /dev/null
+++ b/sw/device/tock/boards/opentitan/src/counter_demo.rs
@@ -0,0 +1,88 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+//! A simple alarm implementation to display a binary counter over GPIO.
+
+use core::cell::Cell;
+use kernel::hil::time::{Alarm, AlarmClient, Frequency};
+use kernel::debug;
+
+pub struct CounterAlarm<'a, A: Alarm<'a>> {
+ alarm: &'a A,
+ /// The current count of the counter
+ count: Cell<u32>,
+ /// How frequently, in ms, to increment the counter
+ interval: Cell<u32>,
+ /// The pins to toggle in order
+ count_pins: &'a [usize],
+ /// Optional text to display over the UART
+ spash_text: &'a [&'a str],
+ /// A counter for lines of the optional text sent
+ spash_count: Cell<u32>,
+}
+
+fn ms_to_tick<'a, A: Alarm<'a>>(ms: u32) -> u32 {
+ let freq = <A::Frequency>::frequency() as u64;
+ let tick = freq * (ms as u64);
+
+ (tick / 1000) as u32
+}
+
+impl<'a, A: Alarm<'a>> CounterAlarm<'a, A> {
+ pub fn new(alarm: &'a A, pins: &'a [usize]) -> CounterAlarm<'a, A> {
+ CounterAlarm {
+ alarm: alarm,
+ count: Cell::new(0),
+ interval: Cell::new(0),
+ count_pins: pins,
+ spash_text: &[],
+ spash_count: Cell::new(0),
+ }
+ }
+
+ pub fn add_spash_text(&mut self, spash: &'a[&'a str]) {
+ self.spash_text = spash;
+ }
+
+ pub fn run(&self, interval_ms: u32) {
+ self.interval.set(ms_to_tick::<A>(interval_ms));
+ let next_trigger = self.alarm.now().wrapping_add(self.interval.get());
+ self.alarm.set_alarm(next_trigger);
+ }
+}
+
+impl<'a, A: Alarm<'a>> AlarmClient for CounterAlarm<'a, A> {
+ fn fired(&self) {
+ let mut count = self.count.get();
+
+ // Toggle GPIO pins for each bit in count
+ for pin in self.count_pins {
+ unsafe {
+ if count & 1 != 0 {
+ kernel::hil::gpio::Pin::set(&ibex::gpio::PORT[*pin])
+ } else {
+ kernel::hil::gpio::Pin::clear(&ibex::gpio::PORT[*pin])
+ }
+ }
+ count >>= 1;
+ }
+
+ // Hijack this timer to display optional text
+ if self.spash_count.get() < self.spash_text.len() as u32 {
+ debug!("{}", self.spash_text[self.spash_count.get() as usize]);
+ self.spash_count.set(self.spash_count.get() + 1);
+ }
+
+ // Reset the counter if there were any overflow bits
+ if count > 0 {
+ self.count.set(1);
+ } else {
+ self.count.set(self.count.get() + 1);
+ }
+
+ let next_trigger = self.alarm.now().wrapping_add(self.interval.get());
+
+ self.alarm.set_alarm(next_trigger);
+ }
+}
diff --git a/sw/device/tock/boards/opentitan/src/main.rs b/sw/device/tock/boards/opentitan/src/main.rs
index 2d31af1..a96a015 100644
--- a/sw/device/tock/boards/opentitan/src/main.rs
+++ b/sw/device/tock/boards/opentitan/src/main.rs
@@ -15,6 +15,8 @@
use kernel::{create_capability, debug, static_init};
use rv32i::csr;
+mod counter_demo;
+
pub mod io;
//
// Actual memory for holding the active process structures. Need an empty list
@@ -42,6 +44,28 @@
#[link_section = ".stack_buffer"]
pub static mut STACK_MEMORY: [u8; 0x1000] = [0; 0x1000];
+static OT_SPASH: &[&str] = &[
+ "######################################################################################################################################################",
+ "######################################################################################################################################################",
+ "######################################################################################################################################################",
+ "############```*###*```###############################################################################################################################",
+ "############```*###*```###############################################################################``*#############################################",
+ "########````````*#*```````*#################################################################*```######``*####```######################################",
+ "########````****##*****```*#################################################################*```############*```*########*################**##########",
+ "#####```````###########```````#########*``******####```****``*#####**```*`*###*```*#**`*##*````````##*```##````````*##*``````````###``````````*#######",
+ "#####***````##```````##````***########`*#######**###``#######`*###`#######``##*`*######`*###*```#####*```###*```*####*```####*```###```**##*```#######",
+ "##############```````#################`########*`####*#######*`##*`*********##*`#######``###*```#####*```####```*#####``######```###```*####```#######",
+ "#####***````##```````##*```***########`*#######*`###`*#######*`##*`###########*`#######``####```#####*```####```*####*``*####*```###```*####```#######",
+ "#####```````##*******##```````#########***###*`*####```*###*``####*`*####*`###*`#######`*####``````*##```####*``````##*``````````###```#####```#######",
+ "#######*````****###****````#*#############***#######`*##***##########***#######################****#############***######***##########################",
+ "########*```````*#*```````*#########################`*################################################################################################",
+ "############```*###*```###############################################################################################################################",
+ "############```*###*```###############################################################################################################################",
+ "######################################################################################################################################################",
+ "######################################################################################################################################################",
+ "######################################################################################################################################################",
+];
+
/// A structure representing this platform that holds references to all
/// capsules for this platform. We've included an alarm and console.
struct OpenTitan {
@@ -93,13 +117,6 @@
);
DynamicDeferredCall::set_global_instance(dynamic_deferred_caller);
- // Configure kernel debug gpios as early as possible
- kernel::debug::assign_gpios(
- Some(&ibex::gpio::PORT[7]), // First LED
- None,
- None,
- );
-
let chip = static_init!(ibex::chip::Ibex, ibex::chip::Ibex::new());
CHIP = Some(chip);
@@ -119,16 +136,6 @@
)
.finalize(());
- // Initialise the three GPIOs which are useful for debugging.
- hil::gpio::Pin::make_output(&ibex::gpio::PORT[8]);
- hil::gpio::Pin::set(&ibex::gpio::PORT[8]);
-
- hil::gpio::Pin::make_output(&ibex::gpio::PORT[9]);
- hil::gpio::Pin::set(&ibex::gpio::PORT[9]);
-
- hil::gpio::Pin::make_output(&ibex::gpio::PORT[10]);
- hil::gpio::Pin::set(&ibex::gpio::PORT[10]);
-
let alarm = &ibex::timer::TIMER;
alarm.setup();
@@ -159,6 +166,26 @@
// Create the debugger object that handles calls to `debug!()`.
components::debug_writer::DebugWriterComponent::new(uart_mux).finalize(());
+ let counter_demo_mux = static_init!(
+ capsules::virtual_alarm::VirtualMuxAlarm<'static, ibex::timer::RvTimer>,
+ capsules::virtual_alarm::VirtualMuxAlarm::new(mux_alarm)
+ );
+
+ let pins = &[7, 8, 9, 10, 11, 12, 13, 14];
+ for pin in pins {
+ hil::gpio::Pin::make_output(&ibex::gpio::PORT[*pin]);
+ }
+
+ let counter_demo_inst = static_init!(
+ counter_demo::CounterAlarm<'static, capsules::virtual_alarm::VirtualMuxAlarm<ibex::timer::RvTimer>>,
+ counter_demo::CounterAlarm::new(counter_demo_mux, pins)
+ );
+ counter_demo_inst.add_spash_text(OT_SPASH);
+
+ hil::time::Alarm::set_client(counter_demo_mux, counter_demo_inst);
+
+ counter_demo_inst.run(500);
+
debug!("OpenTitan initialisation complete. Entering main loop");
extern "C" {
@@ -183,8 +210,5 @@
&process_mgmt_cap,
);
- // Turn off the fourth GPIO so we know we got here
- hil::gpio::Pin::clear(&ibex::gpio::PORT[10]);
-
board_kernel.kernel_loop(&opentitan, chip, None, &main_loop_cap);
}