ini
[aversive.git] / modules / devices / radio / cc2420 / cc2420.c
1 /*  
2  *  Copyright Droids Corporation (2008)
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,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *  GNU General Public License for more details.
13  *
14  *  You should have received a copy of the GNU General Public License
15  *  along with this program; if not, write to the Free Software
16  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17  *
18  */
19
20 /*
21  * Author : Julien LE GUEN - jlg@jleguen.info
22  */
23
24 #include <aversive.h>
25 #include <aversive/wait.h>
26 #include <aversive/error.h>
27
28 #include <spi.h>
29
30 #include <cc2420.h>
31 #include <cc2420_arch.h>
32 #include <cc2420_config.h>
33
34
35 #define SLAVE_SELECT()          spi_slave_select(g_slave_adr)
36 #define SLAVE_DESELECT()        spi_slave_deselect(g_slave_adr)
37
38 /*
39 #define SLAVE_SELECT() PORTC &= 0xFE
40 #define SLAVE_DESELECT() PORTC |= 0x01
41 */
42
43 volatile static uint8_t g_slave_adr;
44
45
46 /*
47  * Read status byte
48  */
49 uint8_t cc2420_get_status(void)
50 {
51         uint8_t tmp;
52         SLAVE_SELECT();
53         tmp = spi_send_and_receive_byte(SNOP);
54         SLAVE_DESELECT();
55         return tmp;
56 }
57
58 /*
59  * Write to a strobe register
60  * Returns Status byte
61  */
62 uint8_t cc2420_strobe_register(uint8_t reg)
63 {
64         uint8_t tmp;
65         SLAVE_SELECT();
66         tmp = spi_send_and_receive_byte(reg);
67         SLAVE_DESELECT();
68         return tmp;
69 }
70
71 /*
72  * Read a two-bytes register
73  */
74 uint16_t cc2420_read_register(uint8_t reg)
75 {
76         uint16_t value;
77         SLAVE_SELECT();
78         /* Send address and READ action */
79         spi_send_byte(REG_BIT | READ_BIT | (reg & REG_MASK));
80         /* Just send nothing (0x00) and read the value back (MSB first) */
81         value = spi_receive_byte();
82         value = (value<<8) | spi_receive_byte();
83         SLAVE_DESELECT();
84         return value;
85 }
86
87 /*
88  * Write to a two-bytes register
89  */
90 void cc2420_write_register(uint8_t reg, uint16_t value)
91 {
92         SLAVE_SELECT();
93         /* Send address and WRITE action */
94         spi_send_byte(REG_BIT | WRITE_BIT | (reg & REG_MASK));
95         /* Send the value, ignore the status byte in return */
96         spi_send_byte((uint8_t)((value & 0xFF00)>>8));
97         spi_send_byte((uint8_t)(value & 0x00FF));
98         SLAVE_DESELECT();
99 }
100
101 /*
102  * Write the contents of a buffer to TXFIFO
103  * Returns last read status byte
104  */
105 uint8_t cc2420_write_txfifo(uint8_t *buffer, uint8_t length)
106 {
107         uint8_t status;
108         uint8_t i;
109         SLAVE_SELECT();
110         /* Flush the FIFO - don't need the status byte */
111         //spi_send_byte(SFLUSHTX);
112         /* TXFIFO Register address */
113         NOTICE(E_CC2420, "Writing %d bytes to TXFIFO at address 0x%x", length, REG_BIT | WRITE_BIT | TXFIFO);
114         spi_send_byte(REG_BIT | WRITE_BIT | TXFIFO);
115         /* Send all bytes */
116         for(i = 0; i < length; i++)
117         {
118                 /* We may need the status byte at any time
119                  * For instance, to detect TXFIFO underflow */
120                 status = spi_send_and_receive_byte(buffer[i]);
121         }
122         SLAVE_DESELECT();
123         return status;
124 }
125
126 /*
127  * Write the contents of a buffer to RXFIFO
128  * Returns last read status byte
129  */
130 uint8_t cc2420_write_rxfifo(uint8_t *buffer, uint8_t length)
131 {
132         uint8_t status;
133         uint8_t i;
134         SLAVE_SELECT();
135         /* Flush the FIFO - don't need the status byte */
136         spi_send_byte(SFLUSHRX);
137         /* RXFIFO Register address */
138         spi_send_byte(REG_BIT | WRITE_BIT | RXFIFO);
139         /* Send all bytes */
140         for(i = 0; i < length; i++)
141         {
142                 /* We may need the status byte at any time
143                  * For instance, to detect TXFIFO underflow */
144                 status = spi_send_and_receive_byte(buffer[i]);
145         }
146         SLAVE_DESELECT();
147         return status;
148 }
149
150 /*
151  * Read the contents of RXFIFO into a buffer
152  */
153 void cc2420_read_rxfifo(uint8_t *buffer, uint8_t length)
154 {
155         uint8_t i;
156         SLAVE_SELECT();
157         /* RXFIFO Register address */
158         spi_send_byte(REG_BIT | READ_BIT | RXFIFO);
159         /* Read all bytes */
160         for(i = 0; i < length; i++)
161         {
162                 buffer[i] = spi_receive_byte();
163         }
164         SLAVE_DESELECT();
165 }
166
167 /* XXX Ca fait de la merde dans le coin la... */
168
169 /*
170  *      Write to a RAM address one or several byte(s)
171  *      /!\ This is NOT foolproof, you have to be sure of the
172  *      address you write to, and the length of your buffer
173  */
174 void cc2420_write_ram(uint16_t addr, uint8_t *buffer, uint16_t length)
175 {
176         uint16_t i;
177         SLAVE_SELECT();
178         /* Forge the address */
179         spi_send_byte(RAM_BIT | (addr & RAM_MASK));
180         spi_send_byte((((addr>>1) & BANK_MASK) | RAM_READ_WRITE));
181         /* Send the data */
182         for(i = 0; i < length; i++)
183         {
184                 spi_send_byte((uint8_t)buffer[i]);
185         }
186         SLAVE_DESELECT();
187 }
188
189 /*
190  *      Read from RAM. Same warning.
191  */
192 void cc2420_read_ram(uint16_t addr, uint8_t *buffer, uint16_t length)
193 {
194         uint16_t i;
195         SLAVE_SELECT();
196         /* Forge the address */
197         spi_send_byte((RAM_BIT | (addr & RAM_MASK)));
198         spi_send_byte((((addr>>1) & BANK_MASK) | RAM_READ));
199         /* Receive the data */
200         for(i = 0; i < length; i++)
201         {
202                 buffer[i] = spi_receive_byte();
203         }
204         SLAVE_DESELECT();
205 }
206
207
208
209 /*
210  *      Initialize ports and starts-up the chip
211  */
212 void cc2420_init(void)
213 {
214         NOTICE(E_CC2420, "Initialization");
215         /* Check and start SPI module */
216         if (spi_get_mode() == SPI_MODE_UNINIT)
217         {
218                 g_slave_adr = spi_register_ss_line(&CC2420_SS_PORT, CC2420_SS_PIN);
219                 spi_init(SPI_MODE_MASTER, SPI_FORMAT_0, SPI_CLK_RATE_2);
220         }
221
222         NOTICE(E_CC2420, "Registered slave line: %d", g_slave_adr);
223
224         /* Configure all IO ports in input */
225         DDR(CC2420_FIFO_PORT)   &= ~(_BV(CC2420_FIFO_PIN));
226         DDR(CC2420_FIFOP_PORT)  &= ~(_BV(CC2420_FIFOP_PIN));
227         DDR(CC2420_CCA_PORT)    &= ~(_BV(CC2420_CCA_PIN));
228         DDR(CC2420_SFD_PORT)    &= ~(_BV(CC2420_SFD_PIN));
229
230         CC2420_SS_DDR = 0x01;
231
232         /* Enable on-chip voltage regulator */
233 #ifdef CC2420_VREG_ENABLE
234         NOTICE(E_CC2420, "Enable on-chip voltage regulator");
235         DDR(CC2420_VREG_EN_PORT) |= _BV(CC2420_VREG_EN_PIN);
236         CC2420_VREG_EN_PORT |= _BV(CC2420_VREG_EN_PIN);
237         wait_ms(1);
238 #endif
239
240         /* Reset the chip */
241 #ifdef CC2420_RESET_ENABLE
242         NOTICE(E_CC2420, "Reset radio chip");
243         DDR(CC2420_RESET_PORT) |= _BV(CC2420_RESET_PIN);
244         CC2420_RESET_PORT &= ~(_BV(CC2420_RESET_PIN));
245         wait_ms(1);
246         CC2420_RESET_PORT |= _BV(CC2420_RESET_PIN);
247         wait_ms(1);
248 #endif
249
250
251         /* Start the oscillator */
252         NOTICE(E_CC2420, "Start the oscillator");
253         
254         /* Select the CC2420 SS line */
255         SLAVE_SELECT();
256         spi_send_byte(SXOSCON);
257         /* Release SS line */
258         SLAVE_DESELECT();
259
260         /* Wait for stability */
261         while(!CC2420_STATUS_CHECK(XOSC16M_STABLE))
262                 ;
263
264         NOTICE(E_CC2420, "Init done");
265 }