6cf276a0cc5f9740b0ae95926bad45a7e6b1475c
[fw/altos] / target / ee / ee.c
1 /*
2  * Copyright © 2008 Keith Packard <keithp@keithp.com>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
17  */
18
19 #include <stdint.h>
20
21 /*
22  * Validate the SPI-connected EEPROM
23  */
24
25 sfr at 0x80 P0;
26 sfr at 0x90 P1;
27 sfr at 0xA0 P2;
28 sfr at 0xC6 CLKCON;
29
30 sfr at 0xF1 PERCFG;
31 #define PERCFG_T1CFG_ALT_1      (0 << 6)
32 #define PERCFG_T1CFG_ALT_2      (1 << 6)
33
34 #define PERCFG_T3CFG_ALT_1      (0 << 5)
35 #define PERCFG_T3CFG_ALT_2      (1 << 5)
36
37 #define PERCFG_T4CFG_ALT_1      (0 << 4)
38 #define PERCFG_T4CFG_ALT_2      (1 << 4)
39
40 #define PERCFG_U1CFG_ALT_1      (0 << 1)
41 #define PERCFG_U1CFG_ALT_2      (1 << 1)
42
43 #define PERCFG_U0CFG_ALT_1      (0 << 0)
44 #define PERCFG_U0CFG_ALT_2      (1 << 0)
45
46 sfr at 0xF2 ADCCFG;
47 sfr at 0xF3 P0SEL;
48 sfr at 0xF4 P1SEL;
49 sfr at 0xF5 P2SEL;
50
51 sfr at 0xFD P0DIR;
52 sfr at 0xFE P1DIR;
53 sfr at 0xFF P2DIR;
54 sfr at 0x8F P0INP;
55 sfr at 0xF6 P1INP;
56 sfr at 0xF7 P2INP;
57
58 sfr at 0x89 P0IFG;
59 sfr at 0x8A P1IFG;
60 sfr at 0x8B P2IFG;
61
62 sbit at 0x90 P1_0;
63 sbit at 0x91 P1_1;
64 sbit at 0x92 P1_2;
65 sbit at 0x93 P1_3;
66 sbit at 0x94 P1_4;
67 sbit at 0x95 P1_5;
68 sbit at 0x96 P1_6;
69 sbit at 0x97 P1_7;
70
71 /*
72  * UART registers
73  */
74
75 sfr at 0x86 U0CSR;
76 sfr at 0xF8 U1CSR;
77
78 # define UxCSR_MODE_UART                (1 << 7)
79 # define UxCSR_MODE_SPI                 (0 << 7)
80 # define UxCSR_RE                       (1 << 6)
81 # define UxCSR_SLAVE                    (1 << 5)
82 # define UxCSR_MASTER                   (0 << 5)
83 # define UxCSR_FE                       (1 << 4)
84 # define UxCSR_ERR                      (1 << 3)
85 # define UxCSR_RX_BYTE                  (1 << 2)
86 # define UxCSR_TX_BYTE                  (1 << 1)
87 # define UxCSR_ACTIVE                   (1 << 0)
88
89 sfr at 0xc4 U0UCR;
90 sfr at 0xfb U1UCR;
91
92 sfr at 0xc5 U0GCR;
93 sfr at 0xfc U1GCR;
94
95 # define UxGCR_CPOL_NEGATIVE            (0 << 7)
96 # define UxGCR_CPOL_POSITIVE            (1 << 7)
97 # define UxGCR_CPHA_FIRST_EDGE          (0 << 6)
98 # define UxGCR_CPHA_SECOND_EDGE         (1 << 6)
99 # define UxGCR_ORDER_LSB                (0 << 5)
100 # define UxGCR_ORDER_MSB                (1 << 5)
101 # define UxGCR_BAUD_E_MASK              (0x1f)
102 # define UxGCR_BAUD_E_SHIFT             0
103
104 sfr at 0xc1 U0DBUF;
105 sfr at 0xf9 U1DBUF;
106 sfr at 0xc2 U0BAUD;
107 sfr at 0xfa U1BAUD;
108
109 #define MOSI    P1_5
110 #define MISO    P1_4
111 #define SCK     P1_3
112 #define CS      P1_2
113
114 #define DEBUG   P1_1
115
116 #define BITBANG 0
117 #define USART   1
118
119 #define nop()   _asm nop _endasm;
120
121 void
122 delay (unsigned char n)
123 {
124         unsigned char i = 0;
125         unsigned char j = 0;
126
127         while (--n != 0)
128                 while (--i != 0)
129                         while (--j != 0)
130                                 nop();
131 }
132
133 #if BITBANG
134
135 /*
136  * This version directly manipulates the GPIOs to synthesize SPI
137  */
138
139 void
140 bitbang_cs(uint8_t b)
141 {
142         SCK = 0;
143         CS = b;
144         delay(1);
145 }
146
147 void
148 bitbang_out_bit(uint8_t b)
149 {
150         MOSI = b;
151         delay(1);
152         SCK = 1;
153         delay(1);
154         SCK = 0;
155 }
156
157 void
158 bitbang_out_byte(uint8_t byte)
159 {
160         uint8_t s;
161
162         for (s = 0; s < 8; s++) {
163                 uint8_t b = (byte & 0x80) ? 1 : 0;
164                 bitbang_out_bit(b);
165                 byte <<= 1;
166         }
167 }
168
169 uint8_t
170 bitbang_in_bit(void)
171 {
172         uint8_t b;
173         
174         delay(1);
175         SCK = 1;
176         delay(1);
177         b = MISO;
178         SCK = 0;
179         return b;
180 }
181
182 uint8_t
183 bitbang_in_byte(void)
184 {
185         uint8_t byte = 0;
186         uint8_t s;
187         uint8_t b;
188
189         for (s = 0; s < 8; s++) {
190                 b = bitbang_in_bit();
191                 byte = byte << 1;
192                 byte |= b;
193         }
194         return byte;
195 }
196
197 void
198 bit_bang_init(void)
199 {
200         CS = 1;
201         SCK = 0;
202         P1DIR = ((1 << 5) |
203                  (0 << 4) |
204                  (1 << 3) |
205                  (1 << 2) |
206                  (1 << 1));
207 }
208
209 #define spi_init()      bitbang_init()
210 #define spi_out_byte(b) bitbang_out_byte(b)
211 #define spi_in_byte()   bitbang_in_byte()
212 #define spi_cs(b)       bitbang_cs(b)
213 #endif
214
215 #if USART
216
217 /*
218  * This version uses the USART in SPI mode
219  */
220 void
221 usart_init(void)
222 {
223         /*
224          * Configure our chip select line
225          */
226         CS = 1;
227         P1DIR |= (1 << 2);
228         /*
229          * Configure the peripheral pin choices
230          * for both of the serial ports
231          *
232          * Note that telemetrum will use U1CFG_ALT_2
233          * but that overlaps with SPI ALT_2, so until
234          * we can test that this works, we'll set this
235          * to ALT_1
236          */
237         PERCFG = (PERCFG_U1CFG_ALT_1 |
238                   PERCFG_U0CFG_ALT_2);
239
240         /*
241          * Make the SPI pins controlled by the SPI
242          * hardware
243          */
244         P1SEL |= ((1 << 5) | (1 << 4) | (1 << 3));
245
246         /*
247          * SPI in master mode
248          */
249         U0CSR = (UxCSR_MODE_SPI |
250                  UxCSR_MASTER);
251
252         /*
253          * The cc1111 is limited to a 24/8 MHz SPI clock,
254          * while the 25LC1024 is limited to 20MHz. So,
255          * use the 3MHz clock (BAUD_E 17, BAUD_M 0)
256          */
257         U0BAUD = 0;
258         U0GCR = (UxGCR_CPOL_NEGATIVE |
259                  UxGCR_CPHA_FIRST_EDGE |
260                  UxGCR_ORDER_MSB |
261                  (17 << UxGCR_BAUD_E_SHIFT));
262 }
263
264 void
265 usart_cs(uint8_t b)
266 {
267         CS = b;
268 }
269
270 uint8_t
271 usart_in_out(uint8_t byte)
272 {
273         U0DBUF = byte;
274         while ((U0CSR & UxCSR_TX_BYTE) == 0)
275                 ;
276 }
277
278 void
279 usart_out_byte(uint8_t byte)
280 {
281         (void) usart_in_out(byte);
282 }
283
284 uint8_t
285 usart_in_byte(void)
286 {
287         return usart_in_out(0xff);
288 }
289
290 #define spi_init()      usart_init()
291 #define spi_out_byte(b) usart_out_byte(b)
292 #define spi_in_byte()   usart_in_byte()
293 #define spi_cs(b)       usart_cs(b)
294
295 #endif
296
297 uint8_t
298 rdsr(void)
299 {
300         uint8_t status;
301         spi_cs(0);
302         spi_out_byte(0x05);
303         status = spi_in_byte();
304         spi_cs(1);
305         return status;
306 }
307
308 void
309 wrsr(uint8_t status)
310 {
311         spi_cs(0);
312         spi_out_byte(0x01);
313         spi_out_byte(status);
314         spi_cs(1);
315 }
316         
317 void
318 wren(void)
319 {
320         spi_cs(0);
321         spi_out_byte(0x06);
322         spi_cs(1);
323 }
324
325 void
326 write(uint32_t addr, uint8_t *bytes, uint16_t len)
327 {
328         wren();
329         spi_cs(0);
330         spi_out_byte(0x02);
331         spi_out_byte(addr >> 16);
332         spi_out_byte(addr >> 8);
333         spi_out_byte(addr);
334         while (len-- > 0)
335                 spi_out_byte(*bytes++);
336         spi_cs(1);
337         for (;;) {
338                 uint8_t status = rdsr();
339                 if ((status & (1 << 0)) == 0)
340                         break;
341         }
342 }
343
344 void
345 read(uint32_t addr, uint8_t *bytes, uint16_t len)
346 {
347         spi_cs(0);
348         spi_out_byte(0x03);
349         spi_out_byte(addr >> 16);
350         spi_out_byte(addr >> 8);
351         spi_out_byte(addr);
352         while (len-- > 0)
353                 *bytes++ = spi_in_byte();
354         spi_cs(1);
355 }
356
357 void
358 debug_byte(uint8_t byte)
359 {
360         uint8_t s;
361
362         for (s = 0; s < 8; s++) {
363                 DEBUG = byte & 1;
364                 delay(5);
365                 byte >>= 1;
366         }
367 }
368
369 #define STRING  "\360\252"
370 #define LENGTH  2
371
372 main ()
373 {
374         uint8_t status;
375         uint8_t buf[LENGTH];
376         int i;
377
378         P1DIR |= 2;
379         CLKCON = 0;
380         
381         spi_init();
382
383         status = rdsr();
384         /*
385          * Turn off both block-protect bits
386          */
387         status &= ~((1 << 3) | (1 << 2));
388         /*
389          * Turn off write protect enable
390          */
391         status &= ~(1 << 7);
392         wrsr(status);
393         write(0x0, STRING, LENGTH);
394         for (;;) {
395                 read(0x0, buf, LENGTH);
396                 for (i = 0; i < LENGTH; i++)
397                         debug_byte(buf[i]);
398         }
399 }