diff --git a/src/spi/driver/linux-uio/README.md b/src/spi/driver/linux-uio/README.md new file mode 100644 index 00000000..27965ca1 --- /dev/null +++ b/src/spi/driver/linux-uio/README.md @@ -0,0 +1,16 @@ +# OH Linux generic UIO driver + +Modules and devicetree compiled for Pubuntu 2016.3.x + +1. Copy `zynq-parallella-oh-spi.dtb` to SD card boot partition, name it `devicetree.dtb`. +2. Reboot Parallella +3. (OPTIONAL) Load bitstream: `sudo dd if=parallella.bit.bin of=/dev/xdevcfg` +3. Load the required modules: +``` +sudo insmod uio.ko +sudo insmod uio_pdrv_genirq.ko of_id=oh,mio +sudo rmmod uio_pdrv_genirq.ko +sudo insmod uio_pdrv_genirq.ko of_id=oh,mio +chmod 777 /dev/uio0 +``` +4. You can now compile and run uio-test in oh.git/src/spi/driver/spilib diff --git a/src/spi/driver/linux-uio/uio.ko b/src/spi/driver/linux-uio/uio.ko new file mode 100644 index 00000000..74020756 Binary files /dev/null and b/src/spi/driver/linux-uio/uio.ko differ diff --git a/src/spi/driver/linux-uio/uio_pdrv_genirq.ko b/src/spi/driver/linux-uio/uio_pdrv_genirq.ko new file mode 100644 index 00000000..97ea822e Binary files /dev/null and b/src/spi/driver/linux-uio/uio_pdrv_genirq.ko differ diff --git a/src/spi/driver/linux-uio/zynq-parallella-oh-spi.dtb b/src/spi/driver/linux-uio/zynq-parallella-oh-spi.dtb new file mode 100644 index 00000000..176b8316 Binary files /dev/null and b/src/spi/driver/linux-uio/zynq-parallella-oh-spi.dtb differ diff --git a/src/spi/driver/linux-uio/zynq-parallella-oh-spi.dts b/src/spi/driver/linux-uio/zynq-parallella-oh-spi.dts new file mode 100644 index 00000000..3e423b90 --- /dev/null +++ b/src/spi/driver/linux-uio/zynq-parallella-oh-spi.dts @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2016 Parallella Foundation + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +/dts-v1/; +#include "zynq-parallella1.dtsi" + +/ { + model = "Adapteva Parallella Board with OH SPI bitstream"; +}; + +&amba { + spi2: spi2@7fe00000 { + compatible = "oh,spi"; + reg = <0x7fe00000 0x1000>; + interrupt-parent = <&intc>; + interrupts = <0 53 4>; + }; +}; + +&usb_phy0 { + status = "okay"; +}; + +&usb_phy1 { + status = "okay"; +}; + +&usb0 { + status = "okay"; +}; + +&usb1 { + status = "okay"; +}; + +&elink0 { + status = "disabled"; +}; + +&i2c0 { + status = "disabled"; +}; diff --git a/src/spi/driver/spilib/Makefile b/src/spi/driver/spilib/Makefile new file mode 100644 index 00000000..5e7c8730 --- /dev/null +++ b/src/spi/driver/spilib/Makefile @@ -0,0 +1,6 @@ +all: uio-test + +clean: + rm -f uio-test + +.PHONY: all clean diff --git a/src/spi/driver/spilib/README.md b/src/spi/driver/spilib/README.md new file mode 100644 index 00000000..f306c819 --- /dev/null +++ b/src/spi/driver/spilib/README.md @@ -0,0 +1,129 @@ +# Driver layer for SPI + +## User API + +```c +/** + * spi_init - SPI init + * + * @param dev uninitialized device structure + * @param arg target argument (depends on target) + * + * @return 0 on success. Negative on error + */ +int spi_init(spi_dev_t *dev, void *arg); + +/** + * spi_init - SPI finalize + * + * @param dev uninitialized device structure + */ +void spi_init(spi_dev_t *dev); + + +/** + * spi_set_config - Set configuration for SPI device + * + * @param dev device structure + * @param config spi configuration + * + */ +void spi_set_config(spi_dev_t *dev, uint8_t config); +#define spi_set_config(dev, config) spi_reg_write((dev), SPI_CONFIG, (config)) + +/** + * spi_get_config - Get configuration for SPI device + * + * @param dev device structure + * + * @return spi config register + */ +uint8_t spi_get_config(spi_dev_t *dev); +#define spi_get_config(dev) spi_reg_read((dev), SPI_CONFIG) + +/** + * spi_get_status - Get status for SPI device + * + * @param dev device structure + * + */ +uint8_t spi_get_status(spi_dev_t *dev); +#define spi_get_status(dev) spi_reg_read((dev), SPI_STATUS) + +/** + * spi_set_clkdiv - Set master clock divider + * + * @param dev device structure + * @param config spi configuration + * + */ +void spi_set_clkdiv(spi_dev_t *dev, uint8_t clkdiv); +#define spi_set_clkdiv(dev, clkdiv) spi_reg_write((dev), SPI_CLKDIV, (clkdiv)) + +/** + * spi_get_clkdiv - Get master clock divider + * + * @param dev device structure + * + * @return clock divider register + * + */ +uint8_t spi_get_clkdiv(spi_dev_t *dev); +#define spi_get_clkdiv(dev) spi_reg_read((dev), SPI_CLKDIV) + +/** + * spi_transter - Perform one SPI transfer + * + * @param dev device structure + * @param tx transmit data buffer + * @param rx receive data buffer + * @param count number of bytes + * + */ +void spi_transfer(spi_dev_t *dev, uint8_t *tx, uint8_t *rx, unsigned count); + +/*** Raw register access API */ + +#define SPI_CONFIG 0x00 +#define SPI_STATUS 0x01 +#define SPI_CLKDIV 0x02 +#define SPI_TX 0x08 /* master only */ +#define SPI_RX 0x10 +#define SPI_USER0 0x20 /* slave only, first user register */ + +#define SPI_CONFIG_DISABLE (1 << 0) +#define SPI_CONFIG_IRQ_ENABLE (1 << 1) +#define SPI_CONFIG_CPOL (1 << 2) +#define SPI_CONFIG_CPHA (1 << 3) +#define SPI_CONFIG_LSB (1 << 4) +#define SPI_CONFIG_USER_REGS (1 << 5)/* slave only */ + +#define SPI_STATUS_SPLIT (1 << 0) +#define SPI_STATUS_STATE (3 << 1) /* master only */ +#define SPI_STATUS_TX_FIFO_HALF_FULL (1 << 3) /* master only */ + +#define SPI_STATE_IDLE(status) ((status) & SPI_STATUS_STATE == 0) +#define SPI_STATE_SETUP(status) ((status) & SPI_STATUS_STATE == 1) +#define SPI_STATE_DATA(status) ((status) & SPI_STATUS_STATE == 2) +#define SPI_STATE_HOLD(status) ((status) & SPI_STATUS_STATE == 3) +/** + * spi_reg_write - Set SPI device register + * + * @param dev device structure + * @param reg register + * @param val value + * + */ +void spi_reg_write(spi_dev_t *dev, unsigned reg, uint8_t val); + +/** + * spi_reg_read - Get SPI device register + * + * @param dev device structure + * @param reg register + * + * @return register value + */ +uint8_t spi_reg_write(spi_dev_t *dev, unsigned reg); + +``` diff --git a/src/spi/driver/spilib/spi-epiphany.h b/src/spi/driver/spilib/spi-epiphany.h new file mode 100644 index 00000000..294939d3 --- /dev/null +++ b/src/spi/driver/spilib/spi-epiphany.h @@ -0,0 +1,8 @@ +#pragma once +#ifndef _SPI_INTERNAL +# error "Don't include this file directly" +#endif + +#include "spi-generic.h" + +#error "Epiphany target not implemented" diff --git a/src/spi/driver/spilib/spi-generic.h b/src/spi/driver/spilib/spi-generic.h new file mode 100644 index 00000000..8887fe70 --- /dev/null +++ b/src/spi/driver/spilib/spi-generic.h @@ -0,0 +1,149 @@ +#pragma once +#ifndef _SPI_INTERNAL +# error "Don't include this file directly" +#endif + +#include +#include + +struct spi_generic_dev { + volatile uint8_t *regs; +}; + +__spi_unused +static void _spi_reg_write(struct spi_generic_dev *dev, unsigned reg, + uint32_t val) +{ + if (reg & 3) + dev->regs[reg] = (uint8_t) val; + else + *(volatile uint32_t *) &dev->regs[reg] = val; + +} + +__spi_unused +static uint32_t _spi_reg_read(struct spi_generic_dev *dev, unsigned reg) +{ + if (reg & 3) + return (uint32_t) dev->regs[reg]; + else + return *(uint32_t *) &dev->regs[reg]; +} + +__spi_unused +static void _spi_transfer(struct spi_generic_dev *dev, const void *tx, + void *rx, unsigned count) +{ + unsigned n; + const uint8_t *u8_tx = (const uint8_t *) tx; + uint8_t *u8_rx = (uint8_t *) rx; + uint8_t config; + + /* TODO: Flush queues */ + + /* TODO: Enable TX */ + + /* TODO: Tell master to hold SS? */ + + config = _spi_reg_read(dev, SPI_CONFIG); + + while (count) { + union acme { + uint32_t u32; + uint16_t u16[2]; + uint8_t u8[4]; + } __spi_packed; + union acme rx0, rx1, tx0, tx1; + volatile union acme *txfifo = (union acme *) &dev->regs[SPI_TX]; + + if (tx) + memcpy(&tx0.u32, u8_tx, count > 4 ? 4 : count); + if (tx && count > 4) + memcpy(&tx1.u32, &u8_tx[4], count - 4 > 4 ? 4 : count - 4); + + /* Clear status register */ + _spi_reg_write(dev, SPI_STATUS, 0); + while (_spi_reg_read(dev, SPI_STATUS)) + ; + + /* Enable TX */ + config &= ~SPI_CONFIG_DISABLE; + _spi_reg_write(dev, SPI_CONFIG, config); + + /* Write TX data to TX fifo */ + switch (count) { + case 1: + txfifo->u8[0] = tx0.u8[0]; + count -= 1; n = 1; + break; + case 2: + txfifo->u16[0] = tx0.u16[0]; + count -= 2; n = 2; + break; + case 3: + txfifo->u16[0] = tx0.u16[0]; + txfifo->u8[0] = tx0.u8[3]; + count -= 3; n = 3; + break; + case 4: + txfifo->u32 = tx0.u32; + count -= 4; n = 4; + break; + case 5: + txfifo->u32 = tx0.u32; + txfifo->u8[0] = tx1.u8[0]; + count -= 5; n = 5; + break; + case 6: + txfifo->u32 = tx0.u32; + txfifo->u32 = tx1.u16[0]; + count -= 6; n = 6; + break; + case 7: + txfifo->u32 = tx0.u32; + txfifo->u32 = tx1.u16[0]; + txfifo->u32 = tx1.u8[3]; + count -= 7; n = 7; + break; + default: + txfifo->u32 = tx0.u32; + txfifo->u32 = tx1.u32; + count -= 8; n = 8; + break; + }; + + /* Wait for transfer to complete */ + while (_spi_reg_read(dev, SPI_STATUS) & SPI_STATUS_ACTIVE) + ; + while (!(_spi_reg_read(dev, SPI_STATUS) & SPI_STATUS_SPLIT)) + ; + + if (rx) { + uint8_t buf[8] = { 0 }; + unsigned i, j; + + /* Read deserializer */ + rx0.u32 = *(uint32_t *) &dev->regs[SPI_RX0]; + rx1.u32 = *(uint32_t *) &dev->regs[SPI_RX1]; + + memcpy(&buf[0], &rx0, 4); + memcpy(&buf[4], &rx1, 4); + + /* Reverse bytes in transfer */ + for (i = n - 1, j = 0; i > j; i--, j++) { + uint8_t tmp; + tmp = buf[i]; + buf[i] = buf[j]; + buf[j] = tmp; + } + + memcpy(u8_rx, buf, n); + u8_rx += n; + } + + } + + _spi_reg_write(dev, SPI_STATUS, 0); + + /* TODO: Tell master to release SS */ +} diff --git a/src/spi/driver/spilib/spi-simple.h b/src/spi/driver/spilib/spi-simple.h new file mode 100644 index 00000000..fd0f1cde --- /dev/null +++ b/src/spi/driver/spilib/spi-simple.h @@ -0,0 +1,29 @@ +#pragma once +#ifndef _SPI_INTERNAL +# error "Don't include this file directly" +#endif + +#include "spi-generic.h" + +typedef struct spi_generic_dev spi_dev_t; + +__spi_unused +static int spi_init(spi_dev_t *dev, void *arg) +{ + if (!arg) +#ifdef SPI_SIMPLE_DEFAULT_ADDR + arg = (void *) SPI_SIMPLE_DEFAULT_ADDR; +#else + return -EINVAL; +#endif + + dev->regs = (struct spi_registers *) arg; + + return 0; +} + +#define spi_fini(dev) /* nop */ +#define spi_reg_write _spi_reg_write +#define spi_reg_read _spi_reg_read +#define spi_write _spi_write +#define spi_read _spi_read diff --git a/src/spi/driver/spilib/spi-uio.h b/src/spi/driver/spilib/spi-uio.h new file mode 100644 index 00000000..e0355eff --- /dev/null +++ b/src/spi/driver/spilib/spi-uio.h @@ -0,0 +1,51 @@ +#pragma once +#ifndef _SPI_INTERNAL +# error "Don't include this file directly" +#endif + +#include "spi-generic.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +struct spi_uio_dev { + int fd; + struct spi_generic_dev generic; +}; + +typedef struct spi_uio_dev spi_dev_t; + +__spi_unused +static int spi_init(spi_dev_t *dev, void *arg) +{ + char *path = arg; + + dev->fd = open(path, O_RDWR); + if (dev->fd < 0) + return -errno; + + dev->generic.regs = mmap(NULL, 0x1000, PROT_WRITE | PROT_READ, + MAP_SHARED, dev->fd, 0); + if (dev->generic.regs == MAP_FAILED) + return -errno; + + return 0; +} + +__spi_unused +static void spi_fini(spi_dev_t *dev) +{ + munmap((void *) dev->generic.regs, 0x1000); + close(dev->fd); +} + +#define spi_to_generic(dev) (&(dev)->generic) +#define spi_reg_write(dev, reg, val) _spi_reg_write(spi_to_generic((dev)), (reg), (val)) +#define spi_reg_read(dev, reg) _spi_reg_read(spi_to_generic((dev)), (reg)) +#define spi_transfer(dev, tx, rx, count) _spi_transfer(spi_to_generic((dev)), (tx), (rx), (count)) diff --git a/src/spi/driver/spilib/spi.h b/src/spi/driver/spilib/spi.h new file mode 100644 index 00000000..18462c34 --- /dev/null +++ b/src/spi/driver/spilib/spi.h @@ -0,0 +1,179 @@ +#pragma once +#include +#include +#include + +/*** API */ + +/** + * spi_init - SPI init + * + * @param dev uninitialized device structure + * @param arg target argument (depends on target) + * + * @return 0 on success. Negative on error + */ +//int spi_init(spi_dev_t *dev, void *arg); + +/** + * spi_init - SPI finalize + * + * @param dev uninitialized device structure + */ +//void spi_init(spi_dev_t *dev); + + +/** + * spi_set_config - Set configuration for SPI device + * + * @param dev device structure + * @param config spi configuration + * + */ +//void spi_set_config(spi_dev_t *dev, uint8_t config); +#define spi_set_config(dev, config) spi_reg_write((dev), SPI_CONFIG, (config)) + +/** + * spi_get_config - Get configuration for SPI device + * + * @param dev device structure + * + * @return spi config register + */ +//uint8_t spi_get_config(spi_dev_t *dev); +#define spi_get_config(dev) spi_reg_read((dev), SPI_CONFIG) + +/** + * spi_get_status - Get status for SPI device + * + * @param dev device structure + * + */ +//uint8_t spi_get_status(spi_dev_t *dev); +#define spi_get_status(dev) spi_reg_read((dev), SPI_STATUS) + +/** + * spi_set_clkdiv - Set master clock divider + * + * @param dev device structure + * @param config spi configuration + * + */ +//void spi_set_clkdiv(spi_dev_t *dev, uint8_t clkdiv); +#define spi_set_clkdiv(dev, clkdiv) spi_reg_write((dev), SPI_CLKDIV, (clkdiv)) + +/** + * spi_get_clkdiv - Get master clock divider + * + * @param dev device structure + * + * @return clock divider register + * + */ +//uint8_t spi_get_clkdiv(spi_dev_t *dev); +#define spi_get_clkdiv(dev) spi_reg_read((dev), SPI_CLKDIV) + +/** + * spi_transter - Perform one SPI transfer + * + * @param dev device structure + * @param tx transmit data buffer + * @param rx receive data buffer + * @param count number of bytes + * + */ +//void spi_transfer(spi_dev_t *dev, uint8_t *tx, uint8_t *rx, unsigned count); + +/*** Raw register access API */ + +#define SPI_CONFIG 0x00 +#define SPI_STATUS 0x01 +#define SPI_CLKDIV 0x02 +#define SPI_TX 0x08 /* master only */ +#define SPI_RX0 0x10 +#define SPI_RX1 0x14 +#define SPI_USER0 0x20 /* slave only, first user register */ + +#define SPI_CONFIG_DISABLE (1 << 0) +#define SPI_CONFIG_IRQ_ENABLE (1 << 1) +#define SPI_CONFIG_CPOL (1 << 2) +#define SPI_CONFIG_CPHA (1 << 3) +#define SPI_CONFIG_LSB_FIRST (1 << 4) +#define SPI_CONFIG_USER_REGS (1 << 5)/* slave only */ + +#define SPI_STATUS_SPLIT (1 << 0) +#define SPI_STATUS_ACTIVE (1 << 1) /* master only */ +#define SPI_STATUS_TX_FIFO_HALF_FULL (1 << 2) /* master only */ + +/** + * spi_reg_write - Set SPI device register + * + * @param dev device structure + * @param reg register + * @param val value + * + */ +//void spi_reg_write(spi_dev_t *dev, unsigned reg, uint8_t val); + +/** + * spi_reg_read - Get SPI device register + * + * @param dev device structure + * @param reg register + * + * @return register value + */ +//uint8_t spi_reg_write(spi_dev_t *dev, unsigned reg); + +#ifndef __spi_unused +# if defined(__GNUC__) || defined(__clang__) +# define __spi_unused __attribute__((unused)) +# else +# define __spi_unused +# endif +#endif + +#ifndef __spi_packed +# if defined(__GNUC__) || defined(__clang__) +# define __spi_packed __attribute__((packed)) +# else +# define __spi_packed +# endif +#endif + +#ifndef __spi_aligned +# if defined(__GNUC__) || defined(__clang__) +# define __spi_aligned(X) __attribute__((aligned(X))) +# else +# define __spi_aligned(X) +# endif +#endif + +/* Targets */ +#define SPI_TARGET_SIMPLE 0 +#define SPI_TARGET_EPIPHANY 1 +#define SPI_TARGET_UIO 2 + +/* Autodetect target */ +#ifndef SPI_TARGET +# if defined(__epiphany__) +# define SPI_TARGET SPI_TARGET_EPIPHANY +# elif defined(__linux__) +# define SPI_TARGET SPI_TARGET_UIO +#else +# define SPI_TARGET SPI_TARGET_SIMPLE +# endif +#endif + + +#define _SPI_INTERNAL +#if SPI_TARGET == SPI_TARGET_SIMPLE +# include "spi-simple.h" +#elif SPI_TARGET == SPI_TARGET_EPIPHANY +# include "spi-epiphany.h" +#elif SPI_TARGET == SPI_TARGET_UIO +# include "spi-uio.h" +#else +# error "Invalid SPI_TARGET" +#endif +#undef _SPI_INTERNAL diff --git a/src/spi/driver/spilib/test.c b/src/spi/driver/spilib/test.c new file mode 100644 index 00000000..bf8b9f65 --- /dev/null +++ b/src/spi/driver/spilib/test.c @@ -0,0 +1,27 @@ +#define SPI_TARGET SPI_TARGET_SIMPLE +#define SPI_SIMPLE_DEFAULT_ADDR 0xdeadbee0 + +#include +#include "spi.h" + +int main() +{ + int val; + spi_dev_t dev; + + if (spi_init(&dev, NULL)) + exit(EXIT_FAILURE); + + spi_set_direction(&dev, 63, SPI_DIR_IN); + spi_set_direction(&dev, 0, SPI_DIR_OUT); + + val = 1; + spi_write(&dev, 0, val); + val = spi_read(&dev, 63); + spi_write(&dev, 0, ~val & 1); + val = spi_read(&dev, 63); + spi_toggle(&dev, 0); + val = spi_read(&dev, 63); + + return val; +} diff --git a/src/spi/driver/spilib/uio-test.c b/src/spi/driver/spilib/uio-test.c new file mode 100644 index 00000000..680d3dd6 --- /dev/null +++ b/src/spi/driver/spilib/uio-test.c @@ -0,0 +1,177 @@ +#include "spi.h" +#define SPI_TARGET SPI_TARGET_UIO +#include + +/* Assume master/slave pins are connected in loop-back */ + +/* OH SPI slave specifics */ +struct oh_spi_mosi_pkt { + unsigned addr:6; + unsigned mode:2; + uint8_t data[7]; +} __attribute__((packed)); + +struct oh_spi_miso_pkt { + unsigned:8; + uint8_t data[7]; +} __attribute__((packed)); + + +#define SLAVE_WRITE 0x00 +#define SLAVE_READ 0x02 +#define SLAVE_FETCH 0x03 + +void slave_access(spi_dev_t *dev, unsigned mode, unsigned addr, uint8_t *txbuf, + uint8_t *rxbuf, unsigned count) +{ + struct oh_spi_miso_pkt miso; + struct oh_spi_mosi_pkt mosi = { + .addr = addr, + .mode = mode, + .data = { 0 }, + }; + if (txbuf) + memcpy(mosi.data, txbuf, count); + + if (mode == SLAVE_WRITE) + spi_transfer(dev, &mosi, NULL, 1 + count); + else + spi_transfer(dev, &mosi, &miso, 1 + count); + + if (rxbuf) + memcpy(rxbuf, &miso.data[0], count); +} + +void slave_write_n(spi_dev_t *dev, unsigned addr, uint8_t *tx, unsigned count) +{ + slave_access(dev, SLAVE_WRITE, addr, tx, NULL, count); +} + +void slave_write(spi_dev_t *dev, unsigned addr, uint8_t data) +{ + slave_access(dev, SLAVE_WRITE, addr, &data, NULL, 1); +} + +uint8_t slave_read(spi_dev_t *dev, unsigned addr) +{ + uint8_t value; + slave_access(dev, SLAVE_READ, addr, NULL, &value, 1); + return value; +} + +void slave_read_n(spi_dev_t *dev, unsigned addr, uint8_t *rx, + unsigned count) +{ + slave_access(dev, SLAVE_READ, addr, NULL, rx, count); +} + + +int main() +{ + int i, j; + spi_dev_t master; + uint8_t slave_regs[13]; + bool fail = false; + + if (spi_init(&master, (void *) "/dev/uio0")) { + perror("spi_init"); + return 1; + } + + spi_set_clkdiv(&master, 5); + +// slave_write(&master, SPI_CONFIG, 0); + spi_reg_write(&master, SPI_CONFIG, 0); + + printf("status: %#x\n", spi_reg_read(&master, SPI_STATUS)); + + printf("clkdiv: %#x\n", spi_reg_read(&master, SPI_CLKDIV)); + + printf("config: %#x\n", spi_reg_read(&master, SPI_CONFIG)); + + printf("spi_reg_read(28): %#x\n", spi_reg_read(&master, 28)); + + printf("Testing write / read to slave regs loop\n"); + + for (i = 0; i < 10000; i++) { + + for (j = 0; j < 13; j++) + slave_write(&master, SPI_USER0 + j, 0xff - j * 2); + + for (j = 0; j < 13; j++) { + //printf("i: 0x%x\n", i); + slave_regs[j] = slave_read(&master, SPI_USER0 + j); + } + + if (i == 0) { + printf("slave user regs: "); + for (j = 0; j < 13; j++) + printf("0x%02x ", (int) slave_regs[j]); + printf("\n"); + } + + for (j = 0; j < 13; j++) + if (slave_regs[j] != 0xff - j * 2) { + printf("fail\n"); + fail = true; + } + + for (j = 0; j < 13; j++) + slave_write(&master, SPI_USER0 + j, 0xff - j); + + for (j = 0; j < 13; j++) + slave_regs[j] = slave_read(&master, SPI_USER0 + j); + + if (i == 0) { + printf("slave user regs: "); + for (j = 0; j < 13; j++) + printf("0x%02x ", (int) slave_regs[j]); + printf("\n"); + } + + for (j = 0; j < 13; j++) + if (slave_regs[j] != 0xff - j) { + printf("fail\n"); + fail = true; + } + + if (fail) + break; + + } + + printf(fail ? "FAIL\n" : "OK\n"); + + uint8_t pat0[7] = { 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32}; + uint8_t pat1[7] = { 0xfe ^ 0xff, 0xdc ^ 0xff, 0xba ^ 0xff, 0x98 ^ 0xff, + 0x76 ^ 0xff, 0x54 ^ 0xff, 0x32 ^ 0xff }; + uint8_t in0[7] = { 0x0 }; + uint8_t in1[7] = { 0x0 }; + + printf("Testing high bits set and slave addr autoincrement\n"); + slave_write_n(&master, SPI_USER0, pat0, 7); + slave_read_n(&master, SPI_USER0, in0, 7); + slave_write_n(&master, SPI_USER0, pat1, 7); + slave_read_n(&master, SPI_USER0, in1, 7); + + for (i = 0; i < 7; i++) { + printf("pat0[%d] = 0x%02x in0[%d] = 0x%02x\n", + i, (int) pat0[i], i, in0[i]); + printf("pat1[%d] = 0x%02x in1[%d] = 0x%02x\n", + i, (int) pat1[i], i, in1[i]); + if (in0[i] != pat0[i] || in1[i] != pat1[i]) + fail = true; + } + + printf("rx0 = 0x%08x rx1 = 0x%08x\n", + spi_reg_read(&master, SPI_RX0), spi_reg_read(&master, SPI_RX1)); + + spi_fini(&master); + + if (fail) + printf("FAIL\n"); + else + printf("PASS\n"); + + return fail ? 1 : 0; +} diff --git a/src/spi/fpga/axi_spi_timing.xdc b/src/spi/fpga/axi_spi_timing.xdc index 90770f54..fce0ff68 100644 --- a/src/spi/fpga/axi_spi_timing.xdc +++ b/src/spi/fpga/axi_spi_timing.xdc @@ -1,3 +1,4 @@ # SPI slave clock create_clock -name spi_s_sclk -period 10 [get_ports spi_s_sclk] - +# SPI master clock +create_clock -name spi_m_sclk -period 10 [get_ports spi_m_sclk] diff --git a/src/spi/hdl/parallella_spi.v b/src/spi/hdl/parallella_spi.v index 46e14fc1..f884aad6 100644 --- a/src/spi/hdl/parallella_spi.v +++ b/src/spi/hdl/parallella_spi.v @@ -124,7 +124,7 @@ module parallella_spi(/*AUTOARG*/ assign spi_m_sclk = gpio_out[3]; /* NOTE: 0 = in, 1 = out */ - assign gpio_dir[NGPIO-1:0] = {{(NGPIO-8){1'b0}}, 8'b01001011}; + assign gpio_dir[NGPIO-1:0] = {{(NGPIO-11){1'b0}}, 8'b01001011, 3'b000}; assign constant_zero = 1'b0; assign constant_one = 1'b1; diff --git a/src/spi/hdl/spi_master_io.v b/src/spi/hdl/spi_master_io.v index 1dad7d6c..0daa1270 100644 --- a/src/spi/hdl/spi_master_io.v +++ b/src/spi/hdl/spi_master_io.v @@ -146,10 +146,11 @@ module spi_master_io //generate access pulse at rise of ss oh_rise2pulse - pulse (.out (rx_access), + pulse (.nreset(nreset), + .out (rx_access), .clk (clk), .in (ss)); - + oh_ser2par #(.PW(64), .SW(1)) ser2par (//output diff --git a/src/spi/hdl/spi_slave_io.v b/src/spi/hdl/spi_slave_io.v index a85876a7..7feb51b4 100644 --- a/src/spi/hdl/spi_slave_io.v +++ b/src/spi/hdl/spi_slave_io.v @@ -165,9 +165,10 @@ module spi_slave_io #( parameter PW = 104 // packet width .din (ss)); //create single cycle pulse - oh_rise2pulse r2p (.out (ss_pulse), - .clk (clk), - .in (ss_sync)); + oh_rise2pulse r2p (.nreset (nreset), + .out (ss_pulse), + .clk (clk), + .in (ss_sync)); assign spi_fetch = ss_pulse & (command_reg[7:6]==`SPI_FETCH);