/* * spiio.c - Very simple SPI I/O example * * Written 2011 by Werner Almesberger * Copyright 2011 Werner Almesberger * * 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; either version 2 of the License, or * (at your option) any later version. */ #include <stdint.h> #include <stdlib.h> #include <stdio.h> #include <unistd.h> #include <string.h> #include <fcntl.h> #include <sys/mman.h> enum { VDD_OFF = 1 << 2, /* VDD disable, PD02 */ MMC_CMD = 1 << 8, /* CMD, PD08 */ MMC_CLK = 1 << 9, /* CLK, PD09 */ MMC_DAT0 = 1 << 10, /* DAT0, PD10 */ MMC_DAT1 = 1 << 11, /* DAT1, PD11 */ MMC_DAT2 = 1 << 12, /* DAT2, PD12 */ MMC_DAT3 = 1 << 13, /* DAT3/CD, PD13 */ }; #define MOSI MMC_CMD #define MISO MMC_DAT0 #define SCLK MMC_DAT2 #define nSEL MMC_DAT3 #define SOC_BASE 0x10000000 #define REG(n) (*(volatile uint32_t *) (mem+(n))) #define GPIO(n) REG(0x10000+(n)) #define PDPIN GPIO(0x300) /* port D pin level */ #define PDDATS GPIO(0x314) /* port D data set */ #define PDDATC GPIO(0x318) /* port D data clear */ #define PDFUNS GPIO(0x344) /* port D function set */ #define PDFUNC GPIO(0x348) /* port D function clear */ #define PDDIRS GPIO(0x364) /* port D direction set */ #define PDDIRC GPIO(0x368) /* port D direction clear */ #define PAGE_SIZE 4096 static void *mem; /* ----- Low-level SPI operations ------------------------------------------ */ static void spi_begin(void) { PDDATC = nSEL; } static void spi_end(void) { PDDATS = nSEL; } static void spi_send(uint8_t v) { uint8_t mask; for (mask = 0x80; mask; mask >>= 1) { if (v & mask) PDDATS = MOSI; else PDDATC = MOSI; PDDATS = SCLK; PDDATC = SCLK; } } static uint8_t spi_recv(void) { uint8_t res = 0; uint8_t mask; for (mask = 0x80; mask; mask >>= 1) { if (PDPIN & MISO) res |= mask; PDDATS = SCLK; PDDATC = SCLK; } return res; } static uint8_t spi_bidir(uint8_t v) { uint8_t res = 0; uint8_t mask; for (mask = 0x80; mask; mask >>= 1) { if (PDPIN & MISO) res |= mask; if (v & mask) PDDATS = MOSI; else PDDATC = MOSI; PDDATS = SCLK; PDDATC = SCLK; } return res; } /* ---- High-level -------------------------------------------------------- */ static void spi_io(const char *s) { const char *p; uint8_t ch; spi_begin(); for (p = s; *p; p++) { ch = spi_bidir(*s); if (!ch) continue; if (strchr("\t\n\r", ch) || (ch >= ' ' && ch <= '~')) putchar(ch); else putchar('?'); } spi_end(); putchar('\n'); } int main(int argc, char **argv) { int fd, i; fd = open("/dev/mem", O_RDWR | O_SYNC); if (fd < 0) { perror("/dev/mem"); exit(1); } mem = mmap(NULL, PAGE_SIZE*3*16, PROT_READ | PROT_WRITE, MAP_SHARED, fd, SOC_BASE); if (mem == MAP_FAILED) { perror("mmap"); exit(1); } /* set the output levels */ PDDATS = nSEL | VDD_OFF; PDDATC = SCLK; PDFUNC = MOSI | MISO | SCLK | nSEL; /* set the pin directions */ PDDIRC = MISO; PDDIRS = MOSI | SCLK | nSEL; for (i = 1; i != argc; i++) spi_io(argv[i]); /* make all MMC pins inputs */ PDDIRC = MOSI | MISO | SCLK | nSEL; return 0; }