Merge branch 'master' into mm-ms5611
[fw/altos] / src / attiny / ao_spi_attiny.c
diff --git a/src/attiny/ao_spi_attiny.c b/src/attiny/ao_spi_attiny.c
new file mode 100644 (file)
index 0000000..064876d
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ * Copyright © 2011 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include <ao.h>
+
+/*
+ * ATtiny USI as a SPI interface
+ */
+
+/*
+ * Transfer one byte in/out of the USI interface
+ */
+
+/* Three wire mode */
+#define SPI_USICR_WM   ((0 << USIWM1) | (1 << USIWM0)) 
+#define SPI_USICR_CS   ((1 << USICS1) | (0 << USICS0) | (1 << USICLK))
+
+#define SPI_USICR_FAST_2 ((1 << USIWM0) | (1 << USITC))
+#define SPI_USICR_FAST_1 ((1 << USIWM0) | (1 << USITC) | (1 << USICLK))
+
+
+static uint8_t
+ao_spi_transfer(uint8_t i)
+{
+       /* Load data register */
+       USIDR = i;
+
+#if 1
+       USISR = (1 << USIOIF);
+       do {
+               USICR = SPI_USICR_WM | SPI_USICR_CS | (1 << USITC);
+       } while ((USISR & (1 << USIOIF)) == 0);
+#else
+       /* 8 clocks */
+       USICR = SPI_USICR_FAST_1;
+       USICR = SPI_USICR_FAST_2;
+
+       USICR = SPI_USICR_FAST_1;
+       USICR = SPI_USICR_FAST_2;
+
+       USICR = SPI_USICR_FAST_1;
+       USICR = SPI_USICR_FAST_2;
+
+       USICR = SPI_USICR_FAST_1;
+       USICR = SPI_USICR_FAST_2;
+
+       USICR = SPI_USICR_FAST_1;
+       USICR = SPI_USICR_FAST_2;
+
+       USICR = SPI_USICR_FAST_1;
+       USICR = SPI_USICR_FAST_2;
+
+       USICR = SPI_USICR_FAST_1;
+       USICR = SPI_USICR_FAST_2;
+
+       USICR = SPI_USICR_FAST_1;
+       USICR = SPI_USICR_FAST_2;
+#endif
+
+       /* Pull data from the port */
+       return USIDR;
+}
+
+/* Send bytes over SPI.
+ *
+ * This just polls; the SPI is set to go as fast as possible,
+ * so using interrupts would take way too long
+ */
+void
+ao_spi_send_bus(void __xdata *block, uint16_t len) __reentrant
+{
+       uint8_t *d = block;
+
+       while (len--)
+               ao_spi_transfer (*d++);
+}
+
+/* Receive bytes over SPI.
+ *
+ * Poll, sending zeros and reading data back
+ */
+void
+ao_spi_recv_bus(void __xdata *block, uint16_t len) __reentrant
+{
+       uint8_t *d = block;
+
+       while (len--)
+               *d++ = ao_spi_transfer (0xff);
+}
+
+/*
+ * Initialize USI
+ *
+ * Chip select is the responsibility of the caller
+ */
+
+void
+ao_spi_init(void)
+{
+#if 1
+       USICR = (1 << USIWM0) | (1 << USICS1) | (1 << USICLK);
+#else
+       USICR = SPI_USICR_FAST_2;
+#endif
+       SPI_DIR &= ~(1 << DDB0);        /* DI */
+       SPI_DIR |= (1 << DDB1);         /* DO */
+       SPI_DIR |= (1 << DDB2);         /* SCLK */
+       SPI_DIR |= (1 << DDB3);         /* CS */
+}