diff options
Diffstat (limited to 'software')
-rw-r--r-- | software/vectored_interrupts/Makefile | 10 | ||||
-rw-r--r-- | software/vectored_interrupts/vectored_interrupts.c | 270 | ||||
-rw-r--r-- | software/watchdog/.gitignore | 1 | ||||
-rw-r--r-- | software/watchdog/.unsupported-boards | 1 | ||||
-rw-r--r-- | software/watchdog/Makefile | 9 | ||||
-rw-r--r-- | software/watchdog/watchdog.c | 221 |
6 files changed, 512 insertions, 0 deletions
diff --git a/software/vectored_interrupts/Makefile b/software/vectored_interrupts/Makefile new file mode 100644 index 0000000..4365038 --- /dev/null +++ b/software/vectored_interrupts/Makefile @@ -0,0 +1,10 @@ +TARGET = vectored_interrupts +CFLAGS += -O2 -fno-builtin-printf -DVECT_IRQ + +BSP_BASE = ../../bsp + +ASM_SRCS += $(ENV_DIR)/ventry.S +C_SRCS += vectored_interrupts.c +C_SRCS += $(BSP_BASE)/drivers/plic/plic_driver.c + +include $(BSP_BASE)/env/common.mk diff --git a/software/vectored_interrupts/vectored_interrupts.c b/software/vectored_interrupts/vectored_interrupts.c new file mode 100644 index 0000000..cb6a864 --- /dev/null +++ b/software/vectored_interrupts/vectored_interrupts.c @@ -0,0 +1,270 @@ +// See LICENSE for license details. + +#include <stdio.h> +#include <stdlib.h> +#include "platform.h" +#include <string.h> +#include "plic/plic_driver.h" +#include "encoding.h" +#include <unistd.h> + +#ifndef _SIFIVE_COREPLEXIP_ARTY_H +#error 'global_interrupts' demo only supported for Coreplex IP Eval Kits +#endif + +// Global Instance data for the PLIC +// for use by the PLIC Driver. +plic_instance_t g_plic; + +// Structures for registering different interrupt handlers +// for different parts of the application. +typedef void (*interrupt_function_ptr_t) (void); +//array of function pointers which contains the PLIC +//interrupt handlers +interrupt_function_ptr_t g_ext_interrupt_handlers[PLIC_NUM_INTERRUPTS]; + +//ecall countdown +uint32_t ecall_countdown; +//ecall macro used to store argument in a0 +#define ECALL(arg) ({ \ + register uintptr_t a0 asm ("a0") = (uintptr_t)(arg); \ + asm volatile ("ecall" \ + : "+r" (a0) \ + : \ + : "memory"); \ + a0; \ +}) + + +const char * instructions_msg = " \ +\n\ + SIFIVE, INC.\n\ +E31/E51 Coreplex IP Eval Kit 'vectored_interrupts' demo. \n\ +\n\ +This demo demonstrates Vectored Interrupts capabilities of\n\ +the E31/E51 Coreplex. The vector table is defined in \n\ +bsp/env/ventry.S \n\ +Button 0 is a global external interrupt routed to the PLIC.\n\ +Button 1 is a local interrupt.\n\ +Every 10 seconds, an ECALL is made. \n\ +\n"; + +void print_instructions() { + + write (STDOUT_FILENO, instructions_msg, strlen(instructions_msg)); + +} + +void set_timer() { + static uint64_t then = 0; + + volatile uint64_t * mtime = (uint64_t*) (CLINT_CTRL_ADDR + CLINT_MTIME); + volatile uint64_t * mtimecmp = (uint64_t*) (CLINT_CTRL_ADDR + CLINT_MTIMECMP); + if(then != 0) { + //next timer irq is 1 second from previous + then += 1*RTC_FREQ; + } else{ //first time setting the timer + uint64_t now = *mtime; + then = now + 1*RTC_FREQ; + } + *mtimecmp = then; + + set_csr(mie, MIP_MTIP); +} + +/*Entry Point for Machine Timer Interrupt Handler*/ +/*called from bsp/env/ventry.s */ +void handle_m_time_interrupt(){ + static uint32_t onoff=1; + + clear_csr(mie, MIP_MTIP); + + //increment ecall_countdown + ecall_countdown++; + + // Set Green LED + if(onoff) { + GPIO_REG(GPIO_OUTPUT_VAL) |= (0x1 << GREEN_LED_OFFSET) ; + onoff=0; + }else { + GPIO_REG(GPIO_OUTPUT_VAL) &= ~((0x1 << GREEN_LED_OFFSET)) ; + onoff=1; + } + + set_timer(); + //re-enable button1 irq + set_csr(mie, MIP_MLIP(LOCAL_INT_BTN_1)); + +} + +/*Synchronous Trap Handler*/ +/*called from bsp/env/ventry.s */ +void handle_sync_trap(uint32_t arg0) { + uint32_t exception_code = read_csr(mcause); + + //check for machine mode ecall + if(exception_code == CAUSE_MACHINE_ECALL) { + //reset ecall_countdown + ecall_countdown = 0; + + //ecall argument is stored in a0 prior to + //ECALL instruction. + printf("ecall from M-mode: %d\n",arg0); + + //on exceptions, mepc points to the instruction + //which triggered the exception, in order to + //return to the next instruction, increment + //mepc + unsigned long epc = read_csr(mepc); + epc += 4; //return to next instruction + write_csr(mepc, epc); + + } else{ + printf("vUnhandled Trap:\n"); + _exit(1 + read_csr(mcause)); + } +} + +/*Entry Point for PLIC Interrupt Handler*/ +/*called from bsp/env/ventry.s */ +void handle_m_external_interrupt(){ + printf("In PLIC handler\n"); + plic_source int_num = PLIC_claim_interrupt(&g_plic); + if ((int_num >=1 ) && (int_num < PLIC_NUM_INTERRUPTS)) { + g_ext_interrupt_handlers[int_num](); + } + else { + exit(1 + (uintptr_t) int_num); + } + PLIC_complete_interrupt(&g_plic, int_num); +} + +//default empty PLIC handler +void invalid_global_isr() { + printf("Unexpected global interrupt!\n"); +} + +/* b0 global interrupt isr */ +/*called from handle_m_external_interrupt */ +void button_0_handler() { + static uint32_t onoff=1; + // Set Green LED + + printf("In Button 0 handler\n"); + + if(onoff) { + GPIO_REG(GPIO_OUTPUT_VAL) |= (0x1 << BLUE_LED_OFFSET) ; + onoff=0; + }else { + GPIO_REG(GPIO_OUTPUT_VAL) &= ~((0x1 << BLUE_LED_OFFSET)) ; + onoff=1; + } + + //clear irq - interrupt pending register is write 1 to clear + GPIO_REG(GPIO_FALL_IP) |= (1<<BUTTON_0_OFFSET); +} + +/*b1 local vectored irq handler */ +/*called from bsp/env/ventry.s */ +void handle_local_interrupt5() { + static uint32_t onoff=1; + // Set Green LED + + printf("In Button 1 handler\n"); + + if(onoff) { + GPIO_REG(GPIO_OUTPUT_VAL) |= (0x1 << RED_LED_OFFSET) ; + onoff=0; + }else { + GPIO_REG(GPIO_OUTPUT_VAL) &= ~((0x1 << RED_LED_OFFSET)) ; + onoff=1; + } + + //debounce by turning off until next timer tick + clear_csr(mie, MIP_MLIP(LOCAL_INT_BTN_1)); +} + +/*configures Button0 as a global gpio irq*/ +void b0_irq_init() { + + //dissable hw io function + GPIO_REG(GPIO_IOF_EN ) &= ~(1 << BUTTON_0_OFFSET); + + //set to input + GPIO_REG(GPIO_INPUT_EN) |= (1<<BUTTON_0_OFFSET); + GPIO_REG(GPIO_PULLUP_EN) |= (1<<BUTTON_0_OFFSET); + + //set to interrupt on falling edge + GPIO_REG(GPIO_FALL_IE) |= (1<<BUTTON_0_OFFSET); + + PLIC_init(&g_plic, + PLIC_CTRL_ADDR, + PLIC_NUM_INTERRUPTS, + PLIC_NUM_PRIORITIES); + + PLIC_enable_interrupt (&g_plic, INT_DEVICE_BUTTON_0); + PLIC_set_priority(&g_plic, INT_DEVICE_BUTTON_0, 2); + g_ext_interrupt_handlers[INT_DEVICE_BUTTON_0] = button_0_handler; +} + +/*configures Button1 as a local interrupt*/ +void b1_irq_init() { + + //enable the interrupt + set_csr(mie, MIP_MLIP(LOCAL_INT_BTN_1)); + +} + +/*turn down the brightness, and configure GPIO */ +void led_init() { + // Make sure people aren't blinded by LEDs connected here. + PWM0_REG(PWM_CMP0) = 0xFE; + PWM0_REG(PWM_CMP1) = 0xFF; + PWM0_REG(PWM_CMP2) = 0xFF; + PWM0_REG(PWM_CMP3) = 0xFF; + // Set up RGB LEDs for a visual. + GPIO_REG(GPIO_OUTPUT_EN) |= ((0x1<< RED_LED_OFFSET)| (0x1<< GREEN_LED_OFFSET)| (0x1<< BLUE_LED_OFFSET)); + GPIO_REG(GPIO_OUTPUT_VAL) &= ~((0x1<< RED_LED_OFFSET) | (0x1<< GREEN_LED_OFFSET) | (0x1<< BLUE_LED_OFFSET)); + +} + +int main(int argc, char **argv) +{ + uint32_t ecall_count = 0; + + //setup default global interrupt handler + for (int gisr = 0; gisr < PLIC_NUM_INTERRUPTS; gisr++){ + g_ext_interrupt_handlers[PLIC_NUM_INTERRUPTS] = invalid_global_isr; + } + + print_instructions(); + + led_init(); + b0_irq_init(); + b1_irq_init(); + + //initialize ecall_countdown + ecall_countdown = 0; + + // Set up machine timer interrupt. + set_timer(); + + // Enable Global (PLIC) interrupts. + set_csr(mie, MIP_MEIP); + + // Enable all interrupts + set_csr(mstatus, MSTATUS_MIE); + + + while(1){ + asm volatile ("wfi"); + //check if ecall_countdown is 10 + if(ecall_countdown == 10) { + ECALL(ecall_count++); + } + //otherwise wfi + } + + return 0; + +} diff --git a/software/watchdog/.gitignore b/software/watchdog/.gitignore new file mode 100644 index 0000000..35566c7 --- /dev/null +++ b/software/watchdog/.gitignore @@ -0,0 +1 @@ +demo_gpio diff --git a/software/watchdog/.unsupported-boards b/software/watchdog/.unsupported-boards new file mode 100644 index 0000000..1e65df5 --- /dev/null +++ b/software/watchdog/.unsupported-boards @@ -0,0 +1 @@ +coreplexip-e51-arty diff --git a/software/watchdog/Makefile b/software/watchdog/Makefile new file mode 100644 index 0000000..f614a4e --- /dev/null +++ b/software/watchdog/Makefile @@ -0,0 +1,9 @@ +TARGET = watchdog +CFLAGS += -O2 -fno-builtin-printf -DUSE_PLIC -DUSE_M_TIME + +BSP_BASE = ../../bsp + +C_SRCS += watchdog.c +C_SRCS += $(BSP_BASE)/drivers/plic/plic_driver.c + +include $(BSP_BASE)/env/common.mk diff --git a/software/watchdog/watchdog.c b/software/watchdog/watchdog.c new file mode 100644 index 0000000..672ed68 --- /dev/null +++ b/software/watchdog/watchdog.c @@ -0,0 +1,221 @@ +// See LICENSE for license details. + +#include <stdio.h> +#include <stdlib.h> +#include "platform.h" +#include <string.h> +#include "plic/plic_driver.h" +#include "encoding.h" +#include <unistd.h> +#include "stdatomic.h" + +void reset_demo (void); + +// Structures for registering different interrupt handlers +// for different parts of the application. +typedef void (*function_ptr_t) (void); +void no_interrupt_handler (void) {}; +function_ptr_t g_ext_interrupt_handlers[PLIC_NUM_INTERRUPTS]; + + +// Instance data for the PLIC. +plic_instance_t g_plic; + + +/** +* use mtime to wait for a specified number of ticks. +* async determins if this is a busy wait, or if +* an irq is scheduled +*/ +void mtime_wait( uint64_t ticks, uint32_t async) +{ + + volatile uint64_t * mtime = (uint64_t*) (CLINT_CTRL_ADDR + CLINT_MTIME); + uint64_t now = *mtime; + + //if async, schedule irq + if(async) { + volatile uint64_t * mtimecmp = (uint64_t*) (CLINT_CTRL_ADDR + CLINT_MTIMECMP); + uint64_t then = now + ticks; + *mtimecmp = then; + set_csr(mie, MIP_MTIP); + + } else { + //else busy wait + uint64_t then = now + ticks; + while(*mtime<then) {} + + } + +} + +/*Entry Point for PLIC Interrupt Handler*/ +void handle_m_ext_interrupt(){ + plic_source int_num = PLIC_claim_interrupt(&g_plic); + if ((int_num >=1 ) && (int_num < PLIC_NUM_INTERRUPTS)) { + g_ext_interrupt_handlers[int_num](); + } + else { + exit(1 + (uintptr_t) int_num); + } + PLIC_complete_interrupt(&g_plic, int_num); +} + +//global countdown timer +static uint32_t countdown = 10; +/*Entry Point for Machine Timer Interrupt Handler*/ +void handle_m_time_interrupt(){ + + //cleare the timer irq + clear_csr(mie, MIP_MTIP); + + //schedule next timer irq for 1 second + mtime_wait(1*RTC_FREQ, 1); + + //flash a led + GPIO_REG(GPIO_OUTPUT_VAL) ^= (0x1 << BLUE_LED_OFFSET); + + //print the count + printf("watchdog reset in %d\n", countdown--); +} + + +const char * instructions_msg = " \ +\n\ + SIFIVE, INC.\n\ +\n\ + 5555555555555555555555555\n\ + 5555 5555\n\ + 5555 5555\n\ + 5555 5555\n\ + 5555 5555555555555555555555\n\ + 5555 555555555555555555555555\n\ + 5555 5555\n\ + 5555 5555\n\ + 5555 5555\n\ +5555555555555555555555555555 55555\n\ + 55555 555555555 55555\n\ + 55555 55555 55555\n\ + 55555 5 55555\n\ + 55555 55555\n\ + 55555 55555\n\ + 55555 55555\n\ + 55555 55555\n\ + 55555 55555\n\ + 555555555\n\ + 55555\n\ + 5\n\ +\n\ +This application demonstrates the functionality of\n\ +the watchdog timer present in the HiFive1 AON peripheral.\n\ +\n\ +The Watchdog timer will expire in 10 seconds resulting in\n\ +a software reset.\n\ +\n\ +Press a key to prevent a reset\n\ +"; + +void print_instructions() { + + write (STDOUT_FILENO, instructions_msg, strlen(instructions_msg)); + +} + + +/** +* Flash the red led for a second, then set up +* blue for blinking during mtime irq +*/ +void led_init() { + + + // Set up the GPIOs such that the LED GPIO + // can be used as both Inputs and Outputs. + GPIO_REG(GPIO_INPUT_EN) &= ~((0x1<< RED_LED_OFFSET) | (0x1<< GREEN_LED_OFFSET) | (0x1 << BLUE_LED_OFFSET)) ; + GPIO_REG(GPIO_OUTPUT_EN) |= ((0x1<< RED_LED_OFFSET)| (0x1<< GREEN_LED_OFFSET)| (0x1<< BLUE_LED_OFFSET)); + GPIO_REG(GPIO_OUTPUT_VAL) |= ((0x1<< RED_LED_OFFSET) | (0x1<< GREEN_LED_OFFSET) | (0x1<< BLUE_LED_OFFSET)); + + //flash red led to indicate reset + GPIO_REG(GPIO_OUTPUT_VAL) &= ~(0x1 << RED_LED_OFFSET) ; + mtime_wait(1*RTC_FREQ,0); + GPIO_REG(GPIO_OUTPUT_VAL) |= (0x1 << RED_LED_OFFSET) ; +} + +/** +* initialize the watchdog to reset in +* 5 seconds +**/ +void watchdog_init() { + + +//reset in 10 seconds +AON_REG(AON_WDOGKEY) = AON_WDOGKEY_VALUE; +AON_REG(AON_WDOGCMP) = 11; +//wdogconfig: : wdogrsten | enablealways | reset to 0 | max scale +AON_REG(AON_WDOGKEY) = AON_WDOGKEY_VALUE; +AON_REG(AON_WDOGCFG) |= (AON_WDOGCFG_RSTEN | AON_WDOGCFG_ENALWAYS |\ + AON_WDOGCFG_ZEROCMP | AON_WDOGCFG_SCALE) ; + +} + +void reset_demo () { + + // Disable the machine & timer interrupts until setup is done. + clear_csr(mie, MIP_MEIP); + clear_csr(mie, MIP_MTIP); + + //enable uart input + UART0_REG(UART_REG_RXCTRL) = UART_RXEN; + + /************************************************************************** + * Set up the PLIC + *************************************************************************/ + PLIC_init(&g_plic, + PLIC_CTRL_ADDR, + PLIC_NUM_INTERRUPTS, + PLIC_NUM_PRIORITIES); + + for (int ii = 0; ii < PLIC_NUM_INTERRUPTS; ii ++){ + g_ext_interrupt_handlers[ii] = no_interrupt_handler; + } + + + led_init(); + print_instructions(); + watchdog_init(); + + // Enable the Machine-External bit in MIE + set_csr(mie, MIP_MEIP); + // Enable interrupts in general. + set_csr(mstatus, MSTATUS_MIE); +} + +int main(int argc, char **argv) +{ + + reset_demo(); + //schedule a 1 second timer + mtime_wait(1*RTC_FREQ,1); + + + while (1){ + char c; + if(((int32_t) UART0_REG(UART_REG_RXFIFO)) > 0){ + //flash green led to indicate Kick + GPIO_REG(GPIO_OUTPUT_VAL) &= ~(0x1 << GREEN_LED_OFFSET) ; + + printf("Feeding Watchdog.\nHiFive1 will reset in 10 seconds.\n"); + countdown = 10; + AON_REG(AON_WDOGKEY) = AON_WDOGKEY_VALUE; + AON_REG(AON_WDOGFEED) = AON_WDOGFEED_VALUE; + + //busy wait a bit so the user sees the led blink + mtime_wait(5000, 0); + //turn off led + GPIO_REG(GPIO_OUTPUT_VAL) |= (0x1 << GREEN_LED_OFFSET) ; + } + } + + return 0; + +} |