| // Copyright lowRISC contributors. |
| // Licensed under the Apache License, Version 2.0, see LICENSE for details. |
| // SPDX-License-Identifier: Apache-2.0 |
| |
| #include "common.h" |
| #include "gpio.h" |
| #include "spi_device.h" |
| #include "uart.h" |
| |
| #define SPI_MAX 32 |
| |
| /** |
| * Delay loop executing within 8 cycles on ibex |
| */ |
| static void delay_loop_ibex(unsigned long loops) { |
| int out; /* only to notify compiler of modifications to |loops| */ |
| asm volatile( |
| "1: nop \n" // 1 cycle |
| " nop \n" // 1 cycle |
| " nop \n" // 1 cycle |
| " nop \n" // 1 cycle |
| " addi %1, %1, -1 \n" // 1 cycle |
| " bnez %1, 1b \n" // 3 cycles |
| : "=&r"(out) |
| : "0"(loops)); |
| } |
| |
| static int usleep_ibex(unsigned long usec) { |
| unsigned long usec_cycles; |
| usec_cycles = CLK_FIXED_FREQ_HZ * usec / 1000 / 1000 / 8; |
| |
| delay_loop_ibex(usec_cycles); |
| return 0; |
| } |
| |
| static int usleep(unsigned long usec) { return usleep_ibex(usec); } |
| |
| // called from ctr0 when something bad happens |
| // char I=illegal instruction, A=lsu error (address), E=ecall |
| void trap_handler(uint32_t mepc, char c) { |
| uart_send_char(c); |
| uart_send_uint(mepc, 32); |
| while (1) { |
| gpio_write_all(0xAA00); // pattern |
| usleep(200 * 1000); |
| gpio_write_all(0x5500); // pattern |
| usleep(100 * 1000); |
| } |
| } |
| |
| #define MK_PRINT(c) (((c < 32) || (c > 126)) ? '_' : c) |
| |
| int main(int argc, char **argv) { |
| uart_init(UART_BAUD_RATE); |
| |
| // Enable GPIO: 0-7 and 16 is input, 8-15 is output |
| gpio_init(0xFF00); |
| |
| spid_init(); |
| // Add DATE and TIME because I keep fooling myself with old versions |
| uart_send_str( |
| "Hello World! "__DATE__ |
| " "__TIME__ |
| "\r\n"); |
| uart_send_str("Watch the LEDs!\r\n"); |
| |
| // Give a LED pattern as startup indicator for 5 seconds |
| gpio_write_all(0xFF00); // all LEDs on |
| for (int i = 0; i < 32; i++) { |
| usleep(100 * 1000); // 100 ms |
| |
| gpio_write_bit(8 + (i % 8), (i / 8)); |
| } |
| |
| // Now have UART <-> Buttons/LEDs demo |
| // all LEDs off |
| gpio_write_all(0x0000); |
| uart_send_str("Try out the switches on the board\r\n"); |
| uart_send_str("or type anything into the console window.\r\n"); |
| uart_send_str("The LEDs show the ASCII code of the last character.\r\n"); |
| |
| uint32_t gpio_in; |
| uint32_t gpio_in_prev = 0; |
| uint32_t gpio_in_changes; |
| uint8_t spi_buf[SPI_MAX]; |
| uint32_t spi_in; |
| |
| spid_send("SPI!", 4); |
| |
| while (1) { |
| usleep(10 * 1000); // 10 ms |
| |
| // report changed switches over UART |
| gpio_in = gpio_read() & 0x100FF; // 0-7 is switch input, 16 is FTDI |
| gpio_in_changes = (gpio_in & ~gpio_in_prev) | (~gpio_in & gpio_in_prev); |
| for (int b = 0; b < 8; b++) { |
| if (gpio_in_changes & (1 << b)) { |
| int val_now = (gpio_in >> b) & 0x01; |
| uart_send_str("GPIO: Switch "); |
| uart_send_char(b + 48); |
| uart_send_str(" changed to "); |
| uart_send_char(val_now + 48); |
| uart_send_str("\r\n"); |
| } |
| } |
| if (gpio_in_changes & 0x10000) { |
| uart_send_str("FTDI control changed. Enable "); |
| uart_send_str((gpio_in & 0x10000) ? "JTAG\r\n" : "SPI\r\n"); |
| } |
| gpio_in_prev = gpio_in; |
| |
| // SPI character echo |
| spi_in = spid_read_nb(spi_buf, SPI_MAX); |
| if (spi_in) { |
| uint32_t d = (*(uint32_t *)spi_buf) ^ 0x01010101; |
| spid_send(&d, 4); |
| uart_send_str("SPI: "); |
| for (int i = 0; i < spi_in; i++) { |
| uart_send_char(MK_PRINT(spi_buf[i])); |
| } |
| uart_send_str("\r\n"); |
| } |
| // UART echo |
| char rcv_char; |
| while (uart_rcv_char(&rcv_char) != -1) { |
| uart_send_char(rcv_char); |
| gpio_write_all(rcv_char << 8); |
| } |
| } |
| } |