From a4301babff29b2c3fc12106d70d764b10314b890 Mon Sep 17 00:00:00 2001 From: David Harris Date: Sat, 30 Nov 2024 19:41:13 -0800 Subject: [PATCH] GPIO example --- .gitignore | 2 + examples/C/gpio/Makefile | 33 ++++++++++++++++ examples/C/gpio/gpio.c | 28 ++++++++++++++ examples/C/gpio/gpiolib.h | 81 +++++++++++++++++++++++++++++++++++++++ examples/C/hello/hello.c | 4 +- 5 files changed, 147 insertions(+), 1 deletion(-) create mode 100644 examples/C/gpio/Makefile create mode 100644 examples/C/gpio/gpio.c create mode 100644 examples/C/gpio/gpiolib.h diff --git a/.gitignore b/.gitignore index 64fbbbf23..9a0f35cc1 100644 --- a/.gitignore +++ b/.gitignore @@ -153,6 +153,8 @@ examples/C/mcmodel/mcmodel_medany examples/C/mcmodel/mcmodel_medlow examples/C/sum/sum examples/C/sum_mixed/sum_mixed +examples/C/hello/hello +examples/C/gpio/gpio examples/asm/sumtest/sumtest examples/asm/example/example examples/asm/trap/trap diff --git a/examples/C/gpio/Makefile b/examples/C/gpio/Makefile new file mode 100644 index 000000000..c33425ac7 --- /dev/null +++ b/examples/C/gpio/Makefile @@ -0,0 +1,33 @@ +TARGET = gpio + +$(TARGET).objdump: $(TARGET) + riscv64-unknown-elf-objdump -S -D $(TARGET) > $(TARGET).objdump + cp $(TARGET) $(TARGET).elf + +$(TARGET): $(TARGET).c Makefile + riscv64-unknown-elf-gcc -o $(TARGET) -gdwarf-2 -O\ + -march=rv64gc -mabi=lp64d -mcmodel=medany \ + -nostdlib -static -lm -fno-tree-loop-distribute-patterns \ + -T../common/test.ld -I../common \ + $(TARGET).c ../common/crt.S ../common/syscalls.c +# Compiler flags: +# -o $(TARGET) defines the name of the output file +# -g generates debugging symbols for gdb +# -O turns on basic optimization; -O3 turns on heavy optimization; omit for no optimization +# -march=rv64gc -mabi=lp64d =mcmodel=medany generates code for RV64GC with doubles and long/ptrs = 64 bits +# -static forces static linking (no dynamic shared libraries on bare metal) +# -lm links the math library if necessary (when #include math.h) +# -nostdlib avoids inserting standard startup files and default libraries +# because we are using crt.s on bare metal +# -fno-tree-loop-distribute-patterns turns replacing loops with memcpy/memset in the std library +# -T specifies the linker file +# -I specifies the include path (e.g. for util.h) +# The last line defines the C files to compile. +# crt.S is needed as our startup file to initialize the processor +# syscalls.c implements printf through the HTIF for Spike +# other flags from riscv-tests makefiles that don't seem to be important +# -ffast-math -DPREALLOCATE=1 -std=gnu99 \ +# -fno-common -fno-builtin-printf -nostartfiles -lgcc \ + +clean: + rm -f $(TARGET) $(TARGET).objdump diff --git a/examples/C/gpio/gpio.c b/examples/C/gpio/gpio.c new file mode 100644 index 000000000..64f3b5a08 --- /dev/null +++ b/examples/C/gpio/gpio.c @@ -0,0 +1,28 @@ +// gpio.c +// David_Harris@hmc.edu 30 November 2024 +// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 + +// General-Purpose I/O (GPIO) example program illustrating compiled C code +// compile with make +// simulate with: wsim rv64gc hello.elf --sim verilator + +#include +#include "gpiolib.h" + +int main(void) { + printf("GPIO Example!\n\r"); + pinMode(0, INPUT); + pinMode(1, OUTPUT); + pinMode(2, OUTPUT); + + for (int i=0; i<10; i++) { + // Read pin 0 and write it to pin 1 + int val = digitalRead(0); + printf("Pin 0: %d\n", val); + digitalWrite(1, val); + + // Toggle pin 2 + printf("Pin 2: %d\n", i%2); + digitalWrite(2, i%2); + } +} diff --git a/examples/C/gpio/gpiolib.h b/examples/C/gpio/gpiolib.h new file mode 100644 index 000000000..819089554 --- /dev/null +++ b/examples/C/gpio/gpiolib.h @@ -0,0 +1,81 @@ +// gpiolib.h +// Basic Arduino-compatible functions for general-purpose input/output + +// Assumes GPIO0_BASE is set to the memory-mapped GPIO address from +// config/rv64gc/config.vh. + +// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 + +#include + +/////////////////////////////////////////////////////////////////////////////// +// Bitfield Structs +/////////////////////////////////////////////////////////////////////////////// + +typedef struct +{ + volatile uint32_t input_val; // (GPIO offset 0x00) Pin value + volatile uint32_t input_en; // (GPIO offset 0x04) Pin input enable* + volatile uint32_t output_en; // (GPIO offset 0x08) Pin output enable* + volatile uint32_t output_val; // (GPIO offset 0x0C) Output value + volatile uint32_t pue; // (GPIO offset 0x10) Internal pull-up enable* + volatile uint32_t ds; // (GPIO offset 0x14) Pin drive strength + volatile uint32_t rise_ie; // (GPIO offset 0x18) Rise interrupt enable + volatile uint32_t rise_ip; // (GPIO offset 0x1C) Rise interrupt pending + volatile uint32_t fall_ie; // (GPIO offset 0x20) Fall interrupt enable + volatile uint32_t fall_ip; // (GPIO offset 0x24) Fall interrupt pending + volatile uint32_t high_ie; // (GPIO offset 0x28) High interrupt enable + volatile uint32_t high_ip; // (GPIO offset 0x2C) High interrupt pending + volatile uint32_t low_ie; // (GPIO offset 0x30) Low interrupt enable + volatile uint32_t low_ip; // (GPIO offset 0x34) Low interrupt pending + volatile uint32_t iof_en; // (GPIO offset 0x38) HW-Driven functions enable + volatile uint32_t iof_sel; // (GPIO offset 0x3C) HW-Driven functions selection + volatile uint32_t out_xor; // (GPIO offset 0x40) Output XOR (invert) + // Registers marked with * are asynchronously reset to 0. All others are synchronously reset to 0. +} GPIO; + +/////////////////////////////////////////////////////////////////////////////// +// GPIO Constant Definitions +/////////////////////////////////////////////////////////////////////////////// + +#define GPIO0_BASE (0x10060000U) // GPIO memory-mapped base address + +#define GPIO0 ((GPIO*) GPIO0_BASE) // Set up pointer to struct of type GPIO aligned at the base GPIO0 memory-mapped address + +#define LOW 0 +#define HIGH 1 + +#define INPUT 0 +#define OUTPUT 1 +#define GPIO_IOF0 2 + +/////////////////////////////////////////////////////////////////////////////// +// GPIO Functions +/////////////////////////////////////////////////////////////////////////////// + +void pinMode(int pin, int function) +{ + switch(function) { + case INPUT: + GPIO0->input_en |= (1 << pin); // Sets a pin as an input + break; + case OUTPUT: + GPIO0->output_en |= (1 << pin); // Set pin as an output + GPIO0->iof_en &= ~(1 << pin); + break; + case GPIO_IOF0: + GPIO0->iof_sel &= ~(1 << pin); + GPIO0->iof_en |= (1 << pin); + } +} + +void digitalWrite(int pin, int val) +{ + if (val) GPIO0->output_val |= (1 << pin); + else GPIO0->output_val &= ~(1 << pin); +} + +int digitalRead(int pin) +{ + return (GPIO0->input_val >> pin) & 0x1; +} diff --git a/examples/C/hello/hello.c b/examples/C/hello/hello.c index 4e1215cfb..2a6cfa033 100644 --- a/examples/C/hello/hello.c +++ b/examples/C/hello/hello.c @@ -1,5 +1,6 @@ // hello.c // David_Harris@hmc.edu 30 November 2024 +// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 // Hello World program illustrating compiled C code printing via the UART // The Wally team has modified the Berkeley syscalls.c (in examples/C/common) @@ -10,7 +11,8 @@ // such that using \n\r for new lines works best. // compile with make -// simulate with: wsim rv64gc hello.elf --sim verilator +// simulate Wally with: wsim rv64gc hello.elf --sim verilator +// simulate in Spike with: spike hello.elf #include