altos/test: Adjust CRC error rate after FEC fix
[fw/altos] / src / avr / ao_spi_slave.c
1 /*
2  * Copyright © 2011 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 "ao.h"
20
21 uint8_t
22 ao_spi_slave_recv(void *buf, uint16_t len)
23 {
24         uint8_t *b = buf;
25         while (len--) {
26                 while (!(SPSR & (1 << SPIF)))
27                         if ((PINB & (1 << PINB0)))
28                                 return 0;
29                 *b++ = SPDR;
30         }
31         return 1;
32 }
33
34 void
35 ao_spi_slave_send(void *buf, uint16_t len)
36 {
37         uint8_t *b = buf;
38         while (len--) {
39                 SPDR = *b++;
40                 while (!(SPSR & (1 << SPIF)))
41                         if ((PINB & (1 << PINB0)))
42                                 return;
43         }
44         /* Clear pending SPIF bit by reading */
45         (void) SPDR;
46 }
47
48 static uint8_t ao_spi_slave_running;
49
50 ISR(PCINT0_vect, ISR_BLOCK)
51 {
52 #if SPI_SLAVE_PIN_0_3
53         if ((PINB & (1 << PORTB0)) == 0)
54 #endif
55 #if SPI_SLAVE_PIN_2_5
56         if ((PINB & (1 << PORTB2)) == 0)
57 #endif
58         {
59                 if (!ao_spi_slave_running) {
60                         ao_spi_slave_running = 1;
61                         ao_spi_slave();
62                 }
63         } else {
64                 ao_spi_slave_running = 0;
65         }
66 }
67
68 void
69 ao_spi_slave_init(void)
70 {
71         /* We'd like to have a pull-up on SS so that disconnecting the
72          * TM would cause any SPI transaction to abort. However, when
73          * I tried that, SPI transactions would spontaneously abort,
74          * making me assume that we needed a less aggressive pull-up
75          * than is offered inside the AVR
76          */
77 #if SPI_SLAVE_PIN_0_3
78         PCMSK0 |= (1 << PCINT0);        /* Enable PCINT0 pin change */
79         PCICR |= (1 << PCIE0);          /* Enable pin change interrupt */
80
81         DDRB = ((DDRB & 0xf0) |
82                 (1 << 3) |              /* MISO, output */
83                 (0 << 2) |              /* MOSI, input */
84                 (0 << 1) |              /* SCK, input */
85                 (0 << 0));              /* SS, input */
86
87         PORTB = ((PORTB & 0xf0) |
88                  (1 << 3) |             /* MISO, output */
89                  (0 << 2) |             /* MOSI, no pull-up */
90                  (0 << 1) |             /* SCK, no pull-up */
91                  (1 << 0));             /* SS, pull-up */
92 #endif
93 #if SPI_SLAVE_PIN_2_5
94         PCMSK0 |= (1 << PCINT2);        /* Enable PCINT2 pin change */
95         PCICR |= (1 << PCIE0);          /* Enable pin change interrupt */
96
97         DDRB = ((DDRB & 0xf0) |
98                 (0 << 5) |              /* SCK, input */
99                 (1 << 4) |              /* MISO, output */
100                 (0 << 3) |              /* MOSI, input */
101                 (0 << 2));              /* SS, input */
102
103         PORTB = ((PORTB & 0xf0) |
104                  (0 << 5) |             /* SCK, no pull-up */
105                  (1 << 4) |             /* MISO, output */
106                  (0 << 3) |             /* MOSI, no pull-up */
107                  (1 << 2));             /* SS, pull-up */
108 #endif  
109
110         SPCR = (0 << SPIE) |            /* Disable SPI interrupts */
111                 (1 << SPE) |            /* Enable SPI */
112                 (0 << DORD) |           /* MSB first */
113                 (0 << MSTR) |           /* Slave mode */
114                 (0 << CPOL) |           /* Clock low when idle */
115                 (0 << CPHA);            /* Sample at leading clock edge */
116 }