diff --git a/src/spi_software.c b/src/spi_software.c index 54b75dcd..4d5e7d97 100644 --- a/src/spi_software.c +++ b/src/spi_software.c @@ -4,7 +4,9 @@ // // This file may be distributed under the terms of the GNU GPLv3 license. +#include "autoconf.h" // CONFIG_* #include "board/gpio.h" // gpio_out_setup +#include "board/misc.h" // timer_read_time #include "basecmd.h" // oid_alloc #include "command.h" // DECL_COMMAND #include "sched.h" // sched_shutdown @@ -13,6 +15,7 @@ struct spi_software { struct gpio_in miso; struct gpio_out mosi, sclk; + uint32_t sck_ticks; uint8_t mode; }; @@ -20,6 +23,8 @@ void command_spi_set_software_bus(uint32_t *args) { uint8_t mode = args[4]; + uint32_t rate = args[5]; + uint8_t div = 0; if (mode > 3) shutdown("Invalid spi config"); @@ -29,6 +34,9 @@ command_spi_set_software_bus(uint32_t *args) ss->mosi = gpio_out_setup(args[2], 0); ss->sclk = gpio_out_setup(args[3], 0); ss->mode = mode; + while (((CONFIG_CLOCK_FREQ/2) >> div) > rate) + div++; + ss->sck_ticks = 1 << div; spidev_set_software_bus(spi, ss); } DECL_COMMAND(command_spi_set_software_bus, @@ -41,30 +49,49 @@ spi_software_prepare(struct spi_software *ss) gpio_out_write(ss->sclk, ss->mode & 0x02); } +static void +spi_delay(uint32_t end) +{ + while (timer_is_before(timer_read_time(), end)); +} + void spi_software_transfer(struct spi_software *ss, uint8_t receive_data , uint8_t len, uint8_t *data) { + uint32_t t1 = ss->sck_ticks >> 1; + uint32_t t2 = ss->sck_ticks - t1; + uint32_t end = timer_read_time() + t1; while (len--) { uint8_t outbuf = *data; uint8_t inbuf = 0; - for (uint_fast8_t i = 0; i < 8; i++) { - if (ss->mode & 0x01) { + if (ss->mode & 0x01) { + for (uint_fast8_t i = 0; i < 8; i++) { + spi_delay(end); // MODE 1 & 3 gpio_out_toggle(ss->sclk); gpio_out_write(ss->mosi, outbuf & 0x80); + end = timer_read_time() + t2; outbuf <<= 1; - gpio_out_toggle(ss->sclk); inbuf <<= 1; + spi_delay(end); + gpio_out_toggle(ss->sclk); inbuf |= gpio_in_read(ss->miso); - } else { + end = timer_read_time() + t1; + } + } else { + for (uint_fast8_t i = 0; i < 8; i++) { + spi_delay(end); // MODE 0 & 2 gpio_out_write(ss->mosi, outbuf & 0x80); - outbuf <<= 1; gpio_out_toggle(ss->sclk); + end = timer_read_time() + t2; + outbuf <<= 1; inbuf <<= 1; + spi_delay(end); inbuf |= gpio_in_read(ss->miso); gpio_out_toggle(ss->sclk); + end = timer_read_time() + t1; } }