aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJosh Rahm <joshuarahm@gmail.com>2020-11-20 18:41:49 -0700
committerJosh Rahm <joshuarahm@gmail.com>2020-11-20 19:03:01 -0700
commitfd763486d875968941c77386e23936e817856c8e (patch)
treeed85ffe2d6c27b502d06aefa5e63244450bb7028
parent3b6018348d51c77f53adca90e498d7bf268c91c9 (diff)
downloadstm32l4-fd763486d875968941c77386e23936e817856c8e.tar.gz
stm32l4-fd763486d875968941c77386e23936e817856c8e.tar.bz2
stm32l4-fd763486d875968941c77386e23936e817856c8e.zip
Finally got a peripheral interrupt!
-rw-r--r--02-usart/include/arch/arm/arch.h2
-rw-r--r--02-usart/include/arch/x86_64/arch.h2
-rw-r--r--02-usart/include/core/irq.h58
-rw-r--r--02-usart/include/core/nvic.h46
-rw-r--r--02-usart/src/core/irq.c15
-rw-r--r--02-usart/src/main.c4
-rw-r--r--02-usart/src/mem.c19
-rw-r--r--02-usart/test_harness/fake_env.h1
-rw-r--r--02-usart/test_harness/test_harness.c23
-rw-r--r--02-usart/test_harness/test_harness.h26
-rw-r--r--02-usart/tests/test_irq.c37
11 files changed, 203 insertions, 30 deletions
diff --git a/02-usart/include/arch/arm/arch.h b/02-usart/include/arch/arm/arch.h
index a3b93dc..175c984 100644
--- a/02-usart/include/arch/arm/arch.h
+++ b/02-usart/include/arch/arm/arch.h
@@ -7,7 +7,7 @@
#define CORTEX_M4
-#define enable_interrupts() \
+#define enable_all_interrupts() \
asm volatile(" cpsie i ")
diff --git a/02-usart/include/arch/x86_64/arch.h b/02-usart/include/arch/x86_64/arch.h
index a39df9a..a93425d 100644
--- a/02-usart/include/arch/x86_64/arch.h
+++ b/02-usart/include/arch/x86_64/arch.h
@@ -4,7 +4,7 @@
#include "fake_env.h"
#define ARCH_PC
-#define enable_interrupts() do {} while(0)
+#define enable_all_interrupts() do {} while(0)
#define DMA1_BASE (load_fake_ahb1__() + 0x0)
#define DMA2_BASE (load_fake_ahb1__() + 0x400)
diff --git a/02-usart/include/core/irq.h b/02-usart/include/core/irq.h
index ae1126d..f2fe8d9 100644
--- a/02-usart/include/core/irq.h
+++ b/02-usart/include/core/irq.h
@@ -16,6 +16,42 @@ typedef enum {
#undef IRQ_RESERVED
} interrupt_t;
+/* Defines a set of interrupts so they may be enabled all at once. */
+typedef struct {
+ uint32_t sysirqs; /* System iterrupts. */
+ uint32_t irqs[8];
+} interrupt_set_t;
+
+inline static void interrupt_set_add(
+ interrupt_set_t* interrupt_set, interrupt_t interrupt)
+{
+ if (interrupt < 16) {
+ interrupt_set->sysirqs |= 1 << interrupt;
+ return;
+ }
+
+ interrupt -= 16;
+ int loc = interrupt / 32;
+ int off = interrupt % 32;
+
+ interrupt_set->irqs[loc] |= 1 << off;
+}
+
+inline static void interrupt_set_remove(
+ interrupt_set_t* interrupt_set, interrupt_t interrupt)
+{
+ if (interrupt < 16) {
+ interrupt_set->sysirqs &= ~(1 << interrupt);
+ return;
+ }
+
+ interrupt -= 16;
+ int loc = interrupt / 32;
+ int off = interrupt % 32;
+
+ interrupt_set->irqs[loc] &= ~(1 << off);
+}
+
/*
* The interrupt service routines. These link in the function `main` as the
* main function.
@@ -28,6 +64,26 @@ extern const void* vectors[];
*/
void unhandled_isr(uint8_t val);
-void isr_simple_pin_on();
+#define enable_interrupt(val) \
+ {interrupt_set_t itrset = { 0 }; \
+ interrupt_set_add(&itrset, val); \
+ enable_interrupts(&itrset);}
+
+#define disable_interrupt(val) \
+ {interrupt_set_t itrset = { 0 }; \
+ interrupt_set_add(&itrset, val); \
+ disable_interrupts(&itrset);}
+
+/*
+ * Enables the provided interrupt. Note that if the interrupt is one of the
+ * system interrupts (first 16) this function has no effect because those
+ * interrupts are always enabled.
+ */
+void enable_interrupts(interrupt_set_t* interrupts);
+
+/*
+ * Enables the provided interrupt
+ */
+void disable_interrupts(interrupt_set_t* interrupts);
#endif /* CORE_IRQ_H_ */
diff --git a/02-usart/include/core/nvic.h b/02-usart/include/core/nvic.h
new file mode 100644
index 0000000..c761574
--- /dev/null
+++ b/02-usart/include/core/nvic.h
@@ -0,0 +1,46 @@
+#ifndef NVIC_H_
+#define NVIC_H_
+
+#include "arch.h"
+#include "common.h"
+
+typedef __IO struct {
+#define nvic_intlinesnum (0x0F << 0)
+ uint32_t ict_r; /* Interrupt control type register. */
+
+ uint8_t reserved0[0xF8];
+
+ uint32_t ise_r[8];
+
+ uint8_t reserved1[0x60];
+
+ uint32_t ice_r[8];
+
+ uint8_t reserved2[0x60];
+
+ uint32_t isp_r[8];
+
+ uint8_t reserved3[0x60];
+
+ uint32_t icp_r[8];
+
+ uint8_t reserved4[0x60];
+
+ uint32_t iab_r[8];
+
+ uint8_t reserved5[0xE0];
+
+ uint32_t ip_r[60];
+} nvic_t;
+
+static_assert(offsetof(nvic_t, ise_r) == 0x00FC, "Offset check failed");
+static_assert(offsetof(nvic_t, ice_r) == 0x017C, "Offset check failed");
+static_assert(offsetof(nvic_t, isp_r) == 0x01FC, "Offset check failed");
+static_assert(offsetof(nvic_t, icp_r) == 0x027C, "Offset check failed");
+static_assert(offsetof(nvic_t, iab_r) == 0x02FC, "Offset check failed");
+static_assert(offsetof(nvic_t, ip_r) == 0x03FC, "Offset check failed");
+
+#define NVIC (* (nvic_t*) NVIC_BASE)
+
+
+#endif /* NVIC_H_ */
diff --git a/02-usart/src/core/irq.c b/02-usart/src/core/irq.c
index c9b93c2..47ad924 100644
--- a/02-usart/src/core/irq.c
+++ b/02-usart/src/core/irq.c
@@ -1,11 +1,10 @@
#include "core/irq.h"
#include "core/gpio.h"
+#include "core/nvic.h"
#include "arch.h"
#include "delay.h"
-#ifdef ARCH_STM32L4
-
#define IRQ_RESERVED(n)
#define IRQ(name, uname_, n) \
void WEAK name () { \
@@ -80,4 +79,14 @@ void unhandled_isr(uint8_t number)
}
}
-#endif
+void enable_interrupts(interrupt_set_t* interrupts)
+{
+ for (int i = 0; i < sizeof(NVIC.ise_r) / sizeof(uint32_t); ++ i)
+ NVIC.ise_r[i] = interrupts->irqs[i];
+}
+
+void disable_interrupts(interrupt_set_t* interrupts)
+{
+ for (int i = 0; i < sizeof(NVIC.ise_r) / sizeof(uint32_t); ++ i)
+ NVIC.ice_r[i] = interrupts->irqs[i];
+}
diff --git a/02-usart/src/main.c b/02-usart/src/main.c
index 6d22486..8b98cbf 100644
--- a/02-usart/src/main.c
+++ b/02-usart/src/main.c
@@ -6,6 +6,7 @@
#include "core/system.h"
#include "core/usart.h"
#include "core/nvic.h"
+#include "core/irq.h"
#include "delay.h"
#include "mem.h"
@@ -64,6 +65,9 @@ int main()
regset(USART2.c_r1, usart_txeie, 1);
regset(USART2.c_r1, usart_rxneie, 1);
usart_set_enabled(&USART2, USART_ENABLE_TX | USART_ENABLE_RX);
+
+
+ enable_interrupt(IRQ_USART2);
USART2.td_r = (uint8_t) 0x61;
__IO gpio_port_t* port_b = enable_gpio(GPIO_PORT_B);
diff --git a/02-usart/src/mem.c b/02-usart/src/mem.c
index 9fef8bc..65d8b60 100644
--- a/02-usart/src/mem.c
+++ b/02-usart/src/mem.c
@@ -1,6 +1,25 @@
+#include "arch.h"
#include "mem.h"
#include "common.h"
+#ifdef ARCH_STM32L4
+// Provide a definition for memset()
+
+void* memset(void* dest, int c, size_t n)
+{
+ uint8_t c8 = (uint8_t) c;
+ uint8_t* dest8 = (uint8_t*) dest;
+ uint8_t* to = dest8 + n;
+
+ while(dest8 < to) {
+ *(dest8 ++) = c8;
+ }
+
+ return dest;
+}
+
+#endif
+
// void memcpy_(void* dest, const void* src, size_t len)
// {
// uint8_t* dest_ = (uint8_t*) dest;
diff --git a/02-usart/test_harness/fake_env.h b/02-usart/test_harness/fake_env.h
index 09891bc..3cc6310 100644
--- a/02-usart/test_harness/fake_env.h
+++ b/02-usart/test_harness/fake_env.h
@@ -10,5 +10,6 @@ void* load_fake_apb2__();
void* load_fake_sram1__();
void* load_fake_sram2__();
void* load_fake_scb__();
+void* load_fake_nvic__();
#endif /* FAKE_ENV_H_ */
diff --git a/02-usart/test_harness/test_harness.c b/02-usart/test_harness/test_harness.c
index 9f7dd79..3a6d10a 100644
--- a/02-usart/test_harness/test_harness.c
+++ b/02-usart/test_harness/test_harness.c
@@ -46,7 +46,6 @@ static int execute_test(test_t* test)
int status;
int ec;
pid_t pid;
- const char* note = "";
snprintf(
fullname, sizeof(fullname), "%s::%s", iter->test_suite, iter->test_name);
@@ -66,17 +65,21 @@ static int execute_test(test_t* test)
return 1;
}
- ec = WEXITSTATUS(status);
- switch (ec) {
- case 0:
- printf("%s " GREEN "[PASS]" RESET "\n", fullname);
- return 0;
- case 11:
- note = " (SIGSEGV)";
- break;
+ if (WIFEXITED(status)) {
+ switch ((ec = WEXITSTATUS(status))) {
+ case 0:
+ printf("%s " GREEN "[PASS]" RESET "\n", fullname);
+ return 0;
+ default:
+ printf("%s " RED "[FAIL] %d" RESET "\n", fullname, ec);
+ return ec;
+ }
+ } else if (WIFSIGNALED(status)) {
+ int ec = WTERMSIG(status);
+ printf("%s " RED "[FAIL] signaled %d" RESET "\n", fullname, ec);
+ return ec;
}
- printf("%s " RED "[FAIL] %d%s" RESET "\n", fullname, ec, note);
return ec;
}
}
diff --git a/02-usart/test_harness/test_harness.h b/02-usart/test_harness/test_harness.h
index 0a218f8..74f3faa 100644
--- a/02-usart/test_harness/test_harness.h
+++ b/02-usart/test_harness/test_harness.h
@@ -20,20 +20,18 @@ typedef struct {
fprintf(stderr, fmt "\n", v1, v2)
#define FORMAT_STRING(v1, v2) \
- _Pragma("GCC diagnostic push"); \
- _Pragma("GCC diagnostic ignored \"-Wpointer-to-int-cast\""); \
- _Generic(v1, long: GENPR("%ld == %ld", v1, v2), \
- unsigned long: GENPR("%lu == %lu", v1, v2), \
- int: GENPR("%d == %d", v1, v2), \
- unsigned int: GENPR("%u == %u", v1, v2), \
- short: GENPR("%h == %h", v1, v2), \
- unsigned short: GENPR("%hu == %hu", v1, v2), \
- char: GENPR("%c == %c", v1, v2), \
- double: GENPR("%f == %f", v1, v2), \
- unsigned char: fprintf( \
- stderr, "%02x == %02x\n", (unsigned int) v1, (unsigned int) v2),\
- default: GENPR("%p == %p\n", v1, v2)); \
- _Pragma("GCC diagnostic pop")
+ fprintf( \
+ stderr, \
+ _Generic((v1), long: "%ld == %ld\n", \
+ unsigned long: "%lu == %lu\n", \
+ int: "%d == %d\n", \
+ unsigned int: "%u == %u\n", \
+ short: "%hu == %hu\n", \
+ unsigned short: "%hu == %hu\n", \
+ char: "%c == %c\n", \
+ double: "%f == %f\n", \
+ default: "%p == %p\n"), \
+ (v1), (v2)); \
#define TRY_PRINT_TYPE(v1, v2, type, fmt) \
else if (__builtin_types_compatible_p(typeof (v1), type)) { \
diff --git a/02-usart/tests/test_irq.c b/02-usart/tests/test_irq.c
new file mode 100644
index 0000000..89eea11
--- /dev/null
+++ b/02-usart/tests/test_irq.c
@@ -0,0 +1,37 @@
+#include "test_harness.h"
+
+#include "core/irq.h"
+#include "core/nvic.h"
+
+TEST(irq, nvic)
+{
+ interrupt_set_t is = { 0 };
+
+ interrupt_set_add(&is, IRQ_USART2);
+ interrupt_set_add(&is, IRQ_USART3);
+
+ enable_interrupts(&is);
+
+ ASSERT_EQ(is.irqs[1], 0xC0);
+ ASSERT_EQ(NVIC.ise_r[1], 0xC0);
+}
+
+TEST(irq, nvic_edgecase)
+{
+ interrupt_set_t is = { 0 };
+ interrupt_set_add(&is, IRQ_WWDG_IRQ);
+ interrupt_set_add(&is, IRQ_I2C1_ER);
+
+ enable_interrupts(&is);
+
+ ASSERT_EQ(is.irqs[0], 1);
+ ASSERT_EQ(NVIC.ise_r[0], 1);
+ ASSERT_EQ(is.irqs[1], 1);
+ ASSERT_EQ(NVIC.ise_r[1], 1);
+}
+
+TEST(irq, enable_single_interrupt)
+{
+ enable_interrupt(IRQ_USART2);
+ ASSERT_EQ(NVIC.ise_r[1], 0x40);
+}