aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJosh Rahm <joshuarahm@gmail.com>2024-12-04 00:20:36 -0700
committerJosh Rahm <joshuarahm@gmail.com>2024-12-04 00:20:36 -0700
commitd6d04862de9126d0930ae1f4b95ff6077c6eda63 (patch)
treee5266c4017d41b1e77be8bbefa8abafb90fa1504
parent47885d62b689bececb58b7bf9479a5c1ff1c9b5c (diff)
downloadch573-d6d04862de9126d0930ae1f4b95ff6077c6eda63.tar.gz
ch573-d6d04862de9126d0930ae1f4b95ff6077c6eda63.tar.bz2
ch573-d6d04862de9126d0930ae1f4b95ff6077c6eda63.zip
Basic interrupts are working.
-rw-r--r--fdl/ch573/pfic.fdl109
-rw-r--r--fdl/ch573/systick.fdl72
-rw-r--r--include/isr_vector.h16
-rw-r--r--include/systick.h9
-rw-r--r--src/init.c6
-rw-r--r--src/main.c19
-rw-r--r--src/systick.c34
7 files changed, 263 insertions, 2 deletions
diff --git a/fdl/ch573/pfic.fdl b/fdl/ch573/pfic.fdl
new file mode 100644
index 0000000..13ed54f
--- /dev/null
+++ b/fdl/ch573/pfic.fdl
@@ -0,0 +1,109 @@
+import "ch573/common.fdl";
+
+/** Fiddle file for the Programmable Fast Interrupt Controller (PFIC) */
+package ch573.pfic {
+ location pfic_base = 0xE000E000;
+
+ using ch573.common;
+
+ bits interrupts : enum(32) {
+ [[ c: unqualified ]]
+ IRQ_SysTick = 0x1000,
+ };
+
+ /** Type definition for the PFIC structure */
+ type pfic_t : struct {
+ /** PFIC interrupt enable status register */
+ reg interrupt_enable_status(64) @0x00 : struct {
+ intensta_low : (32); // Interrupt enable status for interrupts 31:0
+ intensta_high : (32); // Interrupt enable status for interrupts 63:32
+ };
+
+ /** PFIC interrupt suspension status register */
+ reg interrupt_suspension_status(64) @0x20 : struct {
+ pendsta_low : (32); // Interrupt suspension status for interrupts 31:0
+ pendsta_high : (32); // Interrupt suspension status for interrupts 63:32
+ };
+
+ /** PFIC interrupt priority threshold configuration register */
+ reg interrupt_priority_threshold(32) @0x40 : struct {
+ threshold : (8); // Priority threshold setting
+ reserved(24);
+ };
+
+ /** PFIC fast interrupt service base address registers */
+ reg fast_interrupt_base_address(64) : struct {
+ irqid0 : (8); // IRQ ID for fast interrupt 0
+ offset0 : (24); // Offset address for fast interrupt 0
+ irqid1 : (8); // IRQ ID for fast interrupt 1
+ offset1 : (24); // Offset address for fast interrupt 1
+ };
+
+ reg fast_interrupt_base_address_2(64) : struct {
+ irqid2 : (8); // IRQ ID for fast interrupt 2
+ offset2 : (24); // Offset address for fast interrupt 2
+ irqid3 : (8); // IRQ ID for fast interrupt 3
+ offset3 : (24); // Offset address for fast interrupt 3
+ };
+
+ /** PFIC interrupt enable register */
+ reg interrupt_enable(64) @0x100 : struct {
+ enable_low : (32); // Enable for interrupts 31:0
+ enable_high : (32); // Enable for interrupts 63:32
+ };
+
+ /** PFIC interrupt disable register */
+ reg interrupt_disable(64) : struct {
+ disable_low : (32); // Disable for interrupts 31:0
+ disable_high : (32); // Disable for interrupts 63:32
+ };
+
+ /** PFIC interrupt pending set register */
+ reg interrupt_pending_set(64) : struct {
+ pendset_low : (32); // Pending set for interrupts 31:0
+ pendset_high : (32); // Pending set for interrupts 63:32
+ };
+
+ /** PFIC interrupt pending clear register */
+ reg interrupt_pending_clear(64) : struct {
+ pendreset_low : (32); // Pending clear for interrupts 31:0
+ pendreset_high : (32); // Pending clear for interrupts 63:32
+ };
+
+ /** PFIC interrupt activation status register */
+ reg interrupt_active_status(64) : struct {
+ active_low : (32); // Active status for interrupts 31:0
+ active_high : (32); // Active status for interrupts 63:32
+ };
+
+ /** PFIC interrupt priority configuration registers (IPRIORx) */
+ reg interrupt_priority_config(64) : struct {
+ priority_0_to_3 : (8); // Priority for interrupts 0-3
+ priority_4_to_7 : (8); // Priority for interrupts 4-7
+ priority_8_to_11 : (8); // Priority for interrupts 8-11
+ priority_12_to_15 : (8); // Priority for interrupts 12-15
+ priority_16_to_19 : (8); // Priority for interrupts 16-19
+ priority_20_to_23 : (8); // Priority for interrupts 20-23
+ priority_24_to_27 : (8); // Priority for interrupts 24-27
+ priority_28_to_31 : (8); // Priority for interrupts 28-31
+ };
+
+ /** PFIC system control register */
+ reg system_control(32) : struct {
+ hwstkctrl : bit_t; // Hardware stack enable control
+ nestctrl : bit_t; // Nesting interrupt control
+ sleepdeep : bit_t; // Low power consumption control
+ reserved(29);
+ };
+
+ /** PFIC vector table control register */
+ reg vector_table_control(32) : struct {
+ offset : bit_t; // Offset vector table address
+ reserved(31);
+ };
+ };
+
+ /** Define an instance of the PFIC at the base address */
+ instance pfic at pfic_base : pfic_t;
+};
+
diff --git a/fdl/ch573/systick.fdl b/fdl/ch573/systick.fdl
new file mode 100644
index 0000000..8e05685
--- /dev/null
+++ b/fdl/ch573/systick.fdl
@@ -0,0 +1,72 @@
+import "ch573/common.fdl";
+
+/** Package for SYSTICK (system counter). */
+package ch573.systick {
+ location systick_base = 0xE000F000;
+
+ using ch573.common;
+
+ type systick_t : struct {
+ reg cfg(32) @0x0 : struct {
+ /** Enable the systick. */
+ rw enabled : enable_t;
+
+ /** Enable the systick interrupt. */
+ rw interrupt_enable : enable_t;
+
+ /** Clock source for the systick. */
+ rw clock_source : enum(1) {
+ [[ c: unqualified ]]
+ SYSTICK_CLOCK_SOURCE_HCLK = 1,
+
+ [[ c: unqualified ]]
+ SYSTICK_CLOCK_SOURCE_HCLK_DIV_8 = 0,
+ };
+
+ reserved(5);
+
+ /** Write 1 to reload the systick. */
+ wo st_reload : (1);
+ reserved(23);
+ };
+
+ assert_pos(0x4);
+ union {
+ struct {
+ /** Lower 32 bits of the systick count. */
+ reg count_low(32);
+ assert_pos(0x8);
+
+ /** Upper 32 bits of the systick count. */
+ reg count_high(32);
+ };
+ /** Full 64 bits of the systick count. */
+ reg count(64);
+ };
+
+ assert_pos(0xC);
+ union {
+ struct {
+ /** Lower 32 bits of the systick reload value. */
+ reg reload_low(32);
+ assert_pos(0x10);
+ /** Upper 32 bits of the systick reload value. */
+ reg reload_high(32);
+ };
+ /** Full 64-bit systick reload value. */
+ reg reload(64);
+ };
+
+ reg (32) @0x14 : struct {
+ /** Software interrupt happened. (Set to 1 to trigger a software
+ * interrupt.) */
+ software_interrupt_flag : (1);
+
+ /** Counter interrupt happened. */
+ counter_interrupt_flag : (1);
+ reserved(30);
+ };
+ };
+
+ instance systick at systick_base : systick_t;
+};
diff --git a/include/isr_vector.h b/include/isr_vector.h
index 6059875..3d4070a 100644
--- a/include/isr_vector.h
+++ b/include/isr_vector.h
@@ -51,3 +51,19 @@ void irq_on_wdog_bat(void);
_real__irq_on_##name(); \
} \
static void __attribute__((noinline)) _real__irq_on_##name(void)
+
+inline static void enable_interrupts()
+{
+ int mstatus;
+ asm volatile ("csrr %0, mstatus" : "=r"(mstatus));
+ mstatus |= 0x88;
+ asm volatile ("csrw mstatus, %0" : : "r"(mstatus));
+}
+
+inline static void disable_interrupts()
+{
+ int mstatus;
+ asm volatile ("csrr %0, mstatus" : "=r"(mstatus));
+ mstatus &= ~0x88;
+ asm volatile ("csrw mstatus, %0" : : "r"(mstatus));
+}
diff --git a/include/systick.h b/include/systick.h
new file mode 100644
index 0000000..8933a31
--- /dev/null
+++ b/include/systick.h
@@ -0,0 +1,9 @@
+#pragma once
+
+#include <stdint.h>
+
+void set_systick(uint64_t systick_value);
+
+uint64_t get_systick();
+
+int systick_interrupt();
diff --git a/src/init.c b/src/init.c
index 5a0a7c3..3aacc66 100644
--- a/src/init.c
+++ b/src/init.c
@@ -1,12 +1,17 @@
#include <stddef.h>
#include <stdint.h>
+#include <stdio.h>
+#include "ch573/systick.h"
#include "clock.h"
#include "io.h"
#include "isr_vector.h"
void on_reset(void);
+#define SYSTICK_I CH573_SYSTICK__SYSTICK_T_INTF
+#define SYSTICK ch573_systick__systick
+
void __attribute__((weak, interrupt, __section__(".isr_vector.routines")))
default_irq_handler(void)
{
@@ -111,6 +116,7 @@ static __attribute((__section__(".sinit.1"))) void start(void)
init_data_segments();
/* Set the mtvec to the isr_vector. */
set_mtvec(&isr_vector);
+ enable_interrupts();
/* Initialize stdout. */
init_uart1_for_stdout();
diff --git a/src/main.c b/src/main.c
index 2bbd0b3..9f5808b 100644
--- a/src/main.c
+++ b/src/main.c
@@ -1,10 +1,10 @@
#include <math.h>
#include <stdint.h>
#include <stdio.h>
-#include "string.h"
#include "byte_math.h"
#include "ch573/gpio.h"
+#include "ch573/pfic.h"
#include "ch573/pwr.h"
#include "ch573/uart.h"
#include "clock.h"
@@ -13,8 +13,12 @@
#include "string.h"
#include "sysled.h"
#include "system.h"
+#include "systick.h"
#include "ws2812b.h"
+#define PFIC_I CH573_PFIC__PFIC_T_INTF
+#define PFIC ch573_pfic__pfic
+
#define GPIO_PORT_A ch573_gpio__gpio_port_a
#define GPIO_PORT_B ch573_gpio__gpio_port_b
#define GPIO_PORT CH573_GPIO__GPIO_PORT_T_INTF
@@ -203,14 +207,25 @@ int main(void)
{
char buf[N_LEDS * TOTAL_BYTES_PER_LED];
+ PFIC_I.vector_table_control.set(PFIC, 1);
+ PFIC->interrupt_priority_threshold = 0x10;
+ PFIC->interrupt_enable |= IRQ_SysTick;
+
+ printf(
+ "PFIC enable status 1: %08x\n",
+ (uint32_t)(PFIC->interrupt_enable_status));
+
set_system_clock_60Mhz();
+
+ set_systick(250000);
+
enable_sysled();
enable_spi();
size_t n = sizeof(buf);
struct ws2812b_buf ws_buf;
make_wsb2812b(&ws_buf, buf, n);
- ws_buf.byte_order = BYTE_ORDER_RGB;
+ ws_buf.byte_order = BYTE_ORDER_GRB;
rgb_t color;
uint32_t time = 0;
diff --git a/src/systick.c b/src/systick.c
new file mode 100644
index 0000000..506f6df
--- /dev/null
+++ b/src/systick.c
@@ -0,0 +1,34 @@
+#include "systick.h"
+
+#include <stdio.h>
+
+#include "ch573/systick.h"
+#include "isr_vector.h"
+
+#define SYSTICK_I CH573_SYSTICK__SYSTICK_T_INTF
+#define SYSTICK ch573_systick__systick
+
+void set_systick(uint64_t systick)
+{
+ SYSTICK_I.reload.set(SYSTICK, systick);
+ SYSTICK_I.cfg.st_reload.set(SYSTICK, 1);
+ SYSTICK_I.cfg.interrupt_enable.set(SYSTICK, 1);
+
+ SYSTICK_I.cfg.enabled.set(SYSTICK, ENABLED);
+}
+
+uint64_t get_systick()
+{
+ return ((uint64_t)SYSTICK_I.count_high.get(SYSTICK) << 32) |
+ SYSTICK_I.count_low.get(SYSTICK);
+}
+
+int systick_interrupt()
+{
+ return SYSTICK_I.counter_interrupt_flag.get(SYSTICK);
+}
+
+IRQ(systick)
+{
+ SYSTICK_I.counter_interrupt_flag.set(SYSTICK, 0);
+}