Werner's Miscellanea
Sign in or create your account | Project List | Help
Werner's Miscellanea Git Source Tree
Root/
Source at commit b64d4673d8dc291f783b6459c010705519cb052b created 10 years 27 days ago. By Werner Almesberger, ircstat/mlstat: change "milkymist" label to "m-labs" | |
---|---|
1 | /* |
2 | * spiio.c - Very simple SPI I/O example |
3 | * |
4 | * Written 2011 by Werner Almesberger |
5 | * Copyright 2011 Werner Almesberger |
6 | * |
7 | * This program is free software; you can redistribute it and/or modify |
8 | * it under the terms of the GNU General Public License as published by |
9 | * the Free Software Foundation; either version 2 of the License, or |
10 | * (at your option) any later version. |
11 | */ |
12 | |
13 | |
14 | #include <stdint.h> |
15 | #include <stdlib.h> |
16 | #include <stdio.h> |
17 | #include <unistd.h> |
18 | #include <string.h> |
19 | #include <fcntl.h> |
20 | #include <sys/mman.h> |
21 | |
22 | |
23 | enum { |
24 | VDD_OFF = 1 << 2, /* VDD disable, PD02 */ |
25 | MMC_CMD = 1 << 8, /* CMD, PD08 */ |
26 | MMC_CLK = 1 << 9, /* CLK, PD09 */ |
27 | MMC_DAT0 = 1 << 10, /* DAT0, PD10 */ |
28 | MMC_DAT1 = 1 << 11, /* DAT1, PD11 */ |
29 | MMC_DAT2 = 1 << 12, /* DAT2, PD12 */ |
30 | MMC_DAT3 = 1 << 13, /* DAT3/CD, PD13 */ |
31 | }; |
32 | |
33 | #define MOSI MMC_CMD |
34 | #define MISO MMC_DAT0 |
35 | #define SCLK MMC_DAT2 |
36 | #define nSEL MMC_DAT3 |
37 | |
38 | |
39 | #define SOC_BASE 0x10000000 |
40 | |
41 | #define REG(n) (*(volatile uint32_t *) (mem+(n))) |
42 | |
43 | #define GPIO(n) REG(0x10000+(n)) |
44 | |
45 | #define PDPIN GPIO(0x300) /* port D pin level */ |
46 | #define PDDATS GPIO(0x314) /* port D data set */ |
47 | #define PDDATC GPIO(0x318) /* port D data clear */ |
48 | #define PDFUNS GPIO(0x344) /* port D function set */ |
49 | #define PDFUNC GPIO(0x348) /* port D function clear */ |
50 | #define PDDIRS GPIO(0x364) /* port D direction set */ |
51 | #define PDDIRC GPIO(0x368) /* port D direction clear */ |
52 | |
53 | #define PAGE_SIZE 4096 |
54 | |
55 | |
56 | static void *mem; |
57 | |
58 | |
59 | /* ----- Low-level SPI operations ------------------------------------------ */ |
60 | |
61 | |
62 | static void spi_begin(void) |
63 | { |
64 | PDDATC = nSEL; |
65 | } |
66 | |
67 | |
68 | static void spi_end(void) |
69 | { |
70 | PDDATS = nSEL; |
71 | } |
72 | |
73 | |
74 | static void spi_send(uint8_t v) |
75 | { |
76 | uint8_t mask; |
77 | |
78 | for (mask = 0x80; mask; mask >>= 1) { |
79 | if (v & mask) |
80 | PDDATS = MOSI; |
81 | else |
82 | PDDATC = MOSI; |
83 | PDDATS = SCLK; |
84 | PDDATC = SCLK; |
85 | } |
86 | } |
87 | |
88 | |
89 | static uint8_t spi_recv(void) |
90 | { |
91 | uint8_t res = 0; |
92 | uint8_t mask; |
93 | |
94 | for (mask = 0x80; mask; mask >>= 1) { |
95 | if (PDPIN & MISO) |
96 | res |= mask; |
97 | PDDATS = SCLK; |
98 | PDDATC = SCLK; |
99 | } |
100 | return res; |
101 | } |
102 | |
103 | |
104 | static uint8_t spi_bidir(uint8_t v) |
105 | { |
106 | uint8_t res = 0; |
107 | uint8_t mask; |
108 | |
109 | for (mask = 0x80; mask; mask >>= 1) { |
110 | if (PDPIN & MISO) |
111 | res |= mask; |
112 | if (v & mask) |
113 | PDDATS = MOSI; |
114 | else |
115 | PDDATC = MOSI; |
116 | PDDATS = SCLK; |
117 | PDDATC = SCLK; |
118 | } |
119 | return res; |
120 | } |
121 | |
122 | |
123 | /* ---- High-level -------------------------------------------------------- */ |
124 | |
125 | |
126 | static void spi_io(const char *s) |
127 | { |
128 | const char *p; |
129 | uint8_t ch; |
130 | |
131 | spi_begin(); |
132 | for (p = s; *p; p++) { |
133 | ch = spi_bidir(*s); |
134 | if (!ch) |
135 | continue; |
136 | if (strchr("\t\n\r", ch) || (ch >= ' ' && ch <= '~')) |
137 | putchar(ch); |
138 | else |
139 | putchar('?'); |
140 | } |
141 | spi_end(); |
142 | putchar('\n'); |
143 | } |
144 | |
145 | |
146 | int main(int argc, char **argv) |
147 | { |
148 | int fd, i; |
149 | |
150 | fd = open("/dev/mem", O_RDWR | O_SYNC); |
151 | if (fd < 0) { |
152 | perror("/dev/mem"); |
153 | exit(1); |
154 | } |
155 | mem = mmap(NULL, PAGE_SIZE*3*16, PROT_READ | PROT_WRITE, |
156 | MAP_SHARED, fd, SOC_BASE); |
157 | if (mem == MAP_FAILED) { |
158 | perror("mmap"); |
159 | exit(1); |
160 | } |
161 | |
162 | /* set the output levels */ |
163 | PDDATS = nSEL | VDD_OFF; |
164 | PDDATC = SCLK; |
165 | |
166 | PDFUNC = MOSI | MISO | SCLK | nSEL; |
167 | |
168 | /* set the pin directions */ |
169 | PDDIRC = MISO; |
170 | PDDIRS = MOSI | SCLK | nSEL; |
171 | |
172 | for (i = 1; i != argc; i++) |
173 | spi_io(argv[i]); |
174 | |
175 | /* make all MMC pins inputs */ |
176 | PDDIRC = MOSI | MISO | SCLK | nSEL; |
177 | |
178 | return 0; |
179 | } |
180 |
Branches:
master