]> git.sur5r.net Git - freertos/blobdiff - FreeRTOS/Demo/RISC-V-Qemu-sifive_e-FreedomStudio/main.c
Add a starting point for a Freedom Studio Risc V project.
[freertos] / FreeRTOS / Demo / RISC-V-Qemu-sifive_e-FreedomStudio / main.c
diff --git a/FreeRTOS/Demo/RISC-V-Qemu-sifive_e-FreedomStudio/main.c b/FreeRTOS/Demo/RISC-V-Qemu-sifive_e-FreedomStudio/main.c
new file mode 100644 (file)
index 0000000..af6c97f
--- /dev/null
@@ -0,0 +1,258 @@
+// See LICENSE for license details.\r
+\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#include "platform.h"\r
+#include <string.h>\r
+#include "plic/plic_driver.h"\r
+#include "encoding.h"\r
+#include <unistd.h>\r
+#include "stdatomic.h"\r
+\r
+void reset_demo (void);\r
+\r
+// Structures for registering different interrupt handlers\r
+// for different parts of the application.\r
+typedef void (*function_ptr_t) (void);\r
+\r
+void no_interrupt_handler (void) {};\r
+\r
+function_ptr_t g_ext_interrupt_handlers[PLIC_NUM_INTERRUPTS];\r
+\r
+\r
+// Instance data for the PLIC.\r
+\r
+plic_instance_t g_plic;\r
+\r
+\r
+/*Entry Point for PLIC Interrupt Handler*/\r
+void handle_m_ext_interrupt(){\r
+  plic_source int_num  = PLIC_claim_interrupt(&g_plic);\r
+  if ((int_num >=1 ) && (int_num < PLIC_NUM_INTERRUPTS)) {\r
+    g_ext_interrupt_handlers[int_num]();\r
+  }\r
+  else {\r
+    exit(1 + (uintptr_t) int_num);\r
+  }\r
+  PLIC_complete_interrupt(&g_plic, int_num);\r
+}\r
+\r
+\r
+/*Entry Point for Machine Timer Interrupt Handler*/\r
+void handle_m_time_interrupt(){\r
+\r
+  clear_csr(mie, MIP_MTIP);\r
+\r
+  // Reset the timer for 3s in the future.\r
+  // This also clears the existing timer interrupt.\r
+\r
+  volatile uint64_t * mtime       = (uint64_t*) (CLINT_CTRL_ADDR + CLINT_MTIME);\r
+  volatile uint64_t * mtimecmp    = (uint64_t*) (CLINT_CTRL_ADDR + CLINT_MTIMECMP);\r
+  uint64_t now = *mtime;\r
+  uint64_t then = now + 2 * RTC_FREQ;\r
+  *mtimecmp = then;\r
+\r
+  // read the current value of the LEDS and invert them.\r
+  uint32_t leds = GPIO_REG(GPIO_OUTPUT_VAL);\r
+\r
+  GPIO_REG(GPIO_OUTPUT_VAL) ^= ((0x1 << RED_LED_OFFSET)   |\r
+                               (0x1 << GREEN_LED_OFFSET) |\r
+                               (0x1 << BLUE_LED_OFFSET));\r
+  \r
+  // Re-enable the timer interrupt.\r
+  set_csr(mie, MIP_MTIP);\r
+\r
+}\r
+\r
+\r
+const char * instructions_msg = " \\r
+\n\\r
+                SIFIVE, INC.\n\\r
+\n\\r
+         5555555555555555555555555\n\\r
+        5555                   5555\n\\r
+       5555                     5555\n\\r
+      5555                       5555\n\\r
+     5555       5555555555555555555555\n\\r
+    5555       555555555555555555555555\n\\r
+   5555                             5555\n\\r
+  5555                               5555\n\\r
+ 5555                                 5555\n\\r
+5555555555555555555555555555          55555\n\\r
+ 55555           555555555           55555\n\\r
+   55555           55555           55555\n\\r
+     55555           5           55555\n\\r
+       55555                   55555\n\\r
+         55555               55555\n\\r
+           55555           55555\n\\r
+             55555       55555\n\\r
+               55555   55555\n\\r
+                 555555555\n\\r
+                   55555\n\\r
+                     5\n\\r
+\n\\r
+SiFive E-Series Software Development Kit 'demo_gpio' program.\n\\r
+Every 2 second, the Timer Interrupt will invert the LEDs.\n\\r
+(Arty Dev Kit Only): Press Buttons 0, 1, 2 to Set the LEDs.\n\\r
+Pin 19 (HiFive1) or A5 (Arty Dev Kit) is being bit-banged\n\\r
+for GPIO speed demonstration.\n\\r
+\n\\r
+ ";\r
+\r
+void print_instructions() {\r
+\r
+  write (STDOUT_FILENO, instructions_msg, strlen(instructions_msg));\r
+\r
+}\r
+\r
+#ifdef HAS_BOARD_BUTTONS\r
+void button_0_handler(void) {\r
+\r
+  // Red LED on\r
+  GPIO_REG(GPIO_OUTPUT_VAL) |= (0x1 << RED_LED_OFFSET);\r
+\r
+  // Clear the GPIO Pending interrupt by writing 1.\r
+  GPIO_REG(GPIO_RISE_IP) = (0x1 << BUTTON_0_OFFSET);\r
+\r
+};\r
+\r
+void button_1_handler(void) {\r
+\r
+  // Green LED On\r
+  GPIO_REG(GPIO_OUTPUT_VAL) |= (1 << GREEN_LED_OFFSET);\r
+\r
+  // Clear the GPIO Pending interrupt by writing 1.\r
+  GPIO_REG(GPIO_RISE_IP) = (0x1 << BUTTON_1_OFFSET);\r
+\r
+};\r
+\r
+\r
+void button_2_handler(void) {\r
+\r
+  // Blue LED On\r
+  GPIO_REG(GPIO_OUTPUT_VAL) |= (1 << BLUE_LED_OFFSET);\r
+\r
+  GPIO_REG(GPIO_RISE_IP) = (0x1 << BUTTON_2_OFFSET);\r
+\r
+};\r
+#endif\r
+\r
+void reset_demo (){\r
+\r
+  // Disable the machine & timer interrupts until setup is done.\r
+\r
+  clear_csr(mie, MIP_MEIP);\r
+  clear_csr(mie, MIP_MTIP);\r
+\r
+  for (int ii = 0; ii < PLIC_NUM_INTERRUPTS; ii ++){\r
+    g_ext_interrupt_handlers[ii] = no_interrupt_handler;\r
+  }\r
+\r
+#ifdef HAS_BOARD_BUTTONS\r
+  g_ext_interrupt_handlers[INT_DEVICE_BUTTON_0] = button_0_handler;\r
+  g_ext_interrupt_handlers[INT_DEVICE_BUTTON_1] = button_1_handler;\r
+  g_ext_interrupt_handlers[INT_DEVICE_BUTTON_2] = button_2_handler;\r
+#endif\r
+\r
+  print_instructions();\r
+\r
+#ifdef HAS_BOARD_BUTTONS\r
+\r
+  // Have to enable the interrupt both at the GPIO level,\r
+  // and at the PLIC level.\r
+  PLIC_enable_interrupt (&g_plic, INT_DEVICE_BUTTON_0);\r
+  PLIC_enable_interrupt (&g_plic, INT_DEVICE_BUTTON_1);\r
+  PLIC_enable_interrupt (&g_plic, INT_DEVICE_BUTTON_2);\r
+\r
+  // Priority must be set > 0 to trigger the interrupt.\r
+  PLIC_set_priority(&g_plic, INT_DEVICE_BUTTON_0, 1);\r
+  PLIC_set_priority(&g_plic, INT_DEVICE_BUTTON_1, 1);\r
+  PLIC_set_priority(&g_plic, INT_DEVICE_BUTTON_2, 1);\r
+\r
+  GPIO_REG(GPIO_RISE_IE) |= (1 << BUTTON_0_OFFSET);\r
+  GPIO_REG(GPIO_RISE_IE) |= (1 << BUTTON_1_OFFSET);\r
+  GPIO_REG(GPIO_RISE_IE) |= (1 << BUTTON_2_OFFSET);\r
+\r
+#endif\r
+\r
+    // Set the machine timer to go off in 3 seconds.\r
+    // The\r
+    volatile uint64_t * mtime       = (uint64_t*) (CLINT_CTRL_ADDR + CLINT_MTIME);\r
+    volatile uint64_t * mtimecmp    = (uint64_t*) (CLINT_CTRL_ADDR + CLINT_MTIMECMP);\r
+    uint64_t now = *mtime;\r
+    uint64_t then = now + 2*RTC_FREQ;\r
+    *mtimecmp = then;\r
+\r
+    // Enable the Machine-External bit in MIE\r
+    set_csr(mie, MIP_MEIP);\r
+\r
+    // Enable the Machine-Timer bit in MIE\r
+    set_csr(mie, MIP_MTIP);\r
+\r
+    // Enable interrupts in general.\r
+    set_csr(mstatus, MSTATUS_MIE);\r
+}\r
+\r
+int main(int argc, char **argv)\r
+{\r
+  // Set up the GPIOs such that the LED GPIO\r
+  // can be used as both Inputs and Outputs.\r
+  \r
+\r
+#ifdef HAS_BOARD_BUTTONS\r
+  GPIO_REG(GPIO_OUTPUT_EN)  &= ~((0x1 << BUTTON_0_OFFSET) | (0x1 << BUTTON_1_OFFSET) | (0x1 << BUTTON_2_OFFSET));\r
+  GPIO_REG(GPIO_PULLUP_EN)  &= ~((0x1 << BUTTON_0_OFFSET) | (0x1 << BUTTON_1_OFFSET) | (0x1 << BUTTON_2_OFFSET));\r
+  GPIO_REG(GPIO_INPUT_EN)   |=  ((0x1 << BUTTON_0_OFFSET) | (0x1 << BUTTON_1_OFFSET) | (0x1 << BUTTON_2_OFFSET));\r
+#endif\r
+\r
+  GPIO_REG(GPIO_INPUT_EN)    &= ~((0x1<< RED_LED_OFFSET) | (0x1<< GREEN_LED_OFFSET) | (0x1 << BLUE_LED_OFFSET)) ;\r
+  GPIO_REG(GPIO_OUTPUT_EN)   |=  ((0x1<< RED_LED_OFFSET)| (0x1<< GREEN_LED_OFFSET) | (0x1 << BLUE_LED_OFFSET)) ;\r
+  GPIO_REG(GPIO_OUTPUT_VAL)  |=   (0x1 << BLUE_LED_OFFSET) ;\r
+  GPIO_REG(GPIO_OUTPUT_VAL)  &=  ~((0x1<< RED_LED_OFFSET) | (0x1<< GREEN_LED_OFFSET)) ;\r
+\r
+  \r
+  // For Bit-banging with Atomics demo.\r
+  \r
+  uint32_t bitbang_mask = 0;\r
+#ifdef _SIFIVE_HIFIVE1_H\r
+  bitbang_mask = (1 << PIN_19_OFFSET);\r
+#else\r
+#ifdef _SIFIVE_COREPLEXIP_ARTY_H\r
+  bitbang_mask = (0x1 << JA_0_OFFSET);\r
+#endif\r
+#endif\r
+\r
+  GPIO_REG(GPIO_OUTPUT_EN) |= bitbang_mask;\r
+  \r
+  /**************************************************************************\r
+   * Set up the PLIC\r
+   *\r
+   *************************************************************************/\r
+  PLIC_init(&g_plic,\r
+           PLIC_CTRL_ADDR,\r
+           PLIC_NUM_INTERRUPTS,\r
+           PLIC_NUM_PRIORITIES);\r
+\r
+  reset_demo();\r
+\r
+  /**************************************************************************\r
+   * Demonstrate fast GPIO bit-banging.\r
+   * One can bang it faster than this if you know\r
+   * the entire OUTPUT_VAL that you want to write, but \r
+   * Atomics give a quick way to control a single bit.\r
+   *************************************************************************/\r
+  // For Bit-banging with Atomics demo.\r
+  \r
+  while (1){\r
+    atomic_fetch_xor_explicit(&GPIO_REG(GPIO_OUTPUT_VAL), bitbang_mask, memory_order_relaxed);\r
+  }\r
+\r
+  return 0;\r
+\r
+}\r
+\r
+\r
+void trap_entry( void )\r
+{\r
+#warning Dummy until kernel code is incldued.\r
+}\r